Merged revisions 50562 via svnmerge from
[asterisk/asterisk.git] / main / pbx.c
index 2a0f21d..10c9911 100644 (file)
@@ -100,10 +100,11 @@ AST_APP_OPTIONS(background_opts, {
 #define WAITEXTEN_MOH          (1 << 0)
 
 AST_APP_OPTIONS(waitexten_opts, {
-       AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 1),
+       AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 0),
 });
 
 struct ast_context;
+struct ast_app;
 
 /*!
    \brief ast_exten: An extension
@@ -119,6 +120,7 @@ struct ast_exten {
        const char *label;              /*!< Label */
        struct ast_context *parent;     /*!< The context this extension belongs to  */
        const char *app;                /*!< Application to execute */
+       struct ast_app *cached_app;     /*!< Cached location of application */
        void *data;                     /*!< Data to use (arguments) */
        void (*datad)(void *);          /*!< Data destructor */
        struct ast_exten *peer;         /*!< Next higher priority with our extension */
@@ -175,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 */
 };
@@ -191,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 {
@@ -225,7 +229,6 @@ static int pbx_builtin_ringing(struct ast_channel *, void *);
 static int pbx_builtin_progress(struct ast_channel *, void *);
 static int pbx_builtin_congestion(struct ast_channel *, void *);
 static int pbx_builtin_busy(struct ast_channel *, void *);
-static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
 static int pbx_builtin_noop(struct ast_channel *, void *);
 static int pbx_builtin_gotoif(struct ast_channel *, void *);
 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
@@ -237,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 {
@@ -262,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,
@@ -285,6 +289,9 @@ static struct pbx_builtin {
        "    n - Don't answer the channel before playing the files.\n"
        "    m - Only break if a digit hit matches a one digit\n"
        "          extension in the destination context.\n"
+       "This application sets the following channel variable upon completion:\n"
+       " BACKGROUNDSTATUS    The status of the background attempt as a text string, one of\n"
+       "               SUCCESS | FAILED\n"
        },
 
        { "Busy", pbx_builtin_busy,
@@ -303,6 +310,13 @@ static struct pbx_builtin {
        "Otherwise, this application will wait until the calling channel hangs up.\n"
        },
 
+       { "ExecIfTime", pbx_builtin_execiftime,
+       "Conditional application execution based on the current time",
+       "  ExecIfTime(<times>|<weekdays>|<mdays>|<months>?appname[|appargs]):\n"
+       "This application will execute the specified dialplan application, with optional\n"
+       "arguments, if the current time matches the given time specification.\n"
+       },
+
        { "Goto", pbx_builtin_goto,
        "Jump to a particular priority, extension, or context",
        "  Goto([[context|]extension|]priority): This application will cause the\n"
@@ -331,11 +345,14 @@ static struct pbx_builtin {
        "in the dialplan if the current time matches the given time specification.\n"
        },
 
-       { "ExecIfTime", pbx_builtin_execiftime,
-       "Conditional application execution based on the current time",
-       "  ExecIfTime(<times>|<weekdays>|<mdays>|<months>?appname[|appargs]):\n"
-       "This application will execute the specified dialplan application, with optional\n"
-       "arguments, if the current time matches the given time specification.\n"
+       { "ImportVar", pbx_builtin_importvar,
+       "Import a variable from a channel into a new variable",
+       "  ImportVar(newvar=channelname|variable): This application imports a variable\n"
+       "from the specified channel (as opposed to the current one) and stores it as\n"
+       "a variable in the current channel (the channel that is calling this\n"
+       "application). Variables created by this application have the same inheritance\n"
+       "properties as those created with the Set application. See the documentation for\n"
+       "Set for more information.\n"
        },
 
        { "Hangup", pbx_builtin_hangup,
@@ -375,12 +392,10 @@ static struct pbx_builtin {
        "tone to the user.\n"
        },
 
-       { "SayNumber", pbx_builtin_saynumber,
-       "Say Number",
-       "  SayNumber(digits[,gender]): This application will play the sounds that\n"
-       "correspond to the given number. Optionally, a gender may be specified.\n"
-       "This will use the language that is currently set for the channel. See the\n"
-       "LANGUAGE function for more information on setting the language for the channel.\n"
+       { "SayAlpha", pbx_builtin_saycharacters,
+       "Say Alpha",
+       "  SayAlpha(string): This application will play the sounds that correspond to\n"
+       "the letters of the given string.\n"
        },
 
        { "SayDigits", pbx_builtin_saydigits,
@@ -391,10 +406,12 @@ static struct pbx_builtin {
        "the language for the channel.\n"
        },
 
-       { "SayAlpha", pbx_builtin_saycharacters,
-       "Say Alpha",
-       "  SayAlpha(string): This application will play the sounds that correspond to\n"
-       "the letters of the given string.\n"
+       { "SayNumber", pbx_builtin_saynumber,
+       "Say Number",
+       "  SayNumber(digits[,gender]): This application will play the sounds that\n"
+       "correspond to the given number. Optionally, a gender may be specified.\n"
+       "This will use the language that is currently set for the channel. See the\n"
+       "LANGUAGE function for more information on setting the language for the channel.\n"
        },
 
        { "SayPhonetic", pbx_builtin_sayphonetic,
@@ -403,18 +420,6 @@ static struct pbx_builtin {
        "alphabet that correspond to the letters in the given string.\n"
        },
 
-       { "SetAMAFlags", pbx_builtin_setamaflags,
-       "Set the AMA Flags",
-       "  SetAMAFlags([flag]): This application will set the channel's AMA Flags for\n"
-       "  billing purposes.\n"
-       },
-
-       { "SetGlobalVar", pbx_builtin_setglobalvar,
-       "Set a global variable to a given value",
-       "  SetGlobalVar(variable=value): This application sets a given global variable to\n"
-       "the specified value.\n"
-       },
-
        { "Set", pbx_builtin_setvar,
        "Set channel variable(s) or function value(s)",
        "  Set(name1=value1|name2=value2|..[|options])\n"
@@ -429,14 +434,10 @@ static struct pbx_builtin {
        "        (applies only to variables, not functions)\n"
        },
 
-       { "ImportVar", pbx_builtin_importvar,
-       "Import a variable from a channel into a new variable",
-       "  ImportVar(newvar=channelname|variable): This application imports a variable\n"
-       "from the specified channel (as opposed to the current one) and stores it as\n"
-       "a variable in the current channel (the channel that is calling this\n"
-       "application). Variables created by this application have the same inheritance\n"
-       "properties as those created with the Set application. See the documentation for\n"
-       "Set for more information.\n"
+       { "SetAMAFlags", pbx_builtin_setamaflags,
+       "Set the AMA Flags",
+       "  SetAMAFlags([flag]): This application will set the channel's AMA Flags for\n"
+       "  billing purposes.\n"
        },
 
        { "Wait", pbx_builtin_wait,
@@ -460,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:
@@ -474,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;
 
@@ -522,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;
 }
@@ -536,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;
 }
@@ -741,9 +742,7 @@ static int _extension_match_core(const char *pattern, const char *data, enum ext
 {
        mode &= E_MATCH_MASK;   /* only consider the relevant bits */
 
-       if ( (mode == E_MATCH)
-               && (pattern[0] == '_') 
-               && (strcasecmp(pattern,data)==0) ) /* note: if this test is left out, then _x. will not match _x. !!! */
+       if ( (mode == E_MATCH) && (pattern[0] == '_') && (strcasecmp(pattern,data)==0) ) /* note: if this test is left out, then _x. will not match _x. !!! */
                return 1;
 
        if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
@@ -1098,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';
@@ -1189,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);
@@ -1197,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;
@@ -1210,31 +1212,28 @@ void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, c
        }
 }
 
-/*! \brief CLI function to show installed custom functions
-    \addtogroup CLI_functions
- */
 static int handle_show_functions(int fd, int argc, char *argv[])
 {
        struct ast_custom_function *acf;
        int count_acf = 0;
        int like = 0;
 
-       if (argc == 4 && (!strcmp(argv[2], "like")) ) {
+       if (argc == 5 && (!strcmp(argv[3], "like")) ) {
                like = 1;
-       } else if (argc != 2) {
+       } else if (argc != 3) {
                return RESULT_SHOWUSAGE;
        }
 
        ast_cli(fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
 
-       AST_LIST_LOCK(&acf_root);
-       AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
-               if (!like || strstr(acf->name, argv[3])) {
+       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 " : "");
 
@@ -1250,10 +1249,10 @@ static int handle_show_function(int fd, int argc, char *argv[])
        char stxtitle[40], *syntax = NULL;
        int synopsis_size, description_size, syntax_size;
 
-       if (argc < 3)
+       if (argc < 4)
                return RESULT_SHOWUSAGE;
 
-       if (!(acf = ast_custom_function_find(argv[2]))) {
+       if (!(acf = ast_custom_function_find(argv[3]))) {
                ast_cli(fd, "No function by that name registered.\n");
                return RESULT_FAILURE;
 
@@ -1305,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;
 }
@@ -1321,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;
 }
@@ -1338,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;
 }
@@ -1360,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);
@@ -1407,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);
@@ -1421,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);
@@ -1536,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);
@@ -1604,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;
                        }
@@ -1628,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;
        }
@@ -1668,7 +1672,9 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
                        ast_mutex_unlock(&conlock);
                        return res;     /* the priority we were looking for */
                } else {        /* spawn */
-                       app = pbx_findapp(e->app);
+                       if (!e->cached_app)
+                               e->cached_app = pbx_findapp(e->app);
+                       app = e->cached_app;
                        ast_mutex_unlock(&conlock);
                        if (!app) {
                                ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
@@ -1683,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");
@@ -1740,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;
@@ -1873,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;
@@ -1909,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 */
@@ -1922,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;
@@ -1944,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;
        }
 
@@ -1958,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 */
@@ -1983,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;
 }
 
@@ -1996,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) {
@@ -2005,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;
@@ -2020,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;
 }
 
@@ -2032,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;
@@ -2048,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;
 }
 
@@ -2066,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;
 }
@@ -2090,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;
@@ -2103,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;
 }
@@ -2264,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';
@@ -2273,14 +2280,14 @@ static int __ast_pbx_run(struct ast_channel *c)
                                if (res == AST_PBX_KEEPALIVE) {
                                        if (option_debug)
                                                ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
-                                       else if (option_verbose > 1)
+                                       if (option_verbose > 1)
                                                ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
                                        error = 1;
                                        break;
                                }
                                if (option_debug)
                                        ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
-                               else if (option_verbose > 1)
+                               if (option_verbose > 1)
                                        ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
                                if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
                                        c->_softhangup =0;
@@ -2299,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;
                        }
@@ -2400,7 +2408,7 @@ static int __ast_pbx_run(struct ast_channel *c)
                                /* Something bad happened, or a hangup has been requested. */
                                if (option_debug)
                                        ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
-                               else if (option_verbose > 1)
+                               if (option_verbose > 1)
                                        ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
                                break;
                        }
@@ -2812,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;
                }
        }
@@ -2824,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;
        }
 
@@ -2834,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;
 }
@@ -2860,75 +2868,70 @@ 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_application_help[] =
-"Usage: show application <application> [<application> [<application> [...]]]\n"
-"       Describes a particular application.\n";
-
-static char show_functions_help[] =
-"Usage: show functions [like <text>]\n"
-"       List builtin functions, optionally only those matching a given string\n";
-
-static char show_function_help[] =
-"Usage: show function <function>\n"
-"       Describe a particular dialplan function.\n";
-
 static char show_applications_help[] =
-"Usage: show 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_dialplan_help[] =
-"Usage: show dialplan [exten@][context]\n"
-"       Show dialplan\n";
+static char show_functions_help[] =
+"Usage: core show functions [like <text>]\n"
+"       List builtin functions, optionally only those matching a given string\n";
 
 static char show_switches_help[] =
-"Usage: show switches\n"
-"       Show registered switches\n";
+"Usage: core show switches\n"
+"       List registered switches\n";
 
 static char show_hints_help[] =
-"Usage: show hints\n"
-"       Show registered hints\n";
+"Usage: core show hints\n"
+"       List registered hints\n";
 
 static char show_globals_help[] =
-"Usage: show globals\n"
-"       Show current global dialplan variables and their values\n";
+"Usage: core show globals\n"
+"       List current global dialplan variables and their values\n";
+
+static char show_application_help[] =
+"Usage: core show application <application> [<application> [<application> [...]]]\n"
+"       Describes a particular application.\n";
+
+static char show_function_help[] =
+"Usage: core show function <function>\n"
+"       Describe a particular dialplan function.\n";
+
+static char show_dialplan_help[] =
+"Usage: core show dialplan [exten@][context]\n"
+"       Show dialplan\n";
 
 static char set_global_help[] =
-"Usage: set global <name> <value>\n"
+"Usage: core set global <name> <value>\n"
 "       Set global dialplan variable <name> to <value>\n";
 
 
 /*
- * IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
- *
- */
-
-/*
  * \brief 'show application' CLI command implementation functions ...
  */
 
@@ -2945,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;
 }
@@ -2962,15 +2965,15 @@ static int handle_show_application(int fd, int argc, char *argv[])
        struct ast_app *a;
        int app, no_registered_app = 1;
 
-       if (argc < 3)
+       if (argc < 4)
                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 = 2; app < argc; app++) {
+               for (app = 3; app < argc; app++) {
                        if (!strcasecmp(a->name, argv[app])) {
                                /* Maximum number of characters added by terminal coloring is 22 */
                                char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
@@ -3016,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) {
@@ -3027,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;
@@ -3035,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++;
@@ -3055,35 +3059,32 @@ 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;
 }
 
-/*
- * 'show applications' CLI command implementation functions ...
- */
 static int handle_show_applications(int fd, int argc, char *argv[])
 {
        struct ast_app *a;
@@ -3091,33 +3092,33 @@ 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;
        }
 
-       /* show applications like <keyword> */
-       if ((argc == 4) && (!strcmp(argv[2], "like"))) {
+       /* core list applications like <keyword> */
+       if ((argc == 5) && (!strcmp(argv[3], "like"))) {
                like = 1;
-       } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
+       } else if ((argc > 4) && (!strcmp(argv[3], "describing"))) {
                describing = 1;
        }
 
-       /* show applications describing <keyword1> [<keyword2>] [...] */
+       /* core list applications describing <keyword1> [<keyword2>] [...] */
        if ((!like) && (!describing)) {
                ast_cli(fd, "    -= Registered Asterisk Applications =-\n");
        } else {
                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) {
-                       if (strcasestr(a->name, argv[3])) {
+                       if (strcasestr(a->name, argv[4])) {
                                printapp = 1;
                                total_match++;
                        }
@@ -3126,7 +3127,7 @@ static int handle_show_applications(int fd, int argc, char *argv[])
                                /* Match all words on command line */
                                int i;
                                printapp = 1;
-                               for (i = 3; i < argc; i++) {
+                               for (i = 4; i < argc; i++) {
                                        if (!strcasestr(a->description, argv[i])) {
                                                printapp = 0;
                                        } else {
@@ -3148,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;
 }
@@ -3157,7 +3158,7 @@ static char *complete_show_applications(const char *line, const char *word, int
 {
        static char* choices[] = { "like", "describing", NULL };
 
-       return (pos != 2) ? NULL : ast_cli_complete(word, choices, state);
+       return (pos != 3) ? NULL : ast_cli_complete(word, choices, state);
 }
 
 /*
@@ -3192,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;
@@ -3275,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));
 
@@ -3418,31 +3424,248 @@ 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;
 }
 
-/*! \brief  CLI support for setting global variables */
 static int handle_set_global(int fd, int argc, char *argv[])
 {
-       if (argc != 4)
+       if (argc != 5)
                return RESULT_SHOWUSAGE;
 
-       pbx_builtin_setvar_helper(NULL, argv[2], argv[3]);
-       ast_cli(fd, "\n    -- Global variable %s set to %s\n", argv[2], argv[3]);
+       pbx_builtin_setvar_helper(NULL, argv[3], argv[4]);
+       ast_cli(fd, "\n    -- Global variable %s set to %s\n", argv[3], argv[4]);
 
        return RESULT_SUCCESS;
 }
@@ -3453,47 +3676,84 @@ static int handle_set_global(int fd, int argc, char *argv[])
  * CLI entries for upper commands ...
  */
 static struct ast_cli_entry pbx_cli[] = {
-       { { "show", "applications", NULL }, handle_show_applications,
-         "Shows registered dialplan applications", show_applications_help, complete_show_applications },
-       { { "show", "functions", NULL }, handle_show_functions,
-         "Shows registered dialplan functions", show_functions_help },
-       { { "show" , "function", NULL }, handle_show_function,
-         "Describe a specific dialplan function", show_function_help, complete_show_function },
-       { { "show", "application", NULL }, handle_show_application,
-         "Describe a specific dialplan application", show_application_help, complete_show_application },
-       { { "show", "dialplan", NULL }, handle_show_dialplan,
-         "Show dialplan", show_dialplan_help, complete_show_dialplan_context },
-       { { "show", "switches", NULL }, handle_show_switches,
-         "Show alternative switches", show_switches_help },
-       { { "show", "hints", NULL }, handle_show_hints,
-         "Show dialplan hints", show_hints_help },
-       { { "show", "globals", NULL }, handle_show_globals,
-         "Show global dialplan variables", show_globals_help },
-       { { "set", "global", NULL }, handle_set_global,
-         "Set global dialplan variable", set_global_help },
+       { { "core", "show", "applications", NULL },
+       handle_show_applications, "Shows registered dialplan applications",
+       show_applications_help, complete_show_applications },
+
+       { { "core", "show", "functions", NULL },
+       handle_show_functions, "Shows registered dialplan functions",
+       show_functions_help },
+
+       { { "core", "show", "switches", NULL },
+       handle_show_switches, "Show alternative switches",
+       show_switches_help },
+
+       { { "core", "show", "hints", NULL },
+       handle_show_hints, "Show dialplan hints",
+       show_hints_help },
+
+       { { "core", "show", "globals", NULL },
+       handle_show_globals, "Show global dialplan variables",
+       show_globals_help },
+
+       { { "core", "show" , "function", NULL },
+       handle_show_function, "Describe a specific dialplan function",
+       show_function_help, complete_show_function },
+
+       { { "core", "show", "application", NULL },
+       handle_show_application, "Describe a specific dialplan application",
+       show_application_help, complete_show_application },
+
+       { { "core", "set", "global", NULL },
+       handle_set_global, "Set global dialplan variable",
+       set_global_help },
+
+       { { "dialplan", "show", NULL },
+       handle_show_dialplan, "Show dialplan",
+       show_dialplan_help, complete_show_dialplan_context },
 };
 
+static void unreference_cached_app(struct ast_app *app)
+{
+       struct ast_context *context = NULL;
+       struct ast_exten *eroot = NULL, *e = NULL;
+
+       ast_lock_contexts();
+       while ((context = ast_walk_contexts(context))) {
+               while ((eroot = ast_walk_context_extensions(context, eroot))) {
+                       while ((e = ast_walk_extension_priorities(eroot, e))) {
+                               if (e->cached_app == app)
+                                       e->cached_app = NULL;
+                       }
+               }
+       }
+       ast_unlock_contexts();
+
+       return;
+}
+
 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)) {
-                       AST_LIST_REMOVE_CURRENT(&apps, list);
+                       unreference_cached_app(tmp);
+                       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;
 }
 
-struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
+static struct ast_context *__ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar, int existsokay)
 {
        struct ast_context *tmp, **local_contexts;
        int length = sizeof(struct ast_context) + strlen(name) + 1;
@@ -3506,10 +3766,13 @@ struct ast_context *ast_context_create(struct ast_context **extcontexts, const c
 
        for (tmp = *local_contexts; tmp; tmp = tmp->next) {
                if (!strcasecmp(tmp->name, name)) {
-                       ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
+                       if (!existsokay) {
+                               ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
+                               tmp = NULL;
+                       }
                        if (!extcontexts)
                                ast_mutex_unlock(&conlock);
-                       return NULL;
+                       return tmp;
                }
        }
        if ((tmp = ast_calloc(1, length))) {
@@ -3524,7 +3787,7 @@ struct ast_context *ast_context_create(struct ast_context **extcontexts, const c
                *local_contexts = tmp;
                if (option_debug)
                        ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
-               else if (option_verbose > 2)
+               if (option_verbose > 2)
                        ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
        }
 
@@ -3533,6 +3796,15 @@ struct ast_context *ast_context_create(struct ast_context **extcontexts, const c
        return tmp;
 }
 
+struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
+{
+       return __ast_context_create(extcontexts, name, registrar, 0);
+}
+
+struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar)
+{
+       return __ast_context_create(extcontexts, name, registrar, 1);
+}
 void __ast_context_destroy(struct ast_context *con, const char *registrar);
 
 struct store_hint {
@@ -3566,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)))
@@ -3588,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;
@@ -3616,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;
                }
@@ -3641,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;
@@ -4217,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;
@@ -4286,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
  */
@@ -4311,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;
                }
@@ -4329,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;
@@ -4395,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;
@@ -4413,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;
 
@@ -4489,7 +4756,8 @@ int ast_add_extension2(struct ast_context *con,
                        ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n",
                                tmp->exten, tmp->priority, con->name);
                }
-       } else if (option_verbose > 2) {
+       }
+       if (option_verbose > 2) {
                if (tmp->matchcid) {
                        ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n",
                                tmp->exten, tmp->priority, tmp->cidmatch, con->name);
@@ -4578,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 */
@@ -4592,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 */
@@ -4611,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;
@@ -4630,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) {
@@ -4691,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);
@@ -4803,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);
@@ -4923,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 */
@@ -4931,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;
@@ -4979,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)
@@ -5202,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;
@@ -5218,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;
@@ -5234,17 +5515,20 @@ static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
 
        if (args.options)
                ast_app_parse_options(waitexten_opts, &flags, opts, args.options);
-
-       if (ast_test_flag(&flags, WAITEXTEN_MOH))
+       
+       if (ast_test_flag(&flags, WAITEXTEN_MOH) && !opts[0] ) {
+               ast_log(LOG_WARNING, "The 'm' option has been specified for WaitExten without a class.\n"); 
+       } else if (ast_test_flag(&flags, WAITEXTEN_MOH))
                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)) {
@@ -5272,6 +5556,7 @@ static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
 static int pbx_builtin_background(struct ast_channel *chan, void *data)
 {
        int res = 0;
+       int mres = 0;
        struct ast_flags flags = {0};
        char *parse;
        AST_DECLARE_APP_ARGS(args,
@@ -5281,8 +5566,10 @@ static int pbx_builtin_background(struct ast_channel *chan, void *data)
                AST_APP_ARG(context);
        );
 
-       if (ast_strlen_zero(data))
+       if (ast_strlen_zero(data)) {
                ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
+               return -1;
+       }
 
        parse = ast_strdupa(data);
 
@@ -5306,7 +5593,7 @@ static int pbx_builtin_background(struct ast_channel *chan, void *data)
        /* Answer if need be */
        if (chan->_state != AST_STATE_UP) {
                if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
-                       return 0;
+                       goto done;
                } else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
                        res = ast_answer(chan);
                }
@@ -5315,12 +5602,14 @@ static int pbx_builtin_background(struct ast_channel *chan, void *data)
        if (!res) {
                char *back = args.filename;
                char *front;
+
                ast_stopstream(chan);           /* Stop anything playing */
                /* Stream the list of files */
                while (!res && (front = strsep(&back, "&")) ) {
                        if ( (res = ast_streamfile(chan, front, args.lang)) ) {
                                ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char*)data);
                                res = 0;
+                               mres = 1;
                                break;
                        }
                        if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
@@ -5339,6 +5628,8 @@ static int pbx_builtin_background(struct ast_channel *chan, void *data)
                chan->priority = 0;
                res = 0;
        }
+done:
+       pbx_builtin_setvar_helper(chan, "BACKGROUNDSTATUS", mres ? "FAILED" : "SUCCESS");
        return res;
 }
 
@@ -5354,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;
@@ -5363,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
@@ -5397,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);
@@ -5405,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;
        }
@@ -5433,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);
        }
 }
 
@@ -5464,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 */
@@ -5482,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)
@@ -5551,31 +5843,6 @@ int pbx_builtin_importvar(struct ast_channel *chan, void *data)
        return(0);
 }
 
-/*! \todo XXX overwrites data ? */
-static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data)
-{
-       char *name;
-       char *stringp = data;
-       static int dep_warning = 0;
-
-       if (ast_strlen_zero(data)) {
-               ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
-               return 0;
-       }
-
-       name = strsep(&stringp, "=");
-
-       if (!dep_warning) {
-               dep_warning = 1;
-               ast_log(LOG_WARNING, "SetGlobalVar is deprecated.  Please use Set(GLOBAL(%s)=%s) instead.\n", name, stringp);
-       }
-
-       /*! \todo XXX watch out, leading whitespace ? */
-       pbx_builtin_setvar_helper(NULL, name, stringp);
-
-       return(0);
-}
-
 static int pbx_builtin_noop(struct ast_channel *chan, void *data)
 {
        return 0;
@@ -5585,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)
@@ -5619,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;
        }
 
@@ -5687,7 +5955,7 @@ int load_pbx(void)
                ast_verbose( "Asterisk PBX Core Initializing\n");
                ast_verbose( "Registering builtin applications:\n");
        }
-       ast_cli_register_multiple(pbx_cli, sizeof(pbx_cli) / sizeof(pbx_cli[0]));
+       ast_cli_register_multiple(pbx_cli, sizeof(pbx_cli) / sizeof(struct ast_cli_entry));
 
        /* Register builtin applications */
        for (x=0; x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
@@ -5698,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;
 }