Asterisk - The Open Source Telephony Project GIT-master-a358458
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 = AST_BUILDOPT_SUM, .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 1321 of file app_stack.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1321 of file app_stack.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 1321 of file app_stack.c.

◆ balance_stack()

static void balance_stack ( struct ast_channel chan)
static

Definition at line 926 of file app_stack.c.

927{
928 struct ast_datastore *stack_store;
929 struct gosub_stack_list *oldlist;
930 struct gosub_stack_frame *oldframe;
931 int found;
932
933 stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
934 if (!stack_store) {
935 ast_log(LOG_WARNING, "No %s stack allocated.\n", app_gosub);
936 return;
937 }
938
939 oldlist = stack_store->data;
940 AST_LIST_LOCK(oldlist);
941 do {
942 oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
943 if (!oldframe) {
944 break;
945 }
946 found = oldframe->is_special;
947 gosub_release_frame(chan, oldframe);
948 } while (!found);
949 AST_LIST_UNLOCK(oldlist);
950}
static void gosub_release_frame(struct ast_channel *chan, struct gosub_stack_frame *frame)
Definition: app_stack.c:292
static const char app_gosub[]
Definition: app_stack.c:230
static const struct ast_datastore_info stack_info
Definition: app_stack.c:237
#define ast_log
Definition: astobj2.c:42
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:2399
#define LOG_WARNING
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
#define NULL
Definition: resample.c:96
Structure for a data store object.
Definition: datastore.h:64
void * data
Definition: datastore.h:66
struct gosub_stack_frame::@81 entries
unsigned int is_special
Definition: app_stack.c:249

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, NULL, and stack_info.

Referenced by gosub_run(), and handle_gosub().

◆ expand_gosub_args()

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

Definition at line 448 of file app_stack.c.

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

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

Referenced by load_module().

◆ 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 258 of file app_stack.c.

259{
260 struct ast_var_t *variables;
261 int found = 0;
262 int len;
263 RAII_VAR(char *, local_buffer, NULL, ast_free);
264
265 /* Does this variable already exist? */
266 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
267 if (!strcmp(var, ast_var_name(variables))) {
268 found = 1;
269 break;
270 }
271 }
272
273 if (!found) {
274 if ((variables = ast_var_assign(var, ""))) {
275 AST_LIST_INSERT_HEAD(&frame->varshead, variables, entries);
276 }
278 } else {
280 }
281
282 len = 8 + strlen(var); /* LOCAL() + var */
283 local_buffer = ast_malloc(len);
284 if (!local_buffer) {
285 return 0;
286 }
287 sprintf(local_buffer, "LOCAL(%s)", var);
288 ast_channel_publish_varset(chan, local_buffer, value);
289 return 0;
290}
#define var
Definition: ast_expr2f.c:605
#define ast_free(a)
Definition: astmm.h:180
const char * ast_var_name(const struct ast_var_t *var)
Definition: chanvars.c:60
#define ast_var_assign(name, value)
Definition: chanvars.h:40
void ast_channel_publish_varset(struct ast_channel *chan, const char *variable, const char *value)
Publish a ast_channel_publish_varset for a channel.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
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 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.
struct ast_var_t::@211 entries
struct varshead varshead
Definition: app_stack.c:246
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:941

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

Referenced by gosub_exec(), and local_write().

◆ 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 311 of file app_stack.c.

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

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

Referenced by gosub_exec().

◆ gosub_exec()

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

Definition at line 514 of file app_stack.c.

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

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(), S_COR, stack_info, and strsep().

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

◆ gosub_free()

static void gosub_free ( void *  data)
static

Definition at line 329 of file app_stack.c.

330{
331 struct gosub_stack_list *oldlist = data;
332 struct gosub_stack_frame *oldframe;
333
334 AST_LIST_LOCK(oldlist);
335 while ((oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries))) {
336 gosub_release_frame(NULL, oldframe);
337 }
338 AST_LIST_UNLOCK(oldlist);
339 AST_LIST_HEAD_DESTROY(oldlist);
340 ast_free(oldlist);
341}
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
Definition: linkedlists.h:653

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.

◆ gosub_release_frame()

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

Definition at line 292 of file app_stack.c.

293{
294 struct ast_var_t *vardata;
295
296 /* If chan is not defined, then we're calling it as part of gosub_free,
297 * and the channel variables will be deallocated anyway. Otherwise, we're
298 * just releasing a single frame, so we need to clean up the arguments for
299 * that frame, so that we re-expose the variables from the previous frame
300 * that were hidden by this one.
301 */
302 while ((vardata = AST_LIST_REMOVE_HEAD(&frame->varshead, entries))) {
303 if (chan)
305 ast_var_delete(vardata);
306 }
307
308 ast_free(frame);
309}
void ast_var_delete(struct ast_var_t *var)
Definition: extconf.c:2471

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

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

◆ gosub_run()

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

Definition at line 966 of file app_stack.c.

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

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(), ignore_hangup, gosub_stack_frame::is_special, LOG_ERROR, LOG_WARNING, NULL, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), S_COR, S_OR, and stack_info.

Referenced by load_module().

◆ gosubif_exec()

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

Definition at line 672 of file app_stack.c.

673{
674 char *args;
675 int res=0;
677 AST_APP_ARG(ition);
678 AST_APP_ARG(labels);
679 );
681 AST_APP_ARG(iftrue);
682 AST_APP_ARG(iffalse);
683 );
684
685 if (ast_strlen_zero(data)) {
686 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
687 return 0;
688 }
689
690 args = ast_strdupa(data);
692 if (cond.argc != 2) {
693 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
694 return 0;
695 }
696
697 AST_NONSTANDARD_RAW_ARGS(label, cond.labels, ':');
698
699 if (pbx_checkcondition(cond.ition)) {
700 if (!ast_strlen_zero(label.iftrue))
701 res = gosub_exec(chan, label.iftrue);
702 } else if (!ast_strlen_zero(label.iffalse)) {
703 res = gosub_exec(chan, label.iffalse);
704 }
705
706 return res;
707}
ast_cond_t cond
Definition: app_sla.c:330
#define AST_NONSTANDARD_RAW_ARGS(args, parse, sep)
int pbx_checkcondition(const char *condition)
Evaluate a condition.
Definition: pbx.c:8282

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().

◆ handle_gosub()

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

Definition at line 1114 of file app_stack.c.

1115{
1116 int res;
1117 int priority;
1118 int old_autoloopflag;
1119 int old_in_subroutine;
1120 int old_priority;
1121 const char *old_context;
1122 const char *old_extension;
1123 char *gosub_args;
1124
1125 if (argc < 4 || argc > 5) {
1126 return RESULT_SHOWUSAGE;
1127 }
1128
1129 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] : "");
1130
1131 if (sscanf(argv[3], "%30d", &priority) != 1 || priority < 1) {
1132 /* Lookup the priority label */
1133 priority = ast_findlabel_extension(chan, argv[1], argv[2], argv[3],
1134 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
1135 if (priority < 0) {
1136 ast_log(LOG_ERROR, "Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]);
1137 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
1138 return RESULT_FAILURE;
1139 }
1140 } else if (!ast_exists_extension(chan, argv[1], argv[2], priority,
1141 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
1142 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
1143 return RESULT_FAILURE;
1144 }
1145
1146 if (argc == 5) {
1147 if (ast_asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority, argv[4]) < 0) {
1148 gosub_args = NULL;
1149 }
1150 } else {
1151 if (ast_asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority) < 0) {
1152 gosub_args = NULL;
1153 }
1154 }
1155 if (!gosub_args) {
1156 ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n");
1157 return RESULT_FAILURE;
1158 }
1159
1160 ast_channel_lock(chan);
1161
1162 ast_verb(3, "%s AGI %s(%s) start\n", ast_channel_name(chan), app_gosub, gosub_args);
1163
1164 /* Save autoloop flag */
1165 old_autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
1167
1168 /* Save subroutine flag */
1169 old_in_subroutine = ast_test_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
1170
1171 /* Save previous location, since we're going to change it */
1172 old_context = ast_strdupa(ast_channel_context(chan));
1173 old_extension = ast_strdupa(ast_channel_exten(chan));
1174 old_priority = ast_channel_priority(chan);
1175
1176 ast_debug(4, "%s Original location: %s,%s,%d\n", ast_channel_name(chan),
1177 old_context, old_extension, old_priority);
1178 ast_channel_unlock(chan);
1179
1180 res = gosub_exec(chan, gosub_args);
1181 if (!res) {
1182 struct ast_datastore *stack_store;
1183
1184 /* Mark the return location as special. */
1185 ast_channel_lock(chan);
1186 stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
1187 if (!stack_store) {
1188 /* Should never happen! */
1189 ast_log(LOG_ERROR, "No %s stack!\n", app_gosub);
1190 res = -1;
1191 } else {
1192 struct gosub_stack_list *oldlist;
1193 struct gosub_stack_frame *cur;
1194
1195 oldlist = stack_store->data;
1196 cur = AST_LIST_FIRST(oldlist);
1197 cur->is_special = 1;
1198 }
1199 ast_channel_unlock(chan);
1200 }
1201 if (!res) {
1202 struct ast_pbx *pbx;
1203 struct ast_pbx_args args;
1204 int abnormal_exit;
1205
1206 memset(&args, 0, sizeof(args));
1207 args.no_hangup_chan = 1;
1208
1209 ast_channel_lock(chan);
1210
1211 /* Next dialplan priority. */
1213
1214 /* Suppress warning about PBX already existing */
1215 pbx = ast_channel_pbx(chan);
1217 ast_channel_unlock(chan);
1218
1219 ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n");
1220 ast_pbx_run_args(chan, &args);
1221
1222 ast_channel_lock(chan);
1224 ast_channel_pbx_set(chan, pbx);
1225
1226 /* Did the routine return? */
1227 if (ast_channel_priority(chan) == old_priority
1228 && !strcmp(ast_channel_context(chan), old_context)
1229 && !strcmp(ast_channel_exten(chan), old_extension)) {
1230 ast_verb(3, "%s AGI %s(%s) complete GOSUB_RETVAL=%s\n",
1231 ast_channel_name(chan), app_gosub, gosub_args,
1232 S_OR(pbx_builtin_getvar_helper(chan, "GOSUB_RETVAL"), ""));
1233 abnormal_exit = 0;
1234 } else {
1235 ast_log(LOG_NOTICE, "%s Abnormal AGI %s(%s) exit. Popping routine return locations.\n",
1236 ast_channel_name(chan), app_gosub, gosub_args);
1237 balance_stack(chan);
1238 pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", "");
1239 abnormal_exit = 1;
1240 }
1241 ast_channel_unlock(chan);
1242
1243 ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete%s\n",
1244 abnormal_exit ? " (abnormal exit)" : "");
1245 } else {
1246 ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res);
1247 }
1248
1249 ast_free(gosub_args);
1250
1251 ast_channel_lock(chan);
1252 ast_debug(4, "%s Ending location: %s,%s,%d\n", ast_channel_name(chan),
1254 ast_channel_priority(chan));
1255
1256 /* Restore previous location */
1257 ast_channel_context_set(chan, old_context);
1258 ast_channel_exten_set(chan, old_extension);
1259 ast_channel_priority_set(chan, old_priority);
1260
1261 /* Restore autoloop flag */
1262 ast_set2_flag(ast_channel_flags(chan), old_autoloopflag, AST_FLAG_IN_AUTOLOOP);
1263
1264 /* Restore subroutine flag */
1265 ast_set2_flag(ast_channel_flags(chan), old_in_subroutine, AST_FLAG_SUBROUTINE_EXEC);
1266 ast_channel_unlock(chan);
1267
1268 return RESULT_SUCCESS;
1269}
int ast_agi_send(int fd, struct ast_channel *chan, char *fmt,...)
Sends a string of text to an application connected via AGI.
Definition: res_agi.c:1481
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
void ast_channel_pbx_set(struct ast_channel *chan, struct ast_pbx *value)
#define RESULT_SHOWUSAGE
Definition: cli.h:41
#define RESULT_SUCCESS
Definition: cli.h:40
#define RESULT_FAILURE
Definition: cli.h:42
#define LOG_NOTICE
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:4180
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:4735
int fd
Definition: agi.h:35
Options for ast_pbx_run()
Definition: pbx.h:407
Definition: pbx.h:214

References app_gosub, args, 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, NULL, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), priority, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, S_COR, S_OR, and stack_info.

◆ load_module()

static int load_module ( void  )
static

Definition at line 1291 of file app_stack.c.

1292{
1293 /* Setup the stack application callback functions. */
1294 static struct ast_app_stack_funcs funcs = {
1295 .run_sub = gosub_run,
1296 .expand_sub_args = expand_gosub_args,
1297 };
1298
1300
1308
1309 funcs.module = ast_module_info->self,
1311
1312 return 0;
1313}
int ast_agi_register(struct ast_module *mod, agi_command *cmd)
Registers an AGI command.
Definition: res_agi.c:3815
static int gosubif_exec(struct ast_channel *chan, const char *data)
Definition: app_stack.c:672
static struct ast_custom_function local_function
Definition: app_stack.c:781
static int gosub_run(struct ast_channel *chan, const char *sub_args, int ignore_hangup)
Definition: app_stack.c:966
static const char * expand_gosub_args(struct ast_channel *chan, const char *args)
Definition: app_stack.c:448
static struct agi_command gosub_agi_command
Definition: app_stack.c:1271
static int return_exec(struct ast_channel *chan, const char *data)
Definition: app_stack.c:378
static const char app_return[]
Definition: app_stack.c:232
static struct ast_custom_function peek_function
Definition: app_stack.c:822
static const char app_gosubif[]
Definition: app_stack.c:231
static const char app_pop[]
Definition: app_stack.c:233
static struct ast_custom_function stackpeek_function
Definition: app_stack.c:912
static int pop_exec(struct ast_channel *chan, const char *data)
Definition: app_stack.c:343
void ast_install_stack_functions(const struct ast_app_stack_funcs *funcs)
Set stack application function callbacks.
Definition: main/app.c:273
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
Stack applications callback functions.
int(* run_sub)(struct ast_channel *chan, const char *args, int ignore_hangup)
Callback for the routine to run a subroutine on a channel.
struct ast_module * self
Definition: module.h:342

References app_gosub, app_gosubif, app_pop, app_return, ast_agi_register(), ast_custom_function_register, ast_install_stack_functions(), ast_register_application_xml, expand_gosub_args(), gosub_agi_command, gosub_exec(), gosub_run(), gosubif_exec(), local_function, ast_app_stack_funcs::module, peek_function, pop_exec(), return_exec(), ast_app_stack_funcs::run_sub, ast_module_info::self, and stackpeek_function.

◆ local_read()

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

Definition at line 709 of file app_stack.c.

710{
711 struct ast_datastore *stack_store;
712 struct gosub_stack_list *oldlist;
713 struct gosub_stack_frame *frame;
714 struct ast_var_t *variables;
715
716 if (!chan) {
717 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
718 return -1;
719 }
720
721 ast_channel_lock(chan);
722 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
723 ast_channel_unlock(chan);
724 return -1;
725 }
726
727 oldlist = stack_store->data;
728 AST_LIST_LOCK(oldlist);
729 if (!(frame = AST_LIST_FIRST(oldlist))) {
730 /* Not within a Gosub routine */
731 AST_LIST_UNLOCK(oldlist);
732 ast_channel_unlock(chan);
733 return -1;
734 }
735
736 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
737 if (!strcmp(data, ast_var_name(variables))) {
738 const char *tmp;
739 tmp = pbx_builtin_getvar_helper(chan, data);
741 break;
742 }
743 }
744 AST_LIST_UNLOCK(oldlist);
745 ast_channel_unlock(chan);
746 return 0;
747}
static int tmp()
Definition: bt_open.c:389
char buf[BUFSIZE]
Definition: eagi_proxy.c:66

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(), buf, ast_datastore::data, ast_var_t::entries, len(), LOG_WARNING, NULL, pbx_builtin_getvar_helper(), S_OR, stack_info, tmp(), and gosub_stack_frame::varshead.

◆ local_write()

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

Definition at line 749 of file app_stack.c.

750{
751 struct ast_datastore *stack_store;
752 struct gosub_stack_list *oldlist;
753 struct gosub_stack_frame *frame;
754
755 if (!chan) {
756 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
757 return -1;
758 }
759
760 ast_channel_lock(chan);
761 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
762 ast_log(LOG_ERROR, "Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var);
763 ast_channel_unlock(chan);
764 return -1;
765 }
766
767 oldlist = stack_store->data;
768 AST_LIST_LOCK(oldlist);
769 frame = AST_LIST_FIRST(oldlist);
770
771 if (frame) {
772 frame_set_var(chan, frame, var, value);
773 }
774
775 AST_LIST_UNLOCK(oldlist);
776 ast_channel_unlock(chan);
777
778 return 0;
779}

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, NULL, stack_info, value, and var.

◆ peek_read()

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

Definition at line 787 of file app_stack.c.

788{
789 int found = 0, n;
790 struct ast_var_t *variables;
792 AST_APP_ARG(n);
794 );
795
796 if (!chan) {
797 ast_log(LOG_ERROR, "LOCAL_PEEK must be called on an active channel\n");
798 return -1;
799 }
800
802
803 if (ast_strlen_zero(args.n) || ast_strlen_zero(args.name)) {
804 ast_log(LOG_ERROR, "LOCAL_PEEK requires parameters n and varname\n");
805 return -1;
806 }
807
808 n = atoi(args.n);
809 *buf = '\0';
810
811 ast_channel_lock(chan);
813 if (!strcmp(args.name, ast_var_name(variables)) && ++found > n) {
814 ast_copy_string(buf, ast_var_value(variables), len);
815 break;
816 }
817 }
818 ast_channel_unlock(chan);
819 return 0;
820}
struct varshead * ast_channel_varshead(struct ast_channel *chan)
const char * ast_var_value(const struct ast_var_t *var)
Definition: chanvars.c:80
static const char name[]
Definition: format_mp3.c:68

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(), buf, ast_var_t::entries, len(), LOG_ERROR, and name.

◆ pop_exec()

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

Definition at line 343 of file app_stack.c.

344{
345 struct ast_datastore *stack_store;
346 struct gosub_stack_frame *oldframe;
347 struct gosub_stack_list *oldlist;
348 int res = 0;
349
350 ast_channel_lock(chan);
351 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
352 ast_log(LOG_WARNING, "%s called with no gosub stack allocated.\n", app_pop);
353 ast_channel_unlock(chan);
354 return 0;
355 }
356
357 oldlist = stack_store->data;
358 AST_LIST_LOCK(oldlist);
359 oldframe = AST_LIST_FIRST(oldlist);
360 if (oldframe) {
361 if (oldframe->is_special) {
362 ast_debug(1, "%s attempted to pop special return location.\n", app_pop);
363
364 /* Abort the special routine dialplan execution. Dialplan programming error. */
365 res = -1;
366 } else {
367 AST_LIST_REMOVE_HEAD(oldlist, entries);
368 gosub_release_frame(chan, oldframe);
369 }
370 } else {
371 ast_debug(1, "%s called with an empty gosub stack\n", app_pop);
372 }
373 AST_LIST_UNLOCK(oldlist);
374 ast_channel_unlock(chan);
375 return res;
376}

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_release_frame(), gosub_stack_frame::is_special, LOG_WARNING, NULL, and stack_info.

Referenced by load_module().

◆ return_exec()

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

Definition at line 378 of file app_stack.c.

379{
380 struct ast_datastore *stack_store;
381 struct gosub_stack_frame *oldframe;
382 struct gosub_stack_list *oldlist;
383 const char *retval = data;
384 int res = 0;
385
386 ast_channel_lock(chan);
387 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
388 ast_log(LOG_ERROR, "Return without Gosub: stack is unallocated\n");
389 ast_channel_unlock(chan);
390 return -1;
391 }
392
393 oldlist = stack_store->data;
394 AST_LIST_LOCK(oldlist);
395 oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
396 AST_LIST_UNLOCK(oldlist);
397
398 if (!oldframe) {
399 ast_log(LOG_ERROR, "Return without Gosub: stack is empty\n");
400 ast_channel_unlock(chan);
401 return -1;
402 }
403 if (oldframe->is_special) {
404 /* Exit from special routine. */
405 res = -1;
406 }
407
408 /*
409 * We cannot use ast_explicit_goto() because we MUST restore
410 * what was there before. Channels that do not have a PBX may
411 * not have the context or exten set.
412 */
413 ast_channel_context_set(chan, oldframe->context);
414 ast_channel_exten_set(chan, oldframe->extension);
416 --oldframe->priority;
417 }
418 ast_channel_priority_set(chan, oldframe->priority);
420
421 gosub_release_frame(chan, oldframe);
422
423 /* Set a return value, if any */
424 pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", S_OR(retval, ""));
425 ast_channel_unlock(chan);
426 return res;
427}
static ENTRY retval
Definition: hsearch.c:50
char extension[0]
Definition: app_stack.c:253

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::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, S_OR, and stack_info.

Referenced by load_module().

◆ 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 827 of file app_stack.c.

828{
829 struct ast_datastore *stack_store;
830 struct gosub_stack_list *oldlist;
831 struct gosub_stack_frame *frame;
832 int n;
834 AST_APP_ARG(n);
835 AST_APP_ARG(which);
836 AST_APP_ARG(suppress);
837 );
838
839 if (!chan) {
840 ast_log(LOG_ERROR, "STACK_PEEK must be called on an active channel\n");
841 return -1;
842 }
843
844 data = ast_strdupa(data);
846
847 if (ast_strlen_zero(args.n) || ast_strlen_zero(args.which)) {
848 ast_log(LOG_ERROR, "STACK_PEEK requires parameters n and which\n");
849 return -1;
850 }
851
852 n = atoi(args.n);
853 if (n <= 0) {
854 ast_log(LOG_ERROR, "STACK_PEEK must be called with a positive peek value\n");
855 return -1;
856 }
857
858 ast_channel_lock(chan);
859 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
860 if (!ast_true(args.suppress)) {
861 ast_log(LOG_ERROR, "STACK_PEEK called on a channel without a gosub stack\n");
862 }
863 ast_channel_unlock(chan);
864 return -1;
865 }
866
867 oldlist = stack_store->data;
868
869 AST_LIST_LOCK(oldlist);
870 AST_LIST_TRAVERSE(oldlist, frame, entries) {
871 if (--n == 0) {
872 break;
873 }
874 }
875
876 if (!frame) {
877 /* Too deep */
878 if (!ast_true(args.suppress)) {
879 ast_log(LOG_ERROR, "Stack peek of '%s' is more stack frames than I have\n", args.n);
880 }
881 AST_LIST_UNLOCK(oldlist);
882 ast_channel_unlock(chan);
883 return -1;
884 }
885
886 args.which = ast_skip_blanks(args.which);
887
888 switch (args.which[0]) {
889 case 'l': /* label */
890 ast_str_set(str, len, "%s,%s,%d", frame->context, frame->extension, frame->priority - 1);
891 break;
892 case 'c': /* context */
893 ast_str_set(str, len, "%s", frame->context);
894 break;
895 case 'e': /* extension */
896 ast_str_set(str, len, "%s", frame->extension);
897 break;
898 case 'p': /* priority */
899 ast_str_set(str, len, "%d", frame->priority - 1);
900 break;
901 default:
902 ast_log(LOG_ERROR, "Unknown argument '%s' to STACK_PEEK\n", args.which);
903 break;
904 }
905
906 AST_LIST_UNLOCK(oldlist);
907 ast_channel_unlock(chan);
908
909 return 0;
910}
const char * str
Definition: app_jack.c:147
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
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:1113
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
Definition: strings.h:161

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, len(), LOG_ERROR, NULL, gosub_stack_frame::priority, stack_info, and str.

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1274 of file app_stack.c.

1275{
1277
1279
1287
1288 return 0;
1289}
int ast_agi_unregister(agi_command *cmd)
Unregisters an AGI command.
Definition: res_agi.c:3859
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.

References app_gosub, app_gosubif, app_pop, app_return, ast_agi_unregister(), ast_custom_function_unregister(), ast_install_stack_functions(), ast_unregister_application(), gosub_agi_command, local_function, NULL, peek_function, and stackpeek_function.

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 = AST_BUILDOPT_SUM, .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 1321 of file app_stack.c.

◆ app_gosub

const char app_gosub[] = "Gosub"
static

◆ app_gosubif

const char app_gosubif[] = "GosubIf"
static

Definition at line 231 of file app_stack.c.

Referenced by load_module(), and unload_module().

◆ app_pop

const char app_pop[] = "StackPop"
static

Definition at line 233 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 232 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 1321 of file app_stack.c.

◆ gosub_agi_command

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

Definition at line 1271 of file app_stack.c.

Referenced by load_module(), and unload_module().

◆ 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:749
static int local_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: app_stack.c:709

Definition at line 781 of file app_stack.c.

Referenced by load_module(), and unload_module().

◆ 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:787

Definition at line 822 of file app_stack.c.

Referenced by load_module(), and unload_module().

◆ 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:329

Definition at line 237 of file app_stack.c.

Referenced by balance_stack(), gosub_exec(), gosub_run(), handle_gosub(), local_read(), local_write(), pop_exec(), return_exec(), and stackpeek_read().

◆ 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:827

Definition at line 912 of file app_stack.c.

Referenced by load_module(), and unload_module().