Wed Jan 8 2020 09:49:39

Asterisk developer's documentation


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 <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: 370642 $")
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)) {
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  struct ast_datastore *macro_store = ast_channel_datastore_find(chan, &macro_ds_info, NULL);
252 
253  if (ast_strlen_zero(data)) {
254  ast_log(LOG_WARNING, "Macro() requires arguments. See \"core show application macro\" for help.\n");
255  return -1;
256  }
257 
258  do {
259  if (macro_store) {
260  break;
261  }
262  if (!(macro_store = ast_datastore_alloc(&macro_ds_info, NULL))) {
263  ast_log(LOG_WARNING, "Unable to allocate new datastore.\n");
264  break;
265  }
266  /* Just the existence of this datastore is enough. */
267  macro_store->inheritance = DATASTORE_INHERIT_FOREVER;
268  ast_channel_datastore_add(chan, macro_store);
269  } while (0);
270 
271  /* does the user want a deeper rabbit hole? */
272  ast_channel_lock(chan);
273  if ((s = pbx_builtin_getvar_helper(chan, "MACRO_RECURSION"))) {
274  sscanf(s, "%30d", &maxdepth);
275  }
276 
277  /* Count how many levels deep the rabbit hole goes */
278  if ((s = pbx_builtin_getvar_helper(chan, "MACRO_DEPTH"))) {
279  sscanf(s, "%30d", &depth);
280  }
281 
282  /* Used for detecting whether to return when a Macro is called from another Macro after hangup */
283  if (strcmp(chan->exten, "h") == 0)
284  pbx_builtin_setvar_helper(chan, "MACRO_IN_HANGUP", "1");
285 
286  if ((inhangupc = pbx_builtin_getvar_helper(chan, "MACRO_IN_HANGUP"))) {
287  sscanf(inhangupc, "%30d", &inhangup);
288  }
289  ast_channel_unlock(chan);
290 
291  if (depth >= maxdepth) {
292  ast_log(LOG_ERROR, "Macro(): possible infinite loop detected. Returning early.\n");
293  return 0;
294  }
295  snprintf(depthc, sizeof(depthc), "%d", depth + 1);
296 
297  tmp = ast_strdupa(data);
298  rest = tmp;
299  macro = strsep(&rest, ",");
300  if (ast_strlen_zero(macro)) {
301  ast_log(LOG_WARNING, "Invalid macro name specified\n");
302  return 0;
303  }
304 
305  snprintf(fullmacro, sizeof(fullmacro), "macro-%s", macro);
306  if (!ast_exists_extension(chan, fullmacro, "s", 1,
307  S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
308  if (!ast_context_find(fullmacro))
309  ast_log(LOG_WARNING, "No such context '%s' for macro '%s'\n", fullmacro, macro);
310  else
311  ast_log(LOG_WARNING, "Context '%s' for macro '%s' lacks 's' extension, priority 1\n", fullmacro, macro);
312  return 0;
313  }
314 
315  /* If we are to run the macro exclusively, take the mutex */
316  if (exclusive) {
317  ast_debug(1, "Locking macrolock for '%s'\n", fullmacro);
318  ast_autoservice_start(chan);
319  if (ast_context_lockmacro(fullmacro)) {
320  ast_log(LOG_WARNING, "Failed to lock macro '%s' as in-use\n", fullmacro);
321  ast_autoservice_stop(chan);
322  return 0;
323  }
324  ast_autoservice_stop(chan);
325  }
326 
327  if (!(tmp_subst = ast_str_create(16))) {
328  return -1;
329  }
330 
331  /* Save old info */
332  oldpriority = chan->priority;
333  ast_copy_string(oldexten, chan->exten, sizeof(oldexten));
334  ast_copy_string(oldcontext, chan->context, sizeof(oldcontext));
335  if (ast_strlen_zero(chan->macrocontext)) {
336  ast_copy_string(chan->macrocontext, chan->context, sizeof(chan->macrocontext));
337  ast_copy_string(chan->macroexten, chan->exten, sizeof(chan->macroexten));
338  chan->macropriority = chan->priority;
339  setmacrocontext=1;
340  }
341  argc = 1;
342  /* Save old macro variables */
343  save_macro_exten = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_EXTEN"));
344  pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", oldexten);
345 
346  save_macro_context = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"));
347  pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", oldcontext);
348 
349  save_macro_priority = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_PRIORITY"));
350  snprintf(pc, sizeof(pc), "%d", oldpriority);
351  pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", pc);
352 
353  save_macro_offset = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"));
354  pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", NULL);
355 
356  pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
357 
358  /* Setup environment for new run */
359  chan->exten[0] = 's';
360  chan->exten[1] = '\0';
361  ast_copy_string(chan->context, fullmacro, sizeof(chan->context));
362  chan->priority = 1;
363 
364  ast_channel_lock(chan);
365  while((cur = strsep(&rest, ",")) && (argc < MAX_ARGS)) {
366  const char *argp;
367  /* Save copy of old arguments if we're overwriting some, otherwise
368  let them pass through to the other macro */
369  snprintf(varname, sizeof(varname), "ARG%d", argc);
370  if ((argp = pbx_builtin_getvar_helper(chan, varname))) {
371  oldargs[argc] = ast_strdup(argp);
372  }
373  pbx_builtin_setvar_helper(chan, varname, cur);
374  argc++;
375  }
376  ast_channel_unlock(chan);
377  autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
379  while (ast_exists_extension(chan, chan->context, chan->exten, chan->priority,
380  S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
381  struct ast_context *c;
382  struct ast_exten *e;
383  int foundx;
384  runningapp[0] = '\0';
385  runningdata[0] = '\0';
386 
387  /* What application will execute? */
388  if (ast_rdlock_contexts()) {
389  ast_log(LOG_WARNING, "Failed to lock contexts list\n");
390  } else {
391  for (c = ast_walk_contexts(NULL), e = NULL; c; c = ast_walk_contexts(c)) {
392  if (!strcmp(ast_get_context_name(c), chan->context)) {
393  if (ast_rdlock_context(c)) {
394  ast_log(LOG_WARNING, "Unable to lock context?\n");
395  } else {
396  e = find_matching_priority(c, chan->exten, chan->priority,
397  S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL));
398  if (e) { /* This will only be undefined for pbx_realtime, which is majorly broken. */
399  ast_copy_string(runningapp, ast_get_extension_app(e), sizeof(runningapp));
400  ast_copy_string(runningdata, ast_get_extension_app_data(e), sizeof(runningdata));
401  }
403  }
404  break;
405  }
406  }
407  }
409 
410  /* Reset the macro depth, if it was changed in the last iteration */
411  pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
412 
413  res = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority,
414  S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL),
415  &foundx, 1);
416  if (res) {
417  /* Something bad happened, or a hangup has been requested. */
418  if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
419  (res == '*') || (res == '#')) {
420  /* Just return result as to the previous application as if it had been dialed */
421  ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
422  break;
423  }
424  switch(res) {
425  case MACRO_EXIT_RESULT:
426  res = 0;
427  goto out;
428  default:
429  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);
430  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);
431  goto out;
432  }
433  }
434 
435  ast_debug(1, "Executed application: %s\n", runningapp);
436 
437  if (!strcasecmp(runningapp, "GOSUB")) {
438  gosub_level++;
439  ast_debug(1, "Incrementing gosub_level\n");
440  } else if (!strcasecmp(runningapp, "GOSUBIF")) {
441  char *cond, *app_arg;
442  char *app2;
443  ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata);
444  app2 = ast_str_buffer(tmp_subst);
445  cond = strsep(&app2, "?");
446  app_arg = strsep(&app2, ":");
447  if (pbx_checkcondition(cond)) {
448  if (!ast_strlen_zero(app_arg)) {
449  gosub_level++;
450  ast_debug(1, "Incrementing gosub_level\n");
451  }
452  } else {
453  if (!ast_strlen_zero(app2)) {
454  gosub_level++;
455  ast_debug(1, "Incrementing gosub_level\n");
456  }
457  }
458  } else if (!strcasecmp(runningapp, "RETURN")) {
459  gosub_level--;
460  ast_debug(1, "Decrementing gosub_level\n");
461  } else if (!strcasecmp(runningapp, "STACKPOP")) {
462  gosub_level--;
463  ast_debug(1, "Decrementing gosub_level\n");
464  } else if (!strncasecmp(runningapp, "EXEC", 4)) {
465  /* Must evaluate args to find actual app */
466  char *tmp2, *tmp3 = NULL;
467  ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata);
468  tmp2 = ast_str_buffer(tmp_subst);
469  if (!strcasecmp(runningapp, "EXECIF")) {
470  if ((tmp3 = strchr(tmp2, '|'))) {
471  *tmp3++ = '\0';
472  }
473  if (!pbx_checkcondition(tmp2)) {
474  tmp3 = NULL;
475  }
476  } else {
477  tmp3 = tmp2;
478  }
479 
480  if (tmp3) {
481  ast_debug(1, "Last app: %s\n", tmp3);
482  }
483 
484  if (tmp3 && !strncasecmp(tmp3, "GOSUB", 5)) {
485  gosub_level++;
486  ast_debug(1, "Incrementing gosub_level\n");
487  } else if (tmp3 && !strncasecmp(tmp3, "RETURN", 6)) {
488  gosub_level--;
489  ast_debug(1, "Decrementing gosub_level\n");
490  } else if (tmp3 && !strncasecmp(tmp3, "STACKPOP", 8)) {
491  gosub_level--;
492  ast_debug(1, "Decrementing gosub_level\n");
493  }
494  }
495 
496  if (gosub_level == 0 && strcasecmp(chan->context, fullmacro)) {
497  ast_verb(2, "Channel '%s' jumping out of macro '%s'\n", chan->name, macro);
498  break;
499  }
500 
501  /* don't stop executing extensions when we're in "h" */
502  if (ast_check_hangup(chan) && !inhangup) {
503  ast_debug(1, "Extension %s, macroexten %s, priority %d returned normally even though call was hung up\n", chan->exten, chan->macroexten, chan->priority);
504  goto out;
505  }
506  chan->priority++;
507  }
508  out:
509 
510  /* Don't let the channel change now. */
511  ast_channel_lock(chan);
512 
513  /* Reset the depth back to what it was when the routine was entered (like if we called Macro recursively) */
514  snprintf(depthc, sizeof(depthc), "%d", depth);
515  pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
516  ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
517 
518  for (x = 1; x < argc; x++) {
519  /* Restore old arguments and delete ours */
520  snprintf(varname, sizeof(varname), "ARG%d", x);
521  if (oldargs[x]) {
522  pbx_builtin_setvar_helper(chan, varname, oldargs[x]);
523  ast_free(oldargs[x]);
524  } else {
525  pbx_builtin_setvar_helper(chan, varname, NULL);
526  }
527  }
528 
529  /* Restore macro variables */
530  pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", save_macro_exten);
531  pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", save_macro_context);
532  pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", save_macro_priority);
533  if (save_macro_exten)
534  ast_free(save_macro_exten);
535  if (save_macro_context)
536  ast_free(save_macro_context);
537  if (save_macro_priority)
538  ast_free(save_macro_priority);
539 
540  if (setmacrocontext) {
541  chan->macrocontext[0] = '\0';
542  chan->macroexten[0] = '\0';
543  chan->macropriority = 0;
544  }
545 
546  if (!strcasecmp(chan->context, fullmacro)) {
547  const char *offsets;
548 
549  /* If we're leaving the macro normally, restore original information */
550  chan->priority = oldpriority;
551  ast_copy_string(chan->context, oldcontext, sizeof(chan->context));
552  ast_copy_string(chan->exten, oldexten, sizeof(chan->exten));
553  if ((offsets = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"))) {
554  /* Handle macro offset if it's set by checking the availability of step n + offset + 1, otherwise continue
555  normally if there is any problem */
556  if (sscanf(offsets, "%30d", &offset) == 1) {
557  if (ast_exists_extension(chan, chan->context, chan->exten,
558  chan->priority + offset + 1,
559  S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
560  chan->priority += offset;
561  }
562  }
563  }
564  }
565 
566  pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", save_macro_offset);
567  if (save_macro_offset)
568  ast_free(save_macro_offset);
569 
570  /* Unlock the macro */
571  if (exclusive) {
572  ast_debug(1, "Unlocking macrolock for '%s'\n", fullmacro);
573  if (ast_context_unlockmacro(fullmacro)) {
574  ast_log(LOG_ERROR, "Failed to unlock macro '%s' - that isn't good\n", fullmacro);
575  res = 0;
576  }
577  }
578  ast_channel_unlock(chan);
579  ast_free(tmp_subst);
580 
581  return res;
582 }
583 
584 static int macro_exec(struct ast_channel *chan, const char *data)
585 {
586  return _macro_exec(chan, data, 0);
587 }
588 
589 static int macroexclusive_exec(struct ast_channel *chan, const char *data)
590 {
591  return _macro_exec(chan, data, 1);
592 }
593 
594 static int macroif_exec(struct ast_channel *chan, const char *data)
595 {
596  char *expr = NULL, *label_a = NULL, *label_b = NULL;
597  int res = 0;
598 
599  expr = ast_strdupa(data);
600 
601  if ((label_a = strchr(expr, '?'))) {
602  *label_a = '\0';
603  label_a++;
604  if ((label_b = strchr(label_a, ':'))) {
605  *label_b = '\0';
606  label_b++;
607  }
608  if (pbx_checkcondition(expr))
609  res = macro_exec(chan, label_a);
610  else if (label_b)
611  res = macro_exec(chan, label_b);
612  } else
613  ast_log(LOG_WARNING, "Invalid Syntax.\n");
614 
615  return res;
616 }
617 
618 static int macro_exit_exec(struct ast_channel *chan, const char *data)
619 {
620  return MACRO_EXIT_RESULT;
621 }
622 
623 static int unload_module(void)
624 {
625  int res;
626 
627  res = ast_unregister_application(if_app);
628  res |= ast_unregister_application(exit_app);
629  res |= ast_unregister_application(app);
630  res |= ast_unregister_application(exclusive_app);
631 
632  return res;
633 }
634 
635 static int load_module(void)
636 {
637  int res;
638 
641  res |= ast_register_application_xml(exclusive_app, macroexclusive_exec);
643 
644  return res;
645 }
646 
struct ast_include * ast_walk_context_includes(struct ast_context *con, struct ast_include *inc)
Definition: pbx.c:11203
const char * type
Definition: datastore.h:32
ast_include: include= support in extensions.conf
Definition: pbx.c:904
int ast_unlock_context(struct ast_context *con)
Definition: pbx.c:11065
#define ast_channel_lock(chan)
Definition: channel.h:2466
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:109
Main Channel structure associated with a channel.
Definition: channel.h:742
char * str
Subscriber phone number (Malloced)
Definition: channel.h:241
int ast_get_extension_priority(struct ast_exten *exten)
Definition: pbx.c:11103
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:396
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:884
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
struct ast_party_caller caller
Channel Caller ID information.
Definition: channel.h:804
int ast_autoservice_start(struct ast_channel *chan)
Automatically service a channel for us...
Definition: autoservice.c:179
char * strsep(char **str, const char *delims)
int priority
Definition: channel.h:841
#define MAX_ARGS
Definition: app_macro.c:155
#define ast_strdup(a)
Definition: astmm.h:109
static struct ast_datastore_info macro_ds_info
Definition: app_macro.c:167
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:594
int ast_context_lockmacro(const char *macrocontext)
locks the macrolock in the given given context
Definition: pbx.c:6306
static int load_module(void)
Definition: app_macro.c:635
char context[AST_MAX_CONTEXT]
Definition: channel.h:868
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define LOG_WARNING
Definition: logger.h:144
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
const char * ast_get_extension_app(struct ast_exten *e)
Definition: pbx.c:11141
static int unload_module(void)
Definition: app_macro.c:623
int pbx_checkcondition(const char *condition)
Evaluate a condition.
Definition: pbx.c:10719
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
Definition: pbx.c:4468
Structure for a data store type.
Definition: datastore.h:31
Configuration File Parser.
void * ast_get_extension_app_data(struct ast_exten *e)
Definition: pbx.c:11146
int ast_rdlock_contexts(void)
Read locks the context list.
Definition: pbx.c:11042
struct ast_str * ast_str_create(size_t init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:420
Structure for a data store object.
Definition: datastore.h:54
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:2604
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx.c:7705
#define ast_verb(level,...)
Definition: logger.h:243
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.
Definition: pbx.c:10475
Utility functions.
static char * exclusive_app
Definition: app_macro.c:162
struct ast_party_id id
Caller party ID.
Definition: channel.h:370
const char * ast_get_include_name(struct ast_include *include)
Definition: pbx.c:11093
static int macro_exit_exec(struct ast_channel *chan, const char *data)
Definition: app_macro.c:618
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
int priority
Definition: pbx.c:888
int macropriority
Definition: channel.h:842
General Asterisk PBX channel definitions.
struct ast_exten * ast_walk_context_extensions(struct ast_context *con, struct ast_exten *priority)
Definition: pbx.c:11179
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
ast_cond_t cond
Definition: app_meetme.c:963
#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:83
const char * ast_get_extension_cidmatch(struct ast_exten *e)
Definition: pbx.c:11136
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:5400
struct ast_context * ast_walk_contexts(struct ast_context *con)
Definition: pbx.c:11174
const char * ast_get_context_name(struct ast_context *con)
Definition: pbx.c:11073
Core PBX routines and definitions.
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:238
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:806
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
#define LOG_ERROR
Definition: logger.h:155
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
void * data
Definition: pbx.c:893
struct ast_exten * ast_walk_extension_priorities(struct ast_exten *exten, struct ast_exten *priority)
Definition: pbx.c:11197
int ast_unlock_contexts(void)
Unlocks contexts.
Definition: pbx.c:11047
const ast_string_field name
Definition: channel.h:787
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
struct ast_datastore * ast_datastore_alloc(const struct ast_datastore_info *info, const char *uid)
Definition: datastore.c:98
const char * ast_get_extension_name(struct ast_exten *exten)
Definition: pbx.c:11083
static struct ast_exten * find_matching_priority(struct ast_context *c, const char *exten, int priority, const char *callerid)
Definition: app_macro.c:190
#define ast_channel_unlock(chan)
Definition: channel.h:2467
static int macroexclusive_exec(struct ast_channel *chan, const char *data)
Definition: app_macro.c:589
#define AST_MAX_CONTEXT
Definition: channel.h:136
#define ast_free(a)
Definition: astmm.h:97
char macrocontext[AST_MAX_CONTEXT]
Definition: channel.h:870
int ast_extension_match(const char *pattern, const char *extension)
Determine if a given extension matches a given pattern (in NXX format)
Definition: pbx.c:2943
#define DATASTORE_INHERIT_FOREVER
Definition: channel.h:156
unsigned int inheritance
Definition: datastore.h:58
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:5425
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...
Definition: pbx.c:10546
char macroexten[AST_MAX_EXTENSION]
Definition: channel.h:871
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
static const char app2[]
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive)
Definition: app_macro.c:225
static char * app
Definition: app_macro.c:160
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:38
int ast_get_extension_matchcid(struct ast_exten *e)
Definition: pbx.c:11131
Asterisk module definitions.
static int macro_exec(struct ast_channel *chan, const char *data)
Definition: app_macro.c:584
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2590
ast_context: An extension context
Definition: pbx.c:955
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:247
int ast_context_unlockmacro(const char *macrocontext)
Unlocks the macrolock in the given context.
Definition: pbx.c:6327
struct ast_context * ast_context_find(const char *name)
Find a context.
Definition: pbx.c:2971
char exten[AST_MAX_EXTENSION]
Definition: channel.h:869
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:437
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
int ast_rdlock_context(struct ast_context *con)
Read locks a given context.
Definition: pbx.c:11060
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:292