Asterisk - The Open Source Telephony Project  18.5.0
Data Structures | Functions | Variables
app_stack.c File Reference

Stack applications Gosub, Return, etc. More...

#include "asterisk.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/app.h"
#include "asterisk/manager.h"
#include "asterisk/channel.h"
#include "asterisk/agi.h"
#include "asterisk/stasis_channels.h"
Include dependency graph for app_stack.c:

Go to the source code of this file.

Data Structures

struct  gosub_stack_frame
 
struct  gosub_stack_list
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static void balance_stack (struct ast_channel *chan)
 
static const char * expand_gosub_args (struct ast_channel *chan, const char *args)
 
static int frame_set_var (struct ast_channel *chan, struct gosub_stack_frame *frame, const char *var, const char *value)
 
static struct gosub_stack_framegosub_allocate_frame (const char *context, const char *extension, int priority, int in_subroutine, unsigned char arguments)
 
static int gosub_exec (struct ast_channel *chan, const char *data)
 
static void gosub_free (void *data)
 
static void gosub_release_frame (struct ast_channel *chan, struct gosub_stack_frame *frame)
 
static int gosub_run (struct ast_channel *chan, const char *sub_args, int ignore_hangup)
 
static int gosubif_exec (struct ast_channel *chan, const char *data)
 
static int handle_gosub (struct ast_channel *chan, AGI *agi, int argc, const char *const *argv)
 
static int load_module (void)
 
static int local_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 
static int local_write (struct ast_channel *chan, const char *cmd, char *var, const char *value)
 
static int peek_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
 
static int pop_exec (struct ast_channel *chan, const char *data)
 
static int return_exec (struct ast_channel *chan, const char *data)
 
static int stackpeek_read (struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_LOAD_ORDER , .description = "Dialplan subroutines (Gosub, Return, etc)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .optional_modules = "res_agi", }
 
static const char app_gosub [] = "Gosub"
 
static const char app_gosubif [] = "GosubIf"
 
static const char app_pop [] = "StackPop"
 
static const char app_return [] = "Return"
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct agi_command gosub_agi_command
 
static struct ast_custom_function local_function
 
static struct ast_custom_function peek_function
 
static const struct ast_datastore_info stack_info
 
static struct ast_custom_function stackpeek_function
 

Detailed Description

Stack applications Gosub, Return, etc.

Author
Tilghman Lesher app_s.nosp@m.tack.nosp@m._v003.nosp@m.@the.nosp@m.-tilg.nosp@m.hman.nosp@m..com

Definition in file app_stack.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1325 of file app_stack.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1325 of file app_stack.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 1325 of file app_stack.c.

◆ balance_stack()

static void balance_stack ( struct ast_channel chan)
static

Definition at line 930 of file app_stack.c.

References app_gosub, ast_channel_datastore_find(), AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log, ast_datastore::data, gosub_stack_frame::entries, gosub_release_frame(), gosub_stack_frame::is_special, LOG_WARNING, and NULL.

Referenced by gosub_run(), and handle_gosub().

931 {
932  struct ast_datastore *stack_store;
933  struct gosub_stack_list *oldlist;
934  struct gosub_stack_frame *oldframe;
935  int found;
936 
937  stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
938  if (!stack_store) {
939  ast_log(LOG_WARNING, "No %s stack allocated.\n", app_gosub);
940  return;
941  }
942 
943  oldlist = stack_store->data;
944  AST_LIST_LOCK(oldlist);
945  do {
946  oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
947  if (!oldframe) {
948  break;
949  }
950  found = oldframe->is_special;
951  gosub_release_frame(chan, oldframe);
952  } while (!found);
953  AST_LIST_UNLOCK(oldlist);
954 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
static const char app_gosub[]
Definition: app_stack.c:232
static const struct ast_datastore_info stack_info
Definition: app_stack.c:239
#define LOG_WARNING
Definition: logger.h:274
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
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
#define ast_log
Definition: astobj2.c:42
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
unsigned int is_special
Definition: app_stack.c:251
void * data
Definition: datastore.h:70
struct gosub_stack_frame::@78 entries
static void gosub_release_frame(struct ast_channel *chan, struct gosub_stack_frame *frame)
Definition: app_stack.c:294

◆ expand_gosub_args()

static const char* expand_gosub_args ( struct ast_channel chan,
const char *  args 
)
static

Definition at line 450 of file app_stack.c.

References ast_channel_context(), ast_channel_exten(), ast_channel_lock, ast_channel_unlock, ast_debug, ast_log, ast_malloc, ast_strdupa, ast_strlen_zero, gosub_stack_frame::context, exten, len(), LOG_WARNING, NULL, parse(), and strsep().

Referenced by load_module().

451 {
452  int len;
453  char *parse;
454  char *label;
455  char *new_args;
456  const char *context;
457  const char *exten;
458  const char *pri;
459 
460  /* Separate the context,exten,pri from the optional routine arguments. */
461  parse = ast_strdupa(args);
462  label = strsep(&parse, "(");
463  if (parse) {
464  char *endparen;
465 
466  endparen = strrchr(parse, ')');
467  if (endparen) {
468  *endparen = '\0';
469  } else {
470  ast_log(LOG_WARNING, "Ouch. No closing paren: '%s'?\n", args);
471  }
472  }
473 
474  /* Split context,exten,pri */
475  context = strsep(&label, ",");
476  exten = strsep(&label, ",");
477  pri = strsep(&label, ",");
478  if (!exten) {
479  /* Only a priority in this one */
480  pri = context;
481  exten = NULL;
482  context = NULL;
483  } else if (!pri) {
484  /* Only an extension and priority in this one */
485  pri = exten;
486  exten = context;
487  context = NULL;
488  }
489 
490  ast_channel_lock(chan);
491  if (ast_strlen_zero(exten)) {
492  exten = ast_channel_exten(chan);
493  }
494  if (ast_strlen_zero(context)) {
495  context = ast_channel_context(chan);
496  }
497  len = strlen(context) + strlen(exten) + strlen(pri) + 3;
498  if (!ast_strlen_zero(parse)) {
499  len += 2 + strlen(parse);
500  }
501  new_args = ast_malloc(len);
502  if (new_args) {
503  if (ast_strlen_zero(parse)) {
504  snprintf(new_args, len, "%s,%s,%s", context, exten, pri);
505  } else {
506  snprintf(new_args, len, "%s,%s,%s(%s)", context, exten, pri, parse);
507  }
508  }
509  ast_channel_unlock(chan);
510 
511  ast_debug(4, "Gosub args:%s new_args:%s\n", args, new_args ? new_args : "");
512 
513  return new_args;
514 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:118
#define LOG_WARNING
Definition: logger.h:274
const char * args
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
const char * ast_channel_exten(const struct ast_channel *chan)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define ast_channel_unlock(chan)
Definition: channel.h:2946
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
char * strsep(char **str, const char *delims)
const char * ast_channel_context(const struct ast_channel *chan)
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116

◆ frame_set_var()

static int frame_set_var ( struct ast_channel chan,
struct gosub_stack_frame frame,
const char *  var,
const char *  value 
)
static

Definition at line 260 of file app_stack.c.

References ast_channel_publish_varset(), ast_free, AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_malloc, ast_var_assign, ast_var_name(), gosub_stack_frame::entries, len(), NULL, pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), RAII_VAR, and gosub_stack_frame::varshead.

Referenced by gosub_exec(), and local_write().

261 {
262  struct ast_var_t *variables;
263  int found = 0;
264  int len;
265  RAII_VAR(char *, local_buffer, NULL, ast_free);
266 
267  /* Does this variable already exist? */
268  AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
269  if (!strcmp(var, ast_var_name(variables))) {
270  found = 1;
271  break;
272  }
273  }
274 
275  if (!found) {
276  if ((variables = ast_var_assign(var, ""))) {
277  AST_LIST_INSERT_HEAD(&frame->varshead, variables, entries);
278  }
280  } else {
282  }
283 
284  len = 8 + strlen(var); /* LOCAL() + var */
285  local_buffer = ast_malloc(len);
286  if (!local_buffer) {
287  return 0;
288  }
289  sprintf(local_buffer, "LOCAL(%s)", var);
290  ast_channel_publish_varset(chan, local_buffer, value);
291  return 0;
292 }
struct varshead varshead
Definition: app_stack.c:248
const char * ast_var_name(const struct ast_var_t *var)
Definition: chanvars.c:60
#define var
Definition: ast_expr2f.c:614
void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, without removing any previously set value...
#define NULL
Definition: resample.c:96
int value
Definition: syslog.c:37
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:193
void ast_channel_publish_varset(struct ast_channel *chan, const char *variable, const char *value)
Publish a ast_channel_varset for a channel.
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:710
#define ast_free(a)
Definition: astmm.h:182
struct ast_var_t::@249 entries
#define ast_var_assign(name, value)
Definition: chanvars.h:40
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...

◆ gosub_allocate_frame()

static struct gosub_stack_frame* gosub_allocate_frame ( const char *  context,
const char *  extension,
int  priority,
int  in_subroutine,
unsigned char  arguments 
)
static

Definition at line 313 of file app_stack.c.

References gosub_stack_frame::arguments, ast_calloc, ast_copy_string(), AST_LIST_HEAD_INIT_NOLOCK, NULL, and gosub_stack_frame::priority.

Referenced by gosub_exec().

314 {
315  struct gosub_stack_frame *new = NULL;
316  int len_extension = strlen(extension) + 1;
317  int len_context = strlen(context) + 1;
318 
319  if ((new = ast_calloc(1, sizeof(*new) + len_extension + len_context))) {
320  AST_LIST_HEAD_INIT_NOLOCK(&new->varshead);
321  ast_copy_string(new->extension, extension, len_extension);
322  new->context = new->extension + len_extension;
323  ast_copy_string(new->context, context, len_context);
324  new->priority = priority;
325  new->in_subroutine = in_subroutine ? 1 : 0;
326  new->arguments = arguments;
327  }
328  return new;
329 }
unsigned int in_subroutine
Definition: app_stack.c:253
#define NULL
Definition: resample.c:96
static int priority
structure to hold extensions
unsigned char arguments
Definition: app_stack.c:247
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:680
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:116

◆ gosub_exec()

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

Definition at line 516 of file app_stack.c.

References app_gosub, gosub_stack_frame::arguments, AST_APP_ARG, ast_calloc, 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_name(), ast_channel_priority(), ast_channel_priority_set(), ast_channel_unlock, ast_datastore_alloc, ast_datastore_free(), ast_debug, AST_DECLARE_APP_ARGS, ast_exists_extension(), AST_FLAG_IN_AUTOLOOP, AST_FLAG_SUBROUTINE_EXEC, AST_LIST_FIRST, AST_LIST_HEAD_INIT, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log, ast_parseable_goto(), ast_set_flag, AST_STANDARD_RAW_ARGS, ast_strdupa, ast_strlen_zero, ast_test_flag, ast_datastore::data, gosub_stack_frame::entries, frame_set_var(), gosub_allocate_frame(), LOG_ERROR, LOG_WARNING, NULL, orig_exten(), parse(), S_COR, and strsep().

Referenced by gosub_run(), gosubif_exec(), handle_gosub(), and load_module().

517 {
518  struct ast_datastore *stack_store;
519  struct gosub_stack_list *oldlist;
520  struct gosub_stack_frame *newframe;
521  struct gosub_stack_frame *lastframe;
522  char argname[15];
523  char *parse;
524  char *label;
525  char *caller_id;
526  char *orig_context;
527  char *orig_exten;
528  char *dest_context;
529  char *dest_exten;
530  int orig_in_subroutine;
531  int orig_priority;
532  int dest_priority;
533  int i;
534  int max_argc = 0;
535  AST_DECLARE_APP_ARGS(args2,
536  AST_APP_ARG(argval)[100];
537  );
538 
539  if (ast_strlen_zero(data)) {
540  ast_log(LOG_ERROR, "%s requires an argument: %s([[context,]exten,]priority[(arg1[,...][,argN])])\n", app_gosub, app_gosub);
541  return -1;
542  }
543 
544  /*
545  * Separate the arguments from the label
546  *
547  * NOTE: You cannot use ast_app_separate_args for this, because
548  * '(' cannot be used as a delimiter.
549  */
550  parse = ast_strdupa(data);
551  label = strsep(&parse, "(");
552  if (parse) {
553  char *endparen;
554 
555  endparen = strrchr(parse, ')');
556  if (endparen) {
557  *endparen = '\0';
558  } else {
559  ast_log(LOG_WARNING, "Ouch. No closing paren: '%s'?\n", data);
560  }
561  AST_STANDARD_RAW_ARGS(args2, parse);
562  } else {
563  args2.argc = 0;
564  }
565 
566  ast_channel_lock(chan);
567  orig_context = ast_strdupa(ast_channel_context(chan));
568  orig_exten = ast_strdupa(ast_channel_exten(chan));
569  orig_priority = ast_channel_priority(chan);
570  orig_in_subroutine = ast_test_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
571  ast_channel_unlock(chan);
572 
573  if (ast_parseable_goto(chan, label)) {
574  ast_log(LOG_ERROR, "%s address is invalid: '%s'\n", app_gosub, data);
575  goto error_exit;
576  }
577 
578  ast_channel_lock(chan);
579  dest_context = ast_strdupa(ast_channel_context(chan));
580  dest_exten = ast_strdupa(ast_channel_exten(chan));
581  dest_priority = ast_channel_priority(chan);
583  ++dest_priority;
584  }
585  caller_id = S_COR(ast_channel_caller(chan)->id.number.valid,
586  ast_channel_caller(chan)->id.number.str, NULL);
587  if (caller_id) {
588  caller_id = ast_strdupa(caller_id);
589  }
590  ast_channel_unlock(chan);
591 
592  if (!ast_exists_extension(chan, dest_context, dest_exten, dest_priority, caller_id)) {
593  ast_log(LOG_ERROR, "Attempt to reach a non-existent destination for %s: (Context:%s, Extension:%s, Priority:%d)\n",
594  app_gosub, dest_context, dest_exten, dest_priority);
595  goto error_exit;
596  }
597 
598  /* Now we know that we're going to a new location */
599 
600  ast_channel_lock(chan);
601 
602  /* Find stack datastore return list. */
603  if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
604  ast_debug(1, "Channel %s has no datastore, so we're allocating one.\n",
605  ast_channel_name(chan));
606  stack_store = ast_datastore_alloc(&stack_info, NULL);
607  if (!stack_store) {
608  ast_log(LOG_ERROR, "Unable to allocate new datastore. %s failed.\n",
609  app_gosub);
610  goto error_exit_locked;
611  }
612 
613  oldlist = ast_calloc(1, sizeof(*oldlist));
614  if (!oldlist) {
615  ast_log(LOG_ERROR, "Unable to allocate datastore list head. %s failed.\n",
616  app_gosub);
617  ast_datastore_free(stack_store);
618  goto error_exit_locked;
619  }
620  AST_LIST_HEAD_INIT(oldlist);
621 
622  stack_store->data = oldlist;
623  ast_channel_datastore_add(chan, stack_store);
624  } else {
625  oldlist = stack_store->data;
626  }
627 
628  if ((lastframe = AST_LIST_FIRST(oldlist))) {
629  max_argc = lastframe->arguments;
630  }
631 
632  /* Mask out previous Gosub arguments in this invocation */
633  if (args2.argc > max_argc) {
634  max_argc = args2.argc;
635  }
636 
637  /* Create the return address */
638  newframe = gosub_allocate_frame(orig_context, orig_exten, orig_priority + 1, orig_in_subroutine, max_argc);
639  if (!newframe) {
640  goto error_exit_locked;
641  }
642 
643  /* Set our arguments */
644  for (i = 0; i < max_argc; i++) {
645  snprintf(argname, sizeof(argname), "ARG%d", i + 1);
646  frame_set_var(chan, newframe, argname, i < args2.argc ? args2.argval[i] : "");
647  ast_debug(1, "Setting '%s' to '%s'\n", argname, i < args2.argc ? args2.argval[i] : "");
648  }
649  snprintf(argname, sizeof(argname), "%u", args2.argc);
650  frame_set_var(chan, newframe, "ARGC", argname);
651 
653 
654  /* And finally, save our return address */
655  AST_LIST_LOCK(oldlist);
656  AST_LIST_INSERT_HEAD(oldlist, newframe, entries);
657  AST_LIST_UNLOCK(oldlist);
658  ast_channel_unlock(chan);
659 
660  return 0;
661 
662 error_exit:
663  ast_channel_lock(chan);
664 
665 error_exit_locked:
666  /* Restore the original dialplan location. */
667  ast_channel_context_set(chan, orig_context);
668  ast_channel_exten_set(chan, orig_exten);
669  ast_channel_priority_set(chan, orig_priority);
670  ast_channel_unlock(chan);
671  return -1;
672 }
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
static const char app_gosub[]
Definition: app_stack.c:232
static const struct ast_datastore_info stack_info
Definition: app_stack.c:239
#define ast_test_flag(p, flag)
Definition: utils.h:63
static struct gosub_stack_frame * gosub_allocate_frame(const char *context, const char *extension, int priority, int in_subroutine, unsigned char arguments)
Definition: app_stack.c:313
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define LOG_WARNING
Definition: logger.h:274
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
#define AST_STANDARD_RAW_ARGS(args, parse)
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
static int frame_set_var(struct ast_channel *chan, struct gosub_stack_frame *frame, const char *var, const char *value)
Definition: app_stack.c:260
#define NULL
Definition: resample.c:96
int ast_channel_priority(const struct ast_channel *chan)
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
Definition: datastore.c:68
#define ast_strlen_zero(foo)
Definition: strings.h:52
Number structure.
Definition: app_followme.c:154
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
Definition: pbx.c:8859
#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
static char * orig_exten(int fd, const char *chan, const char *data)
orginate from extension
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)
unsigned char arguments
Definition: app_stack.c:247
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:710
#define ast_channel_unlock(chan)
Definition: channel.h:2946
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
Definition: linkedlists.h:625
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
void * data
Definition: datastore.h:70
char * strsep(char **str, const char *delims)
void ast_channel_context_set(struct ast_channel *chan, const char *value)
const char * ast_channel_name(const struct ast_channel *chan)
struct gosub_stack_frame::@78 entries
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)
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
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ gosub_free()

static void gosub_free ( void *  data)
static

Definition at line 331 of file app_stack.c.

References ast_free, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, gosub_stack_frame::entries, gosub_release_frame(), and NULL.

332 {
333  struct gosub_stack_list *oldlist = data;
334  struct gosub_stack_frame *oldframe;
335 
336  AST_LIST_LOCK(oldlist);
337  while ((oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries))) {
338  gosub_release_frame(NULL, oldframe);
339  }
340  AST_LIST_UNLOCK(oldlist);
341  AST_LIST_HEAD_DESTROY(oldlist);
342  ast_free(oldlist);
343 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
#define NULL
Definition: resample.c:96
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:652
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
#define ast_free(a)
Definition: astmm.h:182
struct gosub_stack_frame::@78 entries
static void gosub_release_frame(struct ast_channel *chan, struct gosub_stack_frame *frame)
Definition: app_stack.c:294

◆ gosub_release_frame()

static void gosub_release_frame ( struct ast_channel chan,
struct gosub_stack_frame frame 
)
static

Definition at line 294 of file app_stack.c.

References ast_free, AST_LIST_REMOVE_HEAD, ast_var_delete(), ast_var_name(), gosub_stack_frame::entries, NULL, pbx_builtin_setvar_helper(), and gosub_stack_frame::varshead.

Referenced by balance_stack(), gosub_free(), pop_exec(), and return_exec().

295 {
296  struct ast_var_t *vardata;
297 
298  /* If chan is not defined, then we're calling it as part of gosub_free,
299  * and the channel variables will be deallocated anyway. Otherwise, we're
300  * just releasing a single frame, so we need to clean up the arguments for
301  * that frame, so that we re-expose the variables from the previous frame
302  * that were hidden by this one.
303  */
304  while ((vardata = AST_LIST_REMOVE_HEAD(&frame->varshead, entries))) {
305  if (chan)
307  ast_var_delete(vardata);
308  }
309 
310  ast_free(frame);
311 }
struct varshead varshead
Definition: app_stack.c:248
const char * ast_var_name(const struct ast_var_t *var)
Definition: chanvars.c:60
#define NULL
Definition: resample.c:96
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
void ast_var_delete(struct ast_var_t *var)
Definition: extconf.c:2473
#define ast_free(a)
Definition: astmm.h:182
struct ast_var_t::@249 entries
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...

◆ gosub_run()

static int gosub_run ( struct ast_channel chan,
const char *  sub_args,
int  ignore_hangup 
)
static

Definition at line 970 of file app_stack.c.

References app_gosub, ast_channel_caller(), ast_channel_clear_softhangup(), ast_channel_context(), ast_channel_context_set(), ast_channel_datastore_find(), ast_channel_exten(), ast_channel_exten_set(), ast_channel_flags(), ast_channel_lock, ast_channel_name(), ast_channel_priority(), ast_channel_priority_set(), ast_channel_softhangup_internal_flag(), ast_channel_unlock, ast_check_hangup(), ast_debug, AST_FLAG_IN_AUTOLOOP, AST_FLAG_SUBROUTINE_EXEC, AST_LIST_FIRST, ast_log, ast_set2_flag, ast_set_flag, AST_SOFTHANGUP_ASYNCGOTO, ast_softhangup_nolock(), ast_spawn_extension(), ast_strdupa, ast_test_flag, ast_verb, balance_stack(), ast_datastore::data, gosub_exec(), gosub_stack_frame::is_special, LOG_ERROR, LOG_NOTICE, NULL, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), S_COR, and S_OR.

Referenced by load_module().

971 {
972  const char *saved_context;
973  const char *saved_exten;
974  int saved_priority;
975  int saved_hangup_flags;
976  int saved_autoloopflag;
977  int saved_in_subroutine;
978  int res;
979 
980  ast_channel_lock(chan);
981 
982  ast_verb(3, "%s Internal %s(%s) start\n",
983  ast_channel_name(chan), app_gosub, sub_args);
984 
985  /* Save non-hangup softhangup flags. */
986  saved_hangup_flags = ast_channel_softhangup_internal_flag(chan)
988  if (saved_hangup_flags) {
990  }
991 
992  /* Save autoloop flag */
993  saved_autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
995 
996  /* Save current dialplan location */
997  saved_context = ast_strdupa(ast_channel_context(chan));
998  saved_exten = ast_strdupa(ast_channel_exten(chan));
999  saved_priority = ast_channel_priority(chan);
1000 
1001  /* Save whether or not we are in a subroutine */
1002  saved_in_subroutine = ast_test_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
1003 
1004  ast_debug(4, "%s Original location: %s,%s,%d\n", ast_channel_name(chan),
1005  saved_context, saved_exten, saved_priority);
1006 
1007  ast_channel_unlock(chan);
1008  res = gosub_exec(chan, sub_args);
1009  ast_debug(4, "%s exited with status %d\n", app_gosub, res);
1010  ast_channel_lock(chan);
1011  if (!res) {
1012  struct ast_datastore *stack_store;
1013 
1014  /* Mark the return location as special. */
1015  stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
1016  if (!stack_store) {
1017  /* Should never happen! */
1018  ast_log(LOG_ERROR, "No %s stack!\n", app_gosub);
1019  res = -1;
1020  } else {
1021  struct gosub_stack_list *oldlist;
1022  struct gosub_stack_frame *cur;
1023 
1024  oldlist = stack_store->data;
1025  cur = AST_LIST_FIRST(oldlist);
1026  cur->is_special = 1;
1027  }
1028  }
1029  if (!res) {
1030  int found = 0; /* set if we find at least one match */
1031 
1032  /*
1033  * Run gosub body autoloop.
1034  *
1035  * Note that this loop is inverted from the normal execution
1036  * loop because we just executed the Gosub application as the
1037  * first extension of the autoloop.
1038  */
1039  do {
1040  /* Check for hangup. */
1041  if (ast_check_hangup(chan)) {
1043  ast_log(LOG_ERROR, "%s An async goto just messed up our execution location.\n",
1044  ast_channel_name(chan));
1045  break;
1046  }
1047  if (!ignore_hangup) {
1048  break;
1049  }
1050  }
1051 
1052  /* Next dialplan priority. */
1054 
1055  ast_channel_unlock(chan);
1056  res = ast_spawn_extension(chan, ast_channel_context(chan),
1058  S_COR(ast_channel_caller(chan)->id.number.valid,
1059  ast_channel_caller(chan)->id.number.str, NULL),
1060  &found, 1);
1061  ast_channel_lock(chan);
1062  } while (!res);
1063  if (found && res) {
1064  /* Something bad happened, or a hangup has been requested. */
1065  ast_debug(1, "Spawn extension (%s,%s,%d) exited with %d on '%s'\n",
1067  ast_channel_priority(chan), res, ast_channel_name(chan));
1068  ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n",
1070  ast_channel_priority(chan), ast_channel_name(chan));
1071  }
1072 
1073  /* Did the routine return? */
1074  if (ast_channel_priority(chan) == saved_priority
1075  && !strcmp(ast_channel_context(chan), saved_context)
1076  && !strcmp(ast_channel_exten(chan), saved_exten)) {
1077  ast_verb(3, "%s Internal %s(%s) complete GOSUB_RETVAL=%s\n",
1078  ast_channel_name(chan), app_gosub, sub_args,
1079  S_OR(pbx_builtin_getvar_helper(chan, "GOSUB_RETVAL"), ""));
1080  } else {
1081  ast_log(LOG_NOTICE, "%s Abnormal '%s(%s)' exit. Popping routine return locations.\n",
1082  ast_channel_name(chan), app_gosub, sub_args);
1083  balance_stack(chan);
1084  pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", "");
1085  }
1086 
1087  /* We executed the requested subroutine to the best of our ability. */
1088  res = 0;
1089  }
1090 
1091  ast_debug(4, "%s Ending location: %s,%s,%d\n", ast_channel_name(chan),
1093  ast_channel_priority(chan));
1094 
1095  /* Restore dialplan location */
1096  if (!(ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO)) {
1097  ast_channel_context_set(chan, saved_context);
1098  ast_channel_exten_set(chan, saved_exten);
1099  ast_channel_priority_set(chan, saved_priority);
1100  }
1101 
1102  /* Restore autoloop flag */
1103  ast_set2_flag(ast_channel_flags(chan), saved_autoloopflag, AST_FLAG_IN_AUTOLOOP);
1104 
1105  /* Restore subroutine flag */
1106  ast_set2_flag(ast_channel_flags(chan), saved_in_subroutine, AST_FLAG_SUBROUTINE_EXEC);
1107 
1108  /* Restore non-hangup softhangup flags. */
1109  if (saved_hangup_flags) {
1110  ast_softhangup_nolock(chan, saved_hangup_flags);
1111  }
1112 
1113  ast_channel_unlock(chan);
1114 
1115  return res;
1116 }
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
static void balance_stack(struct ast_channel *chan)
Definition: app_stack.c:930
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
static const char app_gosub[]
Definition: app_stack.c:232
static const struct ast_datastore_info stack_info
Definition: app_stack.c:239
#define ast_set2_flag(p, value, flag)
Definition: utils.h:94
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define ast_set_flag(p, flag)
Definition: utils.h:70
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
static int gosub_exec(struct ast_channel *chan, const char *data)
Definition: app_stack.c:516
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
Number structure.
Definition: app_followme.c:154
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
Clear a set of softhangup flags from a channel.
Definition: channel.c:2437
#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_channel_exten(const struct ast_channel *chan)
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
#define LOG_NOTICE
Definition: logger.h:263
int ast_softhangup_nolock(struct ast_channel *chan, int reason)
Softly hangup up a channel (no channel lock)
Definition: channel.c:2463
#define ast_channel_unlock(chan)
Definition: channel.h:2946
unsigned int is_special
Definition: app_stack.c:251
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...
int ast_channel_softhangup_internal_flag(struct ast_channel *chan)
void * data
Definition: datastore.h:70
void ast_channel_context_set(struct ast_channel *chan, const char *value)
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
const char * ast_channel_name(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
void ast_channel_priority_set(struct ast_channel *chan, int value)

◆ gosubif_exec()

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

Definition at line 674 of file app_stack.c.

References args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log, AST_NONSTANDARD_RAW_ARGS, ast_strdupa, ast_strlen_zero, cond, gosub_exec(), LOG_WARNING, and pbx_checkcondition().

Referenced by load_module().

675 {
676  char *args;
677  int res=0;
679  AST_APP_ARG(ition);
680  AST_APP_ARG(labels);
681  );
682  AST_DECLARE_APP_ARGS(label,
683  AST_APP_ARG(iftrue);
684  AST_APP_ARG(iffalse);
685  );
686 
687  if (ast_strlen_zero(data)) {
688  ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
689  return 0;
690  }
691 
692  args = ast_strdupa(data);
693  AST_NONSTANDARD_RAW_ARGS(cond, args, '?');
694  if (cond.argc != 2) {
695  ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
696  return 0;
697  }
698 
699  AST_NONSTANDARD_RAW_ARGS(label, cond.labels, ':');
700 
701  if (pbx_checkcondition(cond.ition)) {
702  if (!ast_strlen_zero(label.iftrue))
703  res = gosub_exec(chan, label.iftrue);
704  } else if (!ast_strlen_zero(label.iffalse)) {
705  res = gosub_exec(chan, label.iffalse);
706  }
707 
708  return res;
709 }
#define LOG_WARNING
Definition: logger.h:274
int pbx_checkcondition(const char *condition)
Evaluate a condition.
Definition: pbx.c:8321
const char * args
static int gosub_exec(struct ast_channel *chan, const char *data)
Definition: app_stack.c:516
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
ast_cond_t cond
Definition: app_meetme.c:1090
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
#define AST_NONSTANDARD_RAW_ARGS(args, parse, sep)
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ handle_gosub()

static int handle_gosub ( struct ast_channel chan,
AGI agi,
int  argc,
const char *const *  argv 
)
static

Definition at line 1118 of file app_stack.c.

References app_gosub, ast_agi_send(), ast_asprintf, ast_channel_caller(), ast_channel_context(), ast_channel_context_set(), ast_channel_datastore_find(), ast_channel_exten(), ast_channel_exten_set(), ast_channel_flags(), ast_channel_lock, ast_channel_name(), ast_channel_pbx(), ast_channel_pbx_set(), ast_channel_priority(), ast_channel_priority_set(), ast_channel_unlock, ast_debug, ast_exists_extension(), ast_findlabel_extension(), AST_FLAG_IN_AUTOLOOP, AST_FLAG_SUBROUTINE_EXEC, ast_free, AST_LIST_FIRST, ast_log, ast_pbx_run_args(), ast_set2_flag, ast_set_flag, ast_strdupa, ast_test_flag, ast_verb, balance_stack(), ast_datastore::data, agi_state::fd, gosub_exec(), gosub_stack_frame::is_special, LOG_ERROR, LOG_NOTICE, ast_pbx_args::no_hangup_chan, NULL, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), gosub_stack_frame::priority, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, S_COR, and S_OR.

1119 {
1120  int res;
1121  int priority;
1122  int old_autoloopflag;
1123  int old_in_subroutine;
1124  int old_priority;
1125  const char *old_context;
1126  const char *old_extension;
1127  char *gosub_args;
1128 
1129  if (argc < 4 || argc > 5) {
1130  return RESULT_SHOWUSAGE;
1131  }
1132 
1133  ast_debug(1, "Gosub called with %d arguments: 0:%s 1:%s 2:%s 3:%s 4:%s\n", argc, argv[0], argv[1], argv[2], argv[3], argc == 5 ? argv[4] : "");
1134 
1135  if (sscanf(argv[3], "%30d", &priority) != 1 || priority < 1) {
1136  /* Lookup the priority label */
1137  priority = ast_findlabel_extension(chan, argv[1], argv[2], argv[3],
1138  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
1139  if (priority < 0) {
1140  ast_log(LOG_ERROR, "Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]);
1141  ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
1142  return RESULT_FAILURE;
1143  }
1144  } else if (!ast_exists_extension(chan, argv[1], argv[2], priority,
1145  S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
1146  ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
1147  return RESULT_FAILURE;
1148  }
1149 
1150  if (argc == 5) {
1151  if (ast_asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority, argv[4]) < 0) {
1152  gosub_args = NULL;
1153  }
1154  } else {
1155  if (ast_asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority) < 0) {
1156  gosub_args = NULL;
1157  }
1158  }
1159  if (!gosub_args) {
1160  ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n");
1161  return RESULT_FAILURE;
1162  }
1163 
1164  ast_channel_lock(chan);
1165 
1166  ast_verb(3, "%s AGI %s(%s) start\n", ast_channel_name(chan), app_gosub, gosub_args);
1167 
1168  /* Save autoloop flag */
1169  old_autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
1171 
1172  /* Save subroutine flag */
1173  old_in_subroutine = ast_test_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
1174 
1175  /* Save previous location, since we're going to change it */
1176  old_context = ast_strdupa(ast_channel_context(chan));
1177  old_extension = ast_strdupa(ast_channel_exten(chan));
1178  old_priority = ast_channel_priority(chan);
1179 
1180  ast_debug(4, "%s Original location: %s,%s,%d\n", ast_channel_name(chan),
1181  old_context, old_extension, old_priority);
1182  ast_channel_unlock(chan);
1183 
1184  res = gosub_exec(chan, gosub_args);
1185  if (!res) {
1186  struct ast_datastore *stack_store;
1187 
1188  /* Mark the return location as special. */
1189  ast_channel_lock(chan);
1190  stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
1191  if (!stack_store) {
1192  /* Should never happen! */
1193  ast_log(LOG_ERROR, "No %s stack!\n", app_gosub);
1194  res = -1;
1195  } else {
1196  struct gosub_stack_list *oldlist;
1197  struct gosub_stack_frame *cur;
1198 
1199  oldlist = stack_store->data;
1200  cur = AST_LIST_FIRST(oldlist);
1201  cur->is_special = 1;
1202  }
1203  ast_channel_unlock(chan);
1204  }
1205  if (!res) {
1206  struct ast_pbx *pbx;
1207  struct ast_pbx_args args;
1208  int abnormal_exit;
1209 
1210  memset(&args, 0, sizeof(args));
1211  args.no_hangup_chan = 1;
1212 
1213  ast_channel_lock(chan);
1214 
1215  /* Next dialplan priority. */
1217 
1218  /* Suppress warning about PBX already existing */
1219  pbx = ast_channel_pbx(chan);
1220  ast_channel_pbx_set(chan, NULL);
1221  ast_channel_unlock(chan);
1222 
1223  ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n");
1224  ast_pbx_run_args(chan, &args);
1225 
1226  ast_channel_lock(chan);
1227  ast_free(ast_channel_pbx(chan));
1228  ast_channel_pbx_set(chan, pbx);
1229 
1230  /* Did the routine return? */
1231  if (ast_channel_priority(chan) == old_priority
1232  && !strcmp(ast_channel_context(chan), old_context)
1233  && !strcmp(ast_channel_exten(chan), old_extension)) {
1234  ast_verb(3, "%s AGI %s(%s) complete GOSUB_RETVAL=%s\n",
1235  ast_channel_name(chan), app_gosub, gosub_args,
1236  S_OR(pbx_builtin_getvar_helper(chan, "GOSUB_RETVAL"), ""));
1237  abnormal_exit = 0;
1238  } else {
1239  ast_log(LOG_NOTICE, "%s Abnormal AGI %s(%s) exit. Popping routine return locations.\n",
1240  ast_channel_name(chan), app_gosub, gosub_args);
1241  balance_stack(chan);
1242  pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", "");
1243  abnormal_exit = 1;
1244  }
1245  ast_channel_unlock(chan);
1246 
1247  ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete%s\n",
1248  abnormal_exit ? " (abnormal exit)" : "");
1249  } else {
1250  ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res);
1251  }
1252 
1253  ast_free(gosub_args);
1254 
1255  ast_channel_lock(chan);
1256  ast_debug(4, "%s Ending location: %s,%s,%d\n", ast_channel_name(chan),
1258  ast_channel_priority(chan));
1259 
1260  /* Restore previous location */
1261  ast_channel_context_set(chan, old_context);
1262  ast_channel_exten_set(chan, old_extension);
1263  ast_channel_priority_set(chan, old_priority);
1264 
1265  /* Restore autoloop flag */
1266  ast_set2_flag(ast_channel_flags(chan), old_autoloopflag, AST_FLAG_IN_AUTOLOOP);
1267 
1268  /* Restore subroutine flag */
1269  ast_set2_flag(ast_channel_flags(chan), old_in_subroutine, AST_FLAG_SUBROUTINE_EXEC);
1270  ast_channel_unlock(chan);
1271 
1272  return RESULT_SUCCESS;
1273 }
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
static void balance_stack(struct ast_channel *chan)
Definition: app_stack.c:930
Options for ast_pbx_run()
Definition: pbx.h:391
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
static const char app_gosub[]
Definition: app_stack.c:232
static const struct ast_datastore_info stack_info
Definition: app_stack.c:239
#define ast_set2_flag(p, value, flag)
Definition: utils.h:94
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define RESULT_SHOWUSAGE
Definition: cli.h:41
#define ast_set_flag(p, flag)
Definition: utils.h:70
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
const char * args
#define NULL
Definition: resample.c:96
static int priority
int ast_channel_priority(const struct ast_channel *chan)
#define ast_verb(level,...)
Definition: logger.h:463
static int gosub_exec(struct ast_channel *chan, const char *data)
Definition: app_stack.c:516
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_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:269
Number structure.
Definition: app_followme.c:154
Definition: pbx.h:211
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args)
Execute the PBX in the current thread.
Definition: pbx.c:4739
#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)
#define LOG_ERROR
Definition: logger.h:285
int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
Find the priority of an extension that has the specified label.
Definition: pbx.c:4184
int fd
Definition: agi.h:35
#define LOG_NOTICE
Definition: logger.h:263
#define ast_channel_unlock(chan)
Definition: channel.h:2946
#define ast_free(a)
Definition: astmm.h:182
void ast_channel_pbx_set(struct ast_channel *chan, struct ast_pbx *value)
unsigned int is_special
Definition: app_stack.c:251
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...
void * data
Definition: datastore.h:70
void ast_channel_context_set(struct ast_channel *chan, const char *value)
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
const char * ast_channel_name(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
int AST_OPTIONAL_API_NAME() ast_agi_send(int fd, struct ast_channel *chan, char *fmt,...)
Definition: res_agi.c:1486
void ast_channel_priority_set(struct ast_channel *chan, int value)
#define RESULT_SUCCESS
Definition: cli.h:40
#define RESULT_FAILURE
Definition: cli.h:42

◆ load_module()

static int load_module ( void  )
static

Definition at line 1295 of file app_stack.c.

References app_gosub, app_gosubif, app_pop, app_return, ast_agi_register(), ast_custom_function_register, ast_install_stack_functions(), AST_MODFLAG_DEFAULT, AST_MODFLAG_LOAD_ORDER, AST_MODPRI_APP_DEPEND, AST_MODULE_INFO(), AST_MODULE_SUPPORT_CORE, ast_register_application_xml, ASTERISK_GPL_KEY, expand_gosub_args(), gosub_exec(), gosub_run(), gosubif_exec(), ast_app_stack_funcs::module, pop_exec(), return_exec(), ast_app_stack_funcs::run_sub, ast_module_info::self, and unload_module().

1296 {
1297  /* Setup the stack application callback functions. */
1298  static struct ast_app_stack_funcs funcs = {
1299  .run_sub = gosub_run,
1300  .expand_sub_args = expand_gosub_args,
1301  };
1302 
1304 
1312 
1313  funcs.module = ast_module_info->self,
1315 
1316  return 0;
1317 }
void ast_install_stack_functions(const struct ast_app_stack_funcs *funcs)
Set stack application function callbacks.
Definition: main/app.c:346
static const char app_gosub[]
Definition: app_stack.c:232
static int pop_exec(struct ast_channel *chan, const char *data)
Definition: app_stack.c:345
static int gosub_exec(struct ast_channel *chan, const char *data)
Definition: app_stack.c:516
static int return_exec(struct ast_channel *chan, const char *data)
Definition: app_stack.c:380
static struct ast_custom_function stackpeek_function
Definition: app_stack.c:914
static int gosubif_exec(struct ast_channel *chan, const char *data)
Definition: app_stack.c:674
static const char * expand_gosub_args(struct ast_channel *chan, const char *args)
Definition: app_stack.c:450
static const char app_return[]
Definition: app_stack.c:234
struct ast_module * self
Definition: module.h:342
int AST_OPTIONAL_API_NAME() ast_agi_register(struct ast_module *mod, agi_command *cmd)
Definition: res_agi.c:3783
static struct ast_custom_function peek_function
Definition: app_stack.c:824
Stack applications callback functions.
static int gosub_run(struct ast_channel *chan, const char *sub_args, int ignore_hangup)
Definition: app_stack.c:970
static struct agi_command gosub_agi_command
Definition: app_stack.c:1275
int(* run_sub)(struct ast_channel *chan, const char *args, int ignore_hangup)
Callback for the routine to run a subroutine on a channel.
static const char app_pop[]
Definition: app_stack.c:235
static const char app_gosubif[]
Definition: app_stack.c:233
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1508
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
static struct ast_custom_function local_function
Definition: app_stack.c:783

◆ local_read()

static int local_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Definition at line 711 of file app_stack.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_LIST_FIRST, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_var_name(), ast_datastore::data, gosub_stack_frame::entries, LOG_WARNING, NULL, pbx_builtin_getvar_helper(), S_OR, tmp(), and gosub_stack_frame::varshead.

712 {
713  struct ast_datastore *stack_store;
714  struct gosub_stack_list *oldlist;
715  struct gosub_stack_frame *frame;
716  struct ast_var_t *variables;
717 
718  if (!chan) {
719  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
720  return -1;
721  }
722 
723  ast_channel_lock(chan);
724  if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
725  ast_channel_unlock(chan);
726  return -1;
727  }
728 
729  oldlist = stack_store->data;
730  AST_LIST_LOCK(oldlist);
731  if (!(frame = AST_LIST_FIRST(oldlist))) {
732  /* Not within a Gosub routine */
733  AST_LIST_UNLOCK(oldlist);
734  ast_channel_unlock(chan);
735  return -1;
736  }
737 
738  AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
739  if (!strcmp(data, ast_var_name(variables))) {
740  const char *tmp;
741  tmp = pbx_builtin_getvar_helper(chan, data);
742  ast_copy_string(buf, S_OR(tmp, ""), len);
743  break;
744  }
745  }
746  AST_LIST_UNLOCK(oldlist);
747  ast_channel_unlock(chan);
748  return 0;
749 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
struct varshead varshead
Definition: app_stack.c:248
static const struct ast_datastore_info stack_info
Definition: app_stack.c:239
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
const char * ast_var_name(const struct ast_var_t *var)
Definition: chanvars.c:60
#define LOG_WARNING
Definition: logger.h:274
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
static int tmp()
Definition: bt_open.c:389
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
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_log
Definition: astobj2.c:42
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define ast_channel_unlock(chan)
Definition: channel.h:2946
struct ast_var_t::@249 entries
void * data
Definition: datastore.h:70
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79

◆ local_write()

static int local_write ( struct ast_channel chan,
const char *  cmd,
char *  var,
const char *  value 
)
static

Definition at line 751 of file app_stack.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_LIST_FIRST, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log, ast_datastore::data, frame_set_var(), LOG_ERROR, LOG_WARNING, and NULL.

752 {
753  struct ast_datastore *stack_store;
754  struct gosub_stack_list *oldlist;
755  struct gosub_stack_frame *frame;
756 
757  if (!chan) {
758  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
759  return -1;
760  }
761 
762  ast_channel_lock(chan);
763  if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
764  ast_log(LOG_ERROR, "Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var);
765  ast_channel_unlock(chan);
766  return -1;
767  }
768 
769  oldlist = stack_store->data;
770  AST_LIST_LOCK(oldlist);
771  frame = AST_LIST_FIRST(oldlist);
772 
773  if (frame) {
774  frame_set_var(chan, frame, var, value);
775  }
776 
777  AST_LIST_UNLOCK(oldlist);
778  ast_channel_unlock(chan);
779 
780  return 0;
781 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
static const struct ast_datastore_info stack_info
Definition: app_stack.c:239
#define LOG_WARNING
Definition: logger.h:274
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
#define var
Definition: ast_expr2f.c:614
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
static int frame_set_var(struct ast_channel *chan, struct gosub_stack_frame *frame, const char *var, const char *value)
Definition: app_stack.c:260
#define NULL
Definition: resample.c:96
int value
Definition: syslog.c:37
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285
#define ast_channel_unlock(chan)
Definition: channel.h:2946
void * data
Definition: datastore.h:70

◆ peek_read()

static int peek_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
)
static

Definition at line 789 of file app_stack.c.

References args, AST_APP_ARG, ast_channel_lock, ast_channel_unlock, ast_channel_varshead(), ast_copy_string(), AST_DECLARE_APP_ARGS, AST_LIST_TRAVERSE, ast_log, AST_STANDARD_RAW_ARGS, ast_strlen_zero, ast_var_name(), ast_var_value(), gosub_stack_frame::entries, LOG_ERROR, and name.

790 {
791  int found = 0, n;
792  struct ast_var_t *variables;
794  AST_APP_ARG(n);
795  AST_APP_ARG(name);
796  );
797 
798  if (!chan) {
799  ast_log(LOG_ERROR, "LOCAL_PEEK must be called on an active channel\n");
800  return -1;
801  }
802 
804 
805  if (ast_strlen_zero(args.n) || ast_strlen_zero(args.name)) {
806  ast_log(LOG_ERROR, "LOCAL_PEEK requires parameters n and varname\n");
807  return -1;
808  }
809 
810  n = atoi(args.n);
811  *buf = '\0';
812 
813  ast_channel_lock(chan);
814  AST_LIST_TRAVERSE(ast_channel_varshead(chan), variables, entries) {
815  if (!strcmp(args.name, ast_var_name(variables)) && ++found > n) {
816  ast_copy_string(buf, ast_var_value(variables), len);
817  break;
818  }
819  }
820  ast_channel_unlock(chan);
821  return 0;
822 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
const char * ast_var_value(const struct ast_var_t *var)
Definition: chanvars.c:80
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
const char * ast_var_name(const struct ast_var_t *var)
Definition: chanvars.c:60
#define AST_STANDARD_RAW_ARGS(args, parse)
struct varshead * ast_channel_varshead(struct ast_channel *chan)
const char * args
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
Definition: logger.h:285
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define ast_channel_unlock(chan)
Definition: channel.h:2946
static const char name[]
Definition: cdr_mysql.c:74
struct ast_var_t::@249 entries
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ pop_exec()

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

Definition at line 345 of file app_stack.c.

References app_pop, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_debug, AST_LIST_FIRST, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log, ast_datastore::data, gosub_stack_frame::entries, gosub_release_frame(), gosub_stack_frame::is_special, LOG_WARNING, and NULL.

Referenced by load_module().

346 {
347  struct ast_datastore *stack_store;
348  struct gosub_stack_frame *oldframe;
349  struct gosub_stack_list *oldlist;
350  int res = 0;
351 
352  ast_channel_lock(chan);
353  if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
354  ast_log(LOG_WARNING, "%s called with no gosub stack allocated.\n", app_pop);
355  ast_channel_unlock(chan);
356  return 0;
357  }
358 
359  oldlist = stack_store->data;
360  AST_LIST_LOCK(oldlist);
361  oldframe = AST_LIST_FIRST(oldlist);
362  if (oldframe) {
363  if (oldframe->is_special) {
364  ast_debug(1, "%s attempted to pop special return location.\n", app_pop);
365 
366  /* Abort the special routine dialplan execution. Dialplan programming error. */
367  res = -1;
368  } else {
369  AST_LIST_REMOVE_HEAD(oldlist, entries);
370  gosub_release_frame(chan, oldframe);
371  }
372  } else {
373  ast_debug(1, "%s called with an empty gosub stack\n", app_pop);
374  }
375  AST_LIST_UNLOCK(oldlist);
376  ast_channel_unlock(chan);
377  return res;
378 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
static const struct ast_datastore_info stack_info
Definition: app_stack.c:239
#define LOG_WARNING
Definition: logger.h:274
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
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
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
#define ast_channel_unlock(chan)
Definition: channel.h:2946
unsigned int is_special
Definition: app_stack.c:251
void * data
Definition: datastore.h:70
static const char app_pop[]
Definition: app_stack.c:235
static void gosub_release_frame(struct ast_channel *chan, struct gosub_stack_frame *frame)
Definition: app_stack.c:294

◆ return_exec()

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

Definition at line 380 of file app_stack.c.

References ast_channel_context_set(), ast_channel_datastore_find(), ast_channel_exten_set(), ast_channel_flags(), ast_channel_lock, ast_channel_priority_set(), ast_channel_unlock, AST_FLAG_IN_AUTOLOOP, AST_FLAG_SUBROUTINE_EXEC, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log, ast_set2_flag, ast_test_flag, gosub_stack_frame::context, ast_datastore::data, gosub_stack_frame::entries, gosub_stack_frame::extension, gosub_release_frame(), gosub_stack_frame::in_subroutine, gosub_stack_frame::is_special, LOG_ERROR, NULL, pbx_builtin_setvar_helper(), gosub_stack_frame::priority, retval, and S_OR.

Referenced by load_module().

381 {
382  struct ast_datastore *stack_store;
383  struct gosub_stack_frame *oldframe;
384  struct gosub_stack_list *oldlist;
385  const char *retval = data;
386  int res = 0;
387 
388  ast_channel_lock(chan);
389  if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
390  ast_log(LOG_ERROR, "Return without Gosub: stack is unallocated\n");
391  ast_channel_unlock(chan);
392  return -1;
393  }
394 
395  oldlist = stack_store->data;
396  AST_LIST_LOCK(oldlist);
397  oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
398  AST_LIST_UNLOCK(oldlist);
399 
400  if (!oldframe) {
401  ast_log(LOG_ERROR, "Return without Gosub: stack is empty\n");
402  ast_channel_unlock(chan);
403  return -1;
404  }
405  if (oldframe->is_special) {
406  /* Exit from special routine. */
407  res = -1;
408  }
409 
410  /*
411  * We cannot use ast_explicit_goto() because we MUST restore
412  * what was there before. Channels that do not have a PBX may
413  * not have the context or exten set.
414  */
415  ast_channel_context_set(chan, oldframe->context);
416  ast_channel_exten_set(chan, oldframe->extension);
418  --oldframe->priority;
419  }
420  ast_channel_priority_set(chan, oldframe->priority);
422 
423  gosub_release_frame(chan, oldframe);
424 
425  /* Set a return value, if any */
426  pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", S_OR(retval, ""));
427  ast_channel_unlock(chan);
428  return res;
429 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
unsigned int in_subroutine
Definition: app_stack.c:253
static const struct ast_datastore_info stack_info
Definition: app_stack.c:239
#define ast_set2_flag(p, value, flag)
Definition: utils.h:94
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
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
#define ast_log
Definition: astobj2.c:42
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
#define LOG_ERROR
Definition: logger.h:285
#define ast_channel_unlock(chan)
Definition: channel.h:2946
unsigned int is_special
Definition: app_stack.c:251
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...
void * data
Definition: datastore.h:70
void ast_channel_context_set(struct ast_channel *chan, const char *value)
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
static ENTRY retval
Definition: hsearch.c:50
char extension[0]
Definition: app_stack.c:255
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
void ast_channel_priority_set(struct ast_channel *chan, int value)
static void gosub_release_frame(struct ast_channel *chan, struct gosub_stack_frame *frame)
Definition: app_stack.c:294

◆ stackpeek_read()

static int stackpeek_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
struct ast_str **  str,
ssize_t  len 
)
static

Definition at line 829 of file app_stack.c.

References args, AST_APP_ARG, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_DECLARE_APP_ARGS, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_skip_blanks(), AST_STANDARD_APP_ARGS, ast_str_set(), ast_strdupa, ast_strlen_zero, ast_true(), gosub_stack_frame::context, ast_datastore::data, gosub_stack_frame::entries, gosub_stack_frame::extension, LOG_ERROR, NULL, and gosub_stack_frame::priority.

830 {
831  struct ast_datastore *stack_store;
832  struct gosub_stack_list *oldlist;
833  struct gosub_stack_frame *frame;
834  int n;
836  AST_APP_ARG(n);
837  AST_APP_ARG(which);
838  AST_APP_ARG(suppress);
839  );
840 
841  if (!chan) {
842  ast_log(LOG_ERROR, "STACK_PEEK must be called on an active channel\n");
843  return -1;
844  }
845 
846  data = ast_strdupa(data);
848 
849  if (ast_strlen_zero(args.n) || ast_strlen_zero(args.which)) {
850  ast_log(LOG_ERROR, "STACK_PEEK requires parameters n and which\n");
851  return -1;
852  }
853 
854  n = atoi(args.n);
855  if (n <= 0) {
856  ast_log(LOG_ERROR, "STACK_PEEK must be called with a positive peek value\n");
857  return -1;
858  }
859 
860  ast_channel_lock(chan);
861  if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
862  if (!ast_true(args.suppress)) {
863  ast_log(LOG_ERROR, "STACK_PEEK called on a channel without a gosub stack\n");
864  }
865  ast_channel_unlock(chan);
866  return -1;
867  }
868 
869  oldlist = stack_store->data;
870 
871  AST_LIST_LOCK(oldlist);
872  AST_LIST_TRAVERSE(oldlist, frame, entries) {
873  if (--n == 0) {
874  break;
875  }
876  }
877 
878  if (!frame) {
879  /* Too deep */
880  if (!ast_true(args.suppress)) {
881  ast_log(LOG_ERROR, "Stack peek of '%s' is more stack frames than I have\n", args.n);
882  }
883  AST_LIST_UNLOCK(oldlist);
884  ast_channel_unlock(chan);
885  return -1;
886  }
887 
888  args.which = ast_skip_blanks(args.which);
889 
890  switch (args.which[0]) {
891  case 'l': /* label */
892  ast_str_set(str, len, "%s,%s,%d", frame->context, frame->extension, frame->priority - 1);
893  break;
894  case 'c': /* context */
895  ast_str_set(str, len, "%s", frame->context);
896  break;
897  case 'e': /* extension */
898  ast_str_set(str, len, "%s", frame->extension);
899  break;
900  case 'p': /* priority */
901  ast_str_set(str, len, "%d", frame->priority - 1);
902  break;
903  default:
904  ast_log(LOG_ERROR, "Unknown argument '%s' to STACK_PEEK\n", args.which);
905  break;
906  }
907 
908  AST_LIST_UNLOCK(oldlist);
909  ast_channel_unlock(chan);
910 
911  return 0;
912 }
#define ast_channel_lock(chan)
Definition: channel.h:2945
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
static const struct ast_datastore_info stack_info
Definition: app_stack.c:239
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
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
const char * args
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1065
#define ast_log
Definition: astobj2.c:42
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
#define LOG_ERROR
Definition: logger.h:285
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:157
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define ast_channel_unlock(chan)
Definition: channel.h:2946
void * data
Definition: datastore.h:70
struct gosub_stack_frame::@78 entries
char extension[0]
Definition: app_stack.c:255
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1278 of file app_stack.c.

References app_gosub, app_gosubif, app_pop, app_return, ast_agi_unregister(), ast_custom_function_unregister(), ast_install_stack_functions(), ast_unregister_application(), and NULL.

Referenced by load_module().

1279 {
1281 
1283 
1291 
1292  return 0;
1293 }
void ast_install_stack_functions(const struct ast_app_stack_funcs *funcs)
Set stack application function callbacks.
Definition: main/app.c:346
static const char app_gosub[]
Definition: app_stack.c:232
int AST_OPTIONAL_API_NAME() ast_agi_unregister(agi_command *cmd)
Definition: res_agi.c:3827
#define NULL
Definition: resample.c:96
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
static struct ast_custom_function stackpeek_function
Definition: app_stack.c:914
static const char app_return[]
Definition: app_stack.c:234
static struct ast_custom_function peek_function
Definition: app_stack.c:824
static struct agi_command gosub_agi_command
Definition: app_stack.c:1275
static const char app_pop[]
Definition: app_stack.c:235
static const char app_gosubif[]
Definition: app_stack.c:233
static struct ast_custom_function local_function
Definition: app_stack.c:783

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_LOAD_ORDER , .description = "Dialplan subroutines (Gosub, Return, etc)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .optional_modules = "res_agi", }
static

Definition at line 1325 of file app_stack.c.

◆ app_gosub

const char app_gosub[] = "Gosub"
static

◆ app_gosubif

const char app_gosubif[] = "GosubIf"
static

Definition at line 233 of file app_stack.c.

Referenced by load_module(), and unload_module().

◆ app_pop

const char app_pop[] = "StackPop"
static

Definition at line 235 of file app_stack.c.

Referenced by load_module(), pop_exec(), and unload_module().

◆ app_return

const char app_return[] = "Return"
static

Definition at line 234 of file app_stack.c.

Referenced by load_module(), and unload_module().

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1325 of file app_stack.c.

◆ gosub_agi_command

struct agi_command gosub_agi_command
static
Initial value:
=
{ { "gosub", NULL }, handle_gosub, NULL, NULL, 0 }
#define NULL
Definition: resample.c:96
static int handle_gosub(struct ast_channel *chan, AGI *agi, int argc, const char *const *argv)
Definition: app_stack.c:1118

Definition at line 1275 of file app_stack.c.

◆ local_function

struct ast_custom_function local_function
static
Initial value:
= {
.name = "LOCAL",
.write = local_write,
.read = local_read,
}
static int local_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
Definition: app_stack.c:751
static int local_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: app_stack.c:711

Definition at line 783 of file app_stack.c.

◆ peek_function

struct ast_custom_function peek_function
static
Initial value:
= {
.name = "LOCAL_PEEK",
.read = peek_read,
}
static int peek_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: app_stack.c:789

Definition at line 824 of file app_stack.c.

◆ stack_info

const struct ast_datastore_info stack_info
static
Initial value:
= {
.type = "GOSUB",
.destroy = gosub_free,
}
static void gosub_free(void *data)
Definition: app_stack.c:331

Definition at line 239 of file app_stack.c.

◆ stackpeek_function

struct ast_custom_function stackpeek_function
static
Initial value:
= {
.name = "STACK_PEEK",
.read2 = stackpeek_read,
}
static int stackpeek_read(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
Definition: app_stack.c:829

Definition at line 914 of file app_stack.c.