Asterisk - The Open Source Telephony Project  18.5.0
app_macro.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <[email protected]>
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 <[email protected]>
24  *
25  * \ingroup applications
26  */
27 
28 /*** MODULEINFO
29  <defaultenabled>no</defaultenabled>
30  <support_level>deprecated</support_level>
31  <replacement>app_stack (GoSub)</replacement>
32  ***/
33 
34 #include "asterisk.h"
35 
36 #include "asterisk/file.h"
37 #include "asterisk/channel.h"
38 #include "asterisk/pbx.h"
39 #include "asterisk/module.h"
40 #include "asterisk/extconf.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,
191  int priority, const char *callerid, int iter, int *had_error)
192 {
193  struct ast_exten *e;
194  struct ast_context *c2;
195  int idx;
196 
197  if (iter >= AST_PBX_MAX_STACK) {
198  if (!(*had_error)) {
199  *had_error = 1;
200  ast_log(LOG_ERROR, "Potential infinite loop detected, will not recurse further.\n");
201  }
202  return NULL;
203  }
204 
207  int needmatch = ast_get_extension_matchcid(e);
208  if ((needmatch && ast_extension_match(ast_get_extension_cidmatch(e), callerid)) ||
209  (!needmatch)) {
210  /* This is the matching extension we want */
211  struct ast_exten *p;
213  if (priority != ast_get_extension_priority(p))
214  continue;
215  return p;
216  }
217  }
218  }
219  }
220 
221  /* No match; run through includes */
222  for (idx = 0; idx < ast_context_includes_count(c); idx++) {
223  const struct ast_include *i = ast_context_includes_get(c, idx);
224 
225  for (c2=ast_walk_contexts(NULL); c2; c2=ast_walk_contexts(c2)) {
226  if (!strcmp(ast_get_context_name(c2), ast_get_include_name(i))) {
227  e = find_matching_priority(c2, exten, priority, callerid, iter + 1, had_error);
228  if (e)
229  return e;
230  }
231  }
232  }
233  return NULL;
234 }
235 
236 static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive)
237 {
238  const char *s;
239  char *tmp;
240  char *cur, *rest;
241  char *macro;
242  char fullmacro[80];
243  char varname[80];
244  char runningapp[80], runningdata[1024];
245  char *oldargs[MAX_ARGS + 1] = { NULL, };
246  int argc, x;
247  int res=0;
248  char oldexten[256]="";
249  int oldpriority, gosub_level = 0;
250  char pc[80], depthc[12];
251  char oldcontext[AST_MAX_CONTEXT] = "";
252  const char *inhangupc;
253  int offset, depth = 0, maxdepth = 7;
254  int setmacrocontext=0;
255  int autoloopflag, inhangup = 0;
256  struct ast_str *tmp_subst = NULL;
257  const char *my_macro_exten = NULL;
258  char *save_macro_exten;
259  char *save_macro_context;
260  char *save_macro_priority;
261  char *save_macro_offset;
262  int save_in_subroutine;
263  struct ast_datastore *macro_store = ast_channel_datastore_find(chan, &macro_ds_info, NULL);
264  int had_infinite_include_error = 0;
265  static int deprecation_notice = 0;
266 
267  if (ast_strlen_zero(data)) {
268  ast_log(LOG_WARNING, "Macro() requires arguments. See \"core show application macro\" for help.\n");
269  return -1;
270  }
271 
272  if (!deprecation_notice) {
273  deprecation_notice = 1;
274  ast_log(LOG_WARNING, "Macro() is deprecated and will be removed from a future version of Asterisk.\n");
275  ast_log(LOG_WARNING, "Dialplan should be updated to use Gosub instead.\n");
276  }
277 
278  do {
279  if (macro_store) {
280  break;
281  }
282  if (!(macro_store = ast_datastore_alloc(&macro_ds_info, NULL))) {
283  ast_log(LOG_WARNING, "Unable to allocate new datastore.\n");
284  break;
285  }
286  /* Just the existence of this datastore is enough. */
287  macro_store->inheritance = DATASTORE_INHERIT_FOREVER;
288  ast_channel_datastore_add(chan, macro_store);
289  } while (0);
290 
291  /* does the user want a deeper rabbit hole? */
292  ast_channel_lock(chan);
293  if ((s = pbx_builtin_getvar_helper(chan, "MACRO_RECURSION"))) {
294  sscanf(s, "%30d", &maxdepth);
295  }
296 
297  /* Count how many levels deep the rabbit hole goes */
298  if ((s = pbx_builtin_getvar_helper(chan, "MACRO_DEPTH"))) {
299  sscanf(s, "%30d", &depth);
300  }
301 
302  /* Used for detecting whether to return when a Macro is called from another Macro after hangup */
303  if (strcmp(ast_channel_exten(chan), "h") == 0)
304  pbx_builtin_setvar_helper(chan, "MACRO_IN_HANGUP", "1");
305 
306  if ((inhangupc = pbx_builtin_getvar_helper(chan, "MACRO_IN_HANGUP"))) {
307  sscanf(inhangupc, "%30d", &inhangup);
308  }
309  ast_channel_unlock(chan);
310 
311  if (depth >= maxdepth) {
312  ast_log(LOG_ERROR, "Macro(): possible infinite loop detected. Returning early.\n");
313  return 0;
314  }
315  snprintf(depthc, sizeof(depthc), "%d", depth + 1);
316 
317  tmp = ast_strdupa(data);
318  rest = tmp;
319  macro = strsep(&rest, ",");
320  if (ast_strlen_zero(macro)) {
321  ast_log(LOG_WARNING, "Invalid macro name specified\n");
322  return 0;
323  }
324 
325  snprintf(fullmacro, sizeof(fullmacro), "macro-%s", macro);
326 
327  /* first search for the macro */
328  if (!ast_context_find(fullmacro)) {
329  ast_log(LOG_WARNING, "No such context '%s' for macro '%s'. Was called by %[email protected]%s\n",
330  fullmacro, macro, ast_channel_exten(chan), ast_channel_context(chan));
331  return 0;
332  }
333 
334  /* now search for the right extension */
335  if (ast_exists_extension(chan, fullmacro, "s", 1,
336  S_COR(ast_channel_caller(chan)->id.number.valid,
337  ast_channel_caller(chan)->id.number.str, NULL))) {
338  /* We have a normal macro */
339  my_macro_exten = "s";
340  } else if (ast_exists_extension(chan, fullmacro, "~~s~~", 1,
341  S_COR(ast_channel_caller(chan)->id.number.valid,
342  ast_channel_caller(chan)->id.number.str, NULL))) {
343  /* We have an AEL generated macro */
344  my_macro_exten = "~~s~~";
345  }
346 
347  /* do we have a valid exten? */
348  if (!my_macro_exten) {
350  "Context '%s' for macro '%s' lacks 's' extension, priority 1\n",
351  fullmacro, macro);
352  return 0;
353  }
354 
355  /* If we are to run the macro exclusively, take the mutex */
356  if (exclusive) {
357  ast_debug(1, "Locking macrolock for '%s'\n", fullmacro);
358  ast_autoservice_start(chan);
359  if (ast_context_lockmacro(fullmacro)) {
360  ast_log(LOG_WARNING, "Failed to lock macro '%s' as in-use\n", fullmacro);
361  ast_autoservice_stop(chan);
362  return 0;
363  }
364  ast_autoservice_stop(chan);
365  }
366 
367  if (!(tmp_subst = ast_str_create(16))) {
368  return -1;
369  }
370 
371  /* Save old info */
372  ast_channel_lock(chan);
373  oldpriority = ast_channel_priority(chan);
374  ast_copy_string(oldexten, ast_channel_exten(chan), sizeof(oldexten));
375  ast_copy_string(oldcontext, ast_channel_context(chan), sizeof(oldcontext));
380  setmacrocontext=1;
381  }
382  argc = 1;
383  /* Save old macro variables */
384  save_macro_exten = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_EXTEN"));
385  pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", oldexten);
386 
387  save_macro_context = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"));
388  pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", oldcontext);
389 
390  save_macro_priority = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_PRIORITY"));
391  snprintf(pc, sizeof(pc), "%d", oldpriority);
392  pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", pc);
393 
394  save_macro_offset = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"));
395  pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", NULL);
396 
397  pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
398 
399  save_in_subroutine = ast_test_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
401 
402  /* Setup environment for new run */
403  ast_channel_exten_set(chan, my_macro_exten);
404  ast_channel_context_set(chan, fullmacro);
405  ast_channel_priority_set(chan, 1);
406 
407  while((cur = strsep(&rest, ",")) && (argc < MAX_ARGS)) {
408  const char *argp;
409  /* Save copy of old arguments if we're overwriting some, otherwise
410  let them pass through to the other macro */
411  snprintf(varname, sizeof(varname), "ARG%d", argc);
412  if ((argp = pbx_builtin_getvar_helper(chan, varname))) {
413  oldargs[argc] = ast_strdup(argp);
414  }
415  pbx_builtin_setvar_helper(chan, varname, cur);
416  argc++;
417  }
420  ast_channel_unlock(chan);
421 
423  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
424  struct ast_context *c;
425  struct ast_exten *e;
426  int foundx;
427  runningapp[0] = '\0';
428  runningdata[0] = '\0';
429 
430  /* What application will execute? */
431  if (ast_rdlock_contexts()) {
432  ast_log(LOG_WARNING, "Failed to lock contexts list\n");
433  } else {
434  for (c = ast_walk_contexts(NULL), e = NULL; c; c = ast_walk_contexts(c)) {
435  if (!strcmp(ast_get_context_name(c), ast_channel_context(chan))) {
436  if (ast_rdlock_context(c)) {
437  ast_log(LOG_WARNING, "Unable to lock context?\n");
438  } else {
440  S_COR(ast_channel_caller(chan)->id.number.valid,
441  ast_channel_caller(chan)->id.number.str, NULL),
442  0, &had_infinite_include_error);
443  if (e) { /* This will only be undefined for pbx_realtime, which is majorly broken. */
444  ast_copy_string(runningapp, ast_get_extension_app(e), sizeof(runningapp));
445  ast_copy_string(runningdata, ast_get_extension_app_data(e), sizeof(runningdata));
446  }
448  }
449  break;
450  }
451  }
452  }
454 
455  /* Reset the macro depth, if it was changed in the last iteration */
456  pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
457 
459  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
460  &foundx, 1);
461  if (res) {
462  /* Something bad happened, or a hangup has been requested. */
463  if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
464  (res == '*') || (res == '#')) {
465  /* Just return result as to the previous application as if it had been dialed */
466  ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
467  break;
468  }
469  switch(res) {
470  case MACRO_EXIT_RESULT:
471  res = 0;
472  goto out;
473  default:
474  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);
475  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);
476  goto out;
477  }
478  }
479 
480  ast_debug(1, "Executed application: %s\n", runningapp);
481 
482  if (!strcasecmp(runningapp, "GOSUB")) {
483  gosub_level++;
484  ast_debug(1, "Incrementing gosub_level\n");
485  } else if (!strcasecmp(runningapp, "GOSUBIF")) {
486  char *cond, *app_arg;
487  char *app2;
488  ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata);
489  app2 = ast_str_buffer(tmp_subst);
490  cond = strsep(&app2, "?");
491  app_arg = strsep(&app2, ":");
492  if (pbx_checkcondition(cond)) {
493  if (!ast_strlen_zero(app_arg)) {
494  gosub_level++;
495  ast_debug(1, "Incrementing gosub_level\n");
496  }
497  } else {
498  if (!ast_strlen_zero(app2)) {
499  gosub_level++;
500  ast_debug(1, "Incrementing gosub_level\n");
501  }
502  }
503  } else if (!strcasecmp(runningapp, "RETURN")) {
504  gosub_level--;
505  ast_debug(1, "Decrementing gosub_level\n");
506  } else if (!strcasecmp(runningapp, "STACKPOP")) {
507  gosub_level--;
508  ast_debug(1, "Decrementing gosub_level\n");
509  } else if (!strncasecmp(runningapp, "EXEC", 4)) {
510  /* Must evaluate args to find actual app */
511  char *tmp2, *tmp3 = NULL;
512  ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata);
513  tmp2 = ast_str_buffer(tmp_subst);
514  if (!strcasecmp(runningapp, "EXECIF")) {
515  if ((tmp3 = strchr(tmp2, '|'))) {
516  *tmp3++ = '\0';
517  }
518  if (!pbx_checkcondition(tmp2)) {
519  tmp3 = NULL;
520  }
521  } else {
522  tmp3 = tmp2;
523  }
524 
525  if (tmp3) {
526  ast_debug(1, "Last app: %s\n", tmp3);
527  }
528 
529  if (tmp3 && !strncasecmp(tmp3, "GOSUB", 5)) {
530  gosub_level++;
531  ast_debug(1, "Incrementing gosub_level\n");
532  } else if (tmp3 && !strncasecmp(tmp3, "RETURN", 6)) {
533  gosub_level--;
534  ast_debug(1, "Decrementing gosub_level\n");
535  } else if (tmp3 && !strncasecmp(tmp3, "STACKPOP", 8)) {
536  gosub_level--;
537  ast_debug(1, "Decrementing gosub_level\n");
538  }
539  }
540 
541  if (gosub_level == 0 && strcasecmp(ast_channel_context(chan), fullmacro)) {
542  ast_verb(2, "Channel '%s' jumping out of macro '%s'\n", ast_channel_name(chan), macro);
543  break;
544  }
545 
546  /* don't stop executing extensions when we're in "h" */
547  if (ast_check_hangup(chan) && !inhangup) {
548  ast_debug(1, "Extension %s, macroexten %s, priority %d returned normally even though call was hung up\n",
549  ast_channel_exten(chan),
551  ast_channel_priority(chan));
552  goto out;
553  }
555  }
556  out:
557 
558  /* Don't let the channel change now. */
559  ast_channel_lock(chan);
560 
561  /* Reset the depth back to what it was when the routine was entered (like if we called Macro recursively) */
562  snprintf(depthc, sizeof(depthc), "%d", depth);
563  pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
565  ast_set2_flag(ast_channel_flags(chan), save_in_subroutine, AST_FLAG_SUBROUTINE_EXEC);
566 
567  for (x = 1; x < argc; x++) {
568  /* Restore old arguments and delete ours */
569  snprintf(varname, sizeof(varname), "ARG%d", x);
570  pbx_builtin_setvar_helper(chan, varname, oldargs[x]);
571  ast_free(oldargs[x]);
572  }
573 
574  /* Restore macro variables */
575  pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", save_macro_exten);
576  pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", save_macro_context);
577  pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", save_macro_priority);
578  ast_free(save_macro_exten);
579  ast_free(save_macro_context);
580  ast_free(save_macro_priority);
581 
582  if (setmacrocontext) {
584  ast_channel_macroexten_set(chan, "");
586  }
587 
588  if (!strcasecmp(ast_channel_context(chan), fullmacro)
590  const char *offsets;
591 
592  /* If we're leaving the macro normally, restore original information */
593  ast_channel_priority_set(chan, oldpriority);
594  ast_channel_context_set(chan, oldcontext);
595  ast_channel_exten_set(chan, oldexten);
596  if ((offsets = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"))) {
597  /* Handle macro offset if it's set by checking the availability of step n + offset + 1, otherwise continue
598  normally if there is any problem */
599  if (sscanf(offsets, "%30d", &offset) == 1) {
601  ast_channel_priority(chan) + offset + 1,
602  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
603  ast_channel_priority_set(chan, ast_channel_priority(chan) + offset);
604  }
605  }
606  }
607  }
608 
609  pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", save_macro_offset);
610  ast_free(save_macro_offset);
611 
612  /* Unlock the macro */
613  if (exclusive) {
614  ast_debug(1, "Unlocking macrolock for '%s'\n", fullmacro);
615  if (ast_context_unlockmacro(fullmacro)) {
616  ast_log(LOG_ERROR, "Failed to unlock macro '%s' - that isn't good\n", fullmacro);
617  res = 0;
618  }
619  }
620  ast_channel_unlock(chan);
621  ast_free(tmp_subst);
622 
623  return res;
624 }
625 
626 static int macro_exec(struct ast_channel *chan, const char *data)
627 {
628  return _macro_exec(chan, data, 0);
629 }
630 
631 static int macroexclusive_exec(struct ast_channel *chan, const char *data)
632 {
633  return _macro_exec(chan, data, 1);
634 }
635 
636 static int macroif_exec(struct ast_channel *chan, const char *data)
637 {
638  char *expr = NULL, *label_a = NULL, *label_b = NULL;
639  int res = 0;
640 
641  expr = ast_strdupa(data);
642 
643  if ((label_a = strchr(expr, '?'))) {
644  *label_a = '\0';
645  label_a++;
646  if ((label_b = strchr(label_a, ':'))) {
647  *label_b = '\0';
648  label_b++;
649  }
650  if (pbx_checkcondition(expr))
651  res = macro_exec(chan, label_a);
652  else if (label_b)
653  res = macro_exec(chan, label_b);
654  } else
655  ast_log(LOG_WARNING, "Invalid Syntax.\n");
656 
657  return res;
658 }
659 
660 static int macro_exit_exec(struct ast_channel *chan, const char *data)
661 {
662  return MACRO_EXIT_RESULT;
663 }
664 
665 static int unload_module(void)
666 {
667  int res;
668 
673 
674  return res;
675 }
676 
677 static int load_module(void)
678 {
679  int res;
680 
685 
686  return res;
687 }
688 
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
const char * type
Definition: datastore.h:32
ast_include: include= support in extensions.conf
Definition: pbx_include.c:37
int ast_unlock_context(struct ast_context *con)
Definition: pbx.c:8530
static const struct ast_datastore_info macro_ds_info
Definition: app_macro.c:167
#define ast_channel_lock(chan)
Definition: channel.h:2945
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
Main Channel structure associated with a channel.
int ast_get_extension_priority(struct ast_exten *exten)
Definition: pbx.c:8558
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
ast_exten: An extension The dialplan is saved as a linked list with each context having it&#39;s own link...
Definition: pbx.c:237
static void macro_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
Definition: app_macro.c:172
#define MACRO_EXIT_RESULT
Definition: app_macro.c:158
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:200
const char * ast_get_context_name(struct ast_context *con)
Definition: ael_main.c:421
#define MAX_ARGS
Definition: app_macro.c:155
static char * if_app
Definition: app_macro.c:161
#define ast_set2_flag(p, value, flag)
Definition: utils.h:94
#define ast_test_flag(p, flag)
Definition: utils.h:63
static int macroif_exec(struct ast_channel *chan, const char *data)
Definition: app_macro.c:636
int ast_context_lockmacro(const char *macrocontext)
locks the macrolock in the given context
Definition: pbx.c:5162
static int load_module(void)
Definition: app_macro.c:677
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define LOG_WARNING
Definition: logger.h:274
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
void ast_channel_macrocontext_set(struct ast_channel *chan, const char *value)
const char * ast_get_extension_app(struct ast_exten *e)
Definition: pbx.c:8596
static int unload_module(void)
Definition: app_macro.c:665
static int tmp()
Definition: bt_open.c:389
int pbx_checkcondition(const char *condition)
Evaluate a condition.
Definition: pbx.c:8321
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
struct ast_context * ast_walk_contexts(struct ast_context *con)
Definition: conf2ael.c:618
Structure for a data store type.
Definition: datastore.h:31
void * ast_get_extension_app_data(struct ast_exten *e)
Definition: pbx.c:8601
int ast_rdlock_contexts(void)
Read locks the context list.
Definition: pbx.c:8507
static struct test_val c
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
Structure for a data store object.
Definition: datastore.h:68
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition: channel.c:2404
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
#define NULL
Definition: resample.c:96
static int priority
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
int ast_channel_priority(const struct ast_channel *chan)
#define ast_verb(level,...)
Definition: logger.h:463
static char * exit_app
Definition: app_macro.c:163
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
Utility functions.
#define ast_strlen_zero(foo)
Definition: strings.h:52
static char * exclusive_app
Definition: app_macro.c:162
Number structure.
Definition: app_followme.c:154
void ast_channel_macropriority_set(struct ast_channel *chan, int value)
Configuration File Parser.
static void deprecation_notice(void)
Definition: chan_sip.c:35452
static int macro_exit_exec(struct ast_channel *chan, const char *data)
Definition: app_macro.c:660
static struct ast_exten * find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid, int iter, int *had_error)
Definition: app_macro.c:190
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
struct ast_context * ast_context_find(const char *name)
Find a context.
Definition: extconf.c:4174
General Asterisk PBX channel definitions.
ast_cond_t cond
Definition: app_meetme.c:1090
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:85
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
const char * ast_get_extension_cidmatch(struct ast_exten *e)
Definition: pbx.c:8591
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4179
const char * ast_channel_exten(const struct ast_channel *chan)
Core PBX routines and definitions.
External configuration handlers (realtime and static configuration)
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
int ast_context_includes_count(const struct ast_context *con)
Definition: pbx.c:8697
#define LOG_ERROR
Definition: logger.h:285
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:8512
#define AST_PBX_MAX_STACK
Definition: extconf.h:226
const char * ast_get_extension_name(struct ast_exten *exten)
Definition: pbx.c:8548
struct ast_exten * ast_walk_context_extensions(struct ast_context *con, struct ast_exten *priority)
Definition: ael_main.c:427
#define ast_channel_unlock(chan)
Definition: channel.h:2946
static int macroexclusive_exec(struct ast_channel *chan, const char *data)
Definition: app_macro.c:631
#define AST_MAX_CONTEXT
Definition: channel.h:136
#define ast_free(a)
Definition: astmm.h:182
int ast_extension_match(const char *pattern, const char *extension)
Determine if a given extension matches a given pattern (in NXX format)
Definition: extconf.c:4297
#define DATASTORE_INHERIT_FOREVER
Definition: channel.h:193
unsigned int inheritance
Definition: datastore.h:73
void ast_channel_macroexten_set(struct ast_channel *chan, const char *value)
int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid, int *found, int combined_find_spawn)
Launch a new extension (i.e. new stack)
Definition: pbx.c:4204
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
static const char app2[]
int ast_channel_softhangup_internal_flag(struct ast_channel *chan)
const char * ast_get_include_name(const struct ast_include *include)
Definition: pbx_include.c:50
char * strsep(char **str, const char *delims)
FILE * out
Definition: utils/frame.c:33
struct ast_exten * ast_walk_extension_priorities(struct ast_exten *exten, struct ast_exten *priority)
Definition: extconf.c:4063
void ast_channel_context_set(struct ast_channel *chan, const char *value)
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
const char * ast_channel_name(const struct ast_channel *chan)
static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive)
Definition: app_macro.c:236
static char * app
Definition: app_macro.c:160
const char * ast_channel_context(const struct ast_channel *chan)
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:89
void * data
Definition: pbx.c:248
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
const char * ast_channel_macrocontext(const struct ast_channel *chan)
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
void ast_channel_priority_set(struct ast_channel *chan, int value)
int ast_get_extension_matchcid(struct ast_exten *e)
Definition: pbx.c:8586
Asterisk module definitions.
static int macro_exec(struct ast_channel *chan, const char *data)
Definition: app_macro.c:626
AST_MODULE_INFO_STANDARD_DEPRECATED(ASTERISK_GPL_KEY, "Extension Macros")
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2390
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
ast_context: An extension context - must remain in sync with fake_context
Definition: pbx.c:284
int ast_context_unlockmacro(const char *macrocontext)
Unlocks the macrolock in the given context.
Definition: pbx.c:5184
const struct ast_include * ast_context_includes_get(const struct ast_context *con, int idx)
Definition: pbx.c:8702
const char * ast_channel_macroexten(const struct ast_channel *chan)
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
int ast_rdlock_context(struct ast_context *con)
Read locks a given context.
Definition: pbx.c:8525
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620