diff --git a/apps/app_dial.c b/apps/app_dial.c index 722b0795ea417f85278ef935f97cdba6fedf2872..abfb2dd374edd2956d143eb6fc2602f6f6419310 100755 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -175,6 +175,8 @@ static void *do_parking_thread(void *ignore) pu = pu->next; free(pt); } else if (FD_ISSET(pu->chan->fd, &rfds) || FD_ISSET(pu->chan->fd, &efds)) { + if (FD_ISSET(pu->chan->fd, &efds)) + pu->chan->exception = 1; /* See if they need servicing */ f = ast_read(pu->chan); if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) { @@ -306,6 +308,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu if (o->stillgoing) { o->chan->blocking = 0; if (FD_ISSET(o->chan->fd, &rfds) || FD_ISSET(o->chan->fd, &efds)) { + if (FD_ISSET(o->chan->fd, &efds)) + o->chan->exception = 1; f = ast_read(o->chan); if (f) { if (f->frametype == AST_FRAME_CONTROL) { @@ -347,6 +351,8 @@ static struct ast_channel *wait_for_answer(struct ast_channel *in, struct localu } if (FD_ISSET(in->fd, &rfds) || FD_ISSET(in->fd, &efds)) { /* After unblocking the entirity of the list, check for the main channel */ + if (FD_ISSET(in->fd, &efds)) + in->exception = 1; f = ast_read(in); #if 0 if (f && (f->frametype != AST_FRAME_VOICE)) @@ -370,8 +376,7 @@ static int bridge_call(struct ast_channel *chan, struct ast_channel *peer, int a { /* Copy voice back and forth between the two channels. Give the peer the ability to transfer calls with '#<extension' syntax. */ - struct ast_channel *cs[3]; - int to = -1, len; + int len; struct ast_frame *f; struct ast_channel *who; char newext[256], *ptr; @@ -382,98 +387,79 @@ static int bridge_call(struct ast_channel *chan, struct ast_channel *peer, int a return -1; peer->appl = "Bridged Call"; peer->data = chan->name; - cs[0] = chan; - cs[1] = peer; - for (/* ever */;;) { - who = ast_waitfor_n(cs, 2, &to); - if (!who) { - ast_log(LOG_WARNING, "Nobody there??\n"); - continue; - } - f = ast_read(who); - if (!f || ((f->frametype == AST_FRAME_CONTROL) && - ((f->subclass == AST_CONTROL_HANGUP) || - (f->subclass == AST_CONTROL_BUSY)))) + for (;;) { + res = ast_channel_bridge(chan, peer, AST_BRIDGE_DTMF_CHANNEL_1, &f, &who); + if (res < 0) { + ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name); return -1; - if ((f->frametype == AST_FRAME_VOICE) || - (f->frametype == AST_FRAME_DTMF) || - (f->frametype == AST_FRAME_TEXT)) { - if ((f->frametype == AST_FRAME_DTMF) && (who == peer) && allowredirect && - (f->subclass == '#')) { - if (f->subclass == '#') { - memset(newext, 0, sizeof(newext)); - ptr = newext; - len = ast_pbx_longest_extension(chan->context) + 1; - if (len < ast_pbx_longest_extension("default") + 1) - len = ast_pbx_longest_extension("default") + 1; - + } + + if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) || + (f->subclass == AST_CONTROL_CONGESTION)))) { + res = -1; + break; + } + if ((f->frametype == AST_FRAME_DTMF) && (who == peer) && allowredirect && + (f->subclass == '#')) { + memset(newext, 0, sizeof(newext)); + ptr = newext; + len = ast_pbx_longest_extension(chan->context) + 1; + if (len < ast_pbx_longest_extension("default") + 1) + len = ast_pbx_longest_extension("default") + 1; /* Transfer */ - if ((res=ast_streamfile(peer, "pbx-transfer", chan->language))) - break; - if ((res=ast_waitstream(peer, AST_DIGIT_ANY)) < 0) - break; - ast_stopstream(peer); - if (res > 0) { - /* If they've typed a digit already, handle it */ - newext[0] = res; - ptr++; - len --; - } - res = ast_readstring(peer, ptr, len, 3000, 2000, "#"); - if (res) - break; - if (!strcmp(newext, parking_ext)) { - if (!park_call(chan, peer)) { - /* We return non-zero, but tell the PBX not to hang the channel when - the thread dies -- We have to be careful now though. We are responsible for - hanging up the channel, else it will never be hung up! */ - res=AST_PBX_KEEPALIVE; - break; - } else { - ast_log(LOG_WARNING, "Unable to park call %s\n", chan->name); - } - /* XXX Maybe we should have another message here instead of invalid extension XXX */ - } else if (ast_exists_extension(chan, peer->context, newext, 1)) { - /* Set the channel's new extension, since it exists, using peer context */ - strncpy(chan->exten, newext, sizeof(chan->exten)); - strncpy(chan->context, peer->context, sizeof(chan->context)); - chan->priority = 0; - ast_frfree(f); - res=0; - break; - } else if (ast_exists_extension(chan, "default", newext, 1)) { - /* Set the channel's new extension, since it exists, using peer context */ - strncpy(chan->exten, newext, sizeof(chan->exten)); - strncpy(chan->context, "default", sizeof(chan->context)); - chan->priority = 0; - ast_frfree(f); - res=0; + if ((res=ast_streamfile(peer, "pbx-transfer", chan->language))) + break; + if ((res=ast_waitstream(peer, AST_DIGIT_ANY)) < 0) + break; + ast_stopstream(peer); + if (res > 0) { + /* If they've typed a digit already, handle it */ + newext[0] = res; + ptr++; + len --; + } + res = ast_readstring(peer, ptr, len, 3000, 2000, "#"); + if (res) + break; + if (!strcmp(newext, parking_ext)) { + if (!park_call(chan, peer)) { + /* We return non-zero, but tell the PBX not to hang the channel when + the thread dies -- We have to be careful now though. We are responsible for + hanging up the channel, else it will never be hung up! */ + res=AST_PBX_KEEPALIVE; break; + } else { + ast_log(LOG_WARNING, "Unable to park call %s\n", chan->name); } - res = ast_streamfile(peer, "pbx-invalid", chan->language); - if (res) - break; - res = ast_waitstream(peer, AST_DIGIT_ANY); - ast_stopstream(peer); - res = 0; + /* XXX Maybe we should have another message here instead of invalid extension XXX */ + } else if (ast_exists_extension(chan, peer->context, newext, 1)) { + /* Set the channel's new extension, since it exists, using peer context */ + strncpy(chan->exten, newext, sizeof(chan->exten)); + strncpy(chan->context, peer->context, sizeof(chan->context)); + chan->priority = 0; + ast_frfree(f); + res=0; + break; + } else if (ast_exists_extension(chan, "default", newext, 1)) { + /* Set the channel's new extension, since it exists, using peer context */ + strncpy(chan->exten, newext, sizeof(chan->exten)); + strncpy(chan->context, "default", sizeof(chan->context)); + chan->priority = 0; + ast_frfree(f); + res=0; + break; } + res = ast_streamfile(peer, "pbx-invalid", chan->language); + if (res) + break; + res = ast_waitstream(peer, AST_DIGIT_ANY); + ast_stopstream(peer); + res = 0; } else { -#if 0 - ast_log(LOG_DEBUG, "Read from %s\n", who->name); +#if 1 + ast_log(LOG_DEBUG, "Read from %s (%d,%d)\n", who->name, f->frametype, f->subclass); #endif - if (who == chan) - ast_write(peer, f); - else - ast_write(chan, f); } - ast_frfree(f); - - } else - ast_frfree(f); - /* Swap who gets priority */ - cs[2] = cs[0]; - cs[0] = cs[1]; - cs[1] = cs[2]; } return res; } @@ -482,7 +468,7 @@ static int park_exec(struct ast_channel *chan, void *data) { int res=0; struct localuser *u; - struct ast_channel *peer=NULL, *nchan; + struct ast_channel *peer=NULL; struct parkeduser *pu, *pl=NULL; int park; if (!data) { @@ -509,13 +495,9 @@ static int park_exec(struct ast_channel *chan, void *data) free(pu); } if (peer) { - /* Build a translator if necessary */ - if (peer->format & chan->format) - nchan = chan; - else - nchan = ast_translator_create(chan, peer->format, AST_DIRECTION_BOTH); - if (!nchan) { - ast_log(LOG_WARNING, "Had to drop call because there was no translator for %s to %s.\n", chan->name, peer->name); + res = ast_channel_make_compatible(chan, peer); + if (res < 0) { + ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name); ast_hangup(peer); return -1; } @@ -523,9 +505,7 @@ static int park_exec(struct ast_channel *chan, void *data) were the person called. */ if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park); - res = bridge_call(peer, nchan, 1); - if (nchan != chan) - ast_translator_destroy(nchan); + res = bridge_call(peer, chan, 1); /* Simulate the PBX hanging up */ if (res != AST_PBX_KEEPALIVE) ast_hangup(peer); @@ -546,7 +526,7 @@ static int dial_exec(struct ast_channel *chan, void *data) struct localuser *u; char *info, *peers, *timeout, *tech, *number, *rest, *cur; struct localuser *outgoing=NULL, *tmp; - struct ast_channel *peer, *npeer; + struct ast_channel *peer; int to; int allowredir=0; char numsubst[AST_MAX_EXTENSION]; @@ -562,25 +542,42 @@ static int dial_exec(struct ast_channel *chan, void *data) /* Parse our arguments XXX Check for failure XXX */ info = malloc(strlen((char *)data) + AST_MAX_EXTENSION); + if (!info) { + ast_log(LOG_WARNING, "Out of memory\n"); + return -1; + } strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION); - peers = strtok(info, "|"); - if (!peers) { + peers = info; + if (peers) { + timeout = strchr(info, '|'); + if (timeout) { + *timeout = '\0'; + timeout++; + } + } else + timeout = NULL; + if (!peers || !strlen(peers)) { ast_log(LOG_WARNING, "Dial argument takes format (technology1/number1&technology2/number2...|optional timeout)\n"); goto out; } - timeout = strtok(NULL, "|"); - rest = peers; + + cur = peers; do { - cur = strtok(rest, "&"); /* Remember where to start next time */ - rest = strtok(NULL, "\128"); + rest = strchr(cur, '&'); + if (rest) { + *rest = 0; + rest++; + } /* Get a technology/[device:]number pair */ - tech = strtok(cur, "/"); - number = strtok(NULL, "&"); + tech = cur; + number = strchr(tech, '/'); if (!number) { ast_log(LOG_WARNING, "Dial argument takes format (technology1/[device:]number1&technology2/[device:]number2...|optional timeout)\n"); goto out; } + *number = '\0'; + number++; tmp = malloc(sizeof(struct localuser)); if (!tmp) { ast_log(LOG_WARNING, "Out of memory\n"); @@ -598,15 +595,18 @@ static int dial_exec(struct ast_channel *chan, void *data) ast_log(LOG_DEBUG, "Dialing by extension %s\n", numsubst); } /* Request the peer */ - tmp->chan = ast_request(tech, chan->format, numsubst); + tmp->chan = ast_request(tech, chan->nativeformats, numsubst); if (!tmp->chan) { /* If we can't, just go on to the next call */ ast_log(LOG_WARNING, "Unable to create channel of type '%s'\n", tech); free(tmp); + cur = rest; continue; } tmp->chan->appl = "AppDial"; tmp->chan->data = "(Outgoing Line)"; + if (chan->callerid) + tmp->chan->callerid = strdup(chan->callerid); /* Place the call, but don't wait on the answer */ res = ast_call(tmp->chan, numsubst, 0); if (res) { @@ -627,7 +627,9 @@ static int dial_exec(struct ast_channel *chan, void *data) tmp->stillgoing = -1; tmp->next = outgoing; outgoing = tmp; - } while(rest); + cur = rest; + } while(cur); + if (timeout) to = atoi(timeout) * 1000; else @@ -649,21 +651,15 @@ static int dial_exec(struct ast_channel *chan, void *data) conversation. */ hanguptree(outgoing, peer); outgoing = NULL; - /* Build a translator if necessary */ - if (peer->format & chan->format) - npeer = peer; - else - npeer = ast_translator_create(peer, chan->format, AST_DIRECTION_BOTH); - if (!npeer) { - ast_log(LOG_WARNING, "Had to drop call because there was no translator for %s to %s.\n", chan->name, peer->name); - ast_hangup(peer); - res = -1; - } else { - res = bridge_call(chan, npeer, allowredir); - if (npeer != peer) - ast_translator_destroy(npeer); + /* Make sure channels are compatible */ + res = ast_channel_make_compatible(chan, peer); + if (res < 0) { + ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", chan->name, peer->name); ast_hangup(peer); + return -1; } + res = bridge_call(chan, peer, allowredir); + ast_hangup(peer); } out: hanguptree(outgoing, NULL); @@ -711,3 +707,8 @@ int usecount(void) STANDARD_USECOUNT(res); return res; } + +char *key() +{ + return ASTERISK_GPL_KEY; +} diff --git a/pbx.c b/pbx.c index c84784beb697e43b03610bfb97e0cac851407e09..e70a23f0e97f6234a5588e8445670c2fa9c28a37 100755 --- a/pbx.c +++ b/pbx.c @@ -61,6 +61,11 @@ struct ast_exten { struct ast_exten *next; }; +struct ast_include { + char name[AST_MAX_EXTENSION]; + struct ast_include *next; +}; + /* An extension context */ struct ast_context { /* Name of the context */ @@ -71,6 +76,8 @@ struct ast_context { struct ast_exten *root; /* Link them together */ struct ast_context *next; + /* Include other contexts */ + struct ast_include *includes; }; @@ -158,6 +165,9 @@ static int pbx_exec(struct ast_channel *c, /* Channel */ } +/* Go no deeper than this through includes (not counting loops) */ +#define AST_PBX_MAX_STACK 64 + #define HELPER_EXISTS 0 #define HELPER_SPAWN 1 #define HELPER_EXEC 2 @@ -185,7 +195,7 @@ static void pbx_destroy(struct ast_pbx *p) free(p); } -static int extension_match(char *pattern, char *data) +static inline int extension_match(char *pattern, char *data) { int match; /* If they're the same return */ @@ -271,13 +281,82 @@ struct ast_context *ast_context_find(char *name) return tmp; } -static int pbx_extension_helper(struct ast_channel *c, char *context, char *exten, int priority, int action) +#define STATUS_NO_CONTEXT 1 +#define STATUS_NO_EXTENSION 2 +#define STATUS_NO_PRIORITY 3 +#define STATUS_SUCCESS 4 + +static struct ast_exten *pbx_find_extension(char *context, char *exten, int priority, int action, char *incstack[], int *stacklen, int *status) { + int x; struct ast_context *tmp; - struct ast_exten *e, *reale; + struct ast_exten *e, *eroot; + struct ast_include *i; + /* Initialize status if appropriate */ + if (!*stacklen) + *status = STATUS_NO_CONTEXT; + /* Check for stack overflow */ + if (*stacklen >= AST_PBX_MAX_STACK) { + ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n"); + return NULL; + } + /* Check first to see if we've already been checked */ + for (x=0;x<*stacklen;x++) { + if (!strcasecmp(incstack[x], context)) + return NULL; + } + tmp = contexts; + while(tmp) { + /* Match context */ + if (!strcasecmp(tmp->name, context)) { + if (*status < STATUS_NO_EXTENSION) + *status = STATUS_NO_EXTENSION; + eroot = tmp->root; + while(eroot) { + /* Match extension */ + if (extension_match(eroot->exten, exten) || + ((action == HELPER_CANMATCH) && (extension_close(eroot->exten, exten)))) { + e = eroot; + if (*status < STATUS_NO_PRIORITY) + *status = STATUS_NO_PRIORITY; + while(e) { + /* Match priority */ + if (e->priority == priority) { + *status = STATUS_SUCCESS; + return e; + } + e = e->peer; + } + } + eroot = eroot->next; + } + /* Setup the stack */ + incstack[*stacklen] = tmp->name; + (*stacklen)++; + /* Now try any includes we have in this context */ + i = tmp->includes; + while(i) { + if ((e = pbx_find_extension(i->name, exten, priority, action, incstack, stacklen, status))) + return e; + i = i->next; + } + } + tmp = tmp->next; + } + return NULL; +} + +static int pbx_extension_helper(struct ast_channel *c, char *context, char *exten, int priority, int action) +{ + struct ast_exten *e; struct ast_app *app; int newstack = 0; int res; + int status = 0; + char *incstack[AST_PBX_MAX_STACK]; + int stacklen = 0; + + if (pthread_mutex_lock(&conlock)) { ast_log(LOG_WARNING, "Unable to obtain lock\n"); if ((action == HELPER_EXISTS) || (action == HELPER_CANMATCH)) @@ -285,6 +364,70 @@ static int pbx_extension_helper(struct ast_channel *c, char *context, char *exte else return -1; } + e = pbx_find_extension(context, exten, priority, action, incstack, &stacklen, &status); + if (e) { + switch(action) { + case HELPER_CANMATCH: + pthread_mutex_unlock(&conlock); + return -1; + case HELPER_EXISTS: + pthread_mutex_unlock(&conlock); + return -1; + case HELPER_SPAWN: + newstack++; + /* Fall through */ + case HELPER_EXEC: + app = pbx_findapp(e->app); + pthread_mutex_unlock(&conlock); + if (app) { + strncpy(c->context, context, sizeof(c->context)); + strncpy(c->exten, exten, sizeof(c->exten)); + c->priority = priority; + if (option_debug) + ast_log(LOG_DEBUG, "Launching '%s'\n", app->name); + else if (option_verbose > 2) + ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n", + app->name, c->name, (e->data ? (char *)e->data : NULL), (newstack ? "in new stack" : "in same stack")); + c->appl = app->name; + c->data = e->data; + res = pbx_exec(c, app->execute, e->data, newstack); + c->appl = NULL; + c->data = NULL; + pthread_mutex_unlock(&conlock); + return res; + } else { + ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority); + return -1; + } + default: + ast_log(LOG_WARNING, "Huh (%d)?\n", action); + return -1; + } + } else { + pthread_mutex_unlock(&conlock); + switch(status) { + case STATUS_NO_CONTEXT: + if (action != HELPER_EXISTS) + ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context); + break; + case STATUS_NO_EXTENSION: + if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH)) + ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context); + break; + case STATUS_NO_PRIORITY: + if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH)) + ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context); + break; + default: + ast_log(LOG_DEBUG, "Shouldn't happen!\n"); + } + if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH)) + return -1; + else + return 0; + } + +#if 0 tmp = contexts; while(tmp) { if (!strcasecmp(tmp->name, context)) { @@ -370,9 +513,12 @@ static int pbx_extension_helper(struct ast_channel *c, char *context, char *exte return -1; } else return 0; +#endif } + int ast_pbx_longest_extension(char *context) { + /* XXX Not include-aware XXX */ struct ast_context *tmp; struct ast_exten *e; int len = 0; @@ -418,24 +564,36 @@ int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int p return pbx_extension_helper(c, context, exten, priority, HELPER_SPAWN); } -static void *pbx_thread(void *data) +int ast_pbx_run(struct ast_channel *c) { - /* Oh joyeous kernel, we're a new thread, with nothing to do but - answer this channel and get it going. The setjmp stuff is fairly - confusing, but necessary to get smooth transitions between - the execution of different applications (without the use of - additional threads) */ - struct ast_channel *c = data; int firstpass = 1; char digit; char exten[256]; int pos; int waittime; int res=0; + + /* A little initial setup here */ + if (c->pbx) + ast_log(LOG_WARNING, "%s already has PBX structure??\n"); + c->pbx = malloc(sizeof(struct ast_pbx)); + if (!c->pbx) { + ast_log(LOG_WARNING, "Out of memory\n"); + return -1; + } + memset(c->pbx, 0, sizeof(struct ast_pbx)); + /* Set reasonable defaults */ + c->pbx->rtimeout = 10; + c->pbx->dtimeout = 5; + if (option_debug) ast_log(LOG_DEBUG, "PBX_THREAD(%s)\n", c->name); - else if (option_verbose > 1) - ast_verbose( VERBOSE_PREFIX_2 "Accepting call on '%s'\n", c->name); + else if (option_verbose > 1) { + if (c->callerid) + ast_verbose( VERBOSE_PREFIX_2 "Accepting call on '%s' (%s)\n", c->name, c->callerid); + else + ast_verbose( VERBOSE_PREFIX_2 "Accepting call on '%s'\n", c->name); + } /* Start by trying whatever the channel is set to */ @@ -467,7 +625,7 @@ static void *pbx_thread(void *data) goto out; } /* If we're playing something in the background, wait for it to finish or for a digit */ - if (c->stream || (c->trans && c->trans->stream)) { + if (c->stream) { digit = ast_waitstream(c, AST_DIGIT_ANY); ast_stopstream(c); /* Hang up if something goes wrong */ @@ -541,8 +699,20 @@ out: c->pbx = NULL; if (res != AST_PBX_KEEPALIVE) ast_hangup(c); + return 0; +} + +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. The setjmp stuff is fairly + confusing, but necessary to get smooth transitions between + the execution of different applications (without the use of + additional threads) */ + struct ast_channel *c = data; + ast_pbx_run(c); pthread_exit(NULL); - + return NULL; } int ast_pbx_start(struct ast_channel *c) @@ -552,17 +722,6 @@ int ast_pbx_start(struct ast_channel *c) ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n"); return -1; } - if (c->pbx) - ast_log(LOG_WARNING, "%s already has PBX structure??\n"); - c->pbx = malloc(sizeof(struct ast_pbx)); - if (!c->pbx) { - ast_log(LOG_WARNING, "Out of memory\n"); - return -1; - } - memset(c->pbx, 0, sizeof(struct ast_pbx)); - /* Set reasonable defaults */ - c->pbx->rtimeout = 10; - c->pbx->dtimeout = 5; /* Start a new thread, and get something handling this channel. */ if (pthread_create(&t, NULL, pbx_thread, c)) { ast_log(LOG_WARNING, "Failed to create new channel thread\n"); @@ -655,6 +814,7 @@ struct ast_context *ast_context_create(char *name) strncpy(tmp->name, name, sizeof(tmp->name)); tmp->root = NULL; tmp->next = contexts; + tmp->includes = NULL; contexts = tmp; if (option_debug) ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name); @@ -667,6 +827,36 @@ struct ast_context *ast_context_create(char *name) return tmp; } +int ast_context_add_include2(struct ast_context *con, char *value) +{ + struct ast_include *inc, *incc, *incl = NULL; + inc = malloc(sizeof(struct ast_include)); + if (!inc) { + ast_log(LOG_WARNING, "Out of memory\n"); + return -1; + } + strncpy(inc->name, value, sizeof(inc->name)); + inc->next = NULL; + pthread_mutex_lock(&con->lock); + incc = con->includes; + while(incc) { + incl = incc; + if (!strcasecmp(incc->name, value)) { + /* Already there */ + pthread_mutex_unlock(&con->lock); + return 0; + } + incc = incc->next; + } + if (incl) + incl->next = inc; + else + con->includes = inc; + pthread_mutex_unlock(&con->lock); + return 0; + +} + int ast_add_extension2(struct ast_context *con, int replace, char *extension, int priority, char *application, void *data, void (*datad)(void *)) @@ -815,6 +1005,7 @@ int ast_add_extension2(struct ast_context *con, void ast_context_destroy(struct ast_context *con) { struct ast_context *tmp, *tmpl=NULL; + struct ast_include *tmpi, *tmpil= NULL; pthread_mutex_lock(&conlock); tmp = contexts; while(tmp) { @@ -832,6 +1023,13 @@ void ast_context_destroy(struct ast_context *con) /* Okay, now we're safe to let it go -- in a sense, we were ready to let it go as soon as we locked it. */ pthread_mutex_unlock(&tmp->lock); + for (tmpi = tmp->includes; tmpi; ) { + /* Free includes */ + tmpil = tmpi; + tmpi = tmpi->next; + free(tmpil); + tmpil = tmpi; + } free(tmp); pthread_mutex_unlock(&conlock); return;