Asterisk - The Open Source Telephony Project  18.5.0
Macros | Functions | Variables
app_macro.c File Reference

Dial plan macro Implementation. More...

#include "asterisk.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/extconf.h"
#include "asterisk/config.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "asterisk/app.h"
Include dependency graph for app_macro.c:

Go to the source code of this file.

Macros

#define MACRO_EXIT_RESULT   1024
 
#define MAX_ARGS   80
 

Functions

static int _macro_exec (struct ast_channel *chan, const char *data, int exclusive)
 
 AST_MODULE_INFO_STANDARD_DEPRECATED (ASTERISK_GPL_KEY, "Extension Macros")
 
static struct ast_extenfind_matching_priority (struct ast_context *c, const char *exten, int priority, const char *callerid, int iter, int *had_error)
 
static int load_module (void)
 
static int macro_exec (struct ast_channel *chan, const char *data)
 
static int macro_exit_exec (struct ast_channel *chan, const char *data)
 
static void macro_fixup (void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
 
static int macroexclusive_exec (struct ast_channel *chan, const char *data)
 
static int macroif_exec (struct ast_channel *chan, const char *data)
 
static int unload_module (void)
 

Variables

static char * app = "Macro"
 
static char * exclusive_app = "MacroExclusive"
 
static char * exit_app = "MacroExit"
 
static char * if_app = "MacroIf"
 
static const struct ast_datastore_info macro_ds_info
 

Detailed Description

Dial plan macro Implementation.

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m

Definition in file app_macro.c.

Macro Definition Documentation

◆ MACRO_EXIT_RESULT

#define MACRO_EXIT_RESULT   1024

Definition at line 158 of file app_macro.c.

Referenced by _macro_exec(), and macro_exit_exec().

◆ MAX_ARGS

#define MAX_ARGS   80

Definition at line 155 of file app_macro.c.

Referenced by _macro_exec().

Function Documentation

◆ _macro_exec()

static int _macro_exec ( struct ast_channel chan,
const char *  data,
int  exclusive 
)
static

Definition at line 236 of file app_macro.c.

References app2, ast_autoservice_start(), ast_autoservice_stop(), ast_channel_caller(), ast_channel_context(), ast_channel_context_set(), ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_exten(), ast_channel_exten_set(), ast_channel_flags(), ast_channel_lock, ast_channel_macrocontext(), ast_channel_macrocontext_set(), ast_channel_macroexten(), ast_channel_macroexten_set(), ast_channel_macropriority_set(), ast_channel_name(), ast_channel_priority(), ast_channel_priority_set(), ast_channel_softhangup_internal_flag(), ast_channel_unlock, ast_check_hangup(), ast_context_find(), ast_context_lockmacro(), ast_context_unlockmacro(), ast_copy_string(), ast_datastore_alloc, ast_debug, ast_exists_extension(), AST_FLAG_IN_AUTOLOOP, AST_FLAG_SUBROUTINE_EXEC, ast_free, ast_get_context_name(), ast_get_extension_app(), ast_get_extension_app_data(), ast_log, AST_MAX_CONTEXT, ast_rdlock_context(), ast_rdlock_contexts(), ast_set2_flag, ast_set_flag, AST_SOFTHANGUP_ASYNCGOTO, ast_spawn_extension(), ast_str_buffer(), ast_str_create, ast_str_substitute_variables(), ast_strdup, ast_strdupa, ast_strlen_zero, ast_test_flag, ast_unlock_context(), ast_unlock_contexts(), ast_verb, ast_walk_contexts(), c, cond, DATASTORE_INHERIT_FOREVER, deprecation_notice(), find_matching_priority(), ast_datastore::inheritance, LOG_ERROR, LOG_WARNING, MACRO_EXIT_RESULT, MAX_ARGS, NULL, out, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), pbx_checkcondition(), S_COR, strsep(), and tmp().

Referenced by macro_exec(), and macroexclusive_exec().

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 %s@%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 }
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
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
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
#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
#define ast_set2_flag(p, value, flag)
Definition: utils.h:94
#define ast_test_flag(p, flag)
Definition: utils.h:63
int ast_context_lockmacro(const char *macrocontext)
locks the macrolock in the given context
Definition: pbx.c:5162
#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 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
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
#define NULL
Definition: resample.c:96
int ast_channel_priority(const struct ast_channel *chan)
#define ast_verb(level,...)
Definition: logger.h:463
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
#define ast_strlen_zero(foo)
Definition: strings.h:52
Number structure.
Definition: app_followme.c:154
void ast_channel_macropriority_set(struct ast_channel *chan, int value)
static void deprecation_notice(void)
Definition: chan_sip.c:35452
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
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
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)
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
#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_channel_unlock(chan)
Definition: channel.h:2946
#define AST_MAX_CONTEXT
Definition: channel.h:136
#define ast_free(a)
Definition: astmm.h:182
#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)
void * data
Definition: datastore.h:70
char * strsep(char **str, const char *delims)
FILE * out
Definition: utils/frame.c:33
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)
const char * ast_channel_context(const struct ast_channel *chan)
#define ast_datastore_alloc(info, uid)
Definition: datastore.h:89
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
const char * ast_channel_macrocontext(const struct ast_channel *chan)
void ast_channel_priority_set(struct ast_channel *chan, int value)
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition: channel.c:2390
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 char * ast_channel_macroexten(const struct ast_channel *chan)
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

◆ AST_MODULE_INFO_STANDARD_DEPRECATED()

AST_MODULE_INFO_STANDARD_DEPRECATED ( ASTERISK_GPL_KEY  ,
"Extension Macros"   
)

Referenced by load_module().

◆ find_matching_priority()

static struct ast_exten* find_matching_priority ( struct ast_context c,
const char *  exten,
int  priority,
const char *  callerid,
int  iter,
int *  had_error 
)
static

Definition at line 190 of file app_macro.c.

References ast_context_includes_count(), ast_context_includes_get(), ast_extension_match(), ast_get_context_name(), ast_get_extension_cidmatch(), ast_get_extension_matchcid(), ast_get_extension_name(), ast_get_extension_priority(), ast_get_include_name(), ast_log, AST_PBX_MAX_STACK, ast_walk_context_extensions(), ast_walk_contexts(), ast_walk_extension_priorities(), LOG_ERROR, and NULL.

Referenced by _macro_exec().

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;
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 }
ast_include: include= support in extensions.conf
Definition: pbx_include.c:37
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
int ast_get_extension_priority(struct ast_exten *exten)
Definition: pbx.c:8558
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
const char * ast_get_context_name(struct ast_context *con)
Definition: ael_main.c:421
struct ast_context * ast_walk_contexts(struct ast_context *con)
Definition: conf2ael.c:618
#define NULL
Definition: resample.c:96
static int priority
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_log
Definition: astobj2.c:42
const char * ast_get_extension_cidmatch(struct ast_exten *e)
Definition: pbx.c:8591
int ast_context_includes_count(const struct ast_context *con)
Definition: pbx.c:8697
#define LOG_ERROR
Definition: logger.h:285
#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
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
const char * ast_get_include_name(const struct ast_include *include)
Definition: pbx_include.c:50
struct ast_exten * ast_walk_extension_priorities(struct ast_exten *exten, struct ast_exten *priority)
Definition: extconf.c:4063
int ast_get_extension_matchcid(struct ast_exten *e)
Definition: pbx.c:8586
ast_context: An extension context - must remain in sync with fake_context
Definition: pbx.c:284
const struct ast_include * ast_context_includes_get(const struct ast_context *con, int idx)
Definition: pbx.c:8702

◆ load_module()

static int load_module ( void  )
static

Definition at line 677 of file app_macro.c.

References app, AST_MODULE_INFO_STANDARD_DEPRECATED(), ast_register_application_xml, ASTERISK_GPL_KEY, exclusive_app, exit_app, if_app, macro_exec(), macro_exit_exec(), macroexclusive_exec(), and macroif_exec().

678 {
679  int res;
680 
685 
686  return res;
687 }
static char * if_app
Definition: app_macro.c:161
static int macroif_exec(struct ast_channel *chan, const char *data)
Definition: app_macro.c:636
static char * exit_app
Definition: app_macro.c:163
static char * exclusive_app
Definition: app_macro.c:162
static int macro_exit_exec(struct ast_channel *chan, const char *data)
Definition: app_macro.c:660
static int macroexclusive_exec(struct ast_channel *chan, const char *data)
Definition: app_macro.c:631
static char * app
Definition: app_macro.c:160
static int macro_exec(struct ast_channel *chan, const char *data)
Definition: app_macro.c:626
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626

◆ macro_exec()

static int macro_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 626 of file app_macro.c.

References _macro_exec().

Referenced by load_module(), and macroif_exec().

627 {
628  return _macro_exec(chan, data, 0);
629 }
static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive)
Definition: app_macro.c:236

◆ macro_exit_exec()

static int macro_exit_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 660 of file app_macro.c.

References MACRO_EXIT_RESULT.

Referenced by load_module().

661 {
662  return MACRO_EXIT_RESULT;
663 }
#define MACRO_EXIT_RESULT
Definition: app_macro.c:158

◆ macro_fixup()

static void macro_fixup ( void *  data,
struct ast_channel old_chan,
struct ast_channel new_chan 
)
static

Definition at line 172 of file app_macro.c.

References NULL, pbx_builtin_getvar_helper(), and pbx_builtin_setvar_helper().

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 }
#define NULL
Definition: resample.c:96
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
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...

◆ macroexclusive_exec()

static int macroexclusive_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 631 of file app_macro.c.

References _macro_exec().

Referenced by load_module().

632 {
633  return _macro_exec(chan, data, 1);
634 }
static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive)
Definition: app_macro.c:236

◆ macroif_exec()

static int macroif_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 636 of file app_macro.c.

References ast_log, ast_strdupa, LOG_WARNING, macro_exec(), NULL, and pbx_checkcondition().

Referenced by load_module().

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 }
#define LOG_WARNING
Definition: logger.h:274
int pbx_checkcondition(const char *condition)
Evaluate a condition.
Definition: pbx.c:8321
#define NULL
Definition: resample.c:96
#define ast_log
Definition: astobj2.c:42
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static int macro_exec(struct ast_channel *chan, const char *data)
Definition: app_macro.c:626

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 665 of file app_macro.c.

References app, ast_unregister_application(), exclusive_app, exit_app, and if_app.

666 {
667  int res;
668 
673 
674  return res;
675 }
static char * if_app
Definition: app_macro.c:161
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
static char * exit_app
Definition: app_macro.c:163
static char * exclusive_app
Definition: app_macro.c:162
static char * app
Definition: app_macro.c:160

Variable Documentation

◆ app

char* app = "Macro"
static

Definition at line 160 of file app_macro.c.

Referenced by load_module(), and unload_module().

◆ exclusive_app

char* exclusive_app = "MacroExclusive"
static

Definition at line 162 of file app_macro.c.

Referenced by load_module(), and unload_module().

◆ exit_app

char* exit_app = "MacroExit"
static

Definition at line 163 of file app_macro.c.

Referenced by load_module(), and unload_module().

◆ if_app

char* if_app = "MacroIf"
static

Definition at line 161 of file app_macro.c.

Referenced by load_module(), and unload_module().

◆ macro_ds_info

const struct ast_datastore_info macro_ds_info
static
Initial value:
= {
.type = "MACRO",
.chan_fixup = macro_fixup,
}
static void macro_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
Definition: app_macro.c:172

Definition at line 167 of file app_macro.c.