(closes issue #6019)
authorTilghman Lesher <tilghman@meg.abyt.es>
Mon, 10 Mar 2008 21:48:20 +0000 (21:48 +0000)
committerTilghman Lesher <tilghman@meg.abyt.es>
Mon, 10 Mar 2008 21:48:20 +0000 (21:48 +0000)
 Reported by: ssokol
 Patches:
       20080304__bug6019.diff.txt uploaded by Corydon76 (license 14)
 Tested by: putnopvut

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@107231 65c4cc65-6c06-0410-ace0-fbb531ad65f3

include/asterisk/pbx.h
main/pbx.c
pbx/pbx_config.c

index 14e7af4..f7b97e8 100644 (file)
@@ -839,6 +839,11 @@ int pbx_set_autofallthrough(int newval);
   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 2e3260a..029b68b 100644 (file)
@@ -123,6 +123,8 @@ AST_APP_OPTIONS(waitexten_opts, {
 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
@@ -166,7 +168,6 @@ struct ast_sw {
        char *data;                             /*!< Data load */
        int eval;
        AST_LIST_ENTRY(ast_sw) list;
-       char *tmpdata;
        char stuff[0];
 };
 
@@ -413,6 +414,7 @@ static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
 
 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;
@@ -1644,6 +1646,7 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
        struct ast_sw *sw = NULL;
        struct ast_exten pattern = {NULL, };
        struct scoreboard score = {0, };
+       struct ast_str *tmpdata = NULL;
 
        pattern.label = label;
        pattern.priority = priority;
@@ -1707,6 +1710,65 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
        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(name);
+
+                       if (!asw) {
+                               ast_log(LOG_WARNING, "No such switch '%s'\n", name);
+                               break;
+                       }
+
+                       if (osw && 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;
@@ -1828,8 +1890,13 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
                }
                /* 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)
@@ -1838,7 +1905,7 @@ struct ast_exten *pbx_find_extension(struct ast_channel *chan,
                        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 {
@@ -3618,6 +3685,18 @@ int pbx_set_extenpatternmatchnew(int newval)
        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.
@@ -5781,11 +5860,6 @@ int ast_context_add_switch2(struct ast_context *con, const char *value,
        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)))
@@ -5803,8 +5877,6 @@ int ast_context_add_switch2(struct ast_context *con, const char *value,
                strcpy(new_sw->data, "");
                p++;
        }
-       if (eval)
-               new_sw->tmpdata = p;
        new_sw->eval      = eval;
        new_sw->registrar = registrar;
 
index bf707a9..a35585a 100644 (file)
@@ -47,6 +47,7 @@ static int write_protect_config = 1;
 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 *complete_dialplan_add_include(struct ast_cli_args *a)
  */
 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 @@ static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct a
        }
 
        /* 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 @@ static int unload_module(void)
 {
        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 @@ static int pbx_load_config(const char *config_file)
        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);
        if (!cfg)
@@ -1383,7 +1391,16 @@ static int pbx_load_config(const char *config_file)
        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));
@@ -1640,6 +1657,7 @@ static int pbx_load_module(void)
        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);