aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pbx.c1076
1 files changed, 513 insertions, 563 deletions
diff --git a/pbx.c b/pbx.c
index 2821a9bbd..86e3c28e6 100644
--- a/pbx.c
+++ b/pbx.c
@@ -517,12 +517,6 @@ int pbx_exec(struct ast_channel *c, /*!< Channel */
/*! Go no deeper than this through includes (not counting loops) */
#define AST_PBX_MAX_STACK 128
-#define HELPER_EXISTS 0
-#define HELPER_SPAWN 1
-#define HELPER_CANMATCH 3
-#define HELPER_MATCHMORE 4
-#define HELPER_FINDLABEL 5
-
/*! \brief Find application handle in linked list
*/
struct ast_app *pbx_findapp(const char *app)
@@ -566,115 +560,143 @@ static void pbx_destroy(struct ast_pbx *p)
free(p);
}
-#define EXTENSION_MATCH_CORE(data,pattern,match) {\
- /* All patterns begin with _ */\
- if (pattern[0] != '_') \
- return 0;\
- /* Start optimistic */\
- match=1;\
- pattern++;\
- while(match && *data && *pattern && (*pattern != '/')) {\
- while (*data == '-' && (*(data+1) != '\0')) data++;\
- switch(toupper(*pattern)) {\
- case '[': \
- {\
- int i,border=0;\
- char *where;\
- match=0;\
- pattern++;\
- where=strchr(pattern,']');\
- if (where)\
- border=(int)(where-pattern);\
- if (!where || border > strlen(pattern)) {\
- ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");\
- return match;\
- }\
- for (i=0; i<border; i++) {\
- int res=0;\
- if (i+2<border)\
- if (pattern[i+1]=='-') {\
- if (*data >= pattern[i] && *data <= pattern[i+2]) {\
- res=1;\
- } else {\
- i+=2;\
- continue;\
- }\
- }\
- if (res==1 || *data==pattern[i]) {\
- match = 1;\
- break;\
- }\
- }\
- pattern+=border;\
- break;\
- }\
- case 'N':\
- if ((*data < '2') || (*data > '9'))\
- match=0;\
- break;\
- case 'X':\
- if ((*data < '0') || (*data > '9'))\
- match = 0;\
- break;\
- case 'Z':\
- if ((*data < '1') || (*data > '9'))\
- match = 0;\
- break;\
- case '.':\
- /* Must match */\
- return 1;\
- case '!':\
- /* Early match */\
- return 2;\
- case ' ':\
- case '-':\
- /* Ignore these characters */\
- data--;\
- break;\
- default:\
- if (*data != *pattern)\
- match =0;\
- }\
- data++;\
- pattern++;\
- }\
- /* If we ran off the end of the data and the pattern ends in '!', match */\
- if (match && !*data && (*pattern == '!'))\
- return 2;\
+/*!
+ * When looking up extensions, we can have different requests
+ * identified by the 'action' argument, as follows.
+ * Note that the coding is such that the low 4 bits are the
+ * third argument to extension_match_core.
+ */
+enum ext_match_t {
+ E_MATCHMORE = 0x00, /* extension can match but only with more 'digits' */
+ E_CANMATCH = 0x01, /* extension can match with or without more 'digits' */
+ E_MATCH = 0x02, /* extension is an exact match */
+ E_MATCH_MASK = 0x03, /* mask for the argument to extension_match_core() */
+ E_SPAWN = 0x12, /* want to spawn an extension. Requires exact match */
+ E_FINDLABEL = 0x22 /* returns the priority for a given label. Requires exact match */
+};
+
+/*
+ * Internal function for ast_extension_{match|close}
+ * return 0 on no-match, 1 on match, 2 on early match.
+ * mode is as follows:
+ * E_MATCH success only on exact match
+ * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
+ * E_CANMATCH either of the above.
+ */
+static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
+{
+ mode &= E_MATCH_MASK; /* only consider the relevant bits */
+
+ if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
+ int ld = strlen(data), lp = strlen(pattern);
+
+ if (lp < ld) /* pattern too short, cannot match */
+ return 0;
+ /* depending on the mode, accept full or partial match or both */
+ if (mode == E_MATCH)
+ return !strcmp(pattern, data); /* 1 on match, 0 on fail */
+ if (ld == 0 || !strncasecmp(pattern, data, ld)) /* partial or full match */
+ return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
+ else
+ return 0;
+ }
+ pattern++; /* skip leading _ */
+ while (*data && *pattern && *pattern != '/') {
+ const char *end;
+
+ if (*data == '-') { /* skip '-' in data (just a separator) */
+ data++;
+ continue;
+ }
+ switch (toupper(*pattern)) {
+ case '[': /* a range */
+ end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */
+ if (end == NULL) {
+ ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
+ return 0; /* unconditional failure */
+ }
+ for (pattern++; pattern != end; pattern++) {
+ if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
+ if (*data >= pattern[0] && *data <= pattern[2])
+ break; /* match found */
+ else {
+ pattern += 2; /* skip a total of 3 chars */
+ continue;
+ }
+ } else if (*data == pattern[0])
+ break; /* match found */
+ }
+ if (pattern == end)
+ return 0;
+ pattern = end; /* skip and continue */
+ break;
+ case 'N':
+ if (*data < '2' || *data > '9')
+ return 0;
+ break;
+ case 'X':
+ if (*data < '0' || *data > '9')
+ return 0;
+ break;
+ case 'Z':
+ if (*data < '1' || *data > '9')
+ return 0;
+ break;
+ case '.': /* Must match, even with more digits */
+ return 1;
+ case '!': /* Early match */
+ return 2;
+ case ' ':
+ case '-': /* Ignore these in patterns */
+ data--; /* compensate the final data++ */
+ break;
+ default:
+ if (*data != *pattern)
+ return 0;
+ }
+ data++;
+ pattern++;
+ }
+ if (*data) /* data longer than pattern, no match */
+ return 0;
+ /*
+ * match so far, but ran off the end of the data.
+ * Depending on what is next, determine match or not.
+ */
+ if (*pattern == '\0' || *pattern == '/') /* exact match */
+ return (mode == E_MATCHMORE) ? 0 : 1; /* this is a failure for E_MATCHMORE */
+ else if (*pattern == '!') /* early match */
+ return 2;
+ else /* partial match */
+ return (mode == E_MATCH) ? 0 : 1; /* this is a failure for E_MATCH */
+}
+
+/*
+ * Wrapper around _extension_match_core() to do performance measurement
+ * using the profiling code.
+ */
+static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
+{
+ int i;
+ static int prof_id = -2; /* marker for 'unallocated' id */
+ if (prof_id == -2)
+ prof_id = ast_add_profile("ext_match", 0);
+ ast_mark(prof_id, 1);
+ i = _extension_match_core(pattern, data, mode);
+ ast_mark(prof_id, 0);
+ return i;
}
int ast_extension_match(const char *pattern, const char *data)
{
- int match;
- /* If they're the same return */
- if (!strcmp(pattern, data))
- return 1;
- EXTENSION_MATCH_CORE(data,pattern,match);
- /* Must be at the end of both */
- if (*data || (*pattern && (*pattern != '/')))
- match = 0;
- return match;
+ return extension_match_core(pattern, data, E_MATCH);
}
int ast_extension_close(const char *pattern, const char *data, int needmore)
{
- int match;
- /* If "data" is longer, it can'be a subset of pattern unless
- pattern is a pattern match */
- if ((strlen(pattern) < strlen(data)) && (pattern[0] != '_'))
- return 0;
-
- if ((ast_strlen_zero((char *)data) || !strncasecmp(pattern, data, strlen(data))) &&
- (!needmore || (strlen(pattern) > strlen(data)))) {
- return 1;
- }
- EXTENSION_MATCH_CORE(data,pattern,match);
- /* If there's more or we don't care about more, or if it's a possible early match,
- return non-zero; otherwise it's a miss */
- if (!needmore || *pattern || match == 2) {
- return match;
- } else
- return 0;
+ if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
+ ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
+ return extension_match_core(pattern, data, needmore);
}
struct ast_context *ast_context_find(const char *name)
@@ -726,35 +748,33 @@ struct pbx_find_info {
};
static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
- struct ast_context *bypass,
+ struct ast_context *bypass, struct pbx_find_info *q,
const char *context, const char *exten, int priority,
- const char *label, const char *callerid, int action,
- char *incstack[], int *stacklen, int *status, struct ast_switch **swo,
- char **data, const char **foundcontext)
+ const char *label, const char *callerid, enum ext_match_t action)
{
int x, res;
struct ast_context *tmp;
struct ast_exten *e, *eroot;
struct ast_include *i;
struct ast_sw *sw;
- struct ast_switch *asw;
struct ast_exten *earlymatch = NULL;
/* Initialize status if appropriate */
- if (!*stacklen) {
- *status = STATUS_NO_CONTEXT;
- *swo = NULL;
- *data = NULL;
+ if (q->stacklen == 0) {
+ q->status = STATUS_NO_CONTEXT;
+ q->swo = NULL;
+ q->data = NULL;
+ q->foundcontext = NULL;
}
/* Check for stack overflow */
- if (*stacklen >= AST_PBX_MAX_STACK) {
+ if (q->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))
+ for (x = 0; x < q->stacklen; x++) {
+ if (!strcasecmp(q->incstack[x], context))
return NULL;
}
if (bypass) /* bypass means we only look there */
@@ -767,37 +787,37 @@ static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
if (!tmp)
return NULL;
}
-
- if (*status < STATUS_NO_EXTENSION)
- *status = STATUS_NO_EXTENSION;
+ if (q->status < STATUS_NO_EXTENSION)
+ q->status = STATUS_NO_EXTENSION;
for (eroot = tmp->root; eroot; eroot = eroot->next) {
- int match = 0;
+ int match;
/* Match extension */
- if ((((action != HELPER_MATCHMORE) && ast_extension_match(eroot->exten, exten)) ||
- ((action == HELPER_CANMATCH) && (ast_extension_close(eroot->exten, exten, 0))) ||
- ((action == HELPER_MATCHMORE) && (match = ast_extension_close(eroot->exten, exten, 1)))) &&
+ if ( (match = extension_match_core(eroot->exten, exten, action)) &&
(!eroot->matchcid || matchcid(eroot->cidmatch, callerid))) {
- if (action == HELPER_MATCHMORE && match == 2 && !earlymatch) {
+ if (action == E_MATCHMORE && match == 2 && !earlymatch) {
+ /* XXX not sure the logic is correct here.
+ * we should go in irrespective of earlymatch
+ */
/* It matched an extension ending in a '!' wildcard
So ignore it for now, unless there's a better match */
earlymatch = eroot;
} else {
- if (*status < STATUS_NO_PRIORITY)
- *status = STATUS_NO_PRIORITY;
+ if (q->status < STATUS_NO_PRIORITY)
+ q->status = STATUS_NO_PRIORITY;
for (e = eroot; e; e = e->peer) {
/* Match priority */
- if (action == HELPER_FINDLABEL) {
- if (*status < STATUS_NO_LABEL)
- *status = STATUS_NO_LABEL;
+ if (action == E_FINDLABEL) {
+ if (q->status < STATUS_NO_LABEL)
+ q->status = STATUS_NO_LABEL;
if (label && e->label && !strcmp(label, e->label)) {
- *status = STATUS_SUCCESS;
- *foundcontext = context;
+ q->status = STATUS_SUCCESS;
+ q->foundcontext = context;
return e;
}
} else if (e->priority == priority) {
- *status = STATUS_SUCCESS;
- *foundcontext = context;
+ q->status = STATUS_SUCCESS;
+ q->foundcontext = context;
return e;
}
}
@@ -805,7 +825,7 @@ static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
}
}
if (earlymatch) {
- /* Bizarre logic for HELPER_MATCHMORE. We return zero to break out
+ /* Bizarre logic for E_MATCHMORE. We return zero to break out
of the loop waiting for more digits, and _then_ match (normally)
the extension we ended up with. We got an early-matching wildcard
pattern, so return NULL to break out of the loop. */
@@ -813,40 +833,45 @@ static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
}
/* Check alternative switches */
AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
- if ((asw = pbx_findswitch(sw->name))) {
- /* Substitute variables now */
- if (sw->eval)
- pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
- if (action == HELPER_CANMATCH)
- res = asw->canmatch ? asw->canmatch(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
- else if (action == HELPER_MATCHMORE)
- res = asw->matchmore ? asw->matchmore(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
- else
- res = asw->exists ? asw->exists(chan, context, exten, priority, callerid, sw->eval ? sw->tmpdata : sw->data) : 0;
- if (res) {
- /* Got a match */
- *swo = asw;
- *data = sw->eval ? sw->tmpdata : sw->data;
- *foundcontext = context;
- return NULL;
- }
- } else {
+ struct ast_switch *asw = pbx_findswitch(sw->name);
+ ast_switch_f *aswf = NULL;
+ char *datap;
+
+ if (!asw) {
ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
+ continue;
+ }
+ /* Substitute variables now */
+ if (sw->eval)
+ pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
+
+ /* equivalent of extension_match_core() at the switch level */
+ if (action == E_CANMATCH)
+ aswf = asw->canmatch;
+ else if (action == E_MATCHMORE)
+ aswf = asw->matchmore;
+ else
+ aswf = asw->exists;
+ datap = sw->eval ? sw->tmpdata : sw->data;
+ res = !aswf ? 0 : aswf(chan, context, exten, priority, callerid, datap);
+ if (res) { /* Got a match */
+ q->swo = asw;
+ q->data = datap;
+ q->foundcontext = context;
+ /* XXX keep status = STATUS_NO_CONTEXT ? */
+ return NULL;
}
}
- /* Setup the stack */
- incstack[*stacklen] = tmp->name;
- (*stacklen)++;
+ q->incstack[q->stacklen++] = tmp->name; /* Setup the stack */
/* Now try any includes we have in this context */
for (i = tmp->includes; i; i = i->next) {
if (include_valid(i)) {
- if ((e = pbx_find_extension(chan, bypass, i->rname, exten, priority, label, callerid, action, incstack, stacklen, status, swo, data, foundcontext)))
+ if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action)))
return e;
- if (*swo)
+ if (q->swo)
return NULL;
}
}
-
return NULL;
}
@@ -1257,6 +1282,8 @@ int ast_func_write(struct ast_channel *chan, char *function, const char *value)
static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
{
+ /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
+ zero-filled */
char *cp4;
const char *tmp, *whereweare;
int length, offset, offset2, isfunction;
@@ -1266,8 +1293,6 @@ static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct v
char *vars, *vare;
int pos, brackets, needsub, len;
- /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
- zero-filled */
whereweare=tmp=cp1;
while (!ast_strlen_zero(whereweare) && count) {
/* Assume we're copying the whole remaining string */
@@ -1455,65 +1480,69 @@ static void pbx_substitute_variables(char *passdata, int datalen, struct ast_cha
pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
}
-static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con, const char *context, const char *exten, int priority, const char *label, const char *callerid, int action)
+/*! \brief The return value depends on the action:
+ *
+ * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
+ * and return 0 on failure, -1 on match;
+ * E_FINDLABEL maps the label to a priority, and returns
+ * the priority on success, ... XXX
+ * E_SPAWN, spawn an application,
+ * and return 0 on success, -1 on failure.
+ */
+static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
+ const char *context, const char *exten, int priority,
+ const char *label, const char *callerid, enum ext_match_t action)
{
struct ast_exten *e;
struct ast_app *app;
- struct ast_switch *sw;
- char *data;
- const char *foundcontext=NULL;
int res;
- int status = 0;
- char *incstack[AST_PBX_MAX_STACK];
+ struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
char passdata[EXT_DATA_SIZE];
- int stacklen = 0;
- char tmp[80];
- char tmp2[80];
- char tmp3[EXT_DATA_SIZE];
- char atmp[80];
- char atmp2[EXT_DATA_SIZE+100];
- ast_mutex_lock(&conlock);
+ int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
- e = pbx_find_extension(c, con, context, exten, priority, label, callerid, action, incstack, &stacklen, &status, &sw, &data, &foundcontext);
+ ast_mutex_lock(&conlock);
+ e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
if (e) {
- switch(action) {
- case HELPER_CANMATCH:
- ast_mutex_unlock(&conlock);
- return -1;
- case HELPER_EXISTS:
+ if (matching_action) {
ast_mutex_unlock(&conlock);
- return -1;
- case HELPER_FINDLABEL:
+ return -1; /* success, we found it */
+ } else if (action == E_FINDLABEL) { /* map the label to a priority */
res = e->priority;
ast_mutex_unlock(&conlock);
- return res;
- case HELPER_MATCHMORE:
- ast_mutex_unlock(&conlock);
- return -1;
- case HELPER_SPAWN:
+ return res; /* the priority we were looking for */
+ } else { /* spawn */
app = pbx_findapp(e->app);
ast_mutex_unlock(&conlock);
- if (app) {
- if (c->context != context)
- ast_copy_string(c->context, context, sizeof(c->context));
- if (c->exten != exten)
- ast_copy_string(c->exten, exten, sizeof(c->exten));
- c->priority = priority;
- pbx_substitute_variables(passdata, sizeof(passdata), c, e);
- if (option_debug) {
- ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
- snprintf(atmp, 80, "STACK-%s-%s-%d", context, exten, priority);
- snprintf(atmp2, EXT_DATA_SIZE+100, "%s(\"%s\", \"%s\") %s", app->name, c->name, passdata, "in new stack");
- pbx_builtin_setvar_helper(c, atmp, atmp2);
- }
- if (option_verbose > 2)
- ast_verbose( VERBOSE_PREFIX_3 "Executing %s(\"%s\", \"%s\") %s\n",
- term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
- term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
- term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
- "in new stack");
- manager_event(EVENT_FLAG_CALL, "Newexten",
+ if (!app) {
+ ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
+ return -1;
+ }
+ if (c->context != context)
+ ast_copy_string(c->context, context, sizeof(c->context));
+ if (c->exten != exten)
+ ast_copy_string(c->exten, exten, sizeof(c->exten));
+ c->priority = priority;
+ pbx_substitute_variables(passdata, sizeof(passdata), c, e);
+ if (option_debug) {
+ char atmp[80];
+ char atmp2[EXT_DATA_SIZE+100];
+ ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
+ snprintf(atmp, sizeof(atmp), "STACK-%s-%s-%d", context, exten, priority);
+ snprintf(atmp2, sizeof(atmp2), "%s(\"%s\", \"%s\") %s",
+ app->name, c->name, passdata, "in new stack");
+ pbx_builtin_setvar_helper(c, atmp, atmp2);
+ }
+ if (option_verbose > 2) {
+ char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE];
+ ast_verbose( VERBOSE_PREFIX_3 "Executing [%s:%d] %s(\"%s\", \"%s\") %s\n",
+ context, priority,
+ term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
+ term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
+ term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
+ "in new stack");
+ }
+ manager_event(EVENT_FLAG_CALL, "Newexten",
"Channel: %s\r\n"
"Context: %s\r\n"
"Extension: %s\r\n"
@@ -1522,56 +1551,32 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
"AppData: %s\r\n"
"Uniqueid: %s\r\n",
c->name, c->context, c->exten, c->priority, app->name, passdata, c->uniqueid);
- res = pbx_exec(c, app, passdata);
- 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;
+ return pbx_exec(c, app, passdata); /* 0 on success, -1 on failure */
}
- } else if (sw) {
- switch(action) {
- case HELPER_CANMATCH:
- ast_mutex_unlock(&conlock);
- return -1;
- case HELPER_EXISTS:
- ast_mutex_unlock(&conlock);
- return -1;
- case HELPER_MATCHMORE:
- ast_mutex_unlock(&conlock);
- return -1;
- case HELPER_FINDLABEL:
- ast_mutex_unlock(&conlock);
+ } else if (q.swo) { /* not found here, but in another switch */
+ ast_mutex_unlock(&conlock);
+ if (matching_action)
return -1;
- case HELPER_SPAWN:
- ast_mutex_unlock(&conlock);
- if (sw->exec)
- res = sw->exec(c, foundcontext ? foundcontext : context, exten, priority, callerid, data);
- else {
- ast_log(LOG_WARNING, "No execution engine for switch %s\n", sw->name);
+ else {
+ if (!q.swo->exec) {
+ ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
res = -1;
}
- return res;
- default:
- ast_log(LOG_WARNING, "Huh (%d)?\n", action);
- return -1;
+ return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
}
- } else {
+ } else { /* not found anywhere, see what happened */
ast_mutex_unlock(&conlock);
- switch(status) {
+ switch (q.status) {
case STATUS_NO_CONTEXT:
- if ((action != HELPER_EXISTS) && (action != HELPER_MATCHMORE))
+ if (!matching_action)
ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
break;
case STATUS_NO_EXTENSION:
- if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
+ if (!matching_action)
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) && (action != HELPER_MATCHMORE))
+ if (!matching_action)
ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
break;
case STATUS_NO_LABEL:
@@ -1582,27 +1587,18 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
ast_log(LOG_DEBUG, "Shouldn't happen!\n");
}
- if ((action != HELPER_EXISTS) && (action != HELPER_CANMATCH) && (action != HELPER_MATCHMORE))
- return -1;
- else
- return 0;
+ return (matching_action) ? 0 : -1;
}
-
}
/*! \brief ast_hint_extension: Find hint for given extension in context */
static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
{
struct ast_exten *e;
- struct ast_switch *sw;
- char *data;
- const char *foundcontext = NULL;
- int status = 0;
- char *incstack[AST_PBX_MAX_STACK];
- int stacklen = 0;
+ struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
ast_mutex_lock(&conlock);
- e = pbx_find_extension(c, NULL, context, exten, PRIORITY_HINT, NULL, "", HELPER_EXISTS, incstack, &stacklen, &status, &sw, &data, &foundcontext);
+ e = pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
ast_mutex_unlock(&conlock);
return e;
@@ -1965,32 +1961,32 @@ int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_
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);
+ return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH);
}
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);
+ return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_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);
+ return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_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);
+ return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_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);
+ return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_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);
+ return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN);
}
/* helper function to set extension and priority */
@@ -2000,15 +1996,42 @@ static void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
c->priority = pri;
}
-static int __ast_pbx_run(struct ast_channel *c)
+/*!
+ * \brief collect digits from the channel into the buffer,
+ * return -1 on error, 0 on timeout or done.
+ */
+static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
{
- int firstpass = 1;
int digit;
- char exten[256];
- int pos;
- int waittime;
- int res=0;
+
+ buf[pos] = '\0'; /* make sure it is properly terminated */
+ while (ast_matchmore_extension(c, c->context, buf, 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;
+ } else {
+ if (!digit) /* No entry */
+ break;
+ if (digit < 0) /* Error, maybe a hangup */
+ return -1;
+ if (pos < buflen - 1) { /* XXX maybe error otherwise ? */
+ buf[pos++] = digit;
+ buf[pos] = '\0';
+ }
+ waittime = c->pbx->dtimeout;
+ }
+ }
+ return 0;
+}
+
+static int __ast_pbx_run(struct ast_channel *c)
+{
+ int found = 0; /* set if we find at least one match */
+ int res = 0;
int autoloopflag;
+ int error = 0; /* set an error conditions */
/* A little initial setup here */
if (c->pbx) {
@@ -2056,46 +2079,43 @@ static int __ast_pbx_run(struct ast_channel *c)
if (c->cdr && ast_tvzero(c->cdr->start))
ast_cdr_start(c->cdr);
for (;;) {
- pos = 0;
- digit = 0;
+ char dst_exten[256]; /* buffer to accumulate digits */
+ int pos = 0; /* XXX should check bounds */
+ int digit = 0;
+
+ /* loop on priorities in this context/exten */
while (ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
- memset(exten, 0, sizeof(exten));
+ found = 1;
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 == '#')) {
+ if (strchr("0123456789ABCDEF*#", res)) {
ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
- memset(exten, 0, sizeof(exten));
pos = 0;
- exten[pos++] = digit = res;
+ dst_exten[pos++] = digit = res;
+ dst_exten[pos] = '\0';
break;
}
- switch(res) {
- case AST_PBX_KEEPALIVE:
+ if (res == 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);
- goto out;
+ error = 1;
break;
- 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) {
+ }
+ 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;
+ } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
+ /* atimeout, nothing bad */
+ } else {
+ if (c->cdr)
ast_cdr_update(c);
- }
- goto out;
+ error = 1;
+ break;
}
}
if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c,c->context,"T",1,c->cid.cid_num)) {
@@ -2106,11 +2126,16 @@ static int __ast_pbx_run(struct ast_channel *c)
} else if (c->_softhangup) {
ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
c->exten, c->priority);
- goto out;
+ error = 1;
+ break;
}
- firstpass = 0;
c->priority++;
- }
+ } /* end while - from here on we can use 'break' to go out */
+ if (error)
+ break;
+
+ /* XXX we get here on non-existing extension or a keypress or hangup ? */
+
if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
/* If there is no match at priority 1, it is not a valid extension anymore.
* Try to continue at "i", 1 or exit if the latter does not exist.
@@ -2123,73 +2148,20 @@ static int __ast_pbx_run(struct ast_channel *c)
} 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);
- goto out;
+ error = 1; /* we know what to do with it */
+ break;
}
} 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;
- } else {
- /* Done, wait for an extension */
- waittime = 0;
+ } else { /* keypress received, get more digits for a full extension */
+ int waittime = 0;
if (digit)
waittime = c->pbx->dtimeout;
else if (!autofallthrough)
waittime = c->pbx->rtimeout;
- 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;
- } else {
- 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 */
- set_ext_pri(c, exten, 1);
- } else {
- /* 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);
- set_ext_pri(c, "i", 1);
- } else {
- ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
- goto out;
- }
- } else {
- /* 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);
- set_ext_pri(c, "t", 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;
-
- status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
+ if (!waittime) {
+ const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
if (!status)
status = "UNKNOWN";
if (option_verbose > 2)
@@ -2200,13 +2172,50 @@ static int __ast_pbx_run(struct ast_channel *c)
res = pbx_builtin_congestion(c, "10");
else if (!strcasecmp(status, "BUSY"))
res = pbx_builtin_busy(c, "10");
- goto out;
+ error = 1; /* XXX disable message */
+ break; /* exit from the 'for' loop */
+ }
+
+ if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
+ break;
+ if (ast_exists_extension(c, c->context, dst_exten, 1, c->cid.cid_num)) /* Prepare the next cycle */
+ set_ext_pri(c, dst_exten, 1);
+ else {
+ /* No such extension */
+ if (!ast_strlen_zero(dst_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", dst_exten, c->context, c->name);
+ pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
+ set_ext_pri(c, "i", 1);
+ } else {
+ ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten, c->context);
+ found = 1; /* XXX disable message */
+ break;
+ }
+ } else {
+ /* 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);
+ set_ext_pri(c, "t", 1);
+ } else {
+ ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
+ found = 1; /* XXX disable message */
+ break;
+ }
+ }
+ }
+ if (c->cdr) {
+ if (option_verbose > 2)
+ ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
+ ast_cdr_update(c);
}
}
}
- if (firstpass)
+ if (!found && !error)
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)) {
if (c->cdr && ast_opt_end_cdr_before_h_exten)
ast_cdr_end(c->cdr);
@@ -2266,6 +2275,16 @@ static void decrease_call_count(void)
ast_mutex_unlock(&maxcalllock);
}
+static void destroy_exten(struct ast_exten *e)
+{
+ if (e->priority == PRIORITY_HINT)
+ ast_remove_hint(e);
+
+ if (e->datad)
+ e->datad(e->data);
+ free(e);
+}
+
static void *pbx_thread(void *data)
{
/* Oh joyeous kernel, we're a new thread, with nothing to do but
@@ -2486,104 +2505,72 @@ int ast_context_remove_extension(const char *context, const char *extension, int
int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
{
struct ast_exten *exten, *prev_exten = NULL;
+ struct ast_exten *peer;
ast_mutex_lock(&con->lock);
- /* go through all extensions in context and search the right one ... */
- exten = con->root;
- while (exten) {
-
- /* look for right extension */
+ /* scan the extension list to find matching extension-registrar */
+ for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
if (!strcmp(exten->exten, extension) &&
- (!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;
- }
+ (!registrar || !strcmp(exten->registrar, registrar)))
+ break;
+ }
+ if (!exten) {
+ /* we can't find right extension */
+ ast_mutex_unlock(&con->lock);
+ return -1;
+ }
- 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 &&
- (!registrar || !strcmp(peer->registrar, registrar) )) {
- /* 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;
- }
+ /* 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;
- /* now, free whole priority extension */
- if (peer->priority==PRIORITY_HINT)
- ast_remove_hint(peer);
- peer->datad(peer->data);
- free(peer);
+ /* fire out all peers */
+ while ( (peer = exten) ) {
+ exten = peer->peer; /* prepare for next entry */
+ destroy_exten(peer);
+ }
+ } else {
+ /* scan the priority list to remove extension with exten->priority == priority */
+ struct ast_exten *previous_peer = NULL;
- ast_mutex_unlock(&con->lock);
- return 0;
- } else {
- /* this is not right extension, skip to next peer */
- previous_peer = peer;
- peer = peer->peer;
- }
- }
+ for (peer = exten; peer; previous_peer = peer, peer = peer->peer) {
+ if (peer->priority == priority &&
+ (!registrar || !strcmp(peer->registrar, registrar) ))
+ break; /* found our priority */
+ }
+ if (!peer) { /* not found */
+ ast_mutex_unlock(&con->lock);
+ return -1;
+ }
+ /* we are first priority extension? */
+ if (!previous_peer) {
+ /*
+ * We are first in the priority chain, so must update the extension chain.
+ * The next node is either the next priority or the next extension
+ */
+ struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
- ast_mutex_unlock(&con->lock);
- return -1;
- }
+ if (!prev_exten) /* change the root... */
+ con->root = next_node;
+ else
+ prev_exten->next = next_node; /* unlink */
+ if (peer->peer) /* XXX update the new head of the pri list */
+ peer->peer->next = peer->next;
+ } else { /* easy, we are not first priority in extension */
+ previous_peer->peer = peer->peer;
}
- prev_exten = exten;
- exten = exten->next;
+ /* now, free whole priority extension */
+ destroy_exten(peer);
+ /* XXX should we return -1 ? */
}
-
- /* we can't find right extension */
ast_mutex_unlock(&con->lock);
- return -1;
+ return 0;
}
@@ -3370,13 +3357,17 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char
tmp = *extcontexts;
if (registrar) {
+ /* XXX remove previous contexts from same registrar */
+ ast_log(LOG_WARNING, "must remove any reg %s\n", registrar);
__ast_context_destroy(NULL,registrar);
while (tmp) {
lasttmp = tmp;
tmp = tmp->next;
}
} else {
+ /* XXX remove contexts with the same name */
while (tmp) {
+ ast_log(LOG_WARNING, "must remove %s reg %s\n", tmp->name, tmp->registrar);
__ast_context_destroy(tmp,tmp->registrar);
lasttmp = tmp;
tmp = tmp->next;
@@ -4069,6 +4060,64 @@ static void null_datad(void *foo)
{
}
+/*! \brief add the extension in the priority chain */
+static int add_pri(struct ast_context *con, struct ast_exten *tmp,
+ struct ast_exten *el, struct ast_exten *e, int replace)
+{
+ struct ast_exten *ep;
+
+ for (ep = NULL; e ; ep = e, e = e->peer) {
+ if (e->priority >= tmp->priority)
+ break;
+ }
+ if (!e) { /* go at the end, and ep is surely set because the list is not empty */
+ ep->peer = tmp;
+ return 0; /* success */
+ }
+ if (e->priority == tmp->priority) {
+ /* Can't have something exactly the same. Is this a
+ replacement? If so, replace, otherwise, bonk. */
+ if (!replace) {
+ ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
+ tmp->datad(tmp->data);
+ free(tmp);
+ return -1;
+ }
+ /* we are replacing e, so copy the link fields and then update
+ * whoever pointed to e to point to us
+ */
+ tmp->next = e->next; /* not meaningful if we are not first in the peer list */
+ tmp->peer = e->peer; /* always meaningful */
+ if (ep) /* We're in the peer list, just insert ourselves */
+ ep->peer = tmp;
+ else if (el) /* We're the first extension. Take over e's functions */
+ el->next = tmp;
+ else /* We're the very first extension. */
+ con->root = tmp;
+ if (tmp->priority == PRIORITY_HINT)
+ ast_change_hint(e,tmp);
+ /* Destroy the old one */
+ e->datad(e->data);
+ free(e);
+ } else { /* Slip ourselves in just before e */
+ tmp->peer = e;
+ tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
+ if (ep) /* Easy enough, we're just in the peer list */
+ ep->peer = tmp;
+ else { /* we are the first in some peer list, so link in the ext list */
+ if (el)
+ el->next = tmp; /* in the middle... */
+ else
+ con->root = tmp; /* ... or at the head */
+ e->next = NULL; /* e is no more at the head, so e->next must be reset */
+ }
+ /* And immediately return success. */
+ if (tmp->priority == PRIORITY_HINT)
+ ast_add_hint(tmp);
+ }
+ return 0;
+}
+
/*! \brief
* Main interface to add extensions to the list for out context.
*
@@ -4120,7 +4169,7 @@ int ast_add_extension2(struct ast_context *con,
* priorities (same extension) are kept in a list, according to the
* peer pointer.
*/
- struct ast_exten *tmp, *e, *el = NULL, *ep = NULL;
+ struct ast_exten *tmp, *e, *el = NULL;
int res;
int length;
char *p;
@@ -4197,113 +4246,21 @@ int ast_add_extension2(struct ast_context *con,
else
res = strcasecmp(e->cidmatch, tmp->cidmatch);
}
- if (res == 0) {
- /* We have an exact match, now we find where we are
- and be sure there's no duplicates */
- while(e) {
- if (e->priority == tmp->priority) {
- /* Can't have something exactly the same. Is this a
- replacement? If so, replace, otherwise, bonk. */
- if (replace) {
- if (ep) {
- /* We're in the peer list, insert ourselves */
- ep->peer = tmp;
- tmp->peer = e->peer;
- } else if (el) {
- /* We're the first extension. Take over e's functions */
- el->next = tmp;
- tmp->next = e->next;
- tmp->peer = e->peer;
- } else {
- /* We're the very first extension. */
- con->root = tmp;
- tmp->next = e->next;
- tmp->peer = e->peer;
- }
- if (tmp->priority == PRIORITY_HINT)
- ast_change_hint(e,tmp);
- /* Destroy the old one */
- e->datad(e->data);
- free(e);
- ast_mutex_unlock(&con->lock);
- if (tmp->priority == PRIORITY_HINT)
- ast_change_hint(e, tmp);
- /* And immediately return success. */
- LOG;
- return 0;
- } else {
- ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
- tmp->datad(tmp->data);
- free(tmp);
- ast_mutex_unlock(&con->lock);
- errno = EEXIST;
- return -1;
- }
- } else if (e->priority > tmp->priority) {
- /* Slip ourselves in just before e */
- if (ep) {
- /* Easy enough, we're just in the peer list */
- ep->peer = tmp;
- tmp->peer = e;
- } else if (el) {
- /* We're the first extension in this peer list */
- el->next = tmp;
- tmp->next = e->next;
- e->next = NULL;
- tmp->peer = e;
- } else {
- /* We're the very first extension altogether */
- tmp->next = con->root->next;
- /* Con->root must always exist or we couldn't get here */
- tmp->peer = con->root;
- con->root = tmp;
- }
- ast_mutex_unlock(&con->lock);
-
- /* And immediately return success. */
- if (tmp->priority == PRIORITY_HINT)
- ast_add_hint(tmp);
-
- LOG;
- return 0;
- }
- ep = e;
- e = e->peer;
- }
- /* If we make it here, then it's time for us to go at the very end.
- ep *must* be defined or we couldn't have gotten here. */
- ep->peer = tmp;
+ if (res >= 0)
+ break;
+ }
+ if (e && res == 0) { /* exact match, insert in the pri chain */
+ int ret = add_pri(con, tmp, el, e, replace);
ast_mutex_unlock(&con->lock);
- if (tmp->priority == PRIORITY_HINT)
- ast_add_hint(tmp);
-
- /* And immediately return success. */
- LOG;
- return 0;
-
- } else if (res > 0) {
- /* Insert ourselves just before 'e'. We're the first extension of
- this kind */
- tmp->next = e;
- if (el) {
- /* We're in the list somewhere */
- el->next = tmp;
- } else {
- /* We're at the top of the list */
- con->root = tmp;
+ if (ret < 0)
+ errno = EEXIST;
+ else {
+ LOG;
}
- ast_mutex_unlock(&con->lock);
- if (tmp->priority == PRIORITY_HINT)
- ast_add_hint(tmp);
-
- /* And immediately return success. */
- LOG;
- return 0;
- }
-
- el = e;
+ return ret;
}
- /* If we fall all the way through to here, then we need to be on the end. */
+ /* ok found the insertion place, right before 'e' (if any) */
+ tmp->next = e;
if (el)
el->next = tmp;
else
@@ -4723,16 +4680,6 @@ outgoing_app_cleanup:
return res;
}
-static void destroy_exten(struct ast_exten *e)
-{
- if (e->priority == PRIORITY_HINT)
- ast_remove_hint(e);
-
- if (e->datad)
- e->datad(e->data);
- free(e);
-}
-
void __ast_context_destroy(struct ast_context *con, const char *registrar)
{
struct ast_context *tmp, *tmpl=NULL;
@@ -4745,6 +4692,7 @@ void __ast_context_destroy(struct ast_context *con, const char *registrar)
for (tmp = contexts; tmp; ) {
struct ast_context *next; /* next starting point */
for (; tmp; tmpl = tmp, tmp = tmp->next) {
+ ast_log(LOG_WARNING, "check ctx %s %s\n", tmp->name, tmp->registrar);
if ( (!registrar || !strcasecmp(registrar, tmp->registrar)) &&
(!con || !strcasecmp(tmp->name, con->name)) )
break; /* found it */
@@ -4752,6 +4700,7 @@ void __ast_context_destroy(struct ast_context *con, const char *registrar)
if (!tmp) /* not found, we are done */
break;
ast_mutex_lock(&tmp->lock);
+ ast_log(LOG_WARNING, "delete ctx %s %s\n", tmp->name, tmp->registrar);
next = tmp->next;
if (tmpl)
tmpl->next = next;
@@ -5246,6 +5195,7 @@ void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const
struct varshead *headp;
const char *nametail = name;
+ /* XXX may need locking on the channel ? */
if (name[strlen(name)-1] == ')') {
char *function = ast_strdupa(name);