#include "asterisk.h"
-ASTERISK_REGISTER_FILE()
-
#include "asterisk/_private.h"
#include "asterisk/paths.h" /* use ast_config_AST_SYSTEM_NAME */
#include <ctype.h>
priority.
*/
struct ast_exten {
- char *exten; /*!< Extension name */
+ char *exten; /*!< Clean Extension id */
+ char *name; /*!< Extension name (may include '-' eye candy) */
int matchcid; /*!< Match caller id ? */
const char *cidmatch; /*!< Caller id to match for this extension */
+ const char *cidmatch_display; /*!< Caller id to match (display version) */
int priority; /*!< Priority */
const char *label; /*!< Label */
struct ast_context *parent; /*!< The context this extension belongs to */
struct ast_hashtab *peer_table; /*!< Priorities list in hashtab form -- only on the head of the peer list */
struct ast_hashtab *peer_label_table; /*!< labeled priorities in the peers -- only on the head of the peer list */
const char *registrar; /*!< Registrar */
+ const char *registrar_file; /*!< File name used to register extension */
+ int registrar_line; /*!< Line number the extension was registered in text */
struct ast_exten *next; /*!< Extension with a greater ID */
char stuff[0];
};
-/*! \brief ast_sw: Switch statement in extensions.conf */
-struct ast_sw {
- char *name;
- const char *registrar; /*!< Registrar */
- char *data; /*!< Data load */
- int eval;
- AST_LIST_ENTRY(ast_sw) list;
- char stuff[0];
-};
-
/*! \brief match_char: forms a syntax tree for quick matching of extension patterns */
struct match_char
{
struct ast_context *next; /*!< Link them together */
struct ast_includes includes; /*!< Include other contexts */
struct ast_ignorepats ignorepats; /*!< Patterns for which to continue playing dialtone */
+ struct ast_sws alts; /*!< Alternative switches */
char *registrar; /*!< Registrar -- make sure you malloc this, as the registrar may have to survive module unloads */
int refcount; /*!< each module that would have created this context should inc/dec this as appropriate */
int autohints; /*!< Whether autohints support is enabled or not */
- AST_LIST_HEAD_NOLOCK(, ast_sw) alts; /*!< Alternative switches */
ast_mutex_t macrolock; /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */
char name[0]; /*!< Name of the context */
};
static int ast_add_extension2_lockopt(struct ast_context *con,
int replace, const char *extension, int priority, const char *label, const char *callerid,
const char *application, void *data, void (*datad)(void *),
- const char *registrar, int lock_context);
+ const char *registrar, const char *registrar_file, int registrar_line,
+ int lock_context);
static struct ast_context *find_context_locked(const char *context);
static struct ast_context *find_context(const char *context);
static void get_device_state_causing_channels(struct ao2_container *c);
+static unsigned int ext_strncpy(char *dst, const char *src, size_t dst_size, int nofluff);
/*!
* \internal
e2 = ast_hashtab_lookup(c1->root_table, &ex);
if (!e2) {
if (e1->matchcid == AST_EXT_MATCHCID_ON) {
- ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s (CID match: %s) but it is not in its root_table\n", file, line, c2->name, dummy_name, e1->cidmatch );
+ ast_log(LOG_NOTICE, "Called from: %s:%d: The %s context records "
+ "the exten %s (CID match: %s) but it is not in its root_table\n",
+ file, line, c2->name, dummy_name, e1->cidmatch_display);
} else {
- ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s but it is not in its root_table\n", file, line, c2->name, dummy_name );
+ ast_log(LOG_NOTICE, "Called from: %s:%d: The %s context records "
+ "the exten %s but it is not in its root_table\n",
+ file, line, c2->name, dummy_name);
}
check_contexts_trouble();
}
if (strlen(node->x) > 1) {
ast_cli(fd, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N',
node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "",
- node->exten ? node->exten->exten : "", extenstr);
+ node->exten ? node->exten->name : "", extenstr);
} else {
ast_cli(fd, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N',
node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "",
- node->exten ? node->exten->exten : "", extenstr);
+ node->exten ? node->exten->name : "", extenstr);
}
ast_str_set(&my_prefix, 0, "%s+ ", prefix);
return; \
} \
} else { \
- ast_debug(4, "returning an exact match-- first found-- %s\n", p->exten->exten); \
+ ast_debug(4, "returning an exact match-- first found-- %s\n", p->exten->name); \
return; /* the first match, by definition, will be the best, because of the sorted tree */ \
} \
} \
if (*(str + 1) || p->next_char->x[0] == '!') { \
new_find_extension(str + 1, score, p->next_char, length + 1, spec + p->specificity, callerid, label, action); \
if (score->exten) { \
- ast_debug(4 ,"returning an exact match-- %s\n", score->exten->exten); \
+ ast_debug(4 ,"returning an exact match-- %s\n", score->exten->name); \
return; /* the first match is all we need */ \
} \
} else { \
new_find_extension("/", score, p->next_char, length + 1, spec + p->specificity, callerid, label, action); \
if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) { \
- ast_debug(4,"returning a (can/more) match--- %s\n", score->exten ? score->exten->exten : \
+ ast_debug(4,"returning a (can/more) match--- %s\n", score->exten ? score->exten->name : \
"NULL"); \
return; /* the first match is all we need */ \
} \
if (p->exten && *str2 != '/') {
update_scoreboard(score, length + i, spec + (i * p->specificity), p->exten, '.', callerid, p->deleted, p);
if (score->exten) {
- ast_debug(4,"return because scoreboard has a match with '/'--- %s\n", score->exten->exten);
+ ast_debug(4, "return because scoreboard has a match with '/'--- %s\n",
+ score->exten->name);
return; /* the first match is all we need */
}
}
if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
new_find_extension("/", score, p->next_char, length + i, spec+(p->specificity*i), callerid, label, action);
if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
- ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set--- %s\n", score->exten ? score->exten->exten : "NULL");
+ ast_debug(4, "return because scoreboard has exact match OR "
+ "CANMATCH/MATCHMORE & canmatch set--- %s\n",
+ score->exten ? score->exten->name : "NULL");
return; /* the first match is all we need */
}
}
if (p->exten && *str2 != '/') {
update_scoreboard(score, length + 1, spec + (p->specificity * i), p->exten, '!', callerid, p->deleted, p);
if (score->exten) {
- ast_debug(4, "return because scoreboard has a '!' match--- %s\n", score->exten->exten);
+ ast_debug(4, "return because scoreboard has a '!' match--- %s\n",
+ score->exten->name);
return; /* the first match is all we need */
}
}
if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
new_find_extension("/", score, p->next_char, length + i, spec + (p->specificity * i), callerid, label, action);
if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
- ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/' and '!'--- %s\n", score->exten ? score->exten->exten : "NULL");
+ ast_debug(4, "return because scoreboard has exact match OR "
+ "CANMATCH/MATCHMORE & canmatch set with '/' and '!'--- %s\n",
+ score->exten ? score->exten->name : "NULL");
return; /* the first match is all we need */
}
}
if (p->next_char && callerid && *callerid) {
new_find_extension(callerid, score, p->next_char, length + 1, spec, callerid, label, action);
if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
- ast_debug(4, "return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/'--- %s\n", score->exten ? score->exten->exten : "NULL");
+ ast_debug(4, "return because scoreboard has exact match OR "
+ "CANMATCH/MATCHMORE & canmatch set with '/'--- %s\n",
+ score->exten ? score->exten->name : "NULL");
return; /* the first match is all we need */
}
}
}
if (m2->exten) {
ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n",
- m2->deleted ? "(deleted/invalid)" : m2->exten->exten, e1->exten);
+ m2->deleted ? "(deleted/invalid)" : m2->exten->name, e1->name);
}
m2->exten = e1;
m2->deleted = 0;
if (!pat_node[idx_next].buf[0]) {
if (m2 && m2->exten) {
ast_log(LOG_WARNING, "Found duplicate exten. Had %s found %s\n",
- m2->deleted ? "(deleted/invalid)" : m2->exten->exten, e1->exten);
+ m2->deleted ? "(deleted/invalid)" : m2->exten->name, e1->name);
}
m1->deleted = 0;
m1->exten = e1;
return ext_cmp_pattern(left + 1, right + 1);
}
+static int ext_fluff_count(const char *exten)
+{
+ int fluff = 0;
+
+ if (*exten != '_') {
+ /* not a pattern, simple check. */
+ while (*exten) {
+ if (*exten == '-') {
+ fluff++;
+ }
+ exten++;
+ }
+
+ return fluff;
+ }
+
+ /* do pattern check */
+ while (*exten) {
+ if (*exten == '-') {
+ fluff++;
+ } else if (*exten == '[') {
+ /* skip set, dashes here matter. */
+ exten = strchr(exten, ']');
+
+ if (!exten) {
+ /* we'll end up warning about this later, don't spam logs */
+ return fluff;
+ }
+ }
+ exten++;
+ }
+
+ return fluff;
+}
+
int ast_extension_cmp(const char *a, const char *b)
{
int cmp;
struct ast_context *next;
struct ast_includes includes;
struct ast_ignorepats ignorepats;
+ struct ast_sws alts;
const char *registrar;
int refcount;
int autohints;
- AST_LIST_HEAD_NOLOCK(, ast_sw) alts;
ast_mutex_t macrolock;
char name[256];
};
int x, res;
struct ast_context *tmp = NULL;
struct ast_exten *e = NULL, *eroot = NULL;
- struct ast_sw *sw = NULL;
struct ast_exten pattern = {NULL, };
struct scoreboard score = {0, };
struct ast_str *tmpdata = NULL;
}
/* Check alternative switches */
- AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
- struct ast_switch *asw = pbx_findswitch(sw->name);
+ for (idx = 0; idx < ast_context_switches_count(tmp); idx++) {
+ const struct ast_sw *sw = ast_context_switches_get(tmp, idx);
+ struct ast_switch *asw = pbx_findswitch(ast_get_switch_name(sw));
ast_switch_f *aswf = NULL;
- char *datap;
+ const char *datap;
if (!asw) {
- ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
+ ast_log(LOG_WARNING, "No such switch '%s'\n", ast_get_switch_name(sw));
continue;
}
/* Substitute variables now */
- if (sw->eval) {
+ if (ast_get_switch_eval(sw)) {
if (!(tmpdata = ast_str_thread_get(&switch_data, 512))) {
ast_log(LOG_WARNING, "Can't evaluate switch?!\n");
continue;
}
- pbx_substitute_variables_helper(chan, sw->data, ast_str_buffer(tmpdata), ast_str_size(tmpdata));
+ pbx_substitute_variables_helper(chan, ast_get_switch_data(sw),
+ ast_str_buffer(tmpdata), ast_str_size(tmpdata));
+ datap = ast_str_buffer(tmpdata);
+ } else {
+ datap = ast_get_switch_data(sw);
}
/* equivalent of extension_match_core() at the switch level */
aswf = asw->matchmore;
else /* action == E_MATCH */
aswf = asw->exists;
- datap = sw->eval ? ast_str_buffer(tmpdata) : sw->data;
if (!aswf)
res = 0;
else {
hint_new->last_presence_state = presence_state;
hint_new->last_presence_subtype = subtype;
hint_new->last_presence_message = message;
- message = subtype = NULL;
}
}
ast_channel_pbx(c)->rtimeoutms = 10000;
ast_channel_pbx(c)->dtimeoutms = 5000;
+ ast_channel_lock(c);
autoloopflag = ast_test_flag(ast_channel_flags(c), AST_FLAG_IN_AUTOLOOP); /* save value to restore at the end */
ast_set_flag(ast_channel_flags(c), AST_FLAG_IN_AUTOLOOP);
+ ast_channel_unlock(c);
if (ast_strlen_zero(ast_channel_exten(c))) {
/* If not successful fall back to 's' - but only if there is no given exten */
ast_pbx_hangup_handler_run(c);
}
+ ast_channel_lock(c);
ast_set2_flag(ast_channel_flags(c), autoloopflag, AST_FLAG_IN_AUTOLOOP);
ast_clear_flag(ast_channel_flags(c), AST_FLAG_BRIDGE_HANGUP_RUN); /* from one round to the next, make sure this gets cleared */
+ ast_channel_unlock(c);
pbx_destroy(ast_channel_pbx(c));
ast_channel_pbx_set(c, NULL);
*/
int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
{
- struct ast_sw *i;
+ int idx;
int ret = -1;
ast_wrlock_context(con);
/* walk switches */
- AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
- if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
- (!registrar || !strcmp(i->registrar, registrar))) {
+ for (idx = 0; idx < ast_context_switches_count(con); idx++) {
+ struct ast_sw *i = AST_VECTOR_GET(&con->alts, idx);
+
+ if (!strcmp(ast_get_switch_name(i), sw) &&
+ !strcmp(ast_get_switch_data(i), data) &&
+ (!registrar || !strcmp(ast_get_switch_registrar(i), registrar))) {
+
/* found, remove from list */
ast_verb(3, "Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar);
- AST_LIST_REMOVE_CURRENT(list);
- ast_free(i); /* free switch and return */
+ AST_VECTOR_REMOVE_ORDERED(&con->alts, idx);
+
+ /* free switch and return */
+ sw_free(i);
ret = 0;
break;
}
}
- AST_LIST_TRAVERSE_SAFE_END;
ast_unlock_context(con);
struct ast_exten *peer;
struct ast_exten ex, *exten2, *exten3;
char dummy_name[1024];
+ char dummy_cid[1024];
struct ast_exten *previous_peer = NULL;
struct ast_exten *next_peer = NULL;
int found = 0;
#endif
/* find this particular extension */
ex.exten = dummy_name;
+ ext_strncpy(dummy_name, extension, sizeof(dummy_name), 1);
ex.matchcid = matchcallerid;
- ex.cidmatch = callerid;
- ast_copy_string(dummy_name, extension, sizeof(dummy_name));
+ if (callerid) {
+ ex.cidmatch = dummy_cid;
+ ext_strncpy(dummy_cid, callerid, sizeof(dummy_cid), 1);
+ } else {
+ ex.cidmatch = NULL;
+ }
exten = ast_hashtab_lookup(con->root_table, &ex);
if (exten) {
if (priority == 0) {
if (exten2) {
if (exten2->label) { /* if this exten has a label, remove that, too */
exten3 = ast_hashtab_remove_this_object(exten->peer_label_table,exten2);
- if (!exten3)
- ast_log(LOG_ERROR,"Did not remove this priority label (%d/%s) from the peer_label_table of context %s, extension %s!\n", priority, exten2->label, con->name, exten2->exten);
+ if (!exten3) {
+ ast_log(LOG_ERROR, "Did not remove this priority label (%d/%s) "
+ "from the peer_label_table of context %s, extension %s!\n",
+ priority, exten2->label, con->name, exten2->name);
+ }
}
exten3 = ast_hashtab_remove_this_object(exten->peer_table, exten2);
- if (!exten3)
- ast_log(LOG_ERROR,"Did not remove this priority (%d) from the peer_table of context %s, extension %s!\n", priority, con->name, exten2->exten);
+ if (!exten3) {
+ ast_log(LOG_ERROR, "Did not remove this priority (%d) from the "
+ "peer_table of context %s, extension %s!\n",
+ priority, con->name, exten2->name);
+ }
if (exten2 == exten && exten2->peer) {
exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
ast_hashtab_insert_immediate(con->root_table, exten2->peer);
/* well, if the last priority of an exten is to be removed,
then, the extension is removed, too! */
exten3 = ast_hashtab_remove_this_object(con->root_table, exten);
- if (!exten3)
- ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_table (%s) (priority %d)\n", exten->exten, con->name, priority);
+ if (!exten3) {
+ ast_log(LOG_ERROR, "Did not remove this exten (%s) from the "
+ "context root_table (%s) (priority %d)\n",
+ exten->name, con->name, priority);
+ }
if (con->pattern_tree) {
struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
if (x->exten) { /* this test for safety purposes */
}
} else {
ast_log(LOG_ERROR,"Could not find priority %d of exten %s in context %s!\n",
- priority, exten->exten, con->name);
+ priority, exten->name, con->name);
}
}
} else {
/* scan the extension list to find first matching extension-registrar */
for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
- if (!strcmp(exten->exten, extension) &&
- (!registrar || !strcmp(exten->registrar, registrar)) &&
- (!matchcallerid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(exten->cidmatch) && !strcmp(exten->cidmatch, callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(exten->cidmatch))))
+ if (!strcmp(exten->exten, ex.exten) &&
+ (!matchcallerid ||
+ (!ast_strlen_zero(ex.cidmatch) && !ast_strlen_zero(exten->cidmatch) && !strcmp(exten->cidmatch, ex.cidmatch)) ||
+ (ast_strlen_zero(ex.cidmatch) && ast_strlen_zero(exten->cidmatch)))) {
break;
+ }
}
if (!exten) {
/* we can't find right extension */
/* scan the priority list to remove extension with exten->priority == priority */
for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next;
- peer && !strcmp(peer->exten, extension) &&
- (!callerid || (!matchcallerid && !peer->matchcid) || (matchcallerid && peer->matchcid && !strcmp(peer->cidmatch, callerid))) ;
+ peer && !strcmp(peer->exten, ex.exten) &&
+ (!callerid || (!matchcallerid && !peer->matchcid) || (matchcallerid && peer->matchcid && !strcmp(peer->cidmatch, ex.cidmatch))) ;
peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) {
if ((priority == 0 || peer->priority == priority) &&
}
}
+/*! \brief Writes CLI output of a single extension for show dialplan */
+static void show_dialplan_helper_extension_output(int fd, char *buf1, char *buf2, struct ast_exten *exten)
+{
+ if (ast_get_extension_registrar_file(exten)) {
+ ast_cli(fd, " %-17s %-45s [%s:%d]\n",
+ buf1, buf2,
+ ast_get_extension_registrar_file(exten),
+ ast_get_extension_registrar_line(exten));
+ return;
+ }
+
+ ast_cli(fd, " %-17s %-45s [%s]\n",
+ buf1, buf2, ast_get_extension_registrar(exten));
+}
+
/* XXX not verified */
static int show_dialplan_helper(int fd, const char *context, const char *exten, struct dialplan_counters *dpc, const struct ast_include *rinclude, int includecount, const char *includes[])
{
print_ext(e, buf2, sizeof(buf2));
- ast_cli(fd, " %-17s %-45s [%s]\n", buf, buf2,
- ast_get_extension_registrar(e));
+ show_dialplan_helper_extension_output(fd, buf, buf2, e);
dpc->total_exten++;
/* walk next extension peers */
buf[0] = '\0';
print_ext(p, buf2, sizeof(buf2));
- ast_cli(fd," %-17s %-45s [%s]\n", buf, buf2,
- ast_get_extension_registrar(p));
+ show_dialplan_helper_extension_output(fd, buf, buf2, p);
}
}
}
}
if (!rinclude) {
- struct ast_sw *sw = NULL;
- while ( (sw = ast_walk_context_switches(c, sw)) ) {
+ for (idx = 0; idx < ast_context_switches_count(c); idx++) {
+ const struct ast_sw *sw = ast_context_switches_get(c, idx);
+
snprintf(buf, sizeof(buf), "'%s/%s'",
ast_get_switch_name(sw),
ast_get_switch_data(sw));
static int manager_show_dialplan_helper(struct mansession *s, const struct message *m,
const char *actionidtext, const char *context,
const char *exten, struct dialplan_counters *dpc,
- const struct ast_include *rinclude)
+ const struct ast_include *rinclude,
+ int includecount, const char *includes[])
{
struct ast_context *c;
int res = 0, old_total_exten = dpc->total_exten;
if (exten) {
/* Check all includes for the requested extension */
- manager_show_dialplan_helper(s, m, actionidtext, ast_get_include_name(i), exten, dpc, i);
+ if (includecount >= AST_PBX_MAX_STACK) {
+ ast_log(LOG_WARNING, "Maximum include depth exceeded!\n");
+ } else {
+ int dupe = 0;
+ int x;
+ for (x = 0; x < includecount; x++) {
+ if (!strcasecmp(includes[x], ast_get_include_name(i))) {
+ dupe++;
+ break;
+ }
+ }
+ if (!dupe) {
+ includes[includecount] = ast_get_include_name(i);
+ manager_show_dialplan_helper(s, m, actionidtext, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
+ } else {
+ ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
+ }
+ }
} else {
if (!dpc->total_items++)
manager_dpsendack(s, m);
}
}
if (!rinclude) {
- struct ast_sw *sw = NULL;
- while ( (sw = ast_walk_context_switches(c, sw)) ) {
+ for (idx = 0; idx < ast_context_switches_count(c); idx++) {
+ const struct ast_sw *sw = ast_context_switches_get(c, idx);
+
if (!dpc->total_items++)
manager_dpsendack(s, m);
astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
{
const char *exten, *context;
const char *id = astman_get_header(m, "ActionID");
+ const char *incstack[AST_PBX_MAX_STACK];
char idtext[256];
/* Variables used for different counters */
exten = astman_get_header(m, "Extension");
context = astman_get_header(m, "Context");
- manager_show_dialplan_helper(s, m, idtext, context, exten, &counters, NULL);
+ manager_show_dialplan_helper(s, m, idtext, context, exten, &counters, NULL, 0, incstack);
if (!ast_strlen_zero(context) && !counters.context_existence) {
char errorbuf[BUFSIZ];
tmp->registrar = ast_strdup(registrar);
AST_VECTOR_INIT(&tmp->includes, 0);
AST_VECTOR_INIT(&tmp->ignorepats, 0);
+ AST_VECTOR_INIT(&tmp->alts, 0);
tmp->refcount = 1;
} else {
ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name);
static void context_merge_incls_swits_igps_other_registrars(struct ast_context *new, struct ast_context *old, const char *registrar)
{
int idx;
- struct ast_sw *sw;
ast_verb(3, "merging incls/swits/igpats from old(%s) to new(%s) context, registrar = %s\n", ast_get_context_name(old), ast_get_context_name(new), registrar);
/* copy in the includes, switches, and ignorepats */
}
/* walk through switches */
- for (sw = NULL; (sw = ast_walk_context_switches(old, sw)) ; ) {
- if (strcmp(ast_get_switch_registrar(sw), registrar) == 0)
+ for (idx = 0; idx < ast_context_switches_count(old); idx++) {
+ const struct ast_sw *sw = ast_context_switches_get(old, idx);
+
+ if (!strcmp(ast_get_switch_registrar(sw), registrar)) {
continue; /* not mine */
+ }
ast_context_add_switch2(new, ast_get_switch_name(sw), ast_get_switch_data(sw), ast_get_switch_eval(sw), ast_get_switch_registrar(sw));
}
dupdstr = ast_strdup(prio_item->data);
- res1 = ast_add_extension2(new, 0, prio_item->exten, prio_item->priority, prio_item->label,
- prio_item->matchcid ? prio_item->cidmatch : NULL, prio_item->app, dupdstr, ast_free_ptr, prio_item->registrar);
+ res1 = ast_add_extension2(new, 0, prio_item->name, prio_item->priority, prio_item->label,
+ prio_item->matchcid ? prio_item->cidmatch : NULL, prio_item->app, dupdstr, ast_free_ptr, prio_item->registrar,
+ prio_item->registrar_file, prio_item->registrar_line);
if (!res1 && new_exten_item && new_prio_item){
ast_verb(3,"Dropping old dialplan item %s/%s/%d [%s(%s)] (registrar=%s) due to conflict with new dialplan\n",
- context->name, prio_item->exten, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar);
+ context->name, prio_item->name, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar);
} else {
/* we do NOT pass the priority data from the old to the new -- we pass a copy of it, so no changes to the current dialplan take place,
and no double frees take place, either! */
}
/* ... include new context into context list, unlock, return */
- AST_VECTOR_APPEND(&con->includes, new_include);
+ if (AST_VECTOR_APPEND(&con->includes, new_include)) {
+ include_free(new_include);
+ ast_unlock_context(con);
+ return -1;
+ }
ast_verb(3, "Including context '%s' in context '%s'\n",
ast_get_include_name(new_include), ast_get_context_name(con));
int ast_context_add_switch2(struct ast_context *con, const char *value,
const char *data, int eval, const char *registrar)
{
+ int idx;
struct ast_sw *new_sw;
- struct ast_sw *i;
- int length;
- char *p;
-
- length = sizeof(struct ast_sw);
- length += strlen(value) + 1;
- if (data)
- length += strlen(data);
- length++;
/* allocate new sw structure ... */
- if (!(new_sw = ast_calloc(1, length)))
+ if (!(new_sw = sw_alloc(value, data, eval, registrar))) {
return -1;
- /* ... fill in this structure ... */
- p = new_sw->stuff;
- new_sw->name = p;
- strcpy(new_sw->name, value);
- p += strlen(value) + 1;
- new_sw->data = p;
- if (data) {
- strcpy(new_sw->data, data);
- p += strlen(data) + 1;
- } else {
- strcpy(new_sw->data, "");
- p++;
}
- new_sw->eval = eval;
- new_sw->registrar = registrar;
/* ... try to lock this context ... */
ast_wrlock_context(con);
/* ... go to last sw and check if context is already swd too... */
- AST_LIST_TRAVERSE(&con->alts, i, list) {
- if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
- ast_free(new_sw);
+ for (idx = 0; idx < ast_context_switches_count(con); idx++) {
+ const struct ast_sw *i = ast_context_switches_get(con, idx);
+
+ if (!strcasecmp(ast_get_switch_name(i), ast_get_switch_name(new_sw)) &&
+ !strcasecmp(ast_get_switch_data(i), ast_get_switch_data(new_sw))) {
+ sw_free(new_sw);
ast_unlock_context(con);
errno = EEXIST;
return -1;
}
/* ... sw new context into context list, unlock, return */
- AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
+ if (AST_VECTOR_APPEND(&con->alts, new_sw)) {
+ sw_free(new_sw);
+ ast_unlock_context(con);
+ return -1;
+ }
- ast_verb(3, "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
+ ast_verb(3, "Including switch '%s/%s' in context '%s'\n",
+ ast_get_switch_name(new_sw), ast_get_switch_data(new_sw), ast_get_context_name(con));
ast_unlock_context(con);
return -1;
}
}
- AST_VECTOR_APPEND(&con->ignorepats, ignorepat);
+ if (AST_VECTOR_APPEND(&con->ignorepats, ignorepat)) {
+ ignorepat_free(ignorepat);
+ ast_unlock_context(con);
+ return -1;
+ }
ast_unlock_context(con);
return 0;
c = find_context(context);
if (c) {
ret = ast_add_extension2_lockopt(c, replace, extension, priority, label, callerid,
- application, data, datad, registrar, 1);
+ application, data, datad, registrar, NULL, 0, 1);
}
return ret;
c = find_context_locked(context);
if (c) {
ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
- application, data, datad, registrar);
+ application, data, datad, registrar, NULL, 0);
ast_unlock_contexts();
}
return res;
}
-/*! \brief copy a string skipping whitespace */
-static int ext_strncpy(char *dst, const char *src, int len)
+/*!
+ * \internal
+ * \brief Copy a string skipping whitespace and optionally dashes.
+ *
+ * \param dst Destination buffer to copy src string.
+ * \param src Null terminated string to copy.
+ * \param dst_size Number of bytes in the dst buffer.
+ * \param nofluf Nonzero if '-' chars are not copied.
+ *
+ * \return Number of bytes written to dst including null terminator.
+ */
+static unsigned int ext_strncpy(char *dst, const char *src, size_t dst_size, int nofluff)
{
- int count = 0;
- int insquares = 0;
+ unsigned int count;
+ unsigned int insquares;
+ unsigned int is_pattern;
- while (*src && (count < len - 1)) {
+ if (!dst_size--) {
+ /* There really is no dst buffer */
+ return 0;
+ }
+
+ count = 0;
+ insquares = 0;
+ is_pattern = *src == '_';
+ while (*src && count < dst_size) {
if (*src == '[') {
- insquares = 1;
+ if (is_pattern) {
+ insquares = 1;
+ }
} else if (*src == ']') {
insquares = 0;
} else if (*src == ' ' && !insquares) {
- src++;
+ ++src;
+ continue;
+ } else if (*src == '-' && !insquares && nofluff) {
+ ++src;
continue;
}
- *dst = *src;
- dst++;
- src++;
- count++;
+ *dst++ = *src++;
+ ++count;
}
*dst = '\0';
- return count;
+ return count + 1;
}
/*!
for (ep = NULL; e ; ep = e, e = e->peer) {
if (e->label && tmp->label && e->priority != tmp->priority && !strcmp(e->label, tmp->label)) {
- if (strcmp(e->exten, tmp->exten)) {
+ if (strcmp(e->name, tmp->name)) {
ast_log(LOG_WARNING,
"Extension '%s' priority %d in '%s', label '%s' already in use at aliased extension '%s' priority %d\n",
- tmp->exten, tmp->priority, con->name, tmp->label, e->exten, e->priority);
+ tmp->name, tmp->priority, con->name, tmp->label, e->name, e->priority);
} else {
ast_log(LOG_WARNING,
"Extension '%s' priority %d in '%s', label '%s' already in use at priority %d\n",
- tmp->exten, tmp->priority, con->name, tmp->label, e->priority);
+ tmp->name, tmp->priority, con->name, tmp->label, e->priority);
}
repeated_label = 1;
}
/* Can't have something exactly the same. Is this a
replacement? If so, replace, otherwise, bonk. */
if (!replace) {
- if (strcmp(e->exten, tmp->exten)) {
+ if (strcmp(e->name, tmp->name)) {
ast_log(LOG_WARNING,
"Unable to register extension '%s' priority %d in '%s', already in use by aliased extension '%s'\n",
- tmp->exten, tmp->priority, con->name, e->exten);
+ tmp->name, tmp->priority, con->name, e->name);
} 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->name, tmp->priority, con->name);
}
return -1;
int ast_add_extension2(struct ast_context *con,
int replace, const char *extension, int priority, const char *label, const char *callerid,
const char *application, void *data, void (*datad)(void *),
- const char *registrar)
+ const char *registrar, const char *registrar_file, int registrar_line)
{
return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid,
- application, data, datad, registrar, 1);
+ application, data, datad, registrar, registrar_file, registrar_line, 1);
}
int ast_add_extension2_nolock(struct ast_context *con,
int replace, const char *extension, int priority, const char *label, const char *callerid,
const char *application, void *data, void (*datad)(void *),
- const char *registrar)
+ const char *registrar, const char *registrar_file, int registrar_line)
{
return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid,
- application, data, datad, registrar, 0);
+ application, data, datad, registrar, registrar_file, registrar_line, 0);
}
static int ast_add_extension2_lockopt(struct ast_context *con,
int replace, const char *extension, int priority, const char *label, const char *callerid,
const char *application, void *data, void (*datad)(void *),
- const char *registrar, int lock_context)
+ const char *registrar, const char *registrar_file, int registrar_line, int lock_context)
{
/*
* Sort extensions (or patterns) according to the rules indicated above.
char expand_buf[VAR_BUF_SIZE];
struct ast_exten dummy_exten = {0};
char dummy_name[1024];
+ int exten_fluff;
+ int callerid_fluff;
if (ast_strlen_zero(extension)) {
ast_log(LOG_ERROR,"You have to be kidding-- add exten '' to context %s? Figure out a name and call me back. Action ignored.\n",
/* If we are adding a hint evalulate in variables and global variables */
if (priority == PRIORITY_HINT && strstr(application, "${") && extension[0] != '_') {
+ int inhibited;
struct ast_channel *c = ast_dummy_channel_alloc();
if (c) {
ast_channel_exten_set(c, extension);
ast_channel_context_set(c, con->name);
}
+
+ /*
+ * We can allow dangerous functions when adding a hint since
+ * altering dialplan is itself a privileged activity. Otherwise,
+ * we could never execute dangerous functions.
+ */
+ inhibited = ast_thread_inhibit_escalations_swap(0);
pbx_substitute_variables_helper(c, application, expand_buf, sizeof(expand_buf));
+ if (0 < inhibited) {
+ ast_thread_inhibit_escalations();
+ }
+
application = expand_buf;
if (c) {
ast_channel_unref(c);
}
}
+ exten_fluff = ext_fluff_count(extension);
+ callerid_fluff = callerid ? ext_fluff_count(callerid) : 0;
+
length = sizeof(struct ast_exten);
length += strlen(extension) + 1;
+ if (exten_fluff) {
+ length += strlen(extension) + 1 - exten_fluff;
+ }
length += strlen(application) + 1;
- if (label)
+ if (label) {
length += strlen(label) + 1;
- if (callerid)
+ }
+ if (callerid) {
length += strlen(callerid) + 1;
- else
+ if (callerid_fluff) {
+ length += strlen(callerid) + 1 - callerid_fluff;
+ }
+ } else {
length ++; /* just the '\0' */
+ }
+ if (registrar_file) {
+ length += strlen(registrar_file) + 1;
+ }
/* Be optimistic: Build the extension structure first */
if (!(tmp = ast_calloc(1, length)))
strcpy(p, label);
p += strlen(label) + 1;
}
- tmp->exten = p;
- p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
+ tmp->name = p;
+ p += ext_strncpy(p, extension, strlen(extension) + 1, 0);
+ if (exten_fluff) {
+ tmp->exten = p;
+ p += ext_strncpy(p, extension, strlen(extension) + 1 - exten_fluff, 1);
+ } else {
+ /* no fluff, we don't need a copy. */
+ tmp->exten = tmp->name;
+ }
tmp->priority = priority;
- tmp->cidmatch = p; /* but use p for assignments below */
+ tmp->cidmatch_display = tmp->cidmatch = p; /* but use p for assignments below */
/* Blank callerid and NULL callerid are two SEPARATE things. Do NOT confuse the two!!! */
if (callerid) {
- p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
+ p += ext_strncpy(p, callerid, strlen(callerid) + 1, 0);
+ if (callerid_fluff) {
+ tmp->cidmatch = p;
+ p += ext_strncpy(p, callerid, strlen(callerid) + 1 - callerid_fluff, 1);
+ }
tmp->matchcid = AST_EXT_MATCHCID_ON;
} else {
*p++ = '\0';
tmp->matchcid = AST_EXT_MATCHCID_OFF;
}
+
+ if (registrar_file) {
+ tmp->registrar_file = p;
+ strcpy(p, registrar_file);
+ p += strlen(registrar_file) + 1;
+ } else {
+ tmp->registrar_file = NULL;
+ }
+
tmp->app = p;
strcpy(p, application);
tmp->parent = con;
tmp->data = data;
tmp->datad = datad;
tmp->registrar = registrar;
+ tmp->registrar_line = registrar_line;
if (lock_context) {
ast_wrlock_context(con);
if (con->pattern_tree) { /* usually, on initial load, the pattern_tree isn't formed until the first find_exten; so if we are adding
an extension, and the trie exists, then we need to incrementally add this pattern to it. */
- ast_copy_string(dummy_name, extension, sizeof(dummy_name));
+ ext_strncpy(dummy_name, tmp->exten, sizeof(dummy_name), 1);
dummy_exten.exten = dummy_name;
dummy_exten.matchcid = AST_EXT_MATCHCID_OFF;
dummy_exten.cidmatch = 0;
* so insert in the main list right before 'e' (if any)
*/
tmp->next = e;
- if (el) { /* there is another exten already in this context */
- el->next = tmp;
- tmp->peer_table = ast_hashtab_create(13,
- hashtab_compare_exten_numbers,
+ tmp->peer_table = ast_hashtab_create(13,
+ hashtab_compare_exten_numbers,
+ ast_hashtab_resize_java,
+ ast_hashtab_newsize_java,
+ hashtab_hash_priority,
+ 0);
+ tmp->peer_label_table = ast_hashtab_create(7,
+ hashtab_compare_exten_labels,
ast_hashtab_resize_java,
ast_hashtab_newsize_java,
- hashtab_hash_priority,
+ hashtab_hash_labels,
0);
- tmp->peer_label_table = ast_hashtab_create(7,
- hashtab_compare_exten_labels,
- ast_hashtab_resize_java,
- ast_hashtab_newsize_java,
- hashtab_hash_labels,
- 0);
- if (label) {
- ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
- }
- ast_hashtab_insert_safe(tmp->peer_table, tmp);
+
+ if (el) { /* there is another exten already in this context */
+ el->next = tmp;
} else { /* this is the first exten in this context */
- if (!con->root_table)
+ if (!con->root_table) {
con->root_table = ast_hashtab_create(27,
hashtab_compare_extens,
ast_hashtab_resize_java,
ast_hashtab_newsize_java,
hashtab_hash_extens,
0);
- con->root = tmp;
- con->root->peer_table = ast_hashtab_create(13,
- hashtab_compare_exten_numbers,
- ast_hashtab_resize_java,
- ast_hashtab_newsize_java,
- hashtab_hash_priority,
- 0);
- con->root->peer_label_table = ast_hashtab_create(7,
- hashtab_compare_exten_labels,
- ast_hashtab_resize_java,
- ast_hashtab_newsize_java,
- hashtab_hash_labels,
- 0);
- if (label) {
- ast_hashtab_insert_safe(con->root->peer_label_table, tmp);
}
- ast_hashtab_insert_safe(con->root->peer_table, tmp);
-
+ con->root = tmp;
}
+ if (label) {
+ ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
+ }
+ ast_hashtab_insert_safe(tmp->peer_table, tmp);
ast_hashtab_insert_safe(con->root_table, tmp);
+
if (lock_context) {
ast_unlock_context(con);
}
if (option_debug) {
if (tmp->matchcid == AST_EXT_MATCHCID_ON) {
ast_debug(1, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
- tmp->exten, tmp->priority, tmp->cidmatch, con->name, con);
+ tmp->name, tmp->priority, tmp->cidmatch_display, con->name, con);
} else {
ast_debug(1, "Added extension '%s' priority %d to %s (%p)\n",
- tmp->exten, tmp->priority, con->name, con);
+ tmp->name, tmp->priority, con->name, con);
}
}
if (tmp->matchcid == AST_EXT_MATCHCID_ON) {
ast_verb(3, "Added extension '%s' priority %d (CID match '%s') to %s\n",
- tmp->exten, tmp->priority, tmp->cidmatch, con->name);
+ tmp->name, tmp->priority, tmp->cidmatch_display, con->name);
} else {
ast_verb(3, "Added extension '%s' priority %d to %s\n",
- tmp->exten, tmp->priority, con->name);
+ tmp->name, tmp->priority, con->name);
}
return 0;
int dial_res;
/*! \brief Set when dialing is completed */
unsigned int dialed:1;
- /*! \brief Set when execution is completed */
- unsigned int executed:1;
+ /*! \brief Set if we've spawned a thread to do our work */
+ unsigned int in_separate_thread:1;
};
/*! \brief Destructor for outgoing structure */
RAII_VAR(struct pbx_outgoing *, outgoing, data, ao2_cleanup);
enum ast_dial_result res;
- /* Notify anyone interested that dialing is complete */
res = ast_dial_run(outgoing->dial, NULL, 0);
- ao2_lock(outgoing);
- outgoing->dial_res = res;
- outgoing->dialed = 1;
- ast_cond_signal(&outgoing->cond);
- ao2_unlock(outgoing);
+
+ if (outgoing->in_separate_thread) {
+ /* Notify anyone interested that dialing is complete */
+ ao2_lock(outgoing);
+ outgoing->dial_res = res;
+ outgoing->dialed = 1;
+ ast_cond_signal(&outgoing->cond);
+ ao2_unlock(outgoing);
+ } else {
+ /* We still need the dial result, but we don't need to lock */
+ outgoing->dial_res = res;
+ }
/* If the outgoing leg was not answered we can immediately return and go no further */
if (res != AST_DIAL_RESULT_ANSWERED) {
}
}
- /* Notify anyone else again that may be interested that execution is complete */
- ao2_lock(outgoing);
- outgoing->executed = 1;
- ast_cond_signal(&outgoing->cond);
- ao2_unlock(outgoing);
-
return NULL;
}
const char *app, const char *appdata, int *reason, int synchronous,
const char *cid_num, const char *cid_name, struct ast_variable *vars,
const char *account, struct ast_channel **locked_channel, int early_media,
- const struct ast_assigned_ids *assignedids)
+ const struct ast_assigned_ids *assignedids, const char *predial_callee)
{
RAII_VAR(struct pbx_outgoing *, outgoing, NULL, ao2_cleanup);
struct ast_channel *dialed;
pthread_t thread;
+ char tmp_cid_name[128];
+ char tmp_cid_num[128];
outgoing = ao2_alloc(sizeof(*outgoing), pbx_outgoing_destroy);
if (!outgoing) {
ast_dial_set_global_timeout(outgoing->dial, timeout);
+ if (!ast_strlen_zero(predial_callee)) {
+ /* note casting to void * here to suppress compiler warning message (passing const to non-const function) */
+ ast_dial_option_global_enable(outgoing->dial, AST_DIAL_OPTION_PREDIAL, (void *)predial_callee);
+ }
+
if (ast_dial_prerun(outgoing->dial, NULL, cap)) {
if (synchronous && reason) {
*reason = pbx_dial_reason(AST_DIAL_RESULT_FAILED,
ast_channel_stage_snapshot_done(dialed);
}
ast_set_flag(ast_channel_flags(dialed), AST_FLAG_ORIGINATED);
+
+ if (!ast_strlen_zero(predial_callee)) {
+ char *tmp = NULL;
+ /*
+ * The predial sub routine may have set callerid so set this into the new channel
+ * Note... cid_num and cid_name parameters to this function will always be NULL if
+ * predial_callee is non-NULL so we are not overwriting anything here.
+ */
+ tmp = S_COR(ast_channel_caller(dialed)->id.number.valid, ast_channel_caller(dialed)->id.number.str, NULL);
+ if (tmp) {
+ ast_copy_string(tmp_cid_num, tmp, sizeof(tmp_cid_num));
+ cid_num = tmp_cid_num;
+ }
+ tmp = S_COR(ast_channel_caller(dialed)->id.name.valid, ast_channel_caller(dialed)->id.name.str, NULL);
+ if (tmp) {
+ ast_copy_string(tmp_cid_name, tmp, sizeof(tmp_cid_name));
+ cid_name = tmp_cid_name;
+ }
+ }
ast_channel_unlock(dialed);
if (!ast_strlen_zero(cid_num) || !ast_strlen_zero(cid_name)) {
}
}
+ /* This extra reference is dereferenced by pbx_outgoing_exec */
ao2_ref(outgoing, +1);
- if (ast_pthread_create_detached(&thread, NULL, pbx_outgoing_exec, outgoing)) {
- ast_log(LOG_WARNING, "Unable to spawn dialing thread for '%s/%s'\n", type, addr);
- ao2_ref(outgoing, -1);
- if (locked_channel) {
- if (!synchronous) {
- ast_channel_unlock(dialed);
+
+ if (synchronous == AST_OUTGOING_WAIT_COMPLETE) {
+ /*
+ * Because we are waiting until this is complete anyway, there is no
+ * sense in creating another thread that we will just need to wait
+ * for, so instead we commandeer the current thread.
+ */
+ pbx_outgoing_exec(outgoing);
+ } else {
+ outgoing->in_separate_thread = 1;
+
+ if (ast_pthread_create_detached(&thread, NULL, pbx_outgoing_exec, outgoing)) {
+ ast_log(LOG_WARNING, "Unable to spawn dialing thread for '%s/%s'\n", type, addr);
+ ao2_ref(outgoing, -1);
+ if (locked_channel) {
+ if (!synchronous) {
+ ast_channel_unlock(dialed);
+ }
+ ast_channel_unref(dialed);
}
- ast_channel_unref(dialed);
+ return -1;
}
- return -1;
- }
- if (synchronous) {
- ao2_lock(outgoing);
- /* Wait for dialing to complete */
- while (!outgoing->dialed) {
- ast_cond_wait(&outgoing->cond, ao2_object_get_lockaddr(outgoing));
- }
- if (1 < synchronous
- && outgoing->dial_res == AST_DIAL_RESULT_ANSWERED) {
- /* Wait for execution to complete */
- while (!outgoing->executed) {
+ if (synchronous) {
+ ao2_lock(outgoing);
+ /* Wait for dialing to complete */
+ while (!outgoing->dialed) {
ast_cond_wait(&outgoing->cond, ao2_object_get_lockaddr(outgoing));
}
+ ao2_unlock(outgoing);
}
- ao2_unlock(outgoing);
+ }
+ if (synchronous) {
/* Determine the outcome of the dialing attempt up to it being answered. */
if (reason) {
*reason = pbx_dial_reason(outgoing->dial_res,
const char *account, struct ast_channel **locked_channel, int early_media,
const struct ast_assigned_ids *assignedids)
{
+ return ast_pbx_outgoing_exten_predial(type, cap, addr, timeout, context, exten, priority, reason,
+ synchronous, cid_num, cid_name, vars, account, locked_channel, early_media, assignedids, NULL);
+}
+
+int ast_pbx_outgoing_exten_predial(const char *type, struct ast_format_cap *cap, const char *addr,
+ int timeout, const char *context, const char *exten, int priority, int *reason,
+ int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars,
+ const char *account, struct ast_channel **locked_channel, int early_media,
+ const struct ast_assigned_ids *assignedids, const char *predial_callee)
+{
int res;
int my_reason;
res = pbx_outgoing_attempt(type, cap, addr, timeout, context, exten, priority,
NULL, NULL, reason, synchronous, cid_num, cid_name, vars, account, locked_channel,
- early_media, assignedids);
+ early_media, assignedids, predial_callee);
if (res < 0 /* Call failed to get connected for some reason. */
- && 1 < synchronous
+ && 0 < synchronous
&& ast_exists_extension(NULL, context, "failed", 1, NULL)) {
struct ast_channel *failed;
const char *account, struct ast_channel **locked_channel,
const struct ast_assigned_ids *assignedids)
{
+ return ast_pbx_outgoing_app_predial(type, cap, addr, timeout, app, appdata, reason, synchronous,
+ cid_num, cid_name, vars, account, locked_channel, assignedids, NULL);
+}
+
+int ast_pbx_outgoing_app_predial(const char *type, struct ast_format_cap *cap, const char *addr,
+ int timeout, const char *app, const char *appdata, int *reason, int synchronous,
+ const char *cid_num, const char *cid_name, struct ast_variable *vars,
+ const char *account, struct ast_channel **locked_channel,
+ const struct ast_assigned_ids *assignedids, const char *predial_callee)
+{
if (reason) {
*reason = 0;
}
return pbx_outgoing_attempt(type, cap, addr, timeout, NULL, NULL, 0, app, appdata,
reason, synchronous, cid_num, cid_name, vars, account, locked_channel, 0,
- assignedids);
+ assignedids, predial_callee);
}
/* this is the guts of destroying a context --
static void __ast_internal_context_destroy( struct ast_context *con)
{
- struct ast_sw *sw;
struct ast_exten *e, *el, *en;
struct ast_context *tmp = con;
AST_VECTOR_CALLBACK_VOID(&tmp->ignorepats, ignorepat_free);
AST_VECTOR_FREE(&tmp->ignorepats);
+ /* Free switches */
+ AST_VECTOR_CALLBACK_VOID(&tmp->alts, sw_free);
+ AST_VECTOR_FREE(&tmp->alts);
+
if (tmp->registrar)
ast_free(tmp->registrar);
if (tmp->pattern_tree)
destroy_pattern_tree(tmp->pattern_tree);
- while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
- ast_free(sw);
for (e = tmp->root; e;) {
for (en = e->peer; en;) {
el = en;
/* then search thru and remove any extens that match registrar. */
struct ast_hashtab_iter *exten_iter;
struct ast_hashtab_iter *prio_iter;
- struct ast_sw *sw = NULL;
int idx;
/* remove any ignorepats whose registrar matches */
}
}
/* remove any switches whose registrar matches */
- AST_LIST_TRAVERSE_SAFE_BEGIN(&tmp->alts, sw, list) {
- if (strcmp(sw->registrar,registrar) == 0) {
- AST_LIST_REMOVE_CURRENT(list);
- ast_free(sw);
+ for (idx = ast_context_switches_count(tmp) - 1; idx >= 0; idx--) {
+ struct ast_sw *sw = AST_VECTOR_GET(&tmp->alts, idx);
+
+ if (!strcmp(ast_get_switch_registrar(sw), registrar)) {
+ AST_VECTOR_REMOVE_ORDERED(&tmp->alts, idx);
+ sw_free(sw);
}
}
- AST_LIST_TRAVERSE_SAFE_END;
if (tmp->root_table) { /* it is entirely possible that the context is EMPTY */
exten_iter = ast_hashtab_start_traversal(tmp->root_table);
continue;
}
ast_verb(3, "Remove %s/%s/%d, registrar=%s; con=%s(%p); con->root=%p\n",
- tmp->name, prio_item->exten, prio_item->priority, registrar, con? con->name : "<nil>", con, con? con->root_table: NULL);
+ tmp->name, prio_item->name, prio_item->priority, registrar, con? con->name : "<nil>", con, con? con->root_table: NULL);
ast_copy_string(extension, prio_item->exten, sizeof(extension));
if (prio_item->cidmatch) {
ast_copy_string(cidmatch, prio_item->cidmatch, sizeof(cidmatch));
/* delete the context if it's registrar matches, is empty, has refcount of 1, */
/* it's not empty, if it has includes, ignorepats, or switches that are registered from
another registrar. It's not empty if there are any extensions */
- if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !ast_context_ignorepats_count(tmp) && !ast_context_includes_count(tmp) && AST_LIST_EMPTY(&tmp->alts)) {
+ if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !ast_context_ignorepats_count(tmp) && !ast_context_includes_count(tmp) && !ast_context_switches_count(tmp)) {
ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
ast_hashtab_remove_this_object(contexttab, tmp);
ast_free(hint_app);
}
-/*!
- * \internal
- * \brief Implements the hints data provider.
- */
-static int hints_data_provider_get(const struct ast_data_search *search,
- struct ast_data *data_root)
-{
- struct ast_data *data_hint;
- struct ast_hint *hint;
- int watchers;
- struct ao2_iterator i;
-
- if (ao2_container_count(hints) == 0) {
- return 0;
- }
-
- i = ao2_iterator_init(hints, 0);
- for (; (hint = ao2_iterator_next(&i)); ao2_ref(hint, -1)) {
- watchers = ao2_container_count(hint->callbacks);
- data_hint = ast_data_add_node(data_root, "hint");
- if (!data_hint) {
- continue;
- }
- ast_data_add_str(data_hint, "extension", ast_get_extension_name(hint->exten));
- ast_data_add_str(data_hint, "context", ast_get_context_name(ast_get_extension_context(hint->exten)));
- ast_data_add_str(data_hint, "application", ast_get_extension_app(hint->exten));
- ast_data_add_str(data_hint, "state", ast_extension_state2str(hint->laststate));
- ast_data_add_str(data_hint, "presence_state", ast_presence_state2str(hint->last_presence_state));
- ast_data_add_str(data_hint, "presence_subtype", S_OR(hint->last_presence_subtype, ""));
- ast_data_add_str(data_hint, "presence_subtype", S_OR(hint->last_presence_message, ""));
- ast_data_add_int(data_hint, "watchers", watchers);
-
- if (!ast_data_search_match(search, data_hint)) {
- ast_data_remove_node(data_root, data_hint);
- }
- }
- ao2_iterator_destroy(&i);
-
- return 0;
-}
-
-static const struct ast_data_handler hints_data_provider = {
- .version = AST_DATA_HANDLER_VERSION,
- .get = hints_data_provider_get
-};
-
-static const struct ast_data_entry pbx_data_providers[] = {
- AST_DATA_ENTRY("asterisk/core/hints", &hints_data_provider),
-};
-
static int action_extensionstatelist(struct mansession *s, const struct message *m)
{
const char *action_id = astman_get_header(m, "ActionID");
ast_cli_unregister_multiple(pbx_cli, ARRAY_LEN(pbx_cli));
ast_custom_function_unregister(&exception_function);
ast_custom_function_unregister(&testtime_function);
- ast_data_unregister(NULL);
}
int load_pbx(void)
ast_verb(2, "Registering builtin functions:\n");
ast_cli_register_multiple(pbx_cli, ARRAY_LEN(pbx_cli));
- ast_data_register_multiple_core(pbx_data_providers, ARRAY_LEN(pbx_data_providers));
__ast_custom_function_register(&exception_function, NULL);
__ast_custom_function_register(&testtime_function, NULL);
const char *ast_get_extension_name(struct ast_exten *exten)
{
- return exten ? exten->exten : NULL;
+ return exten ? exten->name : NULL;
}
const char *ast_get_extension_label(struct ast_exten *exten)
return e ? e->registrar : NULL;
}
+const char *ast_get_extension_registrar_file(struct ast_exten *e)
+{
+ return e ? e->registrar_file : NULL;
+}
+
+int ast_get_extension_registrar_line(struct ast_exten *e)
+{
+ return e ? e->registrar_line : 0;
+}
+
int ast_get_extension_matchcid(struct ast_exten *e)
{
return e ? e->matchcid : 0;
const char *ast_get_extension_cidmatch(struct ast_exten *e)
{
- return e ? e->cidmatch : NULL;
+ return e ? e->cidmatch_display : NULL;
}
const char *ast_get_extension_app(struct ast_exten *e)
return e ? e->data : NULL;
}
-const char *ast_get_switch_name(struct ast_sw *sw)
-{
- return sw ? sw->name : NULL;
-}
-
-const char *ast_get_switch_data(struct ast_sw *sw)
-{
- return sw ? sw->data : NULL;
-}
-
-int ast_get_switch_eval(struct ast_sw *sw)
-{
- return sw->eval;
-}
-
-const char *ast_get_switch_registrar(struct ast_sw *sw)
-{
- return sw ? sw->registrar : NULL;
-}
-
/*
* Walking functions ...
*/
return exten->next;
}
-struct ast_sw *ast_walk_context_switches(struct ast_context *con,
- struct ast_sw *sw)
+const struct ast_sw *ast_walk_context_switches(const struct ast_context *con,
+ const struct ast_sw *sw)
{
- if (!sw)
- return con ? AST_LIST_FIRST(&con->alts) : NULL;
- else
- return AST_LIST_NEXT(sw, list);
+ if (sw) {
+ int idx;
+ int next = 0;
+
+ for (idx = 0; idx < ast_context_switches_count(con); idx++) {
+ const struct ast_sw *s = ast_context_switches_get(con, idx);
+
+ if (next) {
+ return s;
+ }
+
+ if (sw == s) {
+ next = 1;
+ }
+ }
+
+ return NULL;
+ }
+
+ if (!ast_context_switches_count(con)) {
+ return NULL;
+ }
+
+ return ast_context_switches_get(con, 0);
+}
+
+int ast_context_switches_count(const struct ast_context *con)
+{
+ return AST_VECTOR_SIZE(&con->alts);
+}
+
+const struct ast_sw *ast_context_switches_get(const struct ast_context *con, int idx)
+{
+ return AST_VECTOR_GET(&con->alts, idx);
}
struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,