Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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 1346 of file app_stack.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1346 of file app_stack.c.

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 1346 of file app_stack.c.

◆ balance_stack()

static void balance_stack ( struct ast_channel chan)
static

Definition at line 951 of file app_stack.c.

952{
953 struct ast_datastore *stack_store;
954 struct gosub_stack_list *oldlist;
955 struct gosub_stack_frame *oldframe;
956 int found;
957
958 stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
959 if (!stack_store) {
960 ast_log(LOG_WARNING, "No %s stack allocated.\n", app_gosub);
961 return;
962 }
963
964 oldlist = stack_store->data;
965 AST_LIST_LOCK(oldlist);
966 do {
967 oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
968 if (!oldframe) {
969 break;
970 }
971 found = oldframe->is_special;
972 gosub_release_frame(chan, oldframe);
973 } while (!found);
974 AST_LIST_UNLOCK(oldlist);
975}
static void gosub_release_frame(struct ast_channel *chan, struct gosub_stack_frame *frame)
Definition: app_stack.c:317
static const char app_gosub[]
Definition: app_stack.c:255
static const struct ast_datastore_info stack_info
Definition: app_stack.c:262
#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:2428
#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:274

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

474{
475 int len;
476 char *parse;
477 char *label;
478 char *new_args;
479 const char *context;
480 const char *exten;
481 const char *pri;
482
483 /* Separate the context,exten,pri from the optional routine arguments. */
484 parse = ast_strdupa(args);
485 label = strsep(&parse, "(");
486 if (parse) {
487 char *endparen;
488
489 endparen = strrchr(parse, ')');
490 if (endparen) {
491 *endparen = '\0';
492 } else {
493 ast_log(LOG_WARNING, "Ouch. No closing paren: '%s'?\n", args);
494 }
495 }
496
497 /* Split context,exten,pri */
498 context = strsep(&label, ",");
499 exten = strsep(&label, ",");
500 pri = strsep(&label, ",");
501 if (!exten) {
502 /* Only a priority in this one */
503 pri = context;
504 exten = NULL;
505 context = NULL;
506 } else if (!pri) {
507 /* Only an extension and priority in this one */
508 pri = exten;
509 exten = context;
510 context = NULL;
511 }
512
513 ast_channel_lock(chan);
514 if (ast_strlen_zero(exten)) {
515 exten = ast_channel_exten(chan);
516 }
519 }
520 len = strlen(context) + strlen(exten) + strlen(pri) + 3;
521 if (!ast_strlen_zero(parse)) {
522 len += 2 + strlen(parse);
523 }
524 new_args = ast_malloc(len);
525 if (new_args) {
526 if (ast_strlen_zero(parse)) {
527 snprintf(new_args, len, "%s,%s,%s", context, exten, pri);
528 } else {
529 snprintf(new_args, len, "%s,%s,%s(%s)", context, exten, pri, parse);
530 }
531 }
532 ast_channel_unlock(chan);
533
534 ast_debug(4, "Gosub args:%s new_args:%s\n", args, new_args ? new_args : "");
535
536 return new_args;
537}
char * strsep(char **str, const char *delims)
#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:2970
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:2971
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#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 283 of file app_stack.c.

284{
285 struct ast_var_t *variables;
286 int found = 0;
287 int len;
288 RAII_VAR(char *, local_buffer, NULL, ast_free);
289
290 /* Does this variable already exist? */
291 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
292 if (!strcmp(var, ast_var_name(variables))) {
293 found = 1;
294 break;
295 }
296 }
297
298 if (!found) {
299 if ((variables = ast_var_assign(var, ""))) {
300 AST_LIST_INSERT_HEAD(&frame->varshead, variables, entries);
301 }
303 } else {
305 }
306
307 len = 8 + strlen(var); /* LOCAL() + var */
308 local_buffer = ast_malloc(len);
309 if (!local_buffer) {
310 return 0;
311 }
312 sprintf(local_buffer, "LOCAL(%s)", var);
313 ast_channel_publish_varset(chan, local_buffer, value);
314 return 0;
315}
#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::@213 entries
struct varshead varshead
Definition: app_stack.c:271
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 336 of file app_stack.c.

337{
338 struct gosub_stack_frame *new = NULL;
339 int len_extension = strlen(extension) + 1;
340 int len_context = strlen(context) + 1;
341
342 if ((new = ast_calloc(1, sizeof(*new) + len_extension + len_context))) {
343 AST_LIST_HEAD_INIT_NOLOCK(&new->varshead);
344 ast_copy_string(new->extension, extension, len_extension);
345 new->context = new->extension + len_extension;
346 ast_copy_string(new->context, context, len_context);
347 new->priority = priority;
348 new->in_subroutine = in_subroutine ? 1 : 0;
349 new->arguments = arguments;
350 }
351 return new;
352}
#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:270
unsigned int in_subroutine
Definition: app_stack.c:276

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

540{
541 struct ast_datastore *stack_store;
542 struct gosub_stack_list *oldlist;
543 struct gosub_stack_frame *newframe;
544 struct gosub_stack_frame *lastframe;
545 char argname[15];
546 char *parse;
547 char *label;
548 char *caller_id;
549 char *orig_context;
550 char *orig_exten;
551 char *dest_context;
552 char *dest_exten;
553 int orig_in_subroutine;
554 int orig_priority;
555 int dest_priority;
556 int i;
557 int max_argc = 0;
559 AST_APP_ARG(argval)[100];
560 );
561
562 if (ast_strlen_zero(data)) {
563 ast_log(LOG_ERROR, "%s requires an argument: %s([[context,]exten,]priority[(arg1[,...][,argN])])\n", app_gosub, app_gosub);
564 return -1;
565 }
566
567 /*
568 * Separate the arguments from the label
569 *
570 * NOTE: You cannot use ast_app_separate_args for this, because
571 * '(' cannot be used as a delimiter.
572 */
573 parse = ast_strdupa(data);
574 label = strsep(&parse, "(");
575 if (parse) {
576 char *endparen;
577
578 endparen = strrchr(parse, ')');
579 if (endparen) {
580 *endparen = '\0';
581 } else {
582 ast_log(LOG_WARNING, "Ouch. No closing paren: '%s'?\n", data);
583 }
584 AST_STANDARD_RAW_ARGS(args2, parse);
585 } else {
586 args2.argc = 0;
587 }
588
589 ast_channel_lock(chan);
590 orig_context = ast_strdupa(ast_channel_context(chan));
592 orig_priority = ast_channel_priority(chan);
593 orig_in_subroutine = ast_test_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
594 ast_channel_unlock(chan);
595
596 if (ast_parseable_goto(chan, label)) {
597 ast_log(LOG_ERROR, "%s address is invalid: '%s'\n", app_gosub, data);
598 goto error_exit;
599 }
600
601 ast_channel_lock(chan);
602 dest_context = ast_strdupa(ast_channel_context(chan));
603 dest_exten = ast_strdupa(ast_channel_exten(chan));
604 dest_priority = ast_channel_priority(chan);
606 ++dest_priority;
607 }
608 caller_id = S_COR(ast_channel_caller(chan)->id.number.valid,
609 ast_channel_caller(chan)->id.number.str, NULL);
610 if (caller_id) {
611 caller_id = ast_strdupa(caller_id);
612 }
613 ast_channel_unlock(chan);
614
615 if (!ast_exists_extension(chan, dest_context, dest_exten, dest_priority, caller_id)) {
616 ast_log(LOG_ERROR, "%s attempted to reach non-existent destination '%s,%s,%d' from '%s,%s,%d'",
617 app_gosub, dest_context, dest_exten, dest_priority, orig_context, orig_exten, orig_priority);
618 goto error_exit;
619 }
620
621 /* Now we know that we're going to a new location */
622
623 ast_channel_lock(chan);
624
625 /* Find stack datastore return list. */
626 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
627 ast_debug(1, "Channel %s has no datastore, so we're allocating one.\n",
628 ast_channel_name(chan));
629 stack_store = ast_datastore_alloc(&stack_info, NULL);
630 if (!stack_store) {
631 ast_log(LOG_ERROR, "Unable to allocate new datastore. %s failed.\n",
632 app_gosub);
633 goto error_exit_locked;
634 }
635
636 oldlist = ast_calloc(1, sizeof(*oldlist));
637 if (!oldlist) {
638 ast_log(LOG_ERROR, "Unable to allocate datastore list head. %s failed.\n",
639 app_gosub);
640 ast_datastore_free(stack_store);
641 goto error_exit_locked;
642 }
643 AST_LIST_HEAD_INIT(oldlist);
644
645 stack_store->data = oldlist;
646 ast_channel_datastore_add(chan, stack_store);
647 } else {
648 oldlist = stack_store->data;
649 }
650
651 if ((lastframe = AST_LIST_FIRST(oldlist))) {
652 max_argc = lastframe->arguments;
653 }
654
655 /* Mask out previous Gosub arguments in this invocation */
656 if (args2.argc > max_argc) {
657 max_argc = args2.argc;
658 }
659
660 /* Create the return address */
661 newframe = gosub_allocate_frame(orig_context, orig_exten, orig_priority + 1, orig_in_subroutine, max_argc);
662 if (!newframe) {
663 goto error_exit_locked;
664 }
665
666 /* Set our arguments */
667 for (i = 0; i < max_argc; i++) {
668 snprintf(argname, sizeof(argname), "ARG%d", i + 1);
669 frame_set_var(chan, newframe, argname, i < args2.argc ? args2.argval[i] : "");
670 ast_debug(1, "Setting '%s' to '%s'\n", argname, i < args2.argc ? args2.argval[i] : "");
671 }
672 snprintf(argname, sizeof(argname), "%u", args2.argc);
673 frame_set_var(chan, newframe, "ARGC", argname);
674
676
677 /* And finally, save our return address */
678 AST_LIST_LOCK(oldlist);
679 AST_LIST_INSERT_HEAD(oldlist, newframe, entries);
680 AST_LIST_UNLOCK(oldlist);
681 ast_channel_unlock(chan);
682
683 return 0;
684
685error_exit:
686 ast_channel_lock(chan);
687
688error_exit_locked:
689 /* Restore the original dialplan location. */
690 ast_channel_context_set(chan, orig_context);
692 ast_channel_priority_set(chan, orig_priority);
693 ast_channel_unlock(chan);
694 return -1;
695}
static int frame_set_var(struct ast_channel *chan, struct gosub_stack_frame *frame, const char *var, const char *value)
Definition: app_stack.c:283
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:336
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:2414
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
int ast_channel_priority(const struct ast_channel *chan)
@ AST_FLAG_IN_AUTOLOOP
Definition: channel.h:1017
@ AST_FLAG_SUBROUTINE_EXEC
Definition: channel.h:1078
void ast_channel_context_set(struct ast_channel *chan, const char *value)
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:4190
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
Definition: pbx.c:8881
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:157
#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 354 of file app_stack.c.

355{
356 struct gosub_stack_list *oldlist = data;
357 struct gosub_stack_frame *oldframe;
358
359 AST_LIST_LOCK(oldlist);
360 while ((oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries))) {
361 gosub_release_frame(NULL, oldframe);
362 }
363 AST_LIST_UNLOCK(oldlist);
364 AST_LIST_HEAD_DESTROY(oldlist);
365 ast_free(oldlist);
366}
#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 317 of file app_stack.c.

318{
319 struct ast_var_t *vardata;
320
321 /* If chan is not defined, then we're calling it as part of gosub_free,
322 * and the channel variables will be deallocated anyway. Otherwise, we're
323 * just releasing a single frame, so we need to clean up the arguments for
324 * that frame, so that we re-expose the variables from the previous frame
325 * that were hidden by this one.
326 */
327 while ((vardata = AST_LIST_REMOVE_HEAD(&frame->varshead, entries))) {
328 if (chan)
330 ast_var_delete(vardata);
331 }
332
333 ast_free(frame);
334}
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 991 of file app_stack.c.

992{
993 const char *saved_context;
994 const char *saved_exten;
995 int saved_priority;
996 int saved_hangup_flags;
997 int saved_autoloopflag;
998 int saved_in_subroutine;
999 int res;
1000
1001 ast_channel_lock(chan);
1002
1003 ast_verb(3, "%s Internal %s(%s) start\n",
1004 ast_channel_name(chan), app_gosub, sub_args);
1005
1006 /* Save non-hangup softhangup flags. */
1007 saved_hangup_flags = ast_channel_softhangup_internal_flag(chan)
1009 if (saved_hangup_flags) {
1011 }
1012
1013 /* Save autoloop flag */
1014 saved_autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
1016
1017 /* Save current dialplan location */
1018 saved_context = ast_strdupa(ast_channel_context(chan));
1019 saved_exten = ast_strdupa(ast_channel_exten(chan));
1020 saved_priority = ast_channel_priority(chan);
1021
1022 /* Save whether or not we are in a subroutine */
1023 saved_in_subroutine = ast_test_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
1024
1025 ast_debug(4, "%s Original location: %s,%s,%d\n", ast_channel_name(chan),
1026 saved_context, saved_exten, saved_priority);
1027
1028 ast_channel_unlock(chan);
1029 res = gosub_exec(chan, sub_args);
1030 ast_debug(4, "%s exited with status %d\n", app_gosub, res);
1031 ast_channel_lock(chan);
1032 if (!res) {
1033 struct ast_datastore *stack_store;
1034
1035 /* Mark the return location as special. */
1036 stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
1037 if (!stack_store) {
1038 /* Should never happen! */
1039 ast_log(LOG_ERROR, "No %s stack!\n", app_gosub);
1040 res = -1;
1041 } else {
1042 struct gosub_stack_list *oldlist;
1043 struct gosub_stack_frame *cur;
1044
1045 oldlist = stack_store->data;
1046 cur = AST_LIST_FIRST(oldlist);
1047 cur->is_special = 1;
1048 }
1049 }
1050 if (!res) {
1051 int found = 0; /* set if we find at least one match */
1052
1053 /*
1054 * Run gosub body autoloop.
1055 *
1056 * Note that this loop is inverted from the normal execution
1057 * loop because we just executed the Gosub application as the
1058 * first extension of the autoloop.
1059 */
1060 do {
1061 /* Check for hangup. */
1062 if (ast_check_hangup(chan)) {
1064 ast_log(LOG_ERROR, "%s An async goto just messed up our execution location.\n",
1065 ast_channel_name(chan));
1066 break;
1067 }
1068 if (!ignore_hangup) {
1069 break;
1070 }
1071 }
1072
1073 /* Next dialplan priority. */
1075
1076 ast_channel_unlock(chan);
1077 res = ast_spawn_extension(chan, ast_channel_context(chan),
1079 S_COR(ast_channel_caller(chan)->id.number.valid,
1080 ast_channel_caller(chan)->id.number.str, NULL),
1081 &found, 1);
1082 ast_channel_lock(chan);
1083 } while (!res);
1084 if (found && res) {
1085 /* Something bad happened, or a hangup has been requested. */
1086 ast_debug(1, "Spawn extension (%s,%s,%d) exited with %d on '%s'\n",
1088 ast_channel_priority(chan), res, ast_channel_name(chan));
1089 ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n",
1092 }
1093
1094 /* Did the routine return? */
1095 if (ast_channel_priority(chan) == saved_priority
1096 && !strcmp(ast_channel_context(chan), saved_context)
1097 && !strcmp(ast_channel_exten(chan), saved_exten)) {
1098 ast_verb(3, "%s Internal %s(%s) complete GOSUB_RETVAL=%s\n",
1099 ast_channel_name(chan), app_gosub, sub_args,
1100 S_OR(pbx_builtin_getvar_helper(chan, "GOSUB_RETVAL"), ""));
1101 } else {
1102 ast_log(LOG_WARNING, "%s Abnormal '%s(%s)' exit. Popping routine return locations.\n",
1103 ast_channel_name(chan), app_gosub, sub_args);
1104 balance_stack(chan);
1105 pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", "");
1106 }
1107
1108 /* We executed the requested subroutine to the best of our ability. */
1109 res = 0;
1110 }
1111
1112 ast_debug(4, "%s Ending location: %s,%s,%d\n", ast_channel_name(chan),
1114 ast_channel_priority(chan));
1115
1116 /* Restore dialplan location */
1118 ast_channel_context_set(chan, saved_context);
1119 ast_channel_exten_set(chan, saved_exten);
1120 ast_channel_priority_set(chan, saved_priority);
1121 }
1122
1123 /* Restore autoloop flag */
1124 ast_set2_flag(ast_channel_flags(chan), saved_autoloopflag, AST_FLAG_IN_AUTOLOOP);
1125
1126 /* Restore subroutine flag */
1127 ast_set2_flag(ast_channel_flags(chan), saved_in_subroutine, AST_FLAG_SUBROUTINE_EXEC);
1128
1129 /* Restore non-hangup softhangup flags. */
1130 if (saved_hangup_flags) {
1131 ast_softhangup_nolock(chan, saved_hangup_flags);
1132 }
1133
1134 ast_channel_unlock(chan);
1135
1136 return res;
1137}
@ ignore_hangup
static int gosub_exec(struct ast_channel *chan, const char *data)
Definition: app_stack.c:539
static void balance_stack(struct ast_channel *chan)
Definition: app_stack.c:951
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
Clear a set of softhangup flags from a channel.
Definition: channel.c:2461
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:445
int ast_softhangup_nolock(struct ast_channel *chan, int cause)
Softly hangup up a channel (no channel lock)
Definition: channel.c:2487
int ast_channel_softhangup_internal_flag(struct ast_channel *chan)
@ AST_SOFTHANGUP_ASYNCGOTO
Definition: channel.h:1146
#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:4215
#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 697 of file app_stack.c.

698{
699 char *args;
700 int res=0;
702 AST_APP_ARG(ition);
703 AST_APP_ARG(labels);
704 );
706 AST_APP_ARG(iftrue);
707 AST_APP_ARG(iffalse);
708 );
709
710 if (ast_strlen_zero(data)) {
711 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
712 return 0;
713 }
714
715 args = ast_strdupa(data);
717 if (cond.argc != 2) {
718 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
719 return 0;
720 }
721
722 AST_NONSTANDARD_RAW_ARGS(label, cond.labels, ':');
723
724 if (pbx_checkcondition(cond.ition)) {
725 if (!ast_strlen_zero(label.iftrue))
726 res = gosub_exec(chan, label.iftrue);
727 } else if (!ast_strlen_zero(label.iffalse)) {
728 res = gosub_exec(chan, label.iffalse);
729 }
730
731 return res;
732}
ast_cond_t cond
Definition: app_sla.c:336
#define AST_NONSTANDARD_RAW_ARGS(args, parse, sep)
int pbx_checkcondition(const char *condition)
Evaluate a condition.
Definition: pbx.c:8297

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

1140{
1141 int res;
1142 int priority;
1143 int old_autoloopflag;
1144 int old_in_subroutine;
1145 int old_priority;
1146 const char *old_context;
1147 const char *old_extension;
1148 char *gosub_args;
1149
1150 if (argc < 4 || argc > 5) {
1151 return RESULT_SHOWUSAGE;
1152 }
1153
1154 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] : "");
1155
1156 if (sscanf(argv[3], "%30d", &priority) != 1 || priority < 1) {
1157 /* Lookup the priority label */
1158 priority = ast_findlabel_extension(chan, argv[1], argv[2], argv[3],
1159 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
1160 if (priority < 0) {
1161 ast_log(LOG_ERROR, "Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]);
1162 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
1163 return RESULT_FAILURE;
1164 }
1165 } else if (!ast_exists_extension(chan, argv[1], argv[2], priority,
1166 S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
1167 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
1168 return RESULT_FAILURE;
1169 }
1170
1171 if (argc == 5) {
1172 if (ast_asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority, argv[4]) < 0) {
1173 gosub_args = NULL;
1174 }
1175 } else {
1176 if (ast_asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority) < 0) {
1177 gosub_args = NULL;
1178 }
1179 }
1180 if (!gosub_args) {
1181 ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n");
1182 return RESULT_FAILURE;
1183 }
1184
1185 ast_channel_lock(chan);
1186
1187 ast_verb(3, "%s AGI %s(%s) start\n", ast_channel_name(chan), app_gosub, gosub_args);
1188
1189 /* Save autoloop flag */
1190 old_autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
1192
1193 /* Save subroutine flag */
1194 old_in_subroutine = ast_test_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
1195
1196 /* Save previous location, since we're going to change it */
1197 old_context = ast_strdupa(ast_channel_context(chan));
1198 old_extension = ast_strdupa(ast_channel_exten(chan));
1199 old_priority = ast_channel_priority(chan);
1200
1201 ast_debug(4, "%s Original location: %s,%s,%d\n", ast_channel_name(chan),
1202 old_context, old_extension, old_priority);
1203 ast_channel_unlock(chan);
1204
1205 res = gosub_exec(chan, gosub_args);
1206 if (!res) {
1207 struct ast_datastore *stack_store;
1208
1209 /* Mark the return location as special. */
1210 ast_channel_lock(chan);
1211 stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
1212 if (!stack_store) {
1213 /* Should never happen! */
1214 ast_log(LOG_ERROR, "No %s stack!\n", app_gosub);
1215 res = -1;
1216 } else {
1217 struct gosub_stack_list *oldlist;
1218 struct gosub_stack_frame *cur;
1219
1220 oldlist = stack_store->data;
1221 cur = AST_LIST_FIRST(oldlist);
1222 cur->is_special = 1;
1223 }
1224 ast_channel_unlock(chan);
1225 }
1226 if (!res) {
1227 struct ast_pbx *pbx;
1228 struct ast_pbx_args args;
1229 int abnormal_exit;
1230
1231 memset(&args, 0, sizeof(args));
1232 args.no_hangup_chan = 1;
1233
1234 ast_channel_lock(chan);
1235
1236 /* Next dialplan priority. */
1238
1239 /* Suppress warning about PBX already existing */
1240 pbx = ast_channel_pbx(chan);
1242 ast_channel_unlock(chan);
1243
1244 ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n");
1245 ast_pbx_run_args(chan, &args);
1246
1247 ast_channel_lock(chan);
1249 ast_channel_pbx_set(chan, pbx);
1250
1251 /* Did the routine return? */
1252 if (ast_channel_priority(chan) == old_priority
1253 && !strcmp(ast_channel_context(chan), old_context)
1254 && !strcmp(ast_channel_exten(chan), old_extension)) {
1255 ast_verb(3, "%s AGI %s(%s) complete GOSUB_RETVAL=%s\n",
1256 ast_channel_name(chan), app_gosub, gosub_args,
1257 S_OR(pbx_builtin_getvar_helper(chan, "GOSUB_RETVAL"), ""));
1258 abnormal_exit = 0;
1259 } else {
1260 ast_log(LOG_NOTICE, "%s Abnormal AGI %s(%s) exit. Popping routine return locations.\n",
1261 ast_channel_name(chan), app_gosub, gosub_args);
1262 balance_stack(chan);
1263 pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", "");
1264 abnormal_exit = 1;
1265 }
1266 ast_channel_unlock(chan);
1267
1268 ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete%s\n",
1269 abnormal_exit ? " (abnormal exit)" : "");
1270 } else {
1271 ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res);
1272 }
1273
1274 ast_free(gosub_args);
1275
1276 ast_channel_lock(chan);
1277 ast_debug(4, "%s Ending location: %s,%s,%d\n", ast_channel_name(chan),
1279 ast_channel_priority(chan));
1280
1281 /* Restore previous location */
1282 ast_channel_context_set(chan, old_context);
1283 ast_channel_exten_set(chan, old_extension);
1284 ast_channel_priority_set(chan, old_priority);
1285
1286 /* Restore autoloop flag */
1287 ast_set2_flag(ast_channel_flags(chan), old_autoloopflag, AST_FLAG_IN_AUTOLOOP);
1288
1289 /* Restore subroutine flag */
1290 ast_set2_flag(ast_channel_flags(chan), old_in_subroutine, AST_FLAG_SUBROUTINE_EXEC);
1291 ast_channel_unlock(chan);
1292
1293 return RESULT_SUCCESS;
1294}
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:1646
#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:4195
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:4750
int fd
Definition: agi.h:35
Options for ast_pbx_run()
Definition: pbx.h:408
Definition: pbx.h:215

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

1317{
1318 /* Setup the stack application callback functions. */
1319 static struct ast_app_stack_funcs funcs = {
1320 .run_sub = gosub_run,
1321 .expand_sub_args = expand_gosub_args,
1322 };
1323
1325
1333
1334 funcs.module = ast_module_info->self,
1336
1337 return 0;
1338}
int ast_agi_register(struct ast_module *mod, agi_command *cmd)
Registers an AGI command.
Definition: res_agi.c:3988
static int gosubif_exec(struct ast_channel *chan, const char *data)
Definition: app_stack.c:697
static struct ast_custom_function local_function
Definition: app_stack.c:806
static int gosub_run(struct ast_channel *chan, const char *sub_args, int ignore_hangup)
Definition: app_stack.c:991
static const char * expand_gosub_args(struct ast_channel *chan, const char *args)
Definition: app_stack.c:473
static struct agi_command gosub_agi_command
Definition: app_stack.c:1296
static int return_exec(struct ast_channel *chan, const char *data)
Definition: app_stack.c:403
static const char app_return[]
Definition: app_stack.c:257
static struct ast_custom_function peek_function
Definition: app_stack.c:847
static const char app_gosubif[]
Definition: app_stack.c:256
static const char app_pop[]
Definition: app_stack.c:258
static struct ast_custom_function stackpeek_function
Definition: app_stack.c:937
static int pop_exec(struct ast_channel *chan, const char *data)
Definition: app_stack.c:368
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:640
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1559
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:356

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

735{
736 struct ast_datastore *stack_store;
737 struct gosub_stack_list *oldlist;
738 struct gosub_stack_frame *frame;
739 struct ast_var_t *variables;
740
741 if (!chan) {
742 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
743 return -1;
744 }
745
746 ast_channel_lock(chan);
747 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
748 ast_channel_unlock(chan);
749 return -1;
750 }
751
752 oldlist = stack_store->data;
753 AST_LIST_LOCK(oldlist);
754 if (!(frame = AST_LIST_FIRST(oldlist))) {
755 /* Not within a Gosub routine */
756 AST_LIST_UNLOCK(oldlist);
757 ast_channel_unlock(chan);
758 return -1;
759 }
760
761 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
762 if (!strcmp(data, ast_var_name(variables))) {
763 const char *tmp;
764 tmp = pbx_builtin_getvar_helper(chan, data);
765 ast_copy_string(buf, S_OR(tmp, ""), len);
766 break;
767 }
768 }
769 AST_LIST_UNLOCK(oldlist);
770 ast_channel_unlock(chan);
771 return 0;
772}
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, 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 774 of file app_stack.c.

775{
776 struct ast_datastore *stack_store;
777 struct gosub_stack_list *oldlist;
778 struct gosub_stack_frame *frame;
779
780 if (!chan) {
781 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
782 return -1;
783 }
784
785 ast_channel_lock(chan);
786 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
787 ast_log(LOG_ERROR, "Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var);
788 ast_channel_unlock(chan);
789 return -1;
790 }
791
792 oldlist = stack_store->data;
793 AST_LIST_LOCK(oldlist);
794 frame = AST_LIST_FIRST(oldlist);
795
796 if (frame) {
797 frame_set_var(chan, frame, var, value);
798 }
799
800 AST_LIST_UNLOCK(oldlist);
801 ast_channel_unlock(chan);
802
803 return 0;
804}

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

813{
814 int found = 0, n;
815 struct ast_var_t *variables;
817 AST_APP_ARG(n);
819 );
820
821 if (!chan) {
822 ast_log(LOG_ERROR, "LOCAL_PEEK must be called on an active channel\n");
823 return -1;
824 }
825
827
828 if (ast_strlen_zero(args.n) || ast_strlen_zero(args.name)) {
829 ast_log(LOG_ERROR, "LOCAL_PEEK requires parameters n and varname\n");
830 return -1;
831 }
832
833 n = atoi(args.n);
834 *buf = '\0';
835
836 ast_channel_lock(chan);
838 if (!strcmp(args.name, ast_var_name(variables)) && ++found > n) {
839 ast_copy_string(buf, ast_var_value(variables), len);
840 break;
841 }
842 }
843 ast_channel_unlock(chan);
844 return 0;
845}
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 368 of file app_stack.c.

369{
370 struct ast_datastore *stack_store;
371 struct gosub_stack_frame *oldframe;
372 struct gosub_stack_list *oldlist;
373 int res = 0;
374
375 ast_channel_lock(chan);
376 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
377 ast_log(LOG_WARNING, "%s called with no gosub stack allocated.\n", app_pop);
378 ast_channel_unlock(chan);
379 return 0;
380 }
381
382 oldlist = stack_store->data;
383 AST_LIST_LOCK(oldlist);
384 oldframe = AST_LIST_FIRST(oldlist);
385 if (oldframe) {
386 if (oldframe->is_special) {
387 ast_debug(1, "%s attempted to pop special return location.\n", app_pop);
388
389 /* Abort the special routine dialplan execution. Dialplan programming error. */
390 res = -1;
391 } else {
392 AST_LIST_REMOVE_HEAD(oldlist, entries);
393 gosub_release_frame(chan, oldframe);
394 }
395 } else {
396 ast_debug(1, "%s called with an empty gosub stack\n", app_pop);
397 }
398 AST_LIST_UNLOCK(oldlist);
399 ast_channel_unlock(chan);
400 return res;
401}

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

404{
405 struct ast_datastore *stack_store;
406 struct gosub_stack_frame *oldframe;
407 struct gosub_stack_list *oldlist;
408 const char *retval = data;
409 int res = 0;
410
411 ast_channel_lock(chan);
412 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
413 ast_log(LOG_ERROR, "Return without Gosub: stack is unallocated\n");
414 ast_channel_unlock(chan);
415 return -1;
416 }
417
418 oldlist = stack_store->data;
419 AST_LIST_LOCK(oldlist);
420 oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
421 AST_LIST_UNLOCK(oldlist);
422
423 if (!oldframe) {
424 ast_log(LOG_ERROR, "Return without Gosub: stack is empty\n");
425 ast_channel_unlock(chan);
426 return -1;
427 }
428 if (oldframe->is_special) {
429 /* Exit from special routine. */
430 res = -1;
431 }
432
433 /*
434 * We cannot use ast_explicit_goto() because we MUST restore
435 * what was there before. Channels that do not have a PBX may
436 * not have the context or exten set.
437 */
438 ast_channel_context_set(chan, oldframe->context);
439 ast_channel_exten_set(chan, oldframe->extension);
441 --oldframe->priority;
442 }
443 ast_channel_priority_set(chan, oldframe->priority);
445
446 gosub_release_frame(chan, oldframe);
447
448 /* Set a return value, if any */
449 pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", S_OR(retval, ""));
450 ast_channel_unlock(chan);
451 return res;
452}
char extension[0]
Definition: app_stack.c:278

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, 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 852 of file app_stack.c.

853{
854 struct ast_datastore *stack_store;
855 struct gosub_stack_list *oldlist;
856 struct gosub_stack_frame *frame;
857 int n;
859 AST_APP_ARG(n);
860 AST_APP_ARG(which);
861 AST_APP_ARG(suppress);
862 );
863
864 if (!chan) {
865 ast_log(LOG_ERROR, "STACK_PEEK must be called on an active channel\n");
866 return -1;
867 }
868
869 data = ast_strdupa(data);
871
872 if (ast_strlen_zero(args.n) || ast_strlen_zero(args.which)) {
873 ast_log(LOG_ERROR, "STACK_PEEK requires parameters n and which\n");
874 return -1;
875 }
876
877 n = atoi(args.n);
878 if (n <= 0) {
879 ast_log(LOG_ERROR, "STACK_PEEK must be called with a positive peek value\n");
880 return -1;
881 }
882
883 ast_channel_lock(chan);
884 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
885 if (!ast_true(args.suppress)) {
886 ast_log(LOG_ERROR, "STACK_PEEK called on a channel without a gosub stack\n");
887 }
888 ast_channel_unlock(chan);
889 return -1;
890 }
891
892 oldlist = stack_store->data;
893
894 AST_LIST_LOCK(oldlist);
895 AST_LIST_TRAVERSE(oldlist, frame, entries) {
896 if (--n == 0) {
897 break;
898 }
899 }
900
901 if (!frame) {
902 /* Too deep */
903 if (!ast_true(args.suppress)) {
904 ast_log(LOG_ERROR, "Stack peek of '%s' is more stack frames than I have\n", args.n);
905 }
906 AST_LIST_UNLOCK(oldlist);
907 ast_channel_unlock(chan);
908 return -1;
909 }
910
911 args.which = ast_skip_blanks(args.which);
912
913 switch (args.which[0]) {
914 case 'l': /* label */
915 ast_str_set(str, len, "%s,%s,%d", frame->context, frame->extension, frame->priority - 1);
916 break;
917 case 'c': /* context */
918 ast_str_set(str, len, "%s", frame->context);
919 break;
920 case 'e': /* extension */
921 ast_str_set(str, len, "%s", frame->extension);
922 break;
923 case 'p': /* priority */
924 ast_str_set(str, len, "%d", frame->priority - 1);
925 break;
926 default:
927 ast_log(LOG_ERROR, "Unknown argument '%s' to STACK_PEEK\n", args.which);
928 break;
929 }
930
931 AST_LIST_UNLOCK(oldlist);
932 ast_channel_unlock(chan);
933
934 return 0;
935}
const char * str
Definition: app_jack.c:150
#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 1299 of file app_stack.c.

1300{
1302
1304
1312
1313 return 0;
1314}
int ast_agi_unregister(agi_command *cmd)
Unregisters an AGI command.
Definition: res_agi.c:4034
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 1346 of file app_stack.c.

◆ app_gosub

const char app_gosub[] = "Gosub"
static

◆ app_gosubif

const char app_gosubif[] = "GosubIf"
static

Definition at line 256 of file app_stack.c.

Referenced by load_module(), and unload_module().

◆ app_pop

const char app_pop[] = "StackPop"
static

Definition at line 258 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 257 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 1346 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:1139

Definition at line 1296 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:774
static int local_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition: app_stack.c:734

Definition at line 806 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:812

Definition at line 847 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:354

Definition at line 262 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:852

Definition at line 937 of file app_stack.c.

Referenced by load_module(), and unload_module().