Newer
Older
cblist = statecbs;
while (cblist) {
if (cblist->callback == callback) {
if (!cbprev)
statecbs = cblist->next;
else
cbprev->next = cblist->next;
free(cblist);
ast_mutex_unlock(&hintlock);
return 0;
}
cbprev = cblist;
cblist = cblist->next;
}
ast_mutex_lock(&hintlock);
/* id greater than zero is a callback with extension */
list = hints;
while (list) {
cblist = list->callbacks;
cbprev = NULL;
while (cblist) {
if (cblist->id==id) {
if (!cbprev)
list->callbacks = cblist->next;
else
cbprev->next = cblist->next;
ast_mutex_unlock(&hintlock);
return 0;
}
cbprev = cblist;
cblist = cblist->next;
}
list = list->next;
ast_mutex_unlock(&hintlock);
return -1;
/*! \brief ast_add_hint: Add hint to hint list, check initial extension state */
static int ast_add_hint(struct ast_exten *e)
{
ast_mutex_lock(&hintlock);
list = hints;
/* Search if hint exists, do nothing */
while (list) {
if (list->exten == e) {
ast_mutex_unlock(&hintlock);
if (option_debug > 1)
ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
return -1;
}
list = list->next;
if (option_debug > 1)
ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
list = malloc(sizeof(struct ast_hint));
if (!list) {
ast_mutex_unlock(&hintlock);
if (option_debug > 1)
ast_log(LOG_DEBUG, "HINTS: Out of memory...\n");
/* Initialize and insert new item at the top */
memset(list, 0, sizeof(struct ast_hint));
list->exten = e;
list->laststate = ast_extension_state2(e);
list->next = hints;
hints = list;
ast_mutex_unlock(&hintlock);
/*! \brief ast_change_hint: Change hint for an extension */
static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
{
ast_mutex_lock(&hintlock);
list = hints;
while(list) {
if (list->exten == oe) {
list->exten = ne;
ast_mutex_unlock(&hintlock);
return 0;
}
list = list->next;
/*! \brief ast_remove_hint: Remove hint from extension */
static int ast_remove_hint(struct ast_exten *e)
/* Cleanup the Notifys if hint is removed */
struct ast_hint *list, *prev = NULL;
struct ast_state_cb *cblist, *cbprev;
ast_mutex_lock(&hintlock);
list = hints;
while(list) {
if (list->exten==e) {
cbprev = NULL;
cblist = list->callbacks;
while (cblist) {
/* Notify with -1 and remove all callbacks */
cbprev = cblist;
cblist = cblist->next;
Kevin P. Fleming
committed
cbprev->callback(list->exten->parent->name, list->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
free(cbprev);
}
list->callbacks = NULL;
if (!prev)
hints = list->next;
else
prev->next = list->next;
free(list);
ast_mutex_unlock(&hintlock);
return 0;
} else {
prev = list;
list = list->next;
}
ast_mutex_unlock(&hintlock);
return -1;
/*! \brief ast_get_hint: Get hint for channel */
int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
{
struct ast_exten *e;
e = ast_hint_extension(c, context, exten);
ast_copy_string(hint, ast_get_extension_app(e), hintsize);
if (name) {
tmp = ast_get_extension_app_data(e);
if (tmp)
ast_copy_string(name, (char *) tmp, namesize);
return -1;
}
return 0;
}
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXISTS);
int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, HELPER_FINDLABEL);
}
int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
{
return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, HELPER_FINDLABEL);
int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_CANMATCH);
int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_MATCHMORE);
}
int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
{
return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_SPAWN);
int ast_exec_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
{
return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, HELPER_EXEC);
}
Kevin P. Fleming
committed
int digit;
char exten[256];
int pos;
int waittime;
Kevin P. Fleming
committed
int autoloopflag;
/* A little initial setup here */
if (c->pbx)
ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
c->pbx = malloc(sizeof(struct ast_pbx));
if (!c->pbx) {
ast_log(LOG_ERROR, "Out of memory\n");
c->cdr = ast_cdr_alloc();
if (!c->cdr) {
ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
free(c->pbx);
return -1;
}
ast_cdr_init(c->cdr, c);
}
}
memset(c->pbx, 0, sizeof(struct ast_pbx));
/* Set reasonable defaults */
c->pbx->rtimeout = 10;
c->pbx->dtimeout = 5;
Kevin P. Fleming
committed
autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);
ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
/* Start by trying whatever the channel is set to */
if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
Kevin P. Fleming
committed
/* If not successful fall back to 's' */
if (option_verbose > 1)
ast_verbose( VERBOSE_PREFIX_2 "Starting %s at %s,%s,%d failed so falling back to exten 's'\n", c->name, c->context, c->exten, c->priority);
ast_copy_string(c->exten, "s", sizeof(c->exten));
if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
/* JK02: And finally back to default if everything else failed */
if (option_verbose > 1)
ast_verbose( VERBOSE_PREFIX_2 "Starting %s at %s,%s,%d still failed so falling back to context 'default'\n", c->name, c->context, c->exten, c->priority);
ast_copy_string(c->context, "default", sizeof(c->context));
if (c->cdr && !c->cdr->start.tv_sec && !c->cdr->start.tv_usec)
while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
/* Something bad happened, or a hangup has been requested. */
if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
(res == '*') || (res == '#')) {
ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
switch(res) {
case AST_PBX_KEEPALIVE:
if (option_debug)
ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
else if (option_verbose > 1)
ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
default:
if (option_debug)
ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
else if (option_verbose > 1)
ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
c->_softhangup =0;
break;
}
/* atimeout */
if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
break;
}
if (c->cdr) {
ast_cdr_update(c);
}
if ((c->_softhangup == AST_SOFTHANGUP_TIMEOUT) && (ast_exists_extension(c,c->context,"T",1,c->cid.cid_num))) {
ast_copy_string(c->exten, "T", sizeof(c->exten));
/* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
c->whentohangup = 0;
c->priority = 0;
c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
ast_copy_string(c->exten, "i", sizeof(c->exten));
c->priority = 1;
} else {
ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
c->name, c->exten, c->context);
} else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
/* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
c->_softhangup = 0;
if (waittime) {
while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
/* As long as we're willing to wait, and as long as it's not defined,
keep reading digits until we can't possibly get a right answer anymore. */
digit = ast_waitfordigit(c, waittime * 1000);
if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
c->_softhangup = 0;
if (!digit)
/* No entry */
break;
if (digit < 0)
/* Error, maybe a hangup */
goto out;
exten[pos++] = digit;
waittime = c->pbx->dtimeout;
}
if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
/* Prepare the next cycle */
ast_copy_string(c->exten, exten, sizeof(c->exten));
/* No such extension */
if (!ast_strlen_zero(exten)) {
/* An invalid extension */
if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
ast_copy_string(c->exten, "i", sizeof(c->exten));
c->priority = 1;
} else {
ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
goto out;
}
/* A simple timeout */
if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
ast_copy_string(c->exten, "t", sizeof(c->exten));
c->priority = 1;
} else {
ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
goto out;
}
}
}
if (c->cdr) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
ast_cdr_update(c);
}
} else {
const char *status;
Kevin P. Fleming
committed
status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
if (!status)
status = "UNKNOWN";
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
if (!strcasecmp(status, "CONGESTION"))
res = pbx_builtin_congestion(c, "10");
else if (!strcasecmp(status, "CHANUNAVAIL"))
res = pbx_builtin_congestion(c, "10");
else if (!strcasecmp(status, "BUSY"))
res = pbx_builtin_busy(c, "10");
goto out;
}
}
if (firstpass)
ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
out:
if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
c->exten[0] = 'h';
c->exten[1] = '\0';
while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
/* Something bad happened, or a hangup has been requested. */
if (option_debug)
ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
else if (option_verbose > 1)
ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
break;
}
c->priority++;
}
}
Kevin P. Fleming
committed
ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
if (res != AST_PBX_KEEPALIVE)
ast_hangup(c);
Kevin P. Fleming
committed
/* Returns 0 on success, non-zero if call limit was reached */
static int increase_call_count(const struct ast_channel *c)
{
int failed = 0;
double curloadavg;
Kevin P. Fleming
committed
ast_mutex_lock(&maxcalllock);
if (option_maxcalls) {
if (countcalls >= option_maxcalls) {
ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
failed = -1;
}
}
if (option_maxload) {
getloadavg(&curloadavg, 1);
if (curloadavg >= option_maxload) {
ast_log(LOG_NOTICE, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
failed = -1;
}
}
Kevin P. Fleming
committed
if (!failed)
countcalls++;
ast_mutex_unlock(&maxcalllock);
return failed;
}
static void decrease_call_count(void)
{
ast_mutex_lock(&maxcalllock);
if (countcalls > 0)
countcalls--;
ast_mutex_unlock(&maxcalllock);
}
static void *pbx_thread(void *data)
{
/* Oh joyeous kernel, we're a new thread, with nothing to do but
answer this channel and get it going.
*/
Kevin P. Fleming
committed
/* NOTE:
The launcher of this function _MUST_ increment 'countcalls'
before invoking the function; it will be decremented when the
PBX has finished running on the channel
*/
Kevin P. Fleming
committed
__ast_pbx_run(c);
decrease_call_count();
Kevin P. Fleming
committed
Kevin P. Fleming
committed
enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
Kevin P. Fleming
committed
if (!c) {
ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
Kevin P. Fleming
committed
return AST_PBX_FAILED;
Kevin P. Fleming
committed
if (increase_call_count(c))
return AST_PBX_CALL_LIMIT;
/* Start a new thread, and get something handling this channel. */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
ast_log(LOG_WARNING, "Failed to create new channel thread\n");
Kevin P. Fleming
committed
return AST_PBX_FAILED;
Kevin P. Fleming
committed
return AST_PBX_SUCCESS;
Kevin P. Fleming
committed
enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
Kevin P. Fleming
committed
enum ast_pbx_result res = AST_PBX_SUCCESS;
if (increase_call_count(c))
return AST_PBX_CALL_LIMIT;
res = __ast_pbx_run(c);
decrease_call_count();
return res;
}
int ast_active_calls(void)
{
return countcalls;
}
int pbx_set_autofallthrough(int newval)
{
int oldval;
oldval = autofallthrough;
if (oldval != newval)
autofallthrough = newval;
return oldval;
}
* This function locks contexts list by &conlist, search for the right context
* structure, leave context list locked and call ast_context_remove_include2
* which removes include, unlock contexts list and return ...
*/
int ast_context_remove_include(const char *context, const char *include, const char *registrar)
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
{
struct ast_context *c;
if (ast_lock_contexts()) return -1;
/* walk contexts and search for the right one ...*/
c = ast_walk_contexts(NULL);
while (c) {
/* we found one ... */
if (!strcmp(ast_get_context_name(c), context)) {
int ret;
/* remove include from this context ... */
ret = ast_context_remove_include2(c, include, registrar);
ast_unlock_contexts();
/* ... return results */
return ret;
}
c = ast_walk_contexts(c);
}
/* we can't find the right one context */
ast_unlock_contexts();
return -1;
}
/*
* When we call this function, &conlock lock must be locked, because when
* we giving *con argument, some process can remove/change this context
* and after that there can be segfault.
*
* This function locks given context, removes include, unlock context and
* return.
*/
int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
if (ast_mutex_lock(&con->lock)) return -1;
/* walk includes */
i = con->includes;
while (i) {
/* find our include */
if (!strcmp(i->name, include) &&
Mark Spencer
committed
(!registrar || !strcmp(i->registrar, registrar))) {
/* remove from list */
if (pi)
pi->next = i->next;
else
con->includes = i->next;
/* free include and return */
free(i);
ast_mutex_unlock(&con->lock);
return 0;
}
pi = i;
i = i->next;
}
/* we can't find the right include */
ast_mutex_unlock(&con->lock);
/*!
* \note This function locks contexts list by &conlist, search for the rigt context
* structure, leave context list locked and call ast_context_remove_switch2
* which removes switch, unlock contexts list and return ...
*/
int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
struct ast_context *c;
if (ast_lock_contexts()) return -1;
/* walk contexts and search for the right one ...*/
c = ast_walk_contexts(NULL);
while (c) {
/* we found one ... */
if (!strcmp(ast_get_context_name(c), context)) {
int ret;
/* remove switch from this context ... */
ret = ast_context_remove_switch2(c, sw, data, registrar);
ast_unlock_contexts();
/* ... return results */
return ret;
}
c = ast_walk_contexts(c);
}
/* we can't find the right one context */
ast_unlock_contexts();
/*!
* \brief This function locks given context, removes switch, unlock context and
* return.
* \note When we call this function, &conlock lock must be locked, because when
* we giving *con argument, some process can remove/change this context
* and after that there can be segfault.
*
*/
int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
if (ast_mutex_lock(&con->lock)) return -1;
/* walk switchs */
i = con->alts;
while (i) {
/* find our switch */
if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
Mark Spencer
committed
(!registrar || !strcmp(i->registrar, registrar))) {
/* remove from list */
if (pi)
pi->next = i->next;
else
con->alts = i->next;
/* free switch and return */
free(i);
ast_mutex_unlock(&con->lock);
return 0;
}
pi = i;
i = i->next;
}
/* we can't find the right switch */
ast_mutex_unlock(&con->lock);
* \note This functions lock contexts list, search for the right context,
* call ast_context_remove_extension2, unlock contexts list and return.
* In this function we are using
*/
int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
{
struct ast_context *c;
if (ast_lock_contexts()) return -1;
/* walk contexts ... */
c = ast_walk_contexts(NULL);
while (c) {
/* ... search for the right one ... */
if (!strcmp(ast_get_context_name(c), context)) {
/* ... remove extension ... */
int ret = ast_context_remove_extension2(c, extension, priority,
registrar);
/* ... unlock contexts list and return */
ast_unlock_contexts();
return ret;
}
c = ast_walk_contexts(c);
}
/* we can't find the right context */
ast_unlock_contexts();
return -1;
}
/*!
* \brief This functionc locks given context, search for the right extension and
* fires out all peer in this extensions with given priority. If priority
* is set to 0, all peers are removed. After that, unlock context and
* return.
* \note When do you want to call this function, make sure that &conlock is locked,
* because some process can handle with your *con context before you lock
* it.
*
int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
{
struct ast_exten *exten, *prev_exten = NULL;
if (ast_mutex_lock(&con->lock)) return -1;
/* go through all extensions in context and search the right one ... */
exten = con->root;
while (exten) {
/* look for right extension */
if (!strcmp(exten->exten, extension) &&
Mark Spencer
committed
(!registrar || !strcmp(exten->registrar, registrar))) {
struct ast_exten *peer;
/* should we free all peers in this extension? (priority == 0)? */
if (priority == 0) {
/* remove this extension from context list */
if (prev_exten)
prev_exten->next = exten->next;
else
con->root = exten->next;
/* fire out all peers */
peer = exten;
while (peer) {
exten = peer->peer;
if (!peer->priority==PRIORITY_HINT)
ast_remove_hint(peer);
peer->datad(peer->data);
free(peer);
peer = exten;
}
ast_mutex_unlock(&con->lock);
return 0;
} else {
/* remove only extension with exten->priority == priority */
struct ast_exten *previous_peer = NULL;
peer = exten;
while (peer) {
/* is this our extension? */
if (peer->priority == priority &&
Mark Spencer
committed
(!registrar || !strcmp(peer->registrar, registrar) )) {
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
/* we are first priority extension? */
if (!previous_peer) {
/* exists previous extension here? */
if (prev_exten) {
/* yes, so we must change next pointer in
* previous connection to next peer
*/
if (peer->peer) {
prev_exten->next = peer->peer;
peer->peer->next = exten->next;
} else
prev_exten->next = exten->next;
} else {
/* no previous extension, we are first
* extension, so change con->root ...
*/
if (peer->peer)
con->root = peer->peer;
else
con->root = exten->next;
}
} else {
/* we are not first priority in extension */
previous_peer->peer = peer->peer;
}
/* now, free whole priority extension */
if (peer->priority==PRIORITY_HINT)
ast_remove_hint(peer);
ast_mutex_unlock(&con->lock);
return 0;
} else {
/* this is not right extension, skip to next peer */
previous_peer = peer;
peer = peer->peer;
}
}
ast_mutex_unlock(&con->lock);
return -1;
}
}
prev_exten = exten;
exten = exten->next;
}
/* we can't find right extension */
ast_mutex_unlock(&con->lock);
/*! \brief Dynamically register a new dial plan application */
int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
Mark Spencer
committed
struct ast_app *tmp, *prev, *cur;
int length;
length = sizeof(struct ast_app);
length += strlen(app) + 1;
if (ast_mutex_lock(&applock)) {
ast_log(LOG_ERROR, "Unable to lock application list\n");
return -1;
}
tmp = apps;
while(tmp) {
if (!strcasecmp(app, tmp->name)) {
ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
ast_mutex_unlock(&applock);
tmp = malloc(length);
memset(tmp, 0, length);
strcpy(tmp->name, app);
tmp->synopsis = synopsis;
tmp->description = description;
Mark Spencer
committed
/* Store in alphabetical order */
cur = apps;
prev = NULL;
while(cur) {
if (strcasecmp(tmp->name, cur->name) < 0)
break;
prev = cur;
cur = cur->next;
}
if (prev) {
tmp->next = prev->next;
prev->next = tmp;
} else {
tmp->next = apps;
apps = tmp;
}
ast_log(LOG_ERROR, "Out of memory\n");
ast_mutex_unlock(&applock);
ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
ast_mutex_unlock(&applock);
if (ast_mutex_lock(&switchlock)) {
ast_log(LOG_ERROR, "Unable to lock switch lock\n");
if (!strcasecmp(tmp->name, sw->name))
break;
prev = tmp;
ast_mutex_unlock(&switchlock);
ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
return -1;
}
sw->next = NULL;
if (prev)
prev->next = sw;
else
switches = sw;
ast_mutex_unlock(&switchlock);
void ast_unregister_switch(struct ast_switch *sw)
if (ast_mutex_lock(&switchlock)) {
ast_log(LOG_ERROR, "Unable to lock switch lock\n");
return;
if (tmp == sw) {
if (prev)
prev->next = tmp->next;
else
switches = tmp->next;
tmp->next = NULL;
break;
ast_mutex_unlock(&switchlock);
/*
* Help for CLI commands ...
*/
static char show_application_help[] =
"Usage: show application <application> [<application> [<application> [...]]]\n"
" Describes a particular application.\n";
static char show_functions_help[] =
"Usage: show functions [like <text>]\n"
" List builtin functions, optionally only those matching a given string\n";
static char show_function_help[] =
"Usage: show function <function>\n"
" Describe a particular dialplan function.\n";
"Usage: show applications [{like|describing} <text>]\n"
" List applications which are currently available.\n"
" If 'like', <text> will be a substring of the app name\n"
" If 'describing', <text> will be a substring of the description\n";
static char show_dialplan_help[] =
"Usage: show dialplan [exten@][context]\n"
" Show dialplan\n";
static char show_switches_help[] =
"Usage: show switches\n"
" Show registered switches\n";
static char show_hints_help[] =
"Usage: show hints\n"
" Show registered hints\n";
/*
* IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
*
*/
/*
* \brief 'show application' CLI command implementation functions ...
*/
/*
* There is a possibility to show informations about more than one
* application at one time. You can type 'show application Dial Echo' and
* you will see informations about these two applications ...
*/
static char *complete_show_application(char *line, char *word,
int pos, int state)