Newer
Older
ast_mutex_unlock(&hintlock);
return -1;
}
memset(cblist, 0, sizeof(struct ast_state_cb));
cblist->id = stateid++; /* Unique ID for this callback */
cblist->callback = callback; /* Pointer to callback routine */
cblist->data = data; /* Data for the callback */
cblist->next = list->callbacks;
list->callbacks = cblist;
ast_mutex_unlock(&hintlock);
/*! \brief ast_extension_state_del: Remove a watcher from the callback list */
int ast_extension_state_del(int id, ast_state_cb_type callback)
{
struct ast_hint *list;
struct ast_state_cb *cblist, *cbprev;
if (!id && !callback)
return -1;
/* id is zero is a callback without extension */
if (!id) {
cbprev = NULL;
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 {
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 %lf 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)
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
{
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);
return -1;
}
/*
* 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)
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
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();
/*
* 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 switch, unlock context and
* return.
*/
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);
return -1;
}
/*
* 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)
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
{
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;
}
/*
* 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.
*
* 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.
*/
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) )) {
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
/* 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);
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\n"
" List builtin functions accessable as $(function args)\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[] =