loader: Fix comments in struct ast_module.
[asterisk/asterisk.git] / main / pbx.c
index a8128ab..b5602b5 100644 (file)
@@ -29,8 +29,6 @@
 
 #include "asterisk.h"
 
-ASTERISK_REGISTER_FILE()
-
 #include "asterisk/_private.h"
 #include "asterisk/paths.h"    /* use ast_config_AST_SYSTEM_NAME */
 #include <ctype.h>
@@ -237,9 +235,11 @@ AST_THREADSTORAGE(extensionstate_buf);
        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  */
@@ -251,38 +251,12 @@ struct ast_exten {
        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_include: include= support in extensions.conf */
-struct ast_include {
-       const char *name;
-       const char *rname;                      /*!< Context to include */
-       const char *registrar;                  /*!< Registrar */
-       int hastime;                            /*!< If time construct exists */
-       struct ast_timing timing;               /*!< time construct */
-       struct ast_include *next;               /*!< Link them together */
-       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 ast_ignorepat: Ignore patterns in dial plan */
-struct ast_ignorepat {
-       const char *registrar;
-       struct ast_ignorepat *next;
-       const char pattern[0];
-};
-
 /*! \brief match_char: forms a syntax tree for quick matching of extension patterns */
 struct match_char
 {
@@ -313,12 +287,12 @@ struct ast_context {
        struct ast_hashtab *root_table;            /*!< For exact matches on the extensions in the pattern tree, and for traversals of the pattern_tree  */
        struct match_char *pattern_tree;        /*!< A tree to speed up extension pattern matching */
        struct ast_context *next;               /*!< Link them together */
-       struct ast_include *includes;           /*!< Include other contexts */
-       struct ast_ignorepat *ignorepats;       /*!< Patterns for which to continue playing dialtone */
+       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 */
 };
@@ -678,10 +652,12 @@ static int ast_add_extension_nolock(const char *context, int replace, const char
 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
@@ -906,9 +882,13 @@ int check_contexts(char *file, int line )
                                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();
                                }
@@ -1001,14 +981,6 @@ int check_contexts(char *file, int line )
 }
 #endif
 
-static inline int include_valid(struct ast_include *i)
-{
-       if (!i->hastime)
-               return 1;
-
-       return ast_check_timing(&(i->timing));
-}
-
 static void pbx_destroy(struct ast_pbx *p)
 {
        ast_free(p);
@@ -1149,11 +1121,11 @@ static void cli_match_char_tree(struct match_char *node, char *prefix, int fd)
        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);
@@ -1268,7 +1240,7 @@ static void new_find_extension(const char *str, struct scoreboard *score, struct
                                                                                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 */           \
                                                                }                                                                                                        \
                                                        }                                                                                                            \
@@ -1281,13 +1253,13 @@ static void new_find_extension(const char *str, struct scoreboard *score, struct
                                                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 */                                                 \
                                                        }                                                                                                                                                \
@@ -1325,14 +1297,17 @@ static void new_find_extension(const char *str, struct scoreboard *score, struct
                                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 */
                                        }
                                }
@@ -1347,14 +1322,17 @@ static void new_find_extension(const char *str, struct scoreboard *score, struct
                                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 */
                                        }
                                }
@@ -1363,7 +1341,9 @@ static void new_find_extension(const char *str, struct scoreboard *score, struct
                                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 */
                                        }
                                }
@@ -1716,7 +1696,7 @@ static struct match_char *add_exten_to_pattern_tree(struct ast_context *con, str
                                }
                                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;
@@ -1742,7 +1722,7 @@ static struct match_char *add_exten_to_pattern_tree(struct ast_context *con, str
                        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;
@@ -2149,6 +2129,41 @@ static int ext_cmp(const char *left, const char *right)
        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;
@@ -2399,12 +2414,12 @@ struct fake_context /* this struct is purely for matching in the hashtab */
        struct ast_hashtab *root_table;
        struct match_char *pattern_tree;
        struct ast_context *next;
-       struct ast_include *includes;
-       struct ast_ignorepat *ignorepats;
+       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];
 };
@@ -2459,11 +2474,10 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
        int x, res;
        struct ast_context *tmp = NULL;
        struct ast_exten *e = NULL, *eroot = NULL;
-       struct ast_include *i = NULL;
-       struct ast_sw *sw = NULL;
        struct ast_exten pattern = {NULL, };
        struct scoreboard score = {0, };
        struct ast_str *tmpdata = NULL;
+       int idx;
 
        pattern.label = label;
        pattern.priority = priority;
@@ -2683,23 +2697,28 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
        }
 
        /* 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 */
@@ -2709,7 +2728,6 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
                        aswf = asw->matchmore;
                else /* action == E_MATCH */
                        aswf = asw->exists;
-               datap = sw->eval ? ast_str_buffer(tmpdata) : sw->data;
                if (!aswf)
                        res = 0;
                else {
@@ -2729,9 +2747,11 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
        }
        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) {
+       for (idx = 0; idx < ast_context_includes_count(tmp); idx++) {
+               const struct ast_include *i = ast_context_includes_get(tmp, idx);
+
                if (include_valid(i)) {
-                       if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action))) {
+                       if ((e = pbx_find_extension(chan, bypass, q, include_rname(i), exten, priority, label, callerid, action))) {
 #ifdef NEED_DEBUG_HERE
                                ast_log(LOG_NOTICE,"Returning recursive match of %s\n", e->exten);
 #endif
@@ -3321,7 +3341,8 @@ static void device_state_notify_callbacks(struct ast_hint *hint, struct ast_str
 {
        struct ao2_iterator cb_iter;
        struct ast_state_cb *state_cb;
-       int state, same_state;
+       int state;
+       int same_state;
        struct ao2_container *device_state_info;
        int first_extended_cb_call = 1;
        char context_name[AST_MAX_CONTEXT];
@@ -3360,7 +3381,8 @@ static void device_state_notify_callbacks(struct ast_hint *hint, struct ast_str
        device_state_info = alloc_device_state_info();
 
        state = ast_extension_state3(*hint_app, device_state_info);
-       if ((same_state = state == hint->laststate) && (~state & AST_EXTENSION_RINGING)) {
+       same_state = state == hint->laststate;
+       if (same_state && (~state & AST_EXTENSION_RINGING)) {
                ao2_cleanup(device_state_info);
                return;
        }
@@ -3369,17 +3391,19 @@ static void device_state_notify_callbacks(struct ast_hint *hint, struct ast_str
        hint->laststate = state;        /* record we saw the change */
 
        /* For general callbacks */
-       cb_iter = ao2_iterator_init(statecbs, 0);
-       for (; !same_state && (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
-               execute_state_callback(state_cb->change_cb,
-                                      context_name,
-                                      exten_name,
-                                      state_cb->data,
-                                      AST_HINT_UPDATE_DEVICE,
-                                      hint,
-                                      NULL);
+       if (!same_state) {
+               cb_iter = ao2_iterator_init(statecbs, 0);
+               for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
+                       execute_state_callback(state_cb->change_cb,
+                               context_name,
+                               exten_name,
+                               state_cb->data,
+                               AST_HINT_UPDATE_DEVICE,
+                               hint,
+                               NULL);
+               }
+               ao2_iterator_destroy(&cb_iter);
        }
-       ao2_iterator_destroy(&cb_iter);
 
        /* For extension callbacks */
        /* extended callbacks are called when the state changed or when AST_STATE_RINGING is
@@ -3394,12 +3418,12 @@ static void device_state_notify_callbacks(struct ast_hint *hint, struct ast_str
                }
                if (state_cb->extended || !same_state) {
                        execute_state_callback(state_cb->change_cb,
-                                              context_name,
-                                              exten_name,
-                                              state_cb->data,
-                                              AST_HINT_UPDATE_DEVICE,
-                                              hint,
-                                              state_cb->extended ? device_state_info : NULL);
+                               context_name,
+                               exten_name,
+                               state_cb->data,
+                               AST_HINT_UPDATE_DEVICE,
+                               hint,
+                               state_cb->extended ? device_state_info : NULL);
                }
        }
        ao2_iterator_destroy(&cb_iter);
@@ -3457,12 +3481,12 @@ static void presence_state_notify_callbacks(struct ast_hint *hint, struct ast_st
        cb_iter = ao2_iterator_init(statecbs, 0);
        for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
                execute_state_callback(state_cb->change_cb,
-                                      context_name,
-                                      exten_name,
-                                      state_cb->data,
-                                      AST_HINT_UPDATE_PRESENCE,
-                                      hint,
-                                      NULL);
+                       context_name,
+                       exten_name,
+                       state_cb->data,
+                       AST_HINT_UPDATE_PRESENCE,
+                       hint,
+                       NULL);
        }
        ao2_iterator_destroy(&cb_iter);
 
@@ -3470,12 +3494,12 @@ static void presence_state_notify_callbacks(struct ast_hint *hint, struct ast_st
        cb_iter = ao2_iterator_init(hint->callbacks, 0);
        for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_cleanup(state_cb)) {
                execute_state_callback(state_cb->change_cb,
-                                      context_name,
-                                      exten_name,
-                                      state_cb->data,
-                                      AST_HINT_UPDATE_PRESENCE,
-                                      hint,
-                                      NULL);
+                       context_name,
+                       exten_name,
+                       state_cb->data,
+                       AST_HINT_UPDATE_PRESENCE,
+                       hint,
+                       NULL);
        }
        ao2_iterator_destroy(&cb_iter);
 }
@@ -3495,27 +3519,32 @@ static int handle_hint_change_message_type(struct stasis_message *msg, enum ast_
 
        hint = stasis_message_data(msg);
 
-       if (reason == AST_HINT_UPDATE_DEVICE) {
+       switch (reason) {
+       case AST_HINT_UPDATE_DEVICE:
                device_state_notify_callbacks(hint, &hint_app);
-       } else if (reason == AST_HINT_UPDATE_PRESENCE) {
-               char *presence_subtype = NULL;
-               char *presence_message = NULL;
-               int state;
+               break;
+       case AST_HINT_UPDATE_PRESENCE:
+               {
+                       char *presence_subtype = NULL;
+                       char *presence_message = NULL;
+                       int state;
 
-               state = extension_presence_state_helper(
-                       hint->exten, &presence_subtype, &presence_message);
+                       state = extension_presence_state_helper(
+                               hint->exten, &presence_subtype, &presence_message);
+                       {
+                               struct ast_presence_state_message presence_state = {
+                                       .state = state > 0 ? state : AST_PRESENCE_INVALID,
+                                       .subtype = presence_subtype,
+                                       .message = presence_message
+                               };
 
-               {
-                       struct ast_presence_state_message presence_state = {
-                               .state = state > 0 ? state : AST_PRESENCE_INVALID,
-                               .subtype = presence_subtype,
-                               .message = presence_message
-                       };
-                       presence_state_notify_callbacks(hint, &hint_app, &presence_state);
-               }
+                               presence_state_notify_callbacks(hint, &hint_app, &presence_state);
+                       }
 
-               ast_free(presence_subtype);
-               ast_free(presence_message);
+                       ast_free(presence_subtype);
+                       ast_free(presence_message);
+               }
+               break;
        }
 
        ast_free(hint_app);
@@ -3731,28 +3760,24 @@ static int extension_state_add_destroy(const char *context, const char *exten,
        return id;
 }
 
-/*! \brief Add watcher for extension states with destructor */
 int ast_extension_state_add_destroy(const char *context, const char *exten,
        ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data)
 {
        return extension_state_add_destroy(context, exten, change_cb, destroy_cb, data, 0);
 }
 
-/*! \brief Add watcher for extension states */
 int ast_extension_state_add(const char *context, const char *exten,
        ast_state_cb_type change_cb, void *data)
 {
        return extension_state_add_destroy(context, exten, change_cb, NULL, data, 0);
 }
 
-/*! \brief Add watcher for extended extension states with destructor */
 int ast_extension_state_add_destroy_extended(const char *context, const char *exten,
        ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data)
 {
        return extension_state_add_destroy(context, exten, change_cb, destroy_cb, data, 1);
 }
 
-/*! \brief Add watcher for extended extension states */
 int ast_extension_state_add_extended(const char *context, const char *exten,
        ast_state_cb_type change_cb, void *data)
 {
@@ -3774,7 +3799,6 @@ static int find_hint_by_cb_id(void *obj, void *arg, int flags)
        return 0;
 }
 
-/*! \brief  ast_extension_state_del: Remove a watcher from the callback list */
 int ast_extension_state_del(int id, ast_state_cb_type change_cb)
 {
        struct ast_state_cb *p_cur;
@@ -3943,7 +3967,6 @@ static int ast_add_hint(struct ast_exten *e)
                        hint_new->last_presence_state = presence_state;
                        hint_new->last_presence_subtype = subtype;
                        hint_new->last_presence_message = message;
-                       message = subtype = NULL;
                }
        }
 
@@ -3980,12 +4003,12 @@ static int ast_add_hint(struct ast_exten *e)
                cb_iter = ao2_iterator_init(statecbs, 0);
                for (; (state_cb = ao2_iterator_next(&cb_iter)); ao2_ref(state_cb, -1)) {
                        execute_state_callback(state_cb->change_cb,
-                                       ast_get_context_name(ast_get_extension_context(e)),
-                                       ast_get_extension_name(e),
-                                       state_cb->data,
-                                       AST_HINT_UPDATE_DEVICE,
-                                       hint_new,
-                                       NULL);
+                               ast_get_context_name(ast_get_extension_context(e)),
+                               ast_get_extension_name(e),
+                               state_cb->data,
+                               AST_HINT_UPDATE_DEVICE,
+                               hint_new,
+                               NULL);
                }
                ao2_iterator_destroy(&cb_iter);
        }
@@ -4277,8 +4300,10 @@ static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c,
        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  */
@@ -4523,8 +4548,10 @@ static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c,
                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);
 
@@ -4782,24 +4809,24 @@ int ast_context_remove_include(const char *context, const char *include, const c
  */
 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
 {
-       struct ast_include *i, *pi = NULL;
        int ret = -1;
+       int idx;
 
        ast_wrlock_context(con);
 
        /* find our include */
-       for (i = con->includes; i; pi = i, i = i->next) {
-               if (!strcmp(i->name, include) &&
-                               (!registrar || !strcmp(i->registrar, registrar))) {
+       for (idx = 0; idx < ast_context_includes_count(con); idx++) {
+               struct ast_include *i = AST_VECTOR_GET(&con->includes, idx);
+
+               if (!strcmp(ast_get_include_name(i), include) &&
+                               (!registrar || !strcmp(ast_get_include_registrar(i), registrar))) {
+
                        /* remove from list */
                        ast_verb(3, "Removing inclusion of context '%s' in context '%s; registrar=%s'\n", include, ast_get_context_name(con), registrar);
-                       if (pi)
-                               pi->next = i->next;
-                       else
-                               con->includes = i->next;
+                       AST_VECTOR_REMOVE_ORDERED(&con->includes, idx);
+
                        /* free include and return */
-                       ast_destroy_timing(&(i->timing));
-                       ast_free(i);
+                       include_free(i);
                        ret = 0;
                        break;
                }
@@ -4839,24 +4866,29 @@ int ast_context_remove_switch(const char *context, const char *sw, const char *d
  */
 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);
 
@@ -4905,6 +4937,7 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char *
        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;
@@ -4920,9 +4953,14 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char *
 #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) {
@@ -4945,13 +4983,19 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char *
                        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);
@@ -4960,8 +5004,11 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char *
                                        /* 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 */
@@ -4972,7 +5019,7 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char *
                                }
                        } 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 {
@@ -4989,10 +5036,12 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char *
 
        /* 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 */
@@ -5003,8 +5052,8 @@ int ast_context_remove_extension_callerid2(struct ast_context *con, const char *
 
        /* 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) &&
@@ -5395,8 +5444,23 @@ static void print_ext(struct ast_exten *e, char * buf, int buflen)
        }
 }
 
+/*! \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, struct ast_include *rinclude, int includecount, const char *includes[])
+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[])
 {
        struct ast_context *c = NULL;
        int res = 0, old_total_exten = dpc->total_exten;
@@ -5405,9 +5469,8 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten,
 
        /* walk all contexts ... */
        while ( (c = ast_walk_contexts(c)) ) {
+               int idx;
                struct ast_exten *e;
-               struct ast_include *i;
-               struct ast_ignorepat *ip;
 #ifndef LOW_MEMORY
                char buf[1024], buf2[1024];
 #else
@@ -5473,8 +5536,7 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten,
 
                        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 */
@@ -5488,14 +5550,14 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten,
                                        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);
                        }
                }
 
                /* walk included and write info ... */
-               i = NULL;
-               while ( (i = ast_walk_context_includes(c, i)) ) {
+               for (idx = 0; idx < ast_context_includes_count(c); idx++) {
+                       const struct ast_include *i = ast_context_includes_get(c, idx);
+
                        snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
                        if (exten) {
                                /* Check all includes for the requested extension */
@@ -5524,10 +5586,11 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten,
                }
 
                /* walk ignore patterns and write info ... */
-               ip = NULL;
-               while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
+               for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) {
+                       const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx);
                        const char *ipname = ast_get_ignorepat_name(ip);
                        char ignorepat[AST_MAX_EXTENSION];
+
                        snprintf(buf, sizeof(buf), "'%s'", ipname);
                        snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
                        if (!exten || ast_extension_match(ignorepat, exten)) {
@@ -5536,8 +5599,9 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten,
                        }
                }
                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));
@@ -5747,7 +5811,8 @@ static void manager_dpsendack(struct mansession *s, const struct message *m)
 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,
-                                       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;
@@ -5768,9 +5833,8 @@ static int manager_show_dialplan_helper(struct mansession *s, const struct messa
 
        c = NULL;               /* walk all contexts ... */
        while ( (c = ast_walk_contexts(c)) ) {
+               int idx;
                struct ast_exten *e;
-               struct ast_include *i;
-               struct ast_ignorepat *ip;
 
                if (context && strcmp(ast_get_context_name(c), context) != 0)
                        continue;       /* not the name we want */
@@ -5825,11 +5889,29 @@ static int manager_show_dialplan_helper(struct mansession *s, const struct messa
                        }
                }
 
-               i = NULL;               /* walk included and write info ... */
-               while ( (i = ast_walk_context_includes(c, i)) ) {
+               for (idx = 0; idx < ast_context_includes_count(c); idx++) {
+                       const struct ast_include *i = ast_context_includes_get(c, idx);
+
                        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);
@@ -5840,8 +5922,8 @@ static int manager_show_dialplan_helper(struct mansession *s, const struct messa
                        }
                }
 
-               ip = NULL;      /* walk ignore patterns and write info ... */
-               while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
+               for (idx = 0; idx < ast_context_ignorepats_count(c); idx++) {
+                       const struct ast_ignorepat *ip = ast_context_ignorepats_get(c, idx);
                        const char *ipname = ast_get_ignorepat_name(ip);
                        char ignorepat[AST_MAX_EXTENSION];
 
@@ -5855,8 +5937,9 @@ static int manager_show_dialplan_helper(struct mansession *s, const struct messa
                        }
                }
                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);
@@ -5884,6 +5967,7 @@ static int manager_show_dialplan(struct mansession *s, const struct message *m)
 {
        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 */
@@ -5899,7 +5983,7 @@ static int manager_show_dialplan(struct mansession *s, const struct message *m)
        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];
@@ -6104,8 +6188,9 @@ struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts,
                tmp->root = NULL;
                tmp->root_table = NULL;
                tmp->registrar = ast_strdup(registrar);
-               tmp->includes = NULL;
-               tmp->ignorepats = NULL;
+               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);
@@ -6156,30 +6241,37 @@ AST_LIST_HEAD_NOLOCK(store_hints, store_hint);
 
 static void context_merge_incls_swits_igps_other_registrars(struct ast_context *new, struct ast_context *old, const char *registrar)
 {
-       struct ast_include *i;
-       struct ast_ignorepat *ip;
-       struct ast_sw *sw;
+       int idx;
 
        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 includes */
-       for (i = NULL; (i = ast_walk_context_includes(old, i)) ; ) {
-               if (strcmp(ast_get_include_registrar(i), registrar) == 0)
+       for (idx = 0; idx < ast_context_includes_count(old); idx++) {
+               const struct ast_include *i = ast_context_includes_get(old, idx);
+
+               if (!strcmp(ast_get_include_registrar(i), registrar)) {
                        continue; /* not mine */
+               }
                ast_context_add_include2(new, ast_get_include_name(i), ast_get_include_registrar(i));
        }
 
        /* 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));
        }
 
        /* walk thru ignorepats ... */
-       for (ip = NULL; (ip = ast_walk_context_ignorepats(old, ip)); ) {
-               if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0)
+       for (idx = 0; idx < ast_context_ignorepats_count(old); idx++) {
+               const struct ast_ignorepat *ip = ast_context_ignorepats_get(old, idx);
+
+               if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0) {
                        continue; /* not mine */
+               }
                ast_context_add_ignorepat2(new, ast_get_ignorepat_name(ip), ast_get_ignorepat_registrar(ip));
        }
 }
@@ -6282,11 +6374,12 @@ static void context_merge(struct ast_context **extcontexts, struct ast_hashtab *
 
                                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! */
@@ -6576,54 +6669,36 @@ int ast_context_add_include2(struct ast_context *con, const char *value,
        const char *registrar)
 {
        struct ast_include *new_include;
-       char *c;
-       struct ast_include *i, *il = NULL; /* include, include_last */
-       int length;
-       char *p;
-
-       length = sizeof(struct ast_include);
-       length += 2 * (strlen(value) + 1);
+       int idx;
 
        /* allocate new include structure ... */
-       if (!(new_include = ast_calloc(1, length)))
+       new_include = include_alloc(value, registrar);
+       if (!new_include) {
                return -1;
-       /* Fill in this structure. Use 'p' for assignments, as the fields
-        * in the structure are 'const char *'
-        */
-       p = new_include->stuff;
-       new_include->name = p;
-       strcpy(p, value);
-       p += strlen(value) + 1;
-       new_include->rname = p;
-       strcpy(p, value);
-       /* Strip off timing info, and process if it is there */
-       if ( (c = strchr(p, ',')) ) {
-               *c++ = '\0';
-               new_include->hastime = ast_build_timing(&(new_include->timing), c);
-       }
-       new_include->next      = NULL;
-       new_include->registrar = registrar;
+       }
 
        ast_wrlock_context(con);
 
        /* ... go to last include and check if context is already included too... */
-       for (i = con->includes; i; i = i->next) {
-               if (!strcasecmp(i->name, new_include->name)) {
-                       ast_destroy_timing(&(new_include->timing));
-                       ast_free(new_include);
+       for (idx = 0; idx < ast_context_includes_count(con); idx++) {
+               const struct ast_include *i = ast_context_includes_get(con, idx);
+
+               if (!strcasecmp(ast_get_include_name(i), ast_get_include_name(new_include))) {
+                       include_free(new_include);
                        ast_unlock_context(con);
                        errno = EEXIST;
                        return -1;
                }
-               il = i;
        }
 
        /* ... include new context into context list, unlock, return */
-       if (il)
-               il->next = new_include;
-       else
-               con->includes = new_include;
-       ast_verb(3, "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
+       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));
 
        ast_unlock_context(con);
 
@@ -6658,43 +6733,24 @@ int ast_context_add_switch(const char *context, const char *sw, const char *data
 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;
@@ -6702,9 +6758,14 @@ int ast_context_add_switch2(struct ast_context *con, const char *value,
        }
 
        /* ... 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);
 
@@ -6730,24 +6791,20 @@ int ast_context_remove_ignorepat(const char *context, const char *ignorepat, con
 
 int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
 {
-       struct ast_ignorepat *ip, *ipl = NULL;
+       int idx;
 
        ast_wrlock_context(con);
 
-       for (ip = con->ignorepats; ip; ip = ip->next) {
-               if (!strcmp(ip->pattern, ignorepat) &&
-                       (!registrar || (registrar == ip->registrar))) {
-                       if (ipl) {
-                               ipl->next = ip->next;
-                               ast_free(ip);
-                       } else {
-                               con->ignorepats = ip->next;
-                               ast_free(ip);
-                       }
+       for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) {
+               struct ast_ignorepat *ip = AST_VECTOR_GET(&con->ignorepats, idx);
+
+               if (!strcmp(ast_get_ignorepat_name(ip), ignorepat) &&
+                       (!registrar || (registrar == ast_get_ignorepat_registrar(ip)))) {
+                       AST_VECTOR_REMOVE_ORDERED(&con->ignorepats, idx);
+                       ignorepat_free(ip);
                        ast_unlock_context(con);
                        return 0;
                }
-               ipl = ip;
        }
 
        ast_unlock_context(con);
@@ -6774,41 +6831,33 @@ int ast_context_add_ignorepat(const char *context, const char *value, const char
 
 int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
 {
-       struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
-       int length;
-       char *pattern;
-       length = sizeof(struct ast_ignorepat);
-       length += strlen(value) + 1;
-       if (!(ignorepat = ast_calloc(1, length)))
+       struct ast_ignorepat *ignorepat = ignorepat_alloc(value, registrar);
+       int idx;
+
+       if (!ignorepat) {
                return -1;
-       /* The cast to char * is because we need to write the initial value.
-        * The field is not supposed to be modified otherwise.  Also, gcc 4.2
-        * sees the cast as dereferencing a type-punned pointer and warns about
-        * it.  This is the workaround (we're telling gcc, yes, that's really
-        * what we wanted to do).
-        */
-       pattern = (char *) ignorepat->pattern;
-       strcpy(pattern, value);
-       ignorepat->next = NULL;
-       ignorepat->registrar = registrar;
+       }
+
        ast_wrlock_context(con);
-       for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
-               ignorepatl = ignorepatc;
-               if (!strcasecmp(ignorepatc->pattern, value)) {
+       for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) {
+               const struct ast_ignorepat *i = ast_context_ignorepats_get(con, idx);
+
+               if (!strcasecmp(ast_get_ignorepat_name(i), value)) {
                        /* Already there */
                        ast_unlock_context(con);
-                       ast_free(ignorepat);
+                       ignorepat_free(ignorepat);
                        errno = EEXIST;
                        return -1;
                }
        }
-       if (ignorepatl)
-               ignorepatl->next = ignorepat;
-       else
-               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;
 
+       return 0;
 }
 
 int ast_ignore_pattern(const char *context, const char *pattern)
@@ -6819,10 +6868,12 @@ int ast_ignore_pattern(const char *context, const char *pattern)
        ast_rdlock_contexts();
        con = ast_context_find(context);
        if (con) {
-               struct ast_ignorepat *pat;
+               int idx;
+
+               for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) {
+                       const struct ast_ignorepat *pat = ast_context_ignorepats_get(con, idx);
 
-               for (pat = con->ignorepats; pat; pat = pat->next) {
-                       if (ast_extension_match(pat->pattern, pattern)) {
+                       if (ast_extension_match(ast_get_ignorepat_name(pat), pattern)) {
                                ret = 1;
                                break;
                        }
@@ -6848,7 +6899,7 @@ static int ast_add_extension_nolock(const char *context, int replace, const char
        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;
@@ -6868,7 +6919,7 @@ int ast_add_extension(const char *context, int replace, const char *extension,
        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();
        }
 
@@ -6945,29 +6996,51 @@ int ast_async_goto_by_name(const char *channame, const char *context, const char
        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;
 }
 
 /*!
@@ -6984,14 +7057,14 @@ static int add_priority(struct ast_context *con, struct ast_exten *tmp,
 
        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;
                }
@@ -7017,14 +7090,14 @@ static int add_priority(struct ast_context *con, struct ast_exten *tmp,
                /* 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;
@@ -7168,19 +7241,19 @@ static int add_priority(struct ast_context *con, struct ast_exten *tmp,
 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);
 }
 
 
@@ -7194,7 +7267,7 @@ int ast_add_extension2_nolock(struct ast_context *con,
 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.
@@ -7209,6 +7282,8 @@ static int ast_add_extension2_lockopt(struct ast_context *con,
        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",
@@ -7218,28 +7293,54 @@ static int ast_add_extension2_lockopt(struct ast_context *con,
 
        /* 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)))
@@ -7255,25 +7356,46 @@ static int ast_add_extension2_lockopt(struct ast_context *con,
                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);
@@ -7281,7 +7403,7 @@ static int ast_add_extension2_lockopt(struct ast_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;
@@ -7343,52 +7465,38 @@ static int ast_add_extension2_lockopt(struct ast_context *con,
                 * 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);
                }
@@ -7399,19 +7507,19 @@ static int ast_add_extension2_lockopt(struct ast_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;
@@ -7437,8 +7545,8 @@ struct pbx_outgoing {
        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 */
@@ -7461,13 +7569,19 @@ static void *pbx_outgoing_exec(void *data)
        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) {
@@ -7507,12 +7621,6 @@ static void *pbx_outgoing_exec(void *data)
                }
        }
 
-       /* 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;
 }
 
@@ -7587,11 +7695,13 @@ static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap,
        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) {
@@ -7618,6 +7728,11 @@ static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap,
 
        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,
@@ -7642,6 +7757,25 @@ static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap,
                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)) {
@@ -7692,34 +7826,42 @@ static int pbx_outgoing_attempt(const char *type, struct ast_format_cap *cap,
                }
        }
 
+       /* 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,
@@ -7750,6 +7892,16 @@ int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const c
        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;
 
@@ -7763,10 +7915,10 @@ int ast_pbx_outgoing_exten(const char *type, struct ast_format_cap *cap, const c
 
        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;
 
@@ -7804,6 +7956,16 @@ int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const cha
        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;
        }
@@ -7816,7 +7978,7 @@ int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const cha
 
        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 --
@@ -7825,22 +7987,21 @@ int ast_pbx_outgoing_app(const char *type, struct ast_format_cap *cap, const cha
 
 static void __ast_internal_context_destroy( struct ast_context *con)
 {
-       struct ast_include *tmpi;
-       struct ast_sw *sw;
        struct ast_exten *e, *el, *en;
-       struct ast_ignorepat *ipi;
        struct ast_context *tmp = con;
 
-       for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
-               struct ast_include *tmpil = tmpi;
-               tmpi = tmpi->next;
-               ast_free(tmpil);
-       }
-       for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
-               struct ast_ignorepat *ipl = ipi;
-               ipi = ipi->next;
-               ast_free(ipl);
-       }
+       /* Free includes */
+       AST_VECTOR_CALLBACK_VOID(&tmp->includes, include_free);
+       AST_VECTOR_FREE(&tmp->includes);
+
+       /* Free ignorepats */
+       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);
 
@@ -7852,8 +8013,6 @@ static void __ast_internal_context_destroy( struct ast_context *con)
        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;
@@ -7900,53 +8059,35 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context
                        /* then search thru and remove any extens that match registrar. */
                        struct ast_hashtab_iter *exten_iter;
                        struct ast_hashtab_iter *prio_iter;
-                       struct ast_ignorepat *ip, *ipl = NULL, *ipn = NULL;
-                       struct ast_include *i, *pi = NULL, *ni = NULL;
-                       struct ast_sw *sw = NULL;
+                       int idx;
 
                        /* remove any ignorepats whose registrar matches */
-                       for (ip = tmp->ignorepats; ip; ip = ipn) {
-                               ipn = ip->next;
-                               if (!strcmp(ip->registrar, registrar)) {
-                                       if (ipl) {
-                                               ipl->next = ip->next;
-                                               ast_free(ip);
-                                               continue; /* don't change ipl */
-                                       } else {
-                                               tmp->ignorepats = ip->next;
-                                               ast_free(ip);
-                                               continue; /* don't change ipl */
-                                       }
+                       for (idx = ast_context_ignorepats_count(tmp) - 1; idx >= 0; idx--) {
+                               struct ast_ignorepat *ip = AST_VECTOR_GET(&tmp->ignorepats, idx);
+
+                               if (!strcmp(ast_get_ignorepat_registrar(ip), registrar)) {
+                                       AST_VECTOR_REMOVE_ORDERED(&tmp->ignorepats, idx);
+                                       ignorepat_free(ip);
                                }
-                               ipl = ip;
                        }
                        /* remove any includes whose registrar matches */
-                       for (i = tmp->includes; i; i = ni) {
-                               ni = i->next;
-                               if (strcmp(i->registrar, registrar) == 0) {
-                                       /* remove from list */
-                                       if (pi) {
-                                               pi->next = i->next;
-                                               /* free include */
-                                               ast_free(i);
-                                               continue; /* don't change pi */
-                                       } else {
-                                               tmp->includes = i->next;
-                                               /* free include */
-                                               ast_free(i);
-                                               continue; /* don't change pi */
-                                       }
+                       for (idx = ast_context_includes_count(tmp) - 1; idx >= 0; idx--) {
+                               struct ast_include *i = AST_VECTOR_GET(&tmp->includes, idx);
+
+                               if (!strcmp(ast_get_include_registrar(i), registrar)) {
+                                       AST_VECTOR_REMOVE_ORDERED(&tmp->includes, idx);
+                                       include_free(i);
                                }
-                               pi = i;
                        }
                        /* 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);
@@ -7970,7 +8111,7 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context
                                                        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));
@@ -7997,7 +8138,7 @@ void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *context
                        /* 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 && !tmp->ignorepats && !tmp->includes && 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);
 
@@ -8177,56 +8318,6 @@ static void presence_state_cb(void *unused, struct stasis_subscription *sub, str
        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");
@@ -8302,7 +8393,6 @@ static void unload_pbx(void)
        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)
@@ -8316,7 +8406,6 @@ 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);
 
@@ -8390,7 +8479,7 @@ struct ast_context *ast_get_extension_context(struct ast_exten *exten)
 
 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)
@@ -8398,16 +8487,6 @@ const char *ast_get_extension_label(struct ast_exten *exten)
        return exten ? exten->label : NULL;
 }
 
-const char *ast_get_include_name(struct ast_include *inc)
-{
-       return inc ? inc->name : NULL;
-}
-
-const char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
-{
-       return ip ? ip->pattern : NULL;
-}
-
 int ast_get_extension_priority(struct ast_exten *exten)
 {
        return exten ? exten->priority : -1;
@@ -8426,14 +8505,14 @@ const char *ast_get_extension_registrar(struct ast_exten *e)
        return e ? e->registrar : NULL;
 }
 
-const char *ast_get_include_registrar(struct ast_include *i)
+const char *ast_get_extension_registrar_file(struct ast_exten *e)
 {
-       return i ? i->registrar : NULL;
+       return e ? e->registrar_file : NULL;
 }
 
-const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
+int ast_get_extension_registrar_line(struct ast_exten *e)
 {
-       return ip ? ip->registrar : NULL;
+       return e ? e->registrar_line : 0;
 }
 
 int ast_get_extension_matchcid(struct ast_exten *e)
@@ -8443,7 +8522,7 @@ int ast_get_extension_matchcid(struct ast_exten *e)
 
 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)
@@ -8456,26 +8535,6 @@ void *ast_get_extension_app_data(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 ...
  */
@@ -8493,13 +8552,43 @@ struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
                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,
@@ -8508,36 +8597,103 @@ struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
        return priority ? priority->peer : exten;
 }
 
-struct ast_include *ast_walk_context_includes(struct ast_context *con,
-       struct ast_include *inc)
+const struct ast_include *ast_walk_context_includes(const struct ast_context *con,
+       const struct ast_include *inc)
 {
-       if (!inc)
-               return con ? con->includes : NULL;
-       else
-               return inc->next;
+       if (inc) {
+               int idx;
+               int next = 0;
+
+               for (idx = 0; idx < ast_context_includes_count(con); idx++) {
+                       const struct ast_include *include = AST_VECTOR_GET(&con->includes, idx);
+
+                       if (next) {
+                               return include;
+                       }
+
+                       if (inc == include) {
+                               next = 1;
+                       }
+               }
+
+               return NULL;
+       }
+
+       if (!ast_context_includes_count(con)) {
+               return NULL;
+       }
+
+       return ast_context_includes_get(con, 0);
 }
 
-struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
-       struct ast_ignorepat *ip)
+int ast_context_includes_count(const struct ast_context *con)
 {
-       if (!ip)
-               return con ? con->ignorepats : NULL;
-       else
-               return ip->next;
+       return AST_VECTOR_SIZE(&con->includes);
+}
+
+const struct ast_include *ast_context_includes_get(const struct ast_context *con, int idx)
+{
+       return AST_VECTOR_GET(&con->includes, idx);
+}
+
+const struct ast_ignorepat *ast_walk_context_ignorepats(const struct ast_context *con,
+       const struct ast_ignorepat *ip)
+{
+       if (!con) {
+               return NULL;
+       }
+
+       if (ip) {
+               int idx;
+               int next = 0;
+
+               for (idx = 0; idx < ast_context_ignorepats_count(con); idx++) {
+                       const struct ast_ignorepat *i = ast_context_ignorepats_get(con, idx);
+
+                       if (next) {
+                               return i;
+                       }
+
+                       if (ip == i) {
+                               next = 1;
+                       }
+               }
+
+               return NULL;
+       }
+
+       if (!ast_context_ignorepats_count(con)) {
+               return NULL;
+       }
+
+       return ast_context_ignorepats_get(con, 0);
+}
+
+int ast_context_ignorepats_count(const struct ast_context *con)
+{
+       return AST_VECTOR_SIZE(&con->ignorepats);
+}
+
+const struct ast_ignorepat *ast_context_ignorepats_get(const struct ast_context *con, int idx)
+{
+       return AST_VECTOR_GET(&con->ignorepats, idx);
 }
 
 int ast_context_verify_includes(struct ast_context *con)
 {
-       struct ast_include *inc = NULL;
+       int idx;
        int res = 0;
 
-       while ( (inc = ast_walk_context_includes(con, inc)) ) {
-               if (ast_context_find(inc->rname))
+       for (idx = 0; idx < ast_context_includes_count(con); idx++) {
+               const struct ast_include *inc = ast_context_includes_get(con, idx);
+
+               if (ast_context_find(include_rname(inc))) {
                        continue;
+               }
 
                res = -1;
                ast_log(LOG_WARNING, "Context '%s' tries to include nonexistent context '%s'\n",
-                       ast_get_context_name(con), inc->rname);
+                       ast_get_context_name(con), include_rname(inc));
                break;
        }