Merged revisions 50562 via svnmerge from
[asterisk/asterisk.git] / main / pbx.c
index 6f6127d..10c9911 100644 (file)
@@ -177,7 +177,7 @@ struct ast_app {
        int (*execute)(struct ast_channel *chan, void *data);
        const char *synopsis;                   /*!< Synopsis text for 'show applications' */
        const char *description;                /*!< Description (help text) for 'show application &lt;name&gt;' */
-       AST_LIST_ENTRY(ast_app) list;           /*!< Next app in list */
+       AST_RWLIST_ENTRY(ast_app) list;         /*!< Next app in list */
        struct module *module;                  /*!< Module this app belongs to */
        char name[0];                           /*!< Name of the application */
 };
@@ -193,12 +193,14 @@ struct ast_state_cb {
 /*! \brief Structure for dial plan hints
 
   \note Hints are pointers from an extension in the dialplan to one or
-  more devices (tech/name) */
+  more devices (tech/name) 
+       - See \ref AstExtState
+*/
 struct ast_hint {
        struct ast_exten *exten;        /*!< Extension */
        int laststate;                  /*!< Last known state */
        struct ast_state_cb *callbacks; /*!< Callback list for this extension */
-       AST_LIST_ENTRY(ast_hint) list;  /*!< Pointer to next hint in list */
+       AST_RWLIST_ENTRY(ast_hint) list;/*!< Pointer to next hint in list */
 };
 
 static const struct cfextension_states {
@@ -238,15 +240,15 @@ static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
 int pbx_builtin_setvar(struct ast_channel *, void *);
 static int pbx_builtin_importvar(struct ast_channel *, void *);
 
-AST_MUTEX_DEFINE_STATIC(globalslock);
+AST_RWLOCK_DEFINE_STATIC(globalslock);
 static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
 
 static int autofallthrough = 1;
 
 AST_MUTEX_DEFINE_STATIC(maxcalllock);
-static int countcalls = 0;
+static int countcalls;
 
-static AST_LIST_HEAD_STATIC(acf_root, ast_custom_function);
+static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function);
 
 /*! \brief Declaration of builtin applications */
 static struct pbx_builtin {
@@ -263,7 +265,8 @@ static struct pbx_builtin {
        "Answer a channel if ringing",
        "  Answer([delay]): If the call has not been answered, this application will\n"
        "answer it. Otherwise, it has no effect on the call. If a delay is specified,\n"
-       "Asterisk will wait this number of milliseconds before answering the call.\n"
+       "Asterisk will wait this number of milliseconds before returning to\n"
+       "the dialplan after answering the call.\n"
        },
 
        { "BackGround", pbx_builtin_background,
@@ -458,12 +461,12 @@ static struct pbx_builtin {
 
 };
 
-static struct ast_context *contexts = NULL;
+static struct ast_context *contexts;
 AST_MUTEX_DEFINE_STATIC(conlock);              /*!< Lock for the ast_context list */
 
-static AST_LIST_HEAD_STATIC(apps, ast_app);
+static AST_RWLIST_HEAD_STATIC(apps, ast_app);
 
-static AST_LIST_HEAD_STATIC(switches, ast_switch);
+static AST_RWLIST_HEAD_STATIC(switches, ast_switch);
 
 static int stateid = 1;
 /* WARNING:
@@ -472,15 +475,15 @@ static int stateid = 1;
    function will take the locks in conlock/hints order, so any other
    paths that require both locks must also take them in that order.
 */
-static AST_LIST_HEAD_STATIC(hints, ast_hint);
-struct ast_state_cb *statecbs = NULL;
+static AST_RWLIST_HEAD_STATIC(hints, ast_hint);
+struct ast_state_cb *statecbs;
 
 /*
    \note This function is special. It saves the stack so that no matter
    how many times it is called, it returns to the same place */
 int pbx_exec(struct ast_channel *c,            /*!< Channel */
-               struct ast_app *app,            /*!< Application */
-               void *data)                     /*!< Data for execution */
+            struct ast_app *app,               /*!< Application */
+            void *data)                        /*!< Data for execution */
 {
        int res;
 
@@ -520,12 +523,12 @@ struct ast_app *pbx_findapp(const char *app)
 {
        struct ast_app *tmp;
 
-       AST_LIST_LOCK(&apps);
-       AST_LIST_TRAVERSE(&apps, tmp, list) {
+       AST_RWLIST_RDLOCK(&apps);
+       AST_RWLIST_TRAVERSE(&apps, tmp, list) {
                if (!strcasecmp(tmp->name, app))
                        break;
        }
-       AST_LIST_UNLOCK(&apps);
+       AST_RWLIST_UNLOCK(&apps);
 
        return tmp;
 }
@@ -534,12 +537,12 @@ static struct ast_switch *pbx_findswitch(const char *sw)
 {
        struct ast_switch *asw;
 
-       AST_LIST_LOCK(&switches);
-       AST_LIST_TRAVERSE(&switches, asw, list) {
+       AST_RWLIST_RDLOCK(&switches);
+       AST_RWLIST_TRAVERSE(&switches, asw, list) {
                if (!strcasecmp(asw->name, sw))
                        break;
        }
-       AST_LIST_UNLOCK(&switches);
+       AST_RWLIST_UNLOCK(&switches);
 
        return asw;
 }
@@ -1094,9 +1097,12 @@ static char *substring(const char *value, int offset, int length, char *workspac
        return ret;
 }
 
-/*! \brief  pbx_retrieve_variable: Support for Asterisk built-in variables and
-      functions in the dialplan
-  ---*/
+/*! \brief  Support for Asterisk built-in variables and functions in the dialplan
+
+\note  See also
+       - \ref AstVar   Channel variables
+       - \ref AstCauses The HANGUPCAUSE variable
+ */
 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
 {
        const char not_found = '\0';
@@ -1185,7 +1191,7 @@ void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, c
                if (!places[i])
                        continue;
                if (places[i] == &globals)
-                       ast_mutex_lock(&globalslock);
+                       ast_rwlock_rdlock(&globalslock);
                AST_LIST_TRAVERSE(places[i], variables, entries) {
                        if (strcasecmp(ast_var_name(variables), var)==0) {
                                s = ast_var_value(variables);
@@ -1193,7 +1199,7 @@ void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, c
                        }
                }
                if (places[i] == &globals)
-                       ast_mutex_unlock(&globalslock);
+                       ast_rwlock_unlock(&globalslock);
        }
        if (s == &not_found || s == NULL)
                *ret = NULL;
@@ -1220,14 +1226,14 @@ static int handle_show_functions(int fd, int argc, char *argv[])
 
        ast_cli(fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
 
-       AST_LIST_LOCK(&acf_root);
-       AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
+       AST_RWLIST_RDLOCK(&acf_root);
+       AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
                if (!like || strstr(acf->name, argv[4])) {
                        count_acf++;
                        ast_cli(fd, "%-20.20s  %-35.35s  %s\n", acf->name, acf->syntax, acf->synopsis);
                }
        }
-       AST_LIST_UNLOCK(&acf_root);
+       AST_RWLIST_UNLOCK(&acf_root);
 
        ast_cli(fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
 
@@ -1298,14 +1304,14 @@ static char *complete_show_function(const char *line, const char *word, int pos,
        int wordlen = strlen(word);
 
        /* case-insensitive for convenience in this 'complete' function */
-       AST_LIST_LOCK(&acf_root);
-       AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
+       AST_RWLIST_RDLOCK(&acf_root);
+       AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
                if (!strncasecmp(word, acf->name, wordlen) && ++which > state) {
                        ret = strdup(acf->name);
                        break;
                }
        }
-       AST_LIST_UNLOCK(&acf_root);
+       AST_RWLIST_UNLOCK(&acf_root);
 
        return ret;
 }
@@ -1314,12 +1320,12 @@ struct ast_custom_function *ast_custom_function_find(const char *name)
 {
        struct ast_custom_function *acf = NULL;
 
-       AST_LIST_LOCK(&acf_root);
-       AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
+       AST_RWLIST_RDLOCK(&acf_root);
+       AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
                if (!strcmp(name, acf->name))
                        break;
        }
-       AST_LIST_UNLOCK(&acf_root);
+       AST_RWLIST_UNLOCK(&acf_root);
 
        return acf;
 }
@@ -1331,17 +1337,17 @@ int ast_custom_function_unregister(struct ast_custom_function *acf)
        if (!acf)
                return -1;
 
-       AST_LIST_LOCK(&acf_root);
-       AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
+       AST_RWLIST_WRLOCK(&acf_root);
+       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
                if (cur == acf) {
-                       AST_LIST_REMOVE_CURRENT(&acf_root, acflist);
+                       AST_RWLIST_REMOVE_CURRENT(&acf_root, acflist);
                        if (option_verbose > 1)
                                ast_verbose(VERBOSE_PREFIX_2 "Unregistered custom function %s\n", acf->name);
                        break;
                }
        }
-       AST_LIST_TRAVERSE_SAFE_END
-       AST_LIST_UNLOCK(&acf_root);
+       AST_RWLIST_TRAVERSE_SAFE_END
+       AST_RWLIST_UNLOCK(&acf_root);
 
        return acf ? 0 : -1;
 }
@@ -1353,26 +1359,28 @@ int ast_custom_function_register(struct ast_custom_function *acf)
        if (!acf)
                return -1;
 
-       AST_LIST_LOCK(&acf_root);
+       AST_RWLIST_WRLOCK(&acf_root);
 
-       if (ast_custom_function_find(acf->name)) {
-               ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
-               AST_LIST_UNLOCK(&acf_root);
-               return -1;
+       AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
+               if (!strcmp(acf->name, cur->name)) {
+                       ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
+                       AST_RWLIST_UNLOCK(&acf_root);
+                       return -1;
+               }
        }
 
        /* Store in alphabetical order */
-       AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
+       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
                if (strcasecmp(acf->name, cur->name) < 0) {
-                       AST_LIST_INSERT_BEFORE_CURRENT(&acf_root, acf, acflist);
+                       AST_RWLIST_INSERT_BEFORE_CURRENT(&acf_root, acf, acflist);
                        break;
                }
        }
-       AST_LIST_TRAVERSE_SAFE_END
+       AST_RWLIST_TRAVERSE_SAFE_END
        if (!cur)
-               AST_LIST_INSERT_TAIL(&acf_root, acf, acflist);
+               AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
 
-       AST_LIST_UNLOCK(&acf_root);
+       AST_RWLIST_UNLOCK(&acf_root);
 
        if (option_verbose > 1)
                ast_verbose(VERBOSE_PREFIX_2 "Registered custom function %s\n", acf->name);
@@ -1400,10 +1408,11 @@ static char *func_args(char *function)
        return args;
 }
 
-int ast_func_read(struct ast_channel *chan, char *function, char *workspace, size_t len)
+int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
 {
-       char *args = func_args(function);
-       struct ast_custom_function *acfptr = ast_custom_function_find(function);
+       char *copy = ast_strdupa(function);
+       char *args = func_args(copy);
+       struct ast_custom_function *acfptr = ast_custom_function_find(copy);
 
        if (acfptr == NULL)
                ast_log(LOG_ERROR, "Function %s not registered\n", function);
@@ -1414,10 +1423,11 @@ int ast_func_read(struct ast_channel *chan, char *function, char *workspace, siz
        return -1;
 }
 
-int ast_func_write(struct ast_channel *chan, char *function, const char *value)
+int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
 {
-       char *args = func_args(function);
-       struct ast_custom_function *acfptr = ast_custom_function_find(function);
+       char *copy = ast_strdupa(function);
+       char *args = func_args(copy);
+       struct ast_custom_function *acfptr = ast_custom_function_find(copy);
 
        if (acfptr == NULL)
                ast_log(LOG_ERROR, "Function %s not registered\n", function);
@@ -1529,8 +1539,8 @@ static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct v
                        if (isfunction) {
                                /* Evaluate function */
                                cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
-
-                               ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
+                               if (option_debug)
+                                       ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
                        } else {
                                /* Retrieve variable value */
                                pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
@@ -1597,7 +1607,8 @@ static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct v
                        length = ast_expr(vars, cp2, count);
 
                        if (length) {
-                               ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
+                               if (option_debug)
+                                       ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
                                count -= length;
                                cp2 += length;
                        }
@@ -1621,7 +1632,7 @@ static void pbx_substitute_variables(char *passdata, int datalen, struct ast_cha
        memset(passdata, 0, datalen);
 
        /* No variables or expressions in e->data, so why scan it? */
-       if (!strchr(e->data, '$') && !strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
+       if (e->data && !strchr(e->data, '$') && !strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
                ast_copy_string(passdata, e->data, datalen);
                return;
        }
@@ -1678,7 +1689,8 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
                        if (option_debug) {
                                char atmp[80];
                                char atmp2[EXT_DATA_SIZE+100];
-                               ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
+                               if (option_debug)
+                                       ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
                                snprintf(atmp, sizeof(atmp), "STACK-%s-%s-%d", context, exten, priority);
                                snprintf(atmp2, sizeof(atmp2), "%s(\"%s\", \"%s\") %s",
                                        app->name, c->name, passdata, "in new stack");
@@ -1735,7 +1747,8 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
                                ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
                        break;
                default:
-                       ast_log(LOG_DEBUG, "Shouldn't happen!\n");
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "Shouldn't happen!\n");
                }
 
                return (matching_action) ? 0 : -1;
@@ -1868,9 +1881,9 @@ void ast_hint_state_changed(const char *device)
 {
        struct ast_hint *hint;
 
-       AST_LIST_LOCK(&hints);
+       AST_RWLIST_RDLOCK(&hints);
 
-       AST_LIST_TRAVERSE(&hints, hint, list) {
+       AST_RWLIST_TRAVERSE(&hints, hint, list) {
                struct ast_state_cb *cblist;
                char buf[AST_MAX_EXTENSION];
                char *parse = buf;
@@ -1904,7 +1917,7 @@ void ast_hint_state_changed(const char *device)
                hint->laststate = state;        /* record we saw the change */
        }
 
-       AST_LIST_UNLOCK(&hints);
+       AST_RWLIST_UNLOCK(&hints);
 }
 
 /*! \brief  ast_extension_state_add: Add watcher for extension states */
@@ -1917,19 +1930,19 @@ int ast_extension_state_add(const char *context, const char *exten,
 
        /* If there's no context and extension:  add callback to statecbs list */
        if (!context && !exten) {
-               AST_LIST_LOCK(&hints);
+               AST_RWLIST_WRLOCK(&hints);
 
                for (cblist = statecbs; cblist; cblist = cblist->next) {
                        if (cblist->callback == callback) {
                                cblist->data = data;
-                               AST_LIST_UNLOCK(&hints);
+                               AST_RWLIST_UNLOCK(&hints);
                                return 0;
                        }
                }
 
                /* Now insert the callback */
                if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
-                       AST_LIST_UNLOCK(&hints);
+                       AST_RWLIST_UNLOCK(&hints);
                        return -1;
                }
                cblist->id = 0;
@@ -1939,7 +1952,7 @@ int ast_extension_state_add(const char *context, const char *exten,
                cblist->next = statecbs;
                statecbs = cblist;
 
-               AST_LIST_UNLOCK(&hints);
+               AST_RWLIST_UNLOCK(&hints);
                return 0;
        }
 
@@ -1953,22 +1966,22 @@ int ast_extension_state_add(const char *context, const char *exten,
        }
 
        /* Find the hint in the list of hints */
-       AST_LIST_LOCK(&hints);
+       AST_RWLIST_WRLOCK(&hints);
 
-       AST_LIST_TRAVERSE(&hints, hint, list) {
+       AST_RWLIST_TRAVERSE(&hints, hint, list) {
                if (hint->exten == e)
                        break;
        }
 
        if (!hint) {
                /* We have no hint, sorry */
-               AST_LIST_UNLOCK(&hints);
+               AST_RWLIST_UNLOCK(&hints);
                return -1;
        }
 
        /* Now insert the callback in the callback list  */
        if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
-               AST_LIST_UNLOCK(&hints);
+               AST_RWLIST_UNLOCK(&hints);
                return -1;
        }
        cblist->id = stateid++;         /* Unique ID for this callback */
@@ -1978,7 +1991,7 @@ int ast_extension_state_add(const char *context, const char *exten,
        cblist->next = hint->callbacks;
        hint->callbacks = cblist;
 
-       AST_LIST_UNLOCK(&hints);
+       AST_RWLIST_UNLOCK(&hints);
        return cblist->id;
 }
 
@@ -1991,7 +2004,7 @@ int ast_extension_state_del(int id, ast_state_cb_type callback)
        if (!id && !callback)
                return -1;
 
-       AST_LIST_LOCK(&hints);
+       AST_RWLIST_WRLOCK(&hints);
 
        if (!id) {      /* id == 0 is a callback without extension */
                for (p_cur = &statecbs; *p_cur; p_cur = &(*p_cur)->next) {
@@ -2000,7 +2013,7 @@ int ast_extension_state_del(int id, ast_state_cb_type callback)
                }
        } else { /* callback with extension, find the callback based on ID */
                struct ast_hint *hint;
-               AST_LIST_TRAVERSE(&hints, hint, list) {
+               AST_RWLIST_TRAVERSE(&hints, hint, list) {
                        for (p_cur = &hint->callbacks; *p_cur; p_cur = &(*p_cur)->next) {
                                if ((*p_cur)->id == id)
                                        break;
@@ -2015,7 +2028,7 @@ int ast_extension_state_del(int id, ast_state_cb_type callback)
                free(cur);
                ret = 0;
        }
-       AST_LIST_UNLOCK(&hints);
+       AST_RWLIST_UNLOCK(&hints);
        return ret;
 }
 
@@ -2027,12 +2040,12 @@ static int ast_add_hint(struct ast_exten *e)
        if (!e)
                return -1;
 
-       AST_LIST_LOCK(&hints);
+       AST_RWLIST_WRLOCK(&hints);
 
        /* Search if hint exists, do nothing */
-       AST_LIST_TRAVERSE(&hints, hint, list) {
+       AST_RWLIST_TRAVERSE(&hints, hint, list) {
                if (hint->exten == e) {
-                       AST_LIST_UNLOCK(&hints);
+                       AST_RWLIST_UNLOCK(&hints);
                        if (option_debug > 1)
                                ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
                        return -1;
@@ -2043,15 +2056,15 @@ static int ast_add_hint(struct ast_exten *e)
                ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
 
        if (!(hint = ast_calloc(1, sizeof(*hint)))) {
-               AST_LIST_UNLOCK(&hints);
+               AST_RWLIST_UNLOCK(&hints);
                return -1;
        }
        /* Initialize and insert new item at the top */
        hint->exten = e;
        hint->laststate = ast_extension_state2(e);
-       AST_LIST_INSERT_HEAD(&hints, hint, list);
+       AST_RWLIST_INSERT_HEAD(&hints, hint, list);
 
-       AST_LIST_UNLOCK(&hints);
+       AST_RWLIST_UNLOCK(&hints);
        return 0;
 }
 
@@ -2061,15 +2074,15 @@ static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
        struct ast_hint *hint;
        int res = -1;
 
-       AST_LIST_LOCK(&hints);
-       AST_LIST_TRAVERSE(&hints, hint, list) {
+       AST_RWLIST_WRLOCK(&hints);
+       AST_RWLIST_TRAVERSE(&hints, hint, list) {
                if (hint->exten == oe) {
                        hint->exten = ne;
                        res = 0;
                        break;
                }
        }
-       AST_LIST_UNLOCK(&hints);
+       AST_RWLIST_UNLOCK(&hints);
 
        return res;
 }
@@ -2085,8 +2098,7 @@ static int ast_remove_hint(struct ast_exten *e)
        if (!e)
                return -1;
 
-       AST_LIST_LOCK(&hints);
-       AST_LIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
+       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
                if (hint->exten == e) {
                        cbprev = NULL;
                        cblist = hint->callbacks;
@@ -2098,14 +2110,13 @@ static int ast_remove_hint(struct ast_exten *e)
                                free(cbprev);
                        }
                        hint->callbacks = NULL;
-                       AST_LIST_REMOVE_CURRENT(&hints, list);
+                       AST_RWLIST_REMOVE_CURRENT(&hints, list);
                        free(hint);
                        res = 0;
                        break;
                }
        }
-       AST_LIST_TRAVERSE_SAFE_END
-       AST_LIST_UNLOCK(&hints);
+       AST_RWLIST_TRAVERSE_SAFE_END
 
        return res;
 }
@@ -2259,7 +2270,8 @@ static int __ast_pbx_run(struct ast_channel *c)
                        if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
                                /* Something bad happened, or a hangup has been requested. */
                                if (strchr("0123456789ABCDEF*#", res)) {
-                                       ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
+                                       if (option_debug)
+                                               ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
                                        pos = 0;
                                        dst_exten[pos++] = digit = res;
                                        dst_exten[pos] = '\0';
@@ -2294,8 +2306,9 @@ static int __ast_pbx_run(struct ast_channel *c)
                                c->whentohangup = 0;
                                c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
                        } else if (c->_softhangup) {
-                               ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
-                                       c->exten, c->priority);
+                               if (option_debug)
+                                       ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
+                                               c->exten, c->priority);
                                error = 1;
                                break;
                        }
@@ -2807,11 +2820,11 @@ int ast_register_application(const char *app, int (*execute)(struct ast_channel
        char tmps[80];
        int length;
 
-       AST_LIST_LOCK(&apps);
-       AST_LIST_TRAVERSE(&apps, tmp, list) {
+       AST_RWLIST_WRLOCK(&apps);
+       AST_RWLIST_TRAVERSE(&apps, tmp, list) {
                if (!strcasecmp(app, tmp->name)) {
                        ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
-                       AST_LIST_UNLOCK(&apps);
+                       AST_RWLIST_UNLOCK(&apps);
                        return -1;
                }
        }
@@ -2819,7 +2832,7 @@ int ast_register_application(const char *app, int (*execute)(struct ast_channel
        length = sizeof(*tmp) + strlen(app) + 1;
 
        if (!(tmp = ast_calloc(1, length))) {
-               AST_LIST_UNLOCK(&apps);
+               AST_RWLIST_UNLOCK(&apps);
                return -1;
        }
 
@@ -2829,20 +2842,20 @@ int ast_register_application(const char *app, int (*execute)(struct ast_channel
        tmp->description = description;
 
        /* Store in alphabetical order */
-       AST_LIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
+       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
                if (strcasecmp(tmp->name, cur->name) < 0) {
-                       AST_LIST_INSERT_BEFORE_CURRENT(&apps, tmp, list);
+                       AST_RWLIST_INSERT_BEFORE_CURRENT(&apps, tmp, list);
                        break;
                }
        }
-       AST_LIST_TRAVERSE_SAFE_END
+       AST_RWLIST_TRAVERSE_SAFE_END
        if (!cur)
-               AST_LIST_INSERT_TAIL(&apps, tmp, list);
+               AST_RWLIST_INSERT_TAIL(&apps, tmp, list);
 
        if (option_verbose > 1)
                ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
 
-       AST_LIST_UNLOCK(&apps);
+       AST_RWLIST_UNLOCK(&apps);
 
        return 0;
 }
@@ -2855,50 +2868,50 @@ int ast_register_switch(struct ast_switch *sw)
 {
        struct ast_switch *tmp;
 
-       AST_LIST_LOCK(&switches);
-       AST_LIST_TRAVERSE(&switches, tmp, list) {
+       AST_RWLIST_WRLOCK(&switches);
+       AST_RWLIST_TRAVERSE(&switches, tmp, list) {
                if (!strcasecmp(tmp->name, sw->name)) {
-                       AST_LIST_UNLOCK(&switches);
+                       AST_RWLIST_UNLOCK(&switches);
                        ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
                        return -1;
                }
        }
-       AST_LIST_INSERT_TAIL(&switches, sw, list);
-       AST_LIST_UNLOCK(&switches);
+       AST_RWLIST_INSERT_TAIL(&switches, sw, list);
+       AST_RWLIST_UNLOCK(&switches);
 
        return 0;
 }
 
 void ast_unregister_switch(struct ast_switch *sw)
 {
-       AST_LIST_LOCK(&switches);
-       AST_LIST_REMOVE(&switches, sw, list);
-       AST_LIST_UNLOCK(&switches);
+       AST_RWLIST_WRLOCK(&switches);
+       AST_RWLIST_REMOVE(&switches, sw, list);
+       AST_RWLIST_UNLOCK(&switches);
 }
 
 /*
  * Help for CLI commands ...
  */
 static char show_applications_help[] =
-"Usage: core list applications [{like|describing} <text>]\n"
+"Usage: core show applications [{like|describing} <text>]\n"
 "       List applications which are currently available.\n"
 "       If 'like', <text> will be a substring of the app name\n"
 "       If 'describing', <text> will be a substring of the description\n";
 
 static char show_functions_help[] =
-"Usage: core list functions [like <text>]\n"
+"Usage: core show functions [like <text>]\n"
 "       List builtin functions, optionally only those matching a given string\n";
 
 static char show_switches_help[] =
-"Usage: core list switches\n"
+"Usage: core show switches\n"
 "       List registered switches\n";
 
 static char show_hints_help[] =
-"Usage: core list hints\n"
+"Usage: core show hints\n"
 "       List registered hints\n";
 
 static char show_globals_help[] =
-"Usage: core list globals\n"
+"Usage: core show globals\n"
 "       List current global dialplan variables and their values\n";
 
 static char show_application_help[] =
@@ -2910,7 +2923,7 @@ static char show_function_help[] =
 "       Describe a particular dialplan function.\n";
 
 static char show_dialplan_help[] =
-"Usage: dialplan show [exten@][context]\n"
+"Usage: core show dialplan [exten@][context]\n"
 "       Show dialplan\n";
 
 static char set_global_help[] =
@@ -2935,14 +2948,14 @@ static char *complete_show_application(const char *line, const char *word, int p
        int wordlen = strlen(word);
 
        /* return the n-th [partial] matching entry */
-       AST_LIST_LOCK(&apps);
-       AST_LIST_TRAVERSE(&apps, a, list) {
+       AST_RWLIST_RDLOCK(&apps);
+       AST_RWLIST_TRAVERSE(&apps, a, list) {
                if (!strncasecmp(word, a->name, wordlen) && ++which > state) {
                        ret = strdup(a->name);
                        break;
                }
        }
-       AST_LIST_UNLOCK(&apps);
+       AST_RWLIST_UNLOCK(&apps);
 
        return ret;
 }
@@ -2956,8 +2969,8 @@ static int handle_show_application(int fd, int argc, char *argv[])
                return RESULT_SHOWUSAGE;
 
        /* ... go through all applications ... */
-       AST_LIST_LOCK(&apps);
-       AST_LIST_TRAVERSE(&apps, a, list) {
+       AST_RWLIST_RDLOCK(&apps);
+       AST_RWLIST_TRAVERSE(&apps, a, list) {
                /* ... compare this application name with all arguments given
                 * to 'show application' command ... */
                for (app = 3; app < argc; app++) {
@@ -3006,7 +3019,7 @@ static int handle_show_application(int fd, int argc, char *argv[])
                        }
                }
        }
-       AST_LIST_UNLOCK(&apps);
+       AST_RWLIST_UNLOCK(&apps);
 
        /* we found at least one app? no? */
        if (no_registered_app) {
@@ -3017,7 +3030,7 @@ static int handle_show_application(int fd, int argc, char *argv[])
        return RESULT_SUCCESS;
 }
 
-/*! \brief  handle_show_hints: CLI support for listing registred dial plan hints */
+/*! \brief  handle_show_hints: CLI support for listing registered dial plan hints */
 static int handle_show_hints(int fd, int argc, char *argv[])
 {
        struct ast_hint *hint;
@@ -3025,14 +3038,15 @@ static int handle_show_hints(int fd, int argc, char *argv[])
        int watchers;
        struct ast_state_cb *watcher;
 
-       if (AST_LIST_EMPTY(&hints)) {
+       AST_RWLIST_RDLOCK(&hints);
+       if (AST_RWLIST_EMPTY(&hints)) {
                ast_cli(fd, "There are no registered dialplan hints\n");
+               AST_RWLIST_UNLOCK(&hints);
                return RESULT_SUCCESS;
        }
        /* ... we have hints ... */
        ast_cli(fd, "\n    -= Registered Asterisk Dial Plan Hints =-\n");
-       AST_LIST_LOCK(&hints);
-       AST_LIST_TRAVERSE(&hints, hint, list) {
+       AST_RWLIST_TRAVERSE(&hints, hint, list) {
                watchers = 0;
                for (watcher = hint->callbacks; watcher; watcher = watcher->next)
                        watchers++;
@@ -3045,28 +3059,28 @@ static int handle_show_hints(int fd, int argc, char *argv[])
        }
        ast_cli(fd, "----------------\n");
        ast_cli(fd, "- %d hints registered\n", num);
-       AST_LIST_UNLOCK(&hints);
+       AST_RWLIST_UNLOCK(&hints);
        return RESULT_SUCCESS;
 }
 
-/*! \brief  handle_show_switches: CLI support for listing registred dial plan switches */
+/*! \brief  handle_show_switches: CLI support for listing registered dial plan switches */
 static int handle_show_switches(int fd, int argc, char *argv[])
 {
        struct ast_switch *sw;
 
-       AST_LIST_LOCK(&switches);
+       AST_RWLIST_RDLOCK(&switches);
 
-       if (AST_LIST_EMPTY(&switches)) {
-               AST_LIST_UNLOCK(&switches);
+       if (AST_RWLIST_EMPTY(&switches)) {
+               AST_RWLIST_UNLOCK(&switches);
                ast_cli(fd, "There are no registered alternative switches\n");
                return RESULT_SUCCESS;
        }
 
        ast_cli(fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
-       AST_LIST_TRAVERSE(&switches, sw, list)
+       AST_RWLIST_TRAVERSE(&switches, sw, list)
                ast_cli(fd, "%s: %s\n", sw->name, sw->description);
 
-       AST_LIST_UNLOCK(&switches);
+       AST_RWLIST_UNLOCK(&switches);
 
        return RESULT_SUCCESS;
 }
@@ -3078,11 +3092,11 @@ static int handle_show_applications(int fd, int argc, char *argv[])
        int total_match = 0;    /* Number of matches in like clause */
        int total_apps = 0;     /* Number of apps registered */
 
-       AST_LIST_LOCK(&apps);
+       AST_RWLIST_RDLOCK(&apps);
 
-       if (AST_LIST_EMPTY(&apps)) {
+       if (AST_RWLIST_EMPTY(&apps)) {
                ast_cli(fd, "There are no registered applications\n");
-               AST_LIST_UNLOCK(&apps);
+               AST_RWLIST_UNLOCK(&apps);
                return -1;
        }
 
@@ -3100,7 +3114,7 @@ static int handle_show_applications(int fd, int argc, char *argv[])
                ast_cli(fd, "    -= Matching Asterisk Applications =-\n");
        }
 
-       AST_LIST_TRAVERSE(&apps, a, list) {
+       AST_RWLIST_TRAVERSE(&apps, a, list) {
                int printapp = 0;
                total_apps++;
                if (like) {
@@ -3135,7 +3149,7 @@ static int handle_show_applications(int fd, int argc, char *argv[])
                ast_cli(fd, "    -= %d Applications Matching =-\n",total_match);
        }
 
-       AST_LIST_UNLOCK(&apps);
+       AST_RWLIST_UNLOCK(&apps);
 
        return RESULT_SUCCESS;
 }
@@ -3179,7 +3193,9 @@ static char *complete_show_dialplan_context(const char *line, const char *word,
        return ret;
 }
 
+/*! \brief Counters for the show dialplan manager command */
 struct dialplan_counters {
+       int total_items;
        int total_context;
        int total_exten;
        int total_prio;
@@ -3262,7 +3278,10 @@ static int show_dialplan_helper(int fd, const char *context, const char *exten,
                        dpc->total_prio++;
 
                        /* write extension name and first peer */
-                       snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
+                       if (e->matchcid)
+                               snprintf(buf, sizeof(buf), "'%s' (CID match '%s') => ", ast_get_extension_name(e), e->cidmatch);
+                       else
+                               snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
 
                        print_ext(e, buf2, sizeof(buf2));
 
@@ -3405,18 +3424,236 @@ static int handle_show_dialplan(int fd, int argc, char *argv[])
        return RESULT_SUCCESS;
 }
 
+/*! \brief Send ack once */
+static void manager_dpsendack(struct mansession *s, const struct message *m)
+{
+       astman_send_listack(s, m, "DialPlan list will follow", "start");
+}
+
+/*! \brief Show dialplan extensions
+ * XXX this function is similar but not exactly the same as the CLI's
+ * show dialplan. Must check whether the difference is intentional or not.
+ */
+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)
+{
+       struct ast_context *c;
+       int res=0, old_total_exten = dpc->total_exten;
+
+       if (ast_strlen_zero(exten))
+               exten = NULL;
+       if (ast_strlen_zero(context))
+               context = NULL;
+
+       if (option_debug > 2)
+               ast_log(LOG_DEBUG, "manager_show_dialplan: Context: -%s- Extension: -%s-\n", context, exten);
+
+       /* try to lock contexts */
+       if (ast_lock_contexts()) {
+               astman_send_error(s, m, "Failed to lock contexts\r\n");
+               ast_log(LOG_WARNING, "Failed to lock contexts list for manager: listdialplan\n");
+               return -1;
+       }
+
+       c = NULL;               /* walk all contexts ... */
+       while ( (c = ast_walk_contexts(c)) ) {
+               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 */
+
+               dpc->context_existence = 1;
+
+               if (option_debug > 2)
+                       ast_log(LOG_DEBUG, "manager_show_dialplan: Found Context: %s \n", ast_get_context_name(c));
+
+               if (ast_lock_context(c)) {      /* failed to lock */
+                       if (option_debug > 2)
+                               ast_log(LOG_DEBUG, "manager_show_dialplan: Failed to lock context\n");
+                       continue;
+               }
+
+               /* XXX note- an empty context is not printed */
+               e = NULL;               /* walk extensions in context  */
+               while ( (e = ast_walk_context_extensions(c, e)) ) {
+                       struct ast_exten *p;
+
+                       /* looking for extension? is this our extension? */
+                       if (exten && !ast_extension_match(ast_get_extension_name(e), exten)) {
+                               /* not the one we are looking for, continue */
+                               if (option_debug > 2)
+                                       ast_log(LOG_DEBUG, "manager_show_dialplan: Skipping extension %s\n", ast_get_extension_name(e));
+                               continue;
+                       }
+                       if (option_debug > 2)
+                               ast_log(LOG_DEBUG, "manager_show_dialplan: Found Extension: %s \n", ast_get_extension_name(e));
+
+                       dpc->extension_existence = 1;
+
+                       /* may we print context info? */        
+                       dpc->total_context++;
+                       dpc->total_exten++;
+
+                       p = NULL;               /* walk next extension peers */
+                       while ( (p = ast_walk_extension_priorities(e, p)) ) {
+                               int prio = ast_get_extension_priority(p);
+
+                               dpc->total_prio++;
+                               if (!dpc->total_items++)
+                                       manager_dpsendack(s, m);
+                               astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
+                               astman_append(s, "Context: %s\r\nExtension: %s\r\n", ast_get_context_name(c), ast_get_extension_name(e) );
+
+                               /* XXX maybe make this conditional, if p != e ? */
+                               if (ast_get_extension_label(p))
+                                       astman_append(s, "ExtensionLabel: %s\r\n", ast_get_extension_label(p));
+
+                               if (prio == PRIORITY_HINT) {
+                                       astman_append(s, "Priority: hint\r\nApplication: %s\r\n", ast_get_extension_app(p));
+                               } else {
+                                       astman_append(s, "Priority: %d\r\nApplication: %s\r\nAppData: %s\r\n", prio, ast_get_extension_app(p), (char *) ast_get_extension_app_data(p));
+                               }
+                               astman_append(s, "Registrar: %s\r\n\r\n", ast_get_extension_registrar(e));
+                       }
+               }
+
+               i = NULL;               /* walk included and write info ... */
+               while ( (i = ast_walk_context_includes(c, i)) ) {
+                       if (exten) {
+                               /* Check all includes for the requested extension */
+                               manager_show_dialplan_helper(s, m, actionidtext, ast_get_include_name(i), exten, dpc, i);
+                       } else {
+                               if (!dpc->total_items++)
+                                       manager_dpsendack(s, m);
+                               astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
+                               astman_append(s, "Context: %s\r\nIncludeContext: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ast_get_include_name(i), ast_get_include_registrar(i));
+                               astman_append(s, "\r\n");
+                               if (option_debug > 2)
+                                       ast_log(LOG_DEBUG, "manager_show_dialplan: Found Included context: %s \n", ast_get_include_name(i));
+                       }
+               }
+
+               ip = NULL;      /* walk ignore patterns and write info ... */
+               while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
+                       const char *ipname = ast_get_ignorepat_name(ip);
+                       char ignorepat[AST_MAX_EXTENSION];
+
+                       snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
+                       if (!exten || ast_extension_match(ignorepat, exten)) {
+                               if (!dpc->total_items++)
+                                       manager_dpsendack(s, m);
+                               astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
+                               astman_append(s, "Context: %s\r\nIgnorePattern: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ipname, ast_get_ignorepat_registrar(ip));
+                               astman_append(s, "\r\n");
+                       }
+               }
+               if (!rinclude) {
+                       struct ast_sw *sw = NULL;
+                       while ( (sw = ast_walk_context_switches(c, sw)) ) {
+                               if (!dpc->total_items++)
+                                       manager_dpsendack(s, m);
+                               astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
+                               astman_append(s, "Context: %s\r\nSwitch: %s/%s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ast_get_switch_name(sw), ast_get_switch_data(sw), ast_get_switch_registrar(sw)); 
+                               astman_append(s, "\r\n");
+                               if (option_debug > 2)
+                                       ast_log(LOG_DEBUG, "manager_show_dialplan: Found Switch : %s \n", ast_get_switch_name(sw));
+                       }
+               }
+
+               ast_unlock_context(c);
+       }
+       ast_unlock_contexts();
+
+       if (dpc->total_exten == old_total_exten) {
+               if (option_debug > 2)
+                       ast_log(LOG_DEBUG, "manager_show_dialplan: Found nothing new\n");
+               /* Nothing new under the sun */
+               return -1;
+       } else {
+               return res;
+       }
+}
+
+/*! \brief  Manager listing of dial plan */
+static int manager_show_dialplan(struct mansession *s, const struct message *m)
+{
+       const char *exten, *context;
+       const char *id = astman_get_header(m, "ActionID");
+       char idtext[256];
+       int res;
+
+       /* Variables used for different counters */
+       struct dialplan_counters counters;
+
+       if (id && !ast_strlen_zero(id))
+               snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
+       else
+               idtext[0] = '\0';
+
+       memset(&counters, 0, sizeof(counters));
+
+       exten = astman_get_header(m, "Extension");
+       context = astman_get_header(m, "Context");
+       
+       res = manager_show_dialplan_helper(s, m, idtext, context, exten, &counters, NULL);
+
+       if (context && !counters.context_existence) {
+               char errorbuf[BUFSIZ];
+       
+               snprintf(errorbuf, sizeof(errorbuf), "Did not find context %s\r\n", context);
+               astman_send_error(s, m, errorbuf);
+               return 0;
+       }
+       if (exten && !counters.extension_existence) {
+               char errorbuf[BUFSIZ];
+
+               if (context)
+                       snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s@%s\r\n", exten, context);
+               else
+                       snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s in any context\r\n", exten);
+               astman_send_error(s, m, errorbuf);
+               return 0;
+       }
+
+       manager_event(EVENT_FLAG_CONFIG, "ShowDialPlanComplete",
+               "EventList: Complete\r\n"
+               "ListItems: %d\r\n"
+               "ListExtensions: %d\r\n"
+               "ListPriorities: %d\r\n"        
+               "ListContexts: %d\r\n"  
+               "%s"
+               "\r\n", counters.total_items, counters.total_exten, counters.total_prio, counters.total_context, idtext);
+
+       /* everything ok */
+       return 0;
+}
+
+static char mandescr_show_dialplan[] =
+"Description: Show dialplan contexts and extensions.\n"
+"Be aware that showing the full dialplan may take a lot of capacity\n"
+"Variables: \n"
+" ActionID: <id>               Action ID for this AMI transaction (optional)\n"
+" Extension: <extension>       Extension (Optional)\n"
+" Context: <context>           Context (Optional)\n"
+"\n";
+
+
 /*! \brief CLI support for listing global variables in a parseable way */
 static int handle_show_globals(int fd, int argc, char *argv[])
 {
        int i = 0;
        struct ast_var_t *newvariable;
 
-       ast_mutex_lock(&globalslock);
+       ast_rwlock_rdlock(&globalslock);
        AST_LIST_TRAVERSE (&globals, newvariable, entries) {
                i++;
                ast_cli(fd, "   %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
        }
-       ast_mutex_unlock(&globalslock);
+       ast_rwlock_unlock(&globalslock);
        ast_cli(fd, "\n    -- %d variables\n", i);
 
        return RESULT_SUCCESS;
@@ -3439,23 +3676,23 @@ static int handle_set_global(int fd, int argc, char *argv[])
  * CLI entries for upper commands ...
  */
 static struct ast_cli_entry pbx_cli[] = {
-       { { "core", "list", "applications", NULL },
+       { { "core", "show", "applications", NULL },
        handle_show_applications, "Shows registered dialplan applications",
        show_applications_help, complete_show_applications },
 
-       { { "core", "list", "functions", NULL },
+       { { "core", "show", "functions", NULL },
        handle_show_functions, "Shows registered dialplan functions",
        show_functions_help },
 
-       { { "core", "list", "switches", NULL },
+       { { "core", "show", "switches", NULL },
        handle_show_switches, "Show alternative switches",
        show_switches_help },
 
-       { { "core", "list", "hints", NULL },
+       { { "core", "show", "hints", NULL },
        handle_show_hints, "Show dialplan hints",
        show_hints_help },
 
-       { { "core", "list", "globals", NULL },
+       { { "core", "show", "globals", NULL },
        handle_show_globals, "Show global dialplan variables",
        show_globals_help },
 
@@ -3499,19 +3736,19 @@ int ast_unregister_application(const char *app)
 {
        struct ast_app *tmp;
 
-       AST_LIST_LOCK(&apps);
-       AST_LIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
+       AST_RWLIST_WRLOCK(&apps);
+       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
                if (!strcasecmp(app, tmp->name)) {
                        unreference_cached_app(tmp);
-                       AST_LIST_REMOVE_CURRENT(&apps, list);
+                       AST_RWLIST_REMOVE_CURRENT(&apps, list);
                        if (option_verbose > 1)
                                ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
                        free(tmp);
                        break;
                }
        }
-       AST_LIST_TRAVERSE_SAFE_END
-       AST_LIST_UNLOCK(&apps);
+       AST_RWLIST_TRAVERSE_SAFE_END
+       AST_RWLIST_UNLOCK(&apps);
 
        return tmp ? 0 : -1;
 }
@@ -3601,10 +3838,10 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char
           other code paths that use this order
        */
        ast_mutex_lock(&conlock);
-       AST_LIST_LOCK(&hints);
+       AST_RWLIST_WRLOCK(&hints);
 
        /* preserve all watchers for hints associated with this registrar */
-       AST_LIST_TRAVERSE(&hints, hint, list) {
+       AST_RWLIST_TRAVERSE(&hints, hint, list) {
                if (hint->callbacks && !strcmp(registrar, hint->exten->parent->registrar)) {
                        length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
                        if (!(this = ast_calloc(1, length)))
@@ -3623,7 +3860,8 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char
        tmp = *extcontexts;
        if (registrar) {
                /* XXX remove previous contexts from same registrar */
-               ast_log(LOG_DEBUG, "must remove any reg %s\n", registrar);
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "must remove any reg %s\n", registrar);
                __ast_context_destroy(NULL,registrar);
                while (tmp) {
                        lasttmp = tmp;
@@ -3651,7 +3889,7 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char
        while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
                exten = ast_hint_extension(NULL, this->context, this->exten);
                /* Find the hint in the list of hints */
-               AST_LIST_TRAVERSE(&hints, hint, list) {
+               AST_RWLIST_TRAVERSE(&hints, hint, list) {
                        if (hint->exten == exten)
                                break;
                }
@@ -3676,7 +3914,7 @@ void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char
                free(this);
        }
 
-       AST_LIST_UNLOCK(&hints);
+       AST_RWLIST_UNLOCK(&hints);
        ast_mutex_unlock(&conlock);
 
        return;
@@ -4252,12 +4490,10 @@ int ast_async_goto(struct ast_channel *chan, const char *context, const char *ex
                /* In order to do it when the channel doesn't really exist within
                   the PBX, we have to make a new channel, masquerade, and start the PBX
                   at the new location */
-               struct ast_channel *tmpchan = ast_channel_alloc(0);
+               struct ast_channel *tmpchan = ast_channel_alloc(0, chan->_state, 0, 0, "AsyncGoto/%s", chan->name);
                if (!tmpchan)
                        res = -1;
                else {
-                       ast_string_field_build(tmpchan, name, "AsyncGoto/%s", chan->name);
-                       ast_setstate(tmpchan, chan->_state);
                        /* Make formats okay */
                        tmpchan->readformat = chan->readformat;
                        tmpchan->writeformat = chan->writeformat;
@@ -4321,10 +4557,6 @@ static int ext_strncpy(char *dst, const char *src, int len)
        return count;
 }
 
-static void null_datad(void *foo)
-{
-}
-
 /*! \brief add the extension in the priority chain.
  * returns 0 on success, -1 on failure
  */
@@ -4346,7 +4578,8 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp,
                   replacement?  If so, replace, otherwise, bonk. */
                if (!replace) {
                        ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
-                       tmp->datad(tmp->data);
+                       if (tmp->datad)
+                               tmp->datad(tmp->data);
                        free(tmp);
                        return -1;
                }
@@ -4364,7 +4597,8 @@ static int add_pri(struct ast_context *con, struct ast_exten *tmp,
                if (tmp->priority == PRIORITY_HINT)
                        ast_change_hint(e,tmp);
                /* Destroy the old one */
-               e->datad(e->data);
+               if (e->datad)
+                       e->datad(e->data);
                free(e);
        } else {        /* Slip ourselves in just before e */
                tmp->peer = e;
@@ -4430,12 +4664,12 @@ int ast_add_extension2(struct ast_context *con,
        /* if we are adding a hint, and there are global variables, and the hint
           contains variable references, then expand them
        */
-       ast_mutex_lock(&globalslock);
+       ast_rwlock_rdlock(&globalslock);
        if (priority == PRIORITY_HINT && AST_LIST_FIRST(&globals) && strstr(application, "${")) {
                pbx_substitute_variables_varshead(&globals, application, expand_buf, sizeof(expand_buf));
                application = expand_buf;
        }
-       ast_mutex_unlock(&globalslock);
+       ast_rwlock_unlock(&globalslock);
 
        length = sizeof(struct ast_exten);
        length += strlen(extension) + 1;
@@ -4448,8 +4682,6 @@ int ast_add_extension2(struct ast_context *con,
                length ++;      /* just the '\0' */
 
        /* Be optimistic:  Build the extension structure first */
-       if (datad == NULL)
-               datad = null_datad;
        if (!(tmp = ast_calloc(1, length)))
                return -1;
 
@@ -4614,7 +4846,7 @@ static void *async_wait(void *data)
 static int ast_pbx_outgoing_cdr_failed(void)
 {
        /* allocate a channel */
-       struct ast_channel *chan = ast_channel_alloc(0);
+       struct ast_channel *chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, 0);
 
        if (!chan)
                return -1;  /* failure */
@@ -4628,7 +4860,7 @@ static int ast_pbx_outgoing_cdr_failed(void)
        }
 
        /* allocation of the cdr was successful */
-       ast_cdr_init(chan->cdr, chan);  /* initilize our channel's cdr */
+       ast_cdr_init(chan->cdr, chan);  /* initialize our channel's cdr */
        ast_cdr_start(chan->cdr);       /* record the start and stop time */
        ast_cdr_end(chan->cdr);
        ast_cdr_failed(chan->cdr);      /* set the status to failed */
@@ -4647,7 +4879,15 @@ int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout
        pthread_attr_t attr;
 
        if (sync) {
-               LOAD_OH(oh);
+               oh.context = context;
+               oh.exten = exten;
+               oh.priority = priority;
+               oh.cid_num = cid_num;
+               oh.cid_name = cid_name;
+               oh.account = account;
+               oh.vars = vars;
+               oh.parent_channel = NULL;
+
                chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
                if (channel) {
                        *channel = chan;
@@ -4666,7 +4906,7 @@ int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout
                                        goto outgoing_exten_cleanup;
                                }
                                /* allocation of the cdr was successful */
-                               ast_cdr_init(chan->cdr, chan);  /* initilize our channel's cdr */
+                               ast_cdr_init(chan->cdr, chan);  /* initialize our channel's cdr */
                                ast_cdr_start(chan->cdr);
                        }
                        if (chan->_state == AST_STATE_UP) {
@@ -4727,9 +4967,8 @@ int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout
                        /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
                        /* check if "failed" exists */
                        if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
-                               chan = ast_channel_alloc(0);
+                               chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "OutgoingSpoolFailed");
                                if (chan) {
-                                       ast_string_field_set(chan, name, "OutgoingSpoolFailed");
                                        if (!ast_strlen_zero(context))
                                                ast_copy_string(chan->context, context, sizeof(chan->context));
                                        set_ext_pri(chan, "failed", 1);
@@ -4839,7 +5078,7 @@ int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout,
                                        goto outgoing_app_cleanup;
                                }
                                /* allocation of the cdr was successful */
-                               ast_cdr_init(chan->cdr, chan);  /* initilize our channel's cdr */
+                               ast_cdr_init(chan->cdr, chan);  /* initialize our channel's cdr */
                                ast_cdr_start(chan->cdr);
                        }
                        ast_set_variables(chan, vars);
@@ -4959,7 +5198,8 @@ void __ast_context_destroy(struct ast_context *con, const char *registrar)
        for (tmp = contexts; tmp; ) {
                struct ast_context *next;       /* next starting point */
                for (; tmp; tmpl = tmp, tmp = tmp->next) {
-                       ast_log(LOG_DEBUG, "check ctx %s %s\n", tmp->name, tmp->registrar);
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "check ctx %s %s\n", tmp->name, tmp->registrar);
                        if ( (!registrar || !strcasecmp(registrar, tmp->registrar)) &&
                             (!con || !strcasecmp(tmp->name, con->name)) )
                                break;  /* found it */
@@ -4967,7 +5207,8 @@ void __ast_context_destroy(struct ast_context *con, const char *registrar)
                if (!tmp)       /* not found, we are done */
                        break;
                ast_mutex_lock(&tmp->lock);
-               ast_log(LOG_DEBUG, "delete ctx %s %s\n", tmp->name, tmp->registrar);
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "delete ctx %s %s\n", tmp->name, tmp->registrar);
                next = tmp->next;
                if (tmpl)
                        tmpl->next = next;
@@ -5015,12 +5256,14 @@ static void wait_for_hangup(struct ast_channel *chan, void *data)
 {
        int res;
        struct ast_frame *f;
+       double waitsec;
        int waittime;
 
-       if (ast_strlen_zero(data) || (sscanf(data, "%d", &waittime) != 1) || (waittime < 0))
-               waittime = -1;
-       if (waittime > -1) {
-               ast_safe_sleep(chan, waittime * 1000);
+       if (ast_strlen_zero(data) || (sscanf(data, "%lg", &waitsec) != 1) || (waitsec < 0))
+               waitsec = -1;
+       if (waitsec > -1) {
+               waittime = waitsec * 1000.0;
+               ast_safe_sleep(chan, waittime);
        } else do {
                res = ast_waitfor(chan, -1);
                if (res < 0)
@@ -5238,11 +5481,12 @@ static int pbx_builtin_execiftime(struct ast_channel *chan, void *data)
  */
 static int pbx_builtin_wait(struct ast_channel *chan, void *data)
 {
+       double s;
        int ms;
 
        /* Wait for "n" seconds */
-       if (data && (ms = atof(data)) > 0) {
-               ms *= 1000;
+       if (data && (s = atof(data)) > 0.0) {
+               ms = s*1000.0;
                return ast_safe_sleep(chan, ms);
        }
        return 0;
@@ -5254,6 +5498,7 @@ static int pbx_builtin_wait(struct ast_channel *chan, void *data)
 static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
 {
        int ms, res;
+       double s;
        struct ast_flags flags = {0};
        char *opts[1] = { NULL };
        char *parse;
@@ -5277,12 +5522,13 @@ static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
                ast_indicate_data(chan, AST_CONTROL_HOLD, opts[0], strlen(opts[0]));
 
        /* Wait for "n" seconds */
-       if (args.timeout && (ms = atof(args.timeout)) > 0)
-                ms *= 1000;
+       if (args.timeout && (s = atof(args.timeout)) > 0)
+                ms = s * 1000.0;
        else if (chan->pbx)
                ms = chan->pbx->rtimeout * 1000;
        else
                ms = 10000;
+
        res = ast_waitfordigit(chan, ms);
        if (!res) {
                if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
@@ -5399,7 +5645,7 @@ static int pbx_builtin_goto(struct ast_channel *chan, void *data)
 }
 
 
-int pbx_builtin_serialize_variables(struct ast_channel *chan, char *buf, size_t size)
+int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **buf)
 {
        struct ast_var_t *variables;
        const char *var, *val;
@@ -5408,13 +5654,14 @@ int pbx_builtin_serialize_variables(struct ast_channel *chan, char *buf, size_t
        if (!chan)
                return 0;
 
-       memset(buf, 0, size);
+       (*buf)->used = 0;
+       (*buf)->str[0] = '\0';
 
        AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
                if ((var=ast_var_name(variables)) && (val=ast_var_value(variables))
                   /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
                   ) {
-                       if (ast_build_string(&buf, &size, "%s=%s\n", var, val)) {
+                       if (ast_str_append(buf, 0, "%s=%s\n", var, val) < 0) {
                                ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
                                break;
                        } else
@@ -5442,7 +5689,7 @@ const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name
                if (!places[i])
                        continue;
                if (places[i] == &globals)
-                       ast_mutex_lock(&globalslock);
+                       ast_rwlock_rdlock(&globalslock);
                AST_LIST_TRAVERSE(places[i], variables, entries) {
                        if (!strcmp(name, ast_var_name(variables))) {
                                ret = ast_var_value(variables);
@@ -5450,7 +5697,7 @@ const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name
                        }
                }
                if (places[i] == &globals)
-                       ast_mutex_unlock(&globalslock);
+                       ast_rwlock_unlock(&globalslock);
                if (ret)
                        break;
        }
@@ -5478,10 +5725,10 @@ void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, cons
                        ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
                newvariable = ast_var_assign(name, value);
                if (headp == &globals)
-                       ast_mutex_lock(&globalslock);
+                       ast_rwlock_wrlock(&globalslock);
                AST_LIST_INSERT_HEAD(headp, newvariable, entries);
                if (headp == &globals)
-                       ast_mutex_unlock(&globalslock);
+                       ast_rwlock_unlock(&globalslock);
        }
 }
 
@@ -5509,7 +5756,7 @@ void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const
        }
 
        if (headp == &globals)
-               ast_mutex_lock(&globalslock);
+               ast_rwlock_wrlock(&globalslock);
        AST_LIST_TRAVERSE (headp, newvariable, entries) {
                if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
                        /* there is already such a variable, delete it */
@@ -5527,7 +5774,7 @@ void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const
        }
 
        if (headp == &globals)
-               ast_mutex_unlock(&globalslock);
+               ast_rwlock_unlock(&globalslock);
 }
 
 int pbx_builtin_setvar(struct ast_channel *chan, void *data)
@@ -5605,10 +5852,10 @@ void pbx_builtin_clear_globals(void)
 {
        struct ast_var_t *vardata;
 
-       ast_mutex_lock(&globalslock);
+       ast_rwlock_wrlock(&globalslock);
        while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
                ast_var_delete(vardata);
-       ast_mutex_unlock(&globalslock);
+       ast_rwlock_unlock(&globalslock);
 }
 
 int pbx_checkcondition(const char *condition)
@@ -5639,7 +5886,8 @@ static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
        branch = pbx_checkcondition(condition) ? branch1 : branch2;
 
        if (ast_strlen_zero(branch)) {
-               ast_log(LOG_DEBUG, "Not taking any branch\n");
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "Not taking any branch\n");
                return 0;
        }
 
@@ -5718,6 +5966,9 @@ int load_pbx(void)
                        return -1;
                }
        }
+       
+       /* Register manager application */
+       ast_manager_register2("ShowDialPlan", EVENT_FLAG_CONFIG, manager_show_dialplan, "List dialplan", mandescr_show_dialplan);
        return 0;
 }