Asterisk - The Open Source Telephony Project GIT-master-27fb039
Loading...
Searching...
No Matches
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 = ASTERISK_GPL_KEY , .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:2389
#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.
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
#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::@85 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 }
517 if (ast_strlen_zero(context)) {
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:2982
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:2983
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 struct @519 args
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65

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(), 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.
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
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::@224 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:981

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.
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, gosub_stack_frame::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:2375
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)
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
@ AST_FLAG_IN_AUTOLOOP
Definition channel.h:1017
@ AST_FLAG_SUBROUTINE_EXEC
Definition channel.h:1078
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.
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
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:4196
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
Definition pbx.c:8891
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.
#define ast_test_flag(p, flag)
Definition utils.h:64
#define ast_set_flag(p, flag)
Definition utils.h:71

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.

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:2469

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:2422
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:2448
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:4221
#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:95

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:8307

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_OPTIONAL_API_NAME() 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:1612
#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:4201
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:4756
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_OPTIONAL_API_NAME() ast_agi_register(struct ast_module *mod, agi_command *cmd)
Registers an AGI command.
Definition res_agi.c:3954
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:1562
Stack applications callback functions.
void *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, 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}

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:2235
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 *attribute_pure 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_OPTIONAL_API_NAME() ast_agi_unregister(agi_command *cmd)
Unregisters an AGI command.
Definition res_agi.c:4000
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 = ASTERISK_GPL_KEY , .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.

1297 { { "gosub", NULL }, handle_gosub, NULL, NULL, 0 };

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.

806 {
807 .name = "LOCAL",
808 .write = local_write,
809 .read = local_read,
810};

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.

847 {
848 .name = "LOCAL_PEEK",
849 .read = peek_read,
850};

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.

262 {
263 .type = "GOSUB",
264 .destroy = gosub_free,
265};

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.

937 {
938 .name = "STACK_PEEK",
939 .read2 = stackpeek_read,
940};

Referenced by load_module(), and unload_module().