Fix race condition that could result in ARI transfer messages not being sent.
[asterisk/asterisk.git] / apps / app_macro.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Dial plan macro Implementation
22  *
23  * \author Mark Spencer <markster@digium.com>
24  * 
25  * \ingroup applications
26  */
27
28 /*** MODULEINFO
29         <support_level>core</support_level>
30         <replacement>app_stack (GoSub)</replacement>
31  ***/
32
33 #include "asterisk.h"
34
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
36
37 #include "asterisk/file.h"
38 #include "asterisk/channel.h"
39 #include "asterisk/pbx.h"
40 #include "asterisk/module.h"
41 #include "asterisk/config.h"
42 #include "asterisk/utils.h"
43 #include "asterisk/lock.h"
44 #include "asterisk/app.h"
45
46 /*** DOCUMENTATION
47         <application name="Macro" language="en_US">
48                 <synopsis>
49                         Macro Implementation.
50                 </synopsis>
51                 <syntax>
52                         <parameter name="name" required="true">
53                                 <para>The name of the macro</para>
54                         </parameter>
55                         <parameter name="args">
56                                 <argument name="arg1" required="true" />
57                                 <argument name="arg2" multiple="true" />
58                         </parameter>
59                 </syntax>
60                 <description>
61                         <para>Executes a macro using the context macro-<replaceable>name</replaceable>,
62                         jumping to the <literal>s</literal> extension of that context and executing each step,
63                         then returning when the steps end.</para>
64                         <para>The calling extension, context, and priority are stored in <variable>MACRO_EXTEN</variable>,
65                         <variable>MACRO_CONTEXT</variable> and <variable>MACRO_PRIORITY</variable> respectively. Arguments
66                         become <variable>ARG1</variable>, <variable>ARG2</variable>, etc in the macro context.</para>
67                         <para>If you Goto out of the Macro context, the Macro will terminate and control will be returned
68                         at the location of the Goto.</para>
69                         <para>If <variable>MACRO_OFFSET</variable> is set at termination, Macro will attempt to continue
70                         at priority MACRO_OFFSET + N + 1 if such a step exists, and N + 1 otherwise.</para>
71                         <warning><para>Because of the way Macro is implemented (it executes the priorities contained within
72                         it via sub-engine), and a fixed per-thread memory stack allowance, macros are limited to 7 levels
73                         of nesting (macro calling macro calling macro, etc.); It may be possible that stack-intensive
74                         applications in deeply nested macros could cause asterisk to crash earlier than this limit.
75                         It is advised that if you need to deeply nest macro calls, that you use the Gosub application
76                         (now allows arguments like a Macro) with explict Return() calls instead.</para></warning>
77                         <warning><para>Use of the application <literal>WaitExten</literal> within a macro will not function
78                         as expected. Please use the <literal>Read</literal> application in order to read DTMF from a channel
79                         currently executing a macro.</para></warning>
80                 </description>
81                 <see-also>
82                         <ref type="application">MacroExit</ref>
83                         <ref type="application">Goto</ref>
84                         <ref type="application">Gosub</ref>
85                 </see-also>
86         </application>
87         <application name="MacroIf" language="en_US">
88                 <synopsis>
89                         Conditional Macro implementation.
90                 </synopsis>
91                 <syntax argsep="?">
92                         <parameter name="expr" required="true" />
93                         <parameter name="destination" required="true" argsep=":">
94                                 <argument name="macroiftrue" required="true">
95                                         <argument name="macroiftrue" required="true" />
96                                         <argument name="arg1" multiple="true" />
97                                 </argument>
98                                 <argument name="macroiffalse">
99                                         <argument name="macroiffalse" required="true" />
100                                         <argument name="arg1" multiple="true" />
101                                 </argument>
102                         </parameter>
103                 </syntax>
104                 <description>
105                         <para>Executes macro defined in <replaceable>macroiftrue</replaceable> if
106                         <replaceable>expr</replaceable> is true (otherwise <replaceable>macroiffalse</replaceable>
107                         if provided)</para>
108                         <para>Arguments and return values as in application Macro()</para>
109                         <xi:include xpointer="xpointer(/docs/application[@name='Macro']/description/warning[2])" />
110                 </description>
111                 <see-also>
112                         <ref type="application">GotoIf</ref>
113                         <ref type="application">GosubIf</ref>
114                         <ref type="function">IF</ref>
115                 </see-also>
116         </application>
117         <application name="MacroExclusive" language="en_US">
118                 <synopsis>
119                         Exclusive Macro Implementation.
120                 </synopsis>
121                 <syntax>
122                         <parameter name="name" required="true">
123                                 <para>The name of the macro</para>
124                         </parameter>
125                         <parameter name="arg1" />
126                         <parameter name="arg2" multiple="true" />
127                 </syntax>
128                 <description>
129                         <para>Executes macro defined in the context macro-<replaceable>name</replaceable>.
130                         Only one call at a time may run the macro. (we'll wait if another call is busy
131                         executing in the Macro)</para>
132                         <para>Arguments and return values as in application Macro()</para>
133                         <xi:include xpointer="xpointer(/docs/application[@name='Macro']/description/warning[2])" />
134                 </description>
135                 <see-also>
136                         <ref type="application">Macro</ref>
137                 </see-also>
138         </application>
139         <application name="MacroExit" language="en_US">
140                 <synopsis>
141                         Exit from Macro.
142                 </synopsis>
143                 <syntax />
144                 <description>
145                         <para>Causes the currently running macro to exit as if it had
146                         ended normally by running out of priorities to execute.
147                         If used outside a macro, will likely cause unexpected behavior.</para>
148                 </description>
149                 <see-also>
150                         <ref type="application">Macro</ref>
151                 </see-also>
152         </application>
153  ***/
154
155 #define MAX_ARGS 80
156
157 /* special result value used to force macro exit */
158 #define MACRO_EXIT_RESULT 1024
159
160 static char *app = "Macro";
161 static char *if_app = "MacroIf";
162 static char *exclusive_app = "MacroExclusive";
163 static char *exit_app = "MacroExit";
164
165 static void macro_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
166
167 static const struct ast_datastore_info macro_ds_info = {
168         .type = "MACRO",
169         .chan_fixup = macro_fixup,
170 };
171
172 static void macro_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
173 {
174         int i;
175         char varname[10];
176         pbx_builtin_setvar_helper(new_chan, "MACRO_DEPTH", "0");
177         pbx_builtin_setvar_helper(new_chan, "MACRO_CONTEXT", NULL);
178         pbx_builtin_setvar_helper(new_chan, "MACRO_EXTEN", NULL);
179         pbx_builtin_setvar_helper(new_chan, "MACRO_PRIORITY", NULL);
180         pbx_builtin_setvar_helper(new_chan, "MACRO_OFFSET", NULL);
181         for (i = 1; i < 100; i++) {
182                 snprintf(varname, sizeof(varname), "ARG%d", i);
183                 while (pbx_builtin_getvar_helper(new_chan, varname)) {
184                         /* Kill all levels of arguments */
185                         pbx_builtin_setvar_helper(new_chan, varname, NULL);
186                 }
187         }
188 }
189
190 static struct ast_exten *find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid)
191 {
192         struct ast_exten *e;
193         struct ast_include *i;
194         struct ast_context *c2;
195
196         for (e=ast_walk_context_extensions(c, NULL); e; e=ast_walk_context_extensions(c, e)) {
197                 if (ast_extension_match(ast_get_extension_name(e), exten)) {
198                         int needmatch = ast_get_extension_matchcid(e);
199                         if ((needmatch && ast_extension_match(ast_get_extension_cidmatch(e), callerid)) ||
200                                 (!needmatch)) {
201                                 /* This is the matching extension we want */
202                                 struct ast_exten *p;
203                                 for (p=ast_walk_extension_priorities(e, NULL); p; p=ast_walk_extension_priorities(e, p)) {
204                                         if (priority != ast_get_extension_priority(p))
205                                                 continue;
206                                         return p;
207                                 }
208                         }
209                 }
210         }
211
212         /* No match; run through includes */
213         for (i=ast_walk_context_includes(c, NULL); i; i=ast_walk_context_includes(c, i)) {
214                 for (c2=ast_walk_contexts(NULL); c2; c2=ast_walk_contexts(c2)) {
215                         if (!strcmp(ast_get_context_name(c2), ast_get_include_name(i))) {
216                                 e = find_matching_priority(c2, exten, priority, callerid);
217                                 if (e)
218                                         return e;
219                         }
220                 }
221         }
222         return NULL;
223 }
224
225 static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive)
226 {
227         const char *s;
228         char *tmp;
229         char *cur, *rest;
230         char *macro;
231         char fullmacro[80];
232         char varname[80];
233         char runningapp[80], runningdata[1024];
234         char *oldargs[MAX_ARGS + 1] = { NULL, };
235         int argc, x;
236         int res=0;
237         char oldexten[256]="";
238         int oldpriority, gosub_level = 0;
239         char pc[80], depthc[12];
240         char oldcontext[AST_MAX_CONTEXT] = "";
241         const char *inhangupc;
242         int offset, depth = 0, maxdepth = 7;
243         int setmacrocontext=0;
244         int autoloopflag, inhangup = 0;
245         struct ast_str *tmp_subst = NULL;
246   
247         char *save_macro_exten;
248         char *save_macro_context;
249         char *save_macro_priority;
250         char *save_macro_offset;
251         int save_in_subroutine;
252         struct ast_datastore *macro_store = ast_channel_datastore_find(chan, &macro_ds_info, NULL);
253
254         if (ast_strlen_zero(data)) {
255                 ast_log(LOG_WARNING, "Macro() requires arguments. See \"core show application macro\" for help.\n");
256                 return -1;
257         }
258
259         do {
260                 if (macro_store) {
261                         break;
262                 }
263                 if (!(macro_store = ast_datastore_alloc(&macro_ds_info, NULL))) {
264                         ast_log(LOG_WARNING, "Unable to allocate new datastore.\n");
265                         break;
266                 }
267                 /* Just the existence of this datastore is enough. */
268                 macro_store->inheritance = DATASTORE_INHERIT_FOREVER;
269                 ast_channel_datastore_add(chan, macro_store);
270         } while (0);
271
272         /* does the user want a deeper rabbit hole? */
273         ast_channel_lock(chan);
274         if ((s = pbx_builtin_getvar_helper(chan, "MACRO_RECURSION"))) {
275                 sscanf(s, "%30d", &maxdepth);
276         }
277         
278         /* Count how many levels deep the rabbit hole goes */
279         if ((s = pbx_builtin_getvar_helper(chan, "MACRO_DEPTH"))) {
280                 sscanf(s, "%30d", &depth);
281         }
282         
283         /* Used for detecting whether to return when a Macro is called from another Macro after hangup */
284         if (strcmp(ast_channel_exten(chan), "h") == 0)
285                 pbx_builtin_setvar_helper(chan, "MACRO_IN_HANGUP", "1");
286         
287         if ((inhangupc = pbx_builtin_getvar_helper(chan, "MACRO_IN_HANGUP"))) {
288                 sscanf(inhangupc, "%30d", &inhangup);
289         }
290         ast_channel_unlock(chan);
291
292         if (depth >= maxdepth) {
293                 ast_log(LOG_ERROR, "Macro():  possible infinite loop detected.  Returning early.\n");
294                 return 0;
295         }
296         snprintf(depthc, sizeof(depthc), "%d", depth + 1);
297
298         tmp = ast_strdupa(data);
299         rest = tmp;
300         macro = strsep(&rest, ",");
301         if (ast_strlen_zero(macro)) {
302                 ast_log(LOG_WARNING, "Invalid macro name specified\n");
303                 return 0;
304         }
305
306         snprintf(fullmacro, sizeof(fullmacro), "macro-%s", macro);
307         if (!ast_exists_extension(chan, fullmacro, "s", 1,
308                 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
309                 if (!ast_context_find(fullmacro)) 
310                         ast_log(LOG_WARNING, "No such context '%s' for macro '%s'. Was called by %s@%s\n", fullmacro, macro, ast_channel_exten(chan), ast_channel_context(chan));
311                 else
312                         ast_log(LOG_WARNING, "Context '%s' for macro '%s' lacks 's' extension, priority 1\n", fullmacro, macro);
313                 return 0;
314         }
315
316         /* If we are to run the macro exclusively, take the mutex */
317         if (exclusive) {
318                 ast_debug(1, "Locking macrolock for '%s'\n", fullmacro);
319                 ast_autoservice_start(chan);
320                 if (ast_context_lockmacro(fullmacro)) {
321                         ast_log(LOG_WARNING, "Failed to lock macro '%s' as in-use\n", fullmacro);
322                         ast_autoservice_stop(chan);
323                         return 0;
324                 }
325                 ast_autoservice_stop(chan);
326         }
327
328         if (!(tmp_subst = ast_str_create(16))) {
329                 return -1;
330         }
331
332         /* Save old info */
333         ast_channel_lock(chan);
334         oldpriority = ast_channel_priority(chan);
335         ast_copy_string(oldexten, ast_channel_exten(chan), sizeof(oldexten));
336         ast_copy_string(oldcontext, ast_channel_context(chan), sizeof(oldcontext));
337         if (ast_strlen_zero(ast_channel_macrocontext(chan))) {
338                 ast_channel_macrocontext_set(chan, ast_channel_context(chan));
339                 ast_channel_macroexten_set(chan, ast_channel_exten(chan));
340                 ast_channel_macropriority_set(chan, ast_channel_priority(chan));
341                 setmacrocontext=1;
342         }
343         argc = 1;
344         /* Save old macro variables */
345         save_macro_exten = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_EXTEN"));
346         pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", oldexten);
347
348         save_macro_context = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"));
349         pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", oldcontext);
350
351         save_macro_priority = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_PRIORITY"));
352         snprintf(pc, sizeof(pc), "%d", oldpriority);
353         pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", pc);
354   
355         save_macro_offset = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"));
356         pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", NULL);
357
358         pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
359
360         save_in_subroutine = ast_test_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
361         ast_set_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
362
363         /* Setup environment for new run */
364         ast_channel_exten_set(chan, "s");
365         ast_channel_context_set(chan, fullmacro);
366         ast_channel_priority_set(chan, 1);
367
368         while((cur = strsep(&rest, ",")) && (argc < MAX_ARGS)) {
369                 const char *argp;
370                 /* Save copy of old arguments if we're overwriting some, otherwise
371                 let them pass through to the other macro */
372                 snprintf(varname, sizeof(varname), "ARG%d", argc);
373                 if ((argp = pbx_builtin_getvar_helper(chan, varname))) {
374                         oldargs[argc] = ast_strdup(argp);
375                 }
376                 pbx_builtin_setvar_helper(chan, varname, cur);
377                 argc++;
378         }
379         ast_channel_unlock(chan);
380         autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
381         ast_set_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
382         while (ast_exists_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan),
383                 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
384                 struct ast_context *c;
385                 struct ast_exten *e;
386                 int foundx;
387                 runningapp[0] = '\0';
388                 runningdata[0] = '\0';
389
390                 /* What application will execute? */
391                 if (ast_rdlock_contexts()) {
392                         ast_log(LOG_WARNING, "Failed to lock contexts list\n");
393                 } else {
394                         for (c = ast_walk_contexts(NULL), e = NULL; c; c = ast_walk_contexts(c)) {
395                                 if (!strcmp(ast_get_context_name(c), ast_channel_context(chan))) {
396                                         if (ast_rdlock_context(c)) {
397                                                 ast_log(LOG_WARNING, "Unable to lock context?\n");
398                                         } else {
399                                                 e = find_matching_priority(c, ast_channel_exten(chan), ast_channel_priority(chan),
400                                                         S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
401                                                 if (e) { /* This will only be undefined for pbx_realtime, which is majorly broken. */
402                                                         ast_copy_string(runningapp, ast_get_extension_app(e), sizeof(runningapp));
403                                                         ast_copy_string(runningdata, ast_get_extension_app_data(e), sizeof(runningdata));
404                                                 }
405                                                 ast_unlock_context(c);
406                                         }
407                                         break;
408                                 }
409                         }
410                 }
411                 ast_unlock_contexts();
412
413                 /* Reset the macro depth, if it was changed in the last iteration */
414                 pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
415
416                 res = ast_spawn_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan),
417                         S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
418                         &foundx, 1);
419                 if (res) {
420                         /* Something bad happened, or a hangup has been requested. */
421                         if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
422                         (res == '*') || (res == '#')) {
423                                 /* Just return result as to the previous application as if it had been dialed */
424                                 ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
425                                 break;
426                         }
427                         switch(res) {
428                         case MACRO_EXIT_RESULT:
429                                 res = 0;
430                                 goto out;
431                         default:
432                                 ast_debug(2, "Spawn extension (%s,%s,%d) exited non-zero on '%s' in macro '%s'\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), ast_channel_name(chan), macro);
433                                 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s' in macro '%s'\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), ast_channel_name(chan), macro);
434                                 goto out;
435                         }
436                 }
437
438                 ast_debug(1, "Executed application: %s\n", runningapp);
439
440                 if (!strcasecmp(runningapp, "GOSUB")) {
441                         gosub_level++;
442                         ast_debug(1, "Incrementing gosub_level\n");
443                 } else if (!strcasecmp(runningapp, "GOSUBIF")) {
444                         char *cond, *app_arg;
445                         char *app2;
446                         ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata);
447                         app2 = ast_str_buffer(tmp_subst);
448                         cond = strsep(&app2, "?");
449                         app_arg = strsep(&app2, ":");
450                         if (pbx_checkcondition(cond)) {
451                                 if (!ast_strlen_zero(app_arg)) {
452                                         gosub_level++;
453                                         ast_debug(1, "Incrementing gosub_level\n");
454                                 }
455                         } else {
456                                 if (!ast_strlen_zero(app2)) {
457                                         gosub_level++;
458                                         ast_debug(1, "Incrementing gosub_level\n");
459                                 }
460                         }
461                 } else if (!strcasecmp(runningapp, "RETURN")) {
462                         gosub_level--;
463                         ast_debug(1, "Decrementing gosub_level\n");
464                 } else if (!strcasecmp(runningapp, "STACKPOP")) {
465                         gosub_level--;
466                         ast_debug(1, "Decrementing gosub_level\n");
467                 } else if (!strncasecmp(runningapp, "EXEC", 4)) {
468                         /* Must evaluate args to find actual app */
469                         char *tmp2, *tmp3 = NULL;
470                         ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata);
471                         tmp2 = ast_str_buffer(tmp_subst);
472                         if (!strcasecmp(runningapp, "EXECIF")) {
473                                 if ((tmp3 = strchr(tmp2, '|'))) {
474                                         *tmp3++ = '\0';
475                                 }
476                                 if (!pbx_checkcondition(tmp2)) {
477                                         tmp3 = NULL;
478                                 }
479                         } else {
480                                 tmp3 = tmp2;
481                         }
482
483                         if (tmp3) {
484                                 ast_debug(1, "Last app: %s\n", tmp3);
485                         }
486
487                         if (tmp3 && !strncasecmp(tmp3, "GOSUB", 5)) {
488                                 gosub_level++;
489                                 ast_debug(1, "Incrementing gosub_level\n");
490                         } else if (tmp3 && !strncasecmp(tmp3, "RETURN", 6)) {
491                                 gosub_level--;
492                                 ast_debug(1, "Decrementing gosub_level\n");
493                         } else if (tmp3 && !strncasecmp(tmp3, "STACKPOP", 8)) {
494                                 gosub_level--;
495                                 ast_debug(1, "Decrementing gosub_level\n");
496                         }
497                 }
498
499                 if (gosub_level == 0 && strcasecmp(ast_channel_context(chan), fullmacro)) {
500                         ast_verb(2, "Channel '%s' jumping out of macro '%s'\n", ast_channel_name(chan), macro);
501                         break;
502                 }
503
504                 /* don't stop executing extensions when we're in "h" */
505                 if (ast_check_hangup(chan) && !inhangup) {
506                         ast_debug(1, "Extension %s, macroexten %s, priority %d returned normally even though call was hung up\n", ast_channel_exten(chan), ast_channel_macroexten(chan), ast_channel_priority(chan));
507                         goto out;
508                 }
509                 ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
510         }
511         out:
512
513         /* Don't let the channel change now. */
514         ast_channel_lock(chan);
515
516         /* Reset the depth back to what it was when the routine was entered (like if we called Macro recursively) */
517         snprintf(depthc, sizeof(depthc), "%d", depth);
518         pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
519         ast_set2_flag(ast_channel_flags(chan), autoloopflag, AST_FLAG_IN_AUTOLOOP);
520         ast_set2_flag(ast_channel_flags(chan), save_in_subroutine, AST_FLAG_SUBROUTINE_EXEC);
521
522         for (x = 1; x < argc; x++) {
523                 /* Restore old arguments and delete ours */
524                 snprintf(varname, sizeof(varname), "ARG%d", x);
525                 if (oldargs[x]) {
526                         pbx_builtin_setvar_helper(chan, varname, oldargs[x]);
527                         ast_free(oldargs[x]);
528                 } else {
529                         pbx_builtin_setvar_helper(chan, varname, NULL);
530                 }
531         }
532
533         /* Restore macro variables */
534         pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", save_macro_exten);
535         pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", save_macro_context);
536         pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", save_macro_priority);
537         if (save_macro_exten)
538                 ast_free(save_macro_exten);
539         if (save_macro_context)
540                 ast_free(save_macro_context);
541         if (save_macro_priority)
542                 ast_free(save_macro_priority);
543
544         if (setmacrocontext) {
545                 ast_channel_macrocontext_set(chan, "");
546                 ast_channel_macroexten_set(chan, "");
547                 ast_channel_macropriority_set(chan, 0);
548         }
549
550         if (!strcasecmp(ast_channel_context(chan), fullmacro)) {
551                 const char *offsets;
552
553                 /* If we're leaving the macro normally, restore original information */
554                 ast_channel_priority_set(chan, oldpriority);
555                 ast_channel_context_set(chan, oldcontext);
556                 ast_channel_exten_set(chan, oldexten);
557                 if ((offsets = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"))) {
558                         /* Handle macro offset if it's set by checking the availability of step n + offset + 1, otherwise continue
559                         normally if there is any problem */
560                         if (sscanf(offsets, "%30d", &offset) == 1) {
561                                 if (ast_exists_extension(chan, ast_channel_context(chan), ast_channel_exten(chan),
562                                         ast_channel_priority(chan) + offset + 1,
563                                         S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
564                                         ast_channel_priority_set(chan, ast_channel_priority(chan) + offset);
565                                 }
566                         }
567                 }
568         }
569
570         pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", save_macro_offset);
571         if (save_macro_offset)
572                 ast_free(save_macro_offset);
573
574         /* Unlock the macro */
575         if (exclusive) {
576                 ast_debug(1, "Unlocking macrolock for '%s'\n", fullmacro);
577                 if (ast_context_unlockmacro(fullmacro)) {
578                         ast_log(LOG_ERROR, "Failed to unlock macro '%s' - that isn't good\n", fullmacro);
579                         res = 0;
580                 }
581         }
582         ast_channel_unlock(chan);
583         ast_free(tmp_subst);
584
585         return res;
586 }
587
588 static int macro_exec(struct ast_channel *chan, const char *data)
589 {
590         return _macro_exec(chan, data, 0);
591 }
592
593 static int macroexclusive_exec(struct ast_channel *chan, const char *data)
594 {
595         return _macro_exec(chan, data, 1);
596 }
597
598 static int macroif_exec(struct ast_channel *chan, const char *data) 
599 {
600         char *expr = NULL, *label_a = NULL, *label_b = NULL;
601         int res = 0;
602
603         expr = ast_strdupa(data);
604
605         if ((label_a = strchr(expr, '?'))) {
606                 *label_a = '\0';
607                 label_a++;
608                 if ((label_b = strchr(label_a, ':'))) {
609                         *label_b = '\0';
610                         label_b++;
611                 }
612                 if (pbx_checkcondition(expr))
613                         res = macro_exec(chan, label_a);
614                 else if (label_b) 
615                         res = macro_exec(chan, label_b);
616         } else
617                 ast_log(LOG_WARNING, "Invalid Syntax.\n");
618
619         return res;
620 }
621                         
622 static int macro_exit_exec(struct ast_channel *chan, const char *data)
623 {
624         return MACRO_EXIT_RESULT;
625 }
626
627 static int unload_module(void)
628 {
629         int res;
630
631         res = ast_unregister_application(if_app);
632         res |= ast_unregister_application(exit_app);
633         res |= ast_unregister_application(app);
634         res |= ast_unregister_application(exclusive_app);
635
636         return res;
637 }
638
639 static int load_module(void)
640 {
641         int res;
642
643         res = ast_register_application_xml(exit_app, macro_exit_exec);
644         res |= ast_register_application_xml(if_app, macroif_exec);
645         res |= ast_register_application_xml(exclusive_app, macroexclusive_exec);
646         res |= ast_register_application_xml(app, macro_exec);
647
648         return res;
649 }
650
651 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Extension Macros");