Index: pbx/pbx_config.c =================================================================== --- pbx/pbx_config.c (revision 105672) +++ pbx/pbx_config.c (working copy) @@ -47,6 +47,7 @@ static int autofallthrough_config = 1; static int clearglobalvars_config = 0; static int extenpatternmatchnew_config = 0; +static char *overrideswitch_config = NULL; AST_MUTEX_DEFINE_STATIC(save_dialplan_lock); @@ -701,7 +702,7 @@ */ static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) { - char filename[256]; + char filename[256], overrideswitch[256] = ""; struct ast_context *c; struct ast_config *cfg; struct ast_variable *v; @@ -781,11 +782,15 @@ } /* fireout general info */ - fprintf(output, "[general]\nstatic=%s\nwriteprotect=%s\nautofallthrough=%s\nclearglobalvars=%s\nextenpatternmatchnew=%s\n\n", + if (overrideswitch_config) { + snprintf(overrideswitch, sizeof(overrideswitch), "overrideswitch=%s\n", overrideswitch_config); + } + fprintf(output, "[general]\nstatic=%s\nwriteprotect=%s\nautofallthrough=%s\nclearglobalvars=%s\n%sextenpatternmatchnew=%s\n\n", static_config ? "yes" : "no", write_protect_config ? "yes" : "no", autofallthrough_config ? "yes" : "no", clearglobalvars_config ? "yes" : "no", + overrideswitch_config ? overrideswitch : "", extenpatternmatchnew_config ? "yes" : "no"); if ((v = ast_variable_browse(cfg, "globals"))) { @@ -1353,6 +1358,9 @@ { if (static_config && !write_protect_config) ast_cli_unregister(&cli_dialplan_save); + if (overrideswitch_config) { + ast_free(overrideswitch_config); + } ast_cli_unregister_multiple(cli_pbx_config, sizeof(cli_pbx_config) / sizeof(struct ast_cli_entry)); ast_context_destroy(NULL, registrar); return 0; @@ -1369,7 +1377,7 @@ struct ast_variable *v; const char *cxt; const char *aft; - const char *newpm; + const char *newpm, *ovsw; struct ast_flags config_flags = { 0 }; cfg = ast_config_load(config_file, config_flags); @@ -1384,7 +1392,16 @@ if ((newpm = ast_variable_retrieve(cfg, "general", "extenpatternmatchnew"))) extenpatternmatchnew_config = ast_true(newpm); clearglobalvars_config = ast_true(ast_variable_retrieve(cfg, "general", "clearglobalvars")); - + if ((ovsw = ast_variable_retrieve(cfg, "general", "overrideswitch"))) { + if (overrideswitch_config) { + ast_free(overrideswitch_config); + } + if (!ast_strlen_zero(ovsw)) { + overrideswitch_config = ast_strdup(ovsw); + } else { + overrideswitch_config = NULL; + } + } if ((cxt = ast_variable_retrieve(cfg, "general", "userscontext"))) ast_copy_string(userscontext, cxt, sizeof(userscontext)); @@ -1636,6 +1653,7 @@ for (con = NULL; (con = ast_walk_contexts(con));) ast_context_verify_includes(con); + pbx_set_overrideswitch(overrideswitch_config); pbx_set_autofallthrough(autofallthrough_config); pbx_set_extenpatternmatchnew(extenpatternmatchnew_config); Index: include/asterisk/pbx.h =================================================================== --- include/asterisk/pbx.h (revision 105672) +++ include/asterisk/pbx.h (working copy) @@ -847,6 +847,11 @@ the old linear-search algorithm. Returns previous value. */ int pbx_set_extenpatternmatchnew(int newval); +/*! Set "overrideswitch" field. If set and of nonzero length, all contexts + * will be tried directly through the named switch prior to any other + * matching within that context. */ +void pbx_set_overrideswitch(const char *newval); + /*! * \note This function will handle locking the channel as needed. */ Index: main/pbx.c =================================================================== --- main/pbx.c (revision 105672) +++ main/pbx.c (working copy) @@ -122,6 +122,8 @@ struct ast_context; struct ast_app; +AST_THREADSTORAGE(switch_data); + /*! \brief ast_exten: An extension The dialplan is saved as a linked list with each context @@ -165,7 +167,6 @@ char *data; /*!< Data load */ int eval; AST_LIST_ENTRY(ast_sw) list; - char *tmpdata; char stuff[0]; }; @@ -410,6 +411,7 @@ static int autofallthrough = 1; static int extenpatternmatchnew = 0; +static char *overrideswitch = NULL; /*! \brief Subscription for device state change events */ static struct ast_event_sub *device_state_sub; @@ -1640,6 +1642,7 @@ struct ast_sw *sw = NULL; struct ast_exten pattern = {NULL, }; struct scoreboard score = {0, }; + struct ast_str *tmpdata; pattern.label = label; pattern.priority = priority; @@ -1703,6 +1706,65 @@ log_match_char_tree(tmp->pattern_tree, ":: "); #endif + do { + if (!ast_strlen_zero(overrideswitch)) { + char *osw = ast_strdupa(overrideswitch), *name; + struct ast_switch *asw; + ast_switch_f *aswf = NULL; + char *datap; + int eval = 0; + + name = strsep(&osw, "/"); + asw = pbx_findswitch(osw); + + if (!asw) { + ast_log(LOG_WARNING, "No such switch '%s'\n", name); + break; + } + + if (strchr(osw, '$')) { + eval = 1; + } + + if (eval && !(tmpdata = ast_str_thread_get(&switch_data, 512))) { + ast_log(LOG_WARNING, "Can't evaluate overrideswitch?!"); + break; + } else if (eval) { + /* Substitute variables now */ + pbx_substitute_variables_helper(chan, osw, tmpdata->str, tmpdata->len); + datap = tmpdata->str; + } else { + datap = osw; + } + + /* equivalent of extension_match_core() at the switch level */ + if (action == E_CANMATCH) + aswf = asw->canmatch; + else if (action == E_MATCHMORE) + aswf = asw->matchmore; + else /* action == E_MATCH */ + aswf = asw->exists; + if (!aswf) { + res = 0; + } else { + if (chan) { + ast_autoservice_start(chan); + } + res = aswf(chan, context, exten, priority, callerid, datap); + if (chan) { + ast_autoservice_stop(chan); + } + } + if (res) { /* Got a match */ + q->swo = asw; + q->data = datap; + q->foundcontext = context; + /* XXX keep status = STATUS_NO_CONTEXT ? */ + return NULL; + } + } + } while (0); + if (extenpatternmatchnew) { new_find_extension(exten, &score, tmp->pattern_tree, 0, 0, callerid); eroot = score.exten; @@ -1824,8 +1886,13 @@ } /* Substitute variables now */ - if (sw->eval) - pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1); + if (sw->eval) { + if (!(tmpdata = ast_str_thread_get(&switch_data, 512))) { + ast_log(LOG_WARNING, "Can't evaluate switch?!"); + continue; + } + pbx_substitute_variables_helper(chan, sw->data, tmpdata->str, tmpdata->len); + } /* equivalent of extension_match_core() at the switch level */ if (action == E_CANMATCH) @@ -1834,7 +1901,7 @@ aswf = asw->matchmore; else /* action == E_MATCH */ aswf = asw->exists; - datap = sw->eval ? sw->tmpdata : sw->data; + datap = sw->eval ? tmpdata->str : sw->data; if (!aswf) res = 0; else { @@ -3614,6 +3681,18 @@ return oldval; } +void pbx_set_overrideswitch(const char *newval) +{ + if (overrideswitch) { + ast_free(overrideswitch); + } + if (!ast_strlen_zero(newval)) { + overrideswitch = ast_strdup(newval); + } else { + overrideswitch = NULL; + } +} + /*! * \brief lookup for a context with a given name, * \retval with conlock held if found. @@ -5681,11 +5760,6 @@ if (data) length += strlen(data); length++; - if (eval) { - /* Create buffer for evaluation of variables */ - length += SWITCH_DATA_LENGTH; - length++; - } /* allocate new sw structure ... */ if (!(new_sw = ast_calloc(1, length))) @@ -5703,8 +5777,6 @@ strcpy(new_sw->data, ""); p++; } - if (eval) - new_sw->tmpdata = p; new_sw->eval = eval; new_sw->registrar = registrar;