Merged revisions 165317 via svnmerge from
authorTilghman Lesher <tilghman@meg.abyt.es>
Wed, 17 Dec 2008 21:18:57 +0000 (21:18 +0000)
committerTilghman Lesher <tilghman@meg.abyt.es>
Wed, 17 Dec 2008 21:18:57 +0000 (21:18 +0000)
https://origsvn.digium.com/svn/asterisk/branches/1.4

........
  r165317 | tilghman | 2008-12-17 15:14:37 -0600 (Wed, 17 Dec 2008) | 4 lines

  Reverse the fix from issue #6176 and add proper handling for that issue.
  (Closes issue #13962, closes issue #13363)
  Fixed by myself (license 14)
........

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

apps/app_macro.c

index 6d9b412..73d62d9 100644 (file)
@@ -155,6 +155,31 @@ static char *if_app = "MacroIf";
 static char *exclusive_app = "MacroExclusive";
 static char *exit_app = "MacroExit";
 
+static void macro_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
+
+struct ast_datastore_info macro_ds_info = {
+       .type = "MACRO",
+       .chan_fixup = macro_fixup,
+};
+
+static void macro_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
+{
+       int i;
+       char varname[10];
+       pbx_builtin_setvar_helper(new_chan, "MACRO_DEPTH", "0");
+       pbx_builtin_setvar_helper(new_chan, "MACRO_CONTEXT", NULL);
+       pbx_builtin_setvar_helper(new_chan, "MACRO_EXTEN", NULL);
+       pbx_builtin_setvar_helper(new_chan, "MACRO_PRIORITY", NULL);
+       pbx_builtin_setvar_helper(new_chan, "MACRO_OFFSET", NULL);
+       for (i = 1; i < 100; i++) {
+               snprintf(varname, sizeof(varname), "ARG%d", i);
+               while (pbx_builtin_getvar_helper(new_chan, varname)) {
+                       /* Kill all levels of arguments */
+                       pbx_builtin_setvar_helper(new_chan, varname, NULL);
+               }
+       }
+}
+
 static struct ast_exten *find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid)
 {
        struct ast_exten *e;
@@ -209,18 +234,32 @@ static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
        const char *inhangupc;
        int offset, depth = 0, maxdepth = 7;
        int setmacrocontext=0;
-       int autoloopflag, dead = 0, inhangup = 0;
+       int autoloopflag, inhangup = 0;
   
        char *save_macro_exten;
        char *save_macro_context;
        char *save_macro_priority;
        char *save_macro_offset;
+       struct ast_datastore *macro_store = ast_channel_datastore_find(chan, &macro_ds_info, NULL);
  
        if (ast_strlen_zero(data)) {
                ast_log(LOG_WARNING, "Macro() requires arguments. See \"core show application macro\" for help.\n");
                return -1;
        }
 
+       do {
+               if (macro_store) {
+                       break;
+               }
+               if (!(macro_store = ast_channel_datastore_alloc(&macro_ds_info, NULL))) {
+                       ast_log(LOG_WARNING, "Unable to allocate new datastore.\n");
+                       break;
+               }
+               /* Just the existence of this datastore is enough. */
+               macro_store->inheritance = DATASTORE_INHERIT_FOREVER;
+               ast_channel_datastore_add(chan, macro_store);
+       } while (0);
+
        /* does the user want a deeper rabbit hole? */
        ast_channel_lock(chan);
        if ((s = pbx_builtin_getvar_helper(chan, "MACRO_RECURSION"))) {
@@ -370,12 +409,10 @@ static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
                        case AST_PBX_KEEPALIVE:
                                ast_debug(2, "Spawn extension (%s,%s,%d) exited KEEPALIVE in macro %s on '%s'\n", chan->context, chan->exten, chan->priority, macro, chan->name);
                                ast_verb(2, "Spawn extension (%s, %s, %d) exited KEEPALIVE in macro '%s' on '%s'\n", chan->context, chan->exten, chan->priority, macro, chan->name);
-                               dead = 1;
                                goto out;
                        default:
                                ast_debug(2, "Spawn extension (%s,%s,%d) exited non-zero on '%s' in macro '%s'\n", chan->context, chan->exten, chan->priority, chan->name, macro);
                                ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s' in macro '%s'\n", chan->context, chan->exten, chan->priority, chan->name, macro);
-                               dead = 1;
                                goto out;
                        }
                }
@@ -448,31 +485,30 @@ static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
                chan->priority++;
        }
        out:
+
+       /* Don't let the channel change now. */
+       ast_channel_lock(chan);
+
        /* Reset the depth back to what it was when the routine was entered (like if we called Macro recursively) */
        snprintf(depthc, sizeof(depthc), "%d", depth);
-       if (!dead) {
-               pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
-               ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
-       }
+       pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
+       ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
 
        for (x = 1; x < argc; x++) {
                /* Restore old arguments and delete ours */
                snprintf(varname, sizeof(varname), "ARG%d", x);
                if (oldargs[x]) {
-                       if (!dead)
-                               pbx_builtin_setvar_helper(chan, varname, oldargs[x]);
+                       pbx_builtin_setvar_helper(chan, varname, oldargs[x]);
                        ast_free(oldargs[x]);
-               } else if (!dead) {
+               } else {
                        pbx_builtin_setvar_helper(chan, varname, NULL);
                }
        }
 
        /* Restore macro variables */
-       if (!dead) {
-               pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", save_macro_exten);
-               pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", save_macro_context);
-               pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", save_macro_priority);
-       }
+       pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", save_macro_exten);
+       pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", save_macro_context);
+       pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", save_macro_priority);
        if (save_macro_exten)
                ast_free(save_macro_exten);
        if (save_macro_context)
@@ -480,13 +516,13 @@ static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
        if (save_macro_priority)
                ast_free(save_macro_priority);
 
-       if (!dead && setmacrocontext) {
+       if (setmacrocontext) {
                chan->macrocontext[0] = '\0';
                chan->macroexten[0] = '\0';
                chan->macropriority = 0;
        }
 
-       if (!dead && !strcasecmp(chan->context, fullmacro)) {
+       if (!strcasecmp(chan->context, fullmacro)) {
                /* If we're leaving the macro normally, restore original information */
                chan->priority = oldpriority;
                ast_copy_string(chan->context, oldcontext, sizeof(chan->context));
@@ -494,7 +530,6 @@ static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
                        /* Copy the extension, so long as we're not in softhangup, where we could be given an asyncgoto */
                        const char *offsets;
                        ast_copy_string(chan->exten, oldexten, sizeof(chan->exten));
-                       ast_channel_lock(chan);
                        if ((offsets = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"))) {
                                /* Handle macro offset if it's set by checking the availability of step n + offset + 1, otherwise continue
                                normally if there is any problem */
@@ -504,12 +539,10 @@ static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
                                        }
                                }
                        }
-                       ast_channel_unlock(chan);
                }
        }
 
-       if (!dead)
-               pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", save_macro_offset);
+       pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", save_macro_offset);
        if (save_macro_offset)
                ast_free(save_macro_offset);
 
@@ -521,6 +554,7 @@ static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
                        res = 0;
                }
        }
+       ast_channel_unlock(chan);
 
        return res;
 }