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"
Go to the source code of this file.
Data Structures | |
struct | gosub_stack_frame |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | frame_set_var (struct ast_channel *chan, struct gosub_stack_frame *frame, const char *var, const char *value) |
static struct gosub_stack_frame * | gosub_allocate_frame (const char *context, const char *extension, int priority, unsigned char arguments) |
static int | gosub_exec (struct ast_channel *chan, void *data) |
static void | gosub_free (void *data) |
static void | gosub_release_frame (struct ast_channel *chan, struct gosub_stack_frame *frame) |
static int | gosubif_exec (struct ast_channel *chan, void *data) |
static int | handle_gosub (struct ast_channel *chan, AGI *agi, int argc, char **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, void *data) |
static int | return_exec (struct ast_channel *chan, void *data) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info __MODULE_INFO_SECTION | __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Dialplan subroutines (Gosub, Return, etc)" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } |
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 struct ast_module_info * | ast_module_info = &__mod_info |
struct agi_command | gosub_agi_command |
static struct ast_custom_function | local_function |
static struct ast_custom_function | peek_function |
static struct ast_datastore_info | stack_info |
static char | usage_gosub [] = " to the dialplan with execution of a Return()\n" |
Stack applications Gosub, Return, etc.
Definition in file app_stack.c.
static void __reg_module | ( | void | ) | [static] |
Definition at line 696 of file app_stack.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 696 of file app_stack.c.
static int frame_set_var | ( | struct ast_channel * | chan, |
struct gosub_stack_frame * | frame, | ||
const char * | var, | ||
const char * | value | ||
) | [static] |
Definition at line 192 of file app_stack.c.
References AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_var_assign(), ast_var_name(), EVENT_FLAG_DIALPLAN, manager_event, pbx_builtin_pushvar_helper(), and pbx_builtin_setvar_helper().
Referenced by gosub_exec(), and local_write().
{ struct ast_var_t *variables; int found = 0; /* Does this variable already exist? */ AST_LIST_TRAVERSE(&frame->varshead, variables, entries) { if (!strcmp(var, ast_var_name(variables))) { found = 1; break; } } if (!found) { variables = ast_var_assign(var, ""); AST_LIST_INSERT_HEAD(&frame->varshead, variables, entries); pbx_builtin_pushvar_helper(chan, var, value); } else { pbx_builtin_setvar_helper(chan, var, value); } manager_event(EVENT_FLAG_DIALPLAN, "VarSet", "Channel: %s\r\n" "Variable: LOCAL(%s)\r\n" "Value: %s\r\n" "Uniqueid: %s\r\n", chan->name, var, value, chan->uniqueid); return 0; }
static struct gosub_stack_frame* gosub_allocate_frame | ( | const char * | context, |
const char * | extension, | ||
int | priority, | ||
unsigned char | arguments | ||
) | [static, read] |
Definition at line 241 of file app_stack.c.
References gosub_stack_frame::arguments, ast_calloc, AST_LIST_HEAD_INIT_NOLOCK, and gosub_stack_frame::priority.
Referenced by gosub_exec().
{ struct gosub_stack_frame *new = NULL; int len_extension = strlen(extension), len_context = strlen(context); if ((new = ast_calloc(1, sizeof(*new) + 2 + len_extension + len_context))) { AST_LIST_HEAD_INIT_NOLOCK(&new->varshead); strcpy(new->extension, extension); new->context = new->extension + len_extension + 1; strcpy(new->context, context); new->priority = priority; new->arguments = arguments; } return new; }
static int gosub_exec | ( | struct ast_channel * | chan, |
void * | data | ||
) | [static] |
Definition at line 328 of file app_stack.c.
References gosub_stack_frame::arguments, AST_APP_ARG, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_copy_string(), ast_datastore_alloc(), ast_datastore_free(), ast_debug, AST_DECLARE_APP_ARGS, ast_exists_extension(), AST_FLAG_IN_AUTOLOOP, ast_free, AST_LIST_FIRST, AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_parseable_goto(), AST_STANDARD_RAW_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_channel::cid, ast_callerid::cid_num, gosub_stack_frame::context, ast_channel::context, ast_datastore::data, gosub_stack_frame::entries, ast_channel::exten, gosub_stack_frame::extension, frame_set_var(), gosub_allocate_frame(), LOG_ERROR, LOG_WARNING, ast_channel::name, gosub_stack_frame::priority, ast_channel::priority, and strsep().
Referenced by gosubif_exec(), and load_module().
{ struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); AST_LIST_HEAD(, gosub_stack_frame) *oldlist; struct gosub_stack_frame *newframe, *lastframe; char argname[15], *tmp = ast_strdupa(data), *label, *endparen; int i, max_argc = 0; AST_DECLARE_APP_ARGS(args2, AST_APP_ARG(argval)[100]; ); if (ast_strlen_zero(data)) { ast_log(LOG_ERROR, "%s requires an argument: %s([[context,]exten,]priority[(arg1[,...][,argN])])\n", app_gosub, app_gosub); return -1; } if (!stack_store) { ast_debug(1, "Channel %s has no datastore, so we're allocating one.\n", chan->name); stack_store = ast_datastore_alloc(&stack_info, NULL); if (!stack_store) { ast_log(LOG_ERROR, "Unable to allocate new datastore. Gosub will fail.\n"); return -1; } oldlist = ast_calloc(1, sizeof(*oldlist)); if (!oldlist) { ast_log(LOG_ERROR, "Unable to allocate datastore list head. Gosub will fail.\n"); ast_datastore_free(stack_store); return -1; } stack_store->data = oldlist; AST_LIST_HEAD_INIT(oldlist); ast_channel_datastore_add(chan, stack_store); } else { oldlist = stack_store->data; } if ((lastframe = AST_LIST_FIRST(oldlist))) { max_argc = lastframe->arguments; } /* Separate the arguments from the label */ /* NOTE: you cannot use ast_app_separate_args for this, because '(' cannot be used as a delimiter. */ label = strsep(&tmp, "("); if (tmp) { endparen = strrchr(tmp, ')'); if (endparen) *endparen = '\0'; else ast_log(LOG_WARNING, "Ouch. No closing paren: '%s'?\n", (char *)data); AST_STANDARD_RAW_ARGS(args2, tmp); } else args2.argc = 0; /* Mask out previous arguments in this invocation */ if (args2.argc > max_argc) { max_argc = args2.argc; } /* Create the return address, but don't save it until we know that the Gosub destination exists */ newframe = gosub_allocate_frame(chan->context, chan->exten, chan->priority + 1, max_argc); if (!newframe) { return -1; } if (ast_parseable_goto(chan, label)) { ast_log(LOG_ERROR, "Gosub address is invalid: '%s'\n", (char *)data); ast_free(newframe); return -1; } if (!ast_exists_extension(chan, chan->context, chan->exten, ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP) ? chan->priority + 1 : chan->priority, chan->cid.cid_num)) { ast_log(LOG_ERROR, "Attempt to reach a non-existent destination for gosub: (Context:%s, Extension:%s, Priority:%d)\n", chan->context, chan->exten, ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP) ? chan->priority + 1 : chan->priority); ast_copy_string(chan->context, newframe->context, sizeof(chan->context)); ast_copy_string(chan->exten, newframe->extension, sizeof(chan->exten)); chan->priority = newframe->priority; ast_free(newframe); return -1; } /* Now that we know for certain that we're going to a new location, set our arguments */ for (i = 0; i < max_argc; i++) { snprintf(argname, sizeof(argname), "ARG%d", i + 1); frame_set_var(chan, newframe, argname, i < args2.argc ? args2.argval[i] : ""); ast_debug(1, "Setting '%s' to '%s'\n", argname, i < args2.argc ? args2.argval[i] : ""); } snprintf(argname, sizeof(argname), "%d", args2.argc); frame_set_var(chan, newframe, "ARGC", argname); /* And finally, save our return address */ oldlist = stack_store->data; AST_LIST_LOCK(oldlist); AST_LIST_INSERT_HEAD(oldlist, newframe, entries); AST_LIST_UNLOCK(oldlist); return 0; }
static void gosub_free | ( | void * | data | ) | [static] |
Definition at line 257 of file app_stack.c.
References ast_free, AST_LIST_HEAD, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, gosub_stack_frame::entries, and gosub_release_frame().
{ AST_LIST_HEAD(, gosub_stack_frame) *oldlist = data; struct gosub_stack_frame *oldframe; AST_LIST_LOCK(oldlist); while ((oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries))) { gosub_release_frame(NULL, oldframe); } AST_LIST_UNLOCK(oldlist); AST_LIST_HEAD_DESTROY(oldlist); ast_free(oldlist); }
static void gosub_release_frame | ( | struct ast_channel * | chan, |
struct gosub_stack_frame * | frame | ||
) | [static] |
Definition at line 222 of file app_stack.c.
References ast_free, AST_LIST_REMOVE_HEAD, ast_var_delete(), ast_var_name(), gosub_stack_frame::entries, pbx_builtin_setvar_helper(), and gosub_stack_frame::varshead.
Referenced by gosub_free(), pop_exec(), and return_exec().
{ struct ast_var_t *vardata; /* If chan is not defined, then we're calling it as part of gosub_free, * and the channel variables will be deallocated anyway. Otherwise, we're * just releasing a single frame, so we need to clean up the arguments for * that frame, so that we re-expose the variables from the previous frame * that were hidden by this one. */ while ((vardata = AST_LIST_REMOVE_HEAD(&frame->varshead, entries))) { if (chan) pbx_builtin_setvar_helper(chan, ast_var_name(vardata), NULL); ast_var_delete(vardata); } ast_free(frame); }
static int gosubif_exec | ( | struct ast_channel * | chan, |
void * | data | ||
) | [static] |
Definition at line 429 of file app_stack.c.
References 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().
{ char *args; int res=0; AST_DECLARE_APP_ARGS(cond, AST_APP_ARG(ition); AST_APP_ARG(labels); ); AST_DECLARE_APP_ARGS(label, AST_APP_ARG(iftrue); AST_APP_ARG(iffalse); ); if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n"); return 0; } args = ast_strdupa(data); AST_NONSTANDARD_RAW_ARGS(cond, args, '?'); if (cond.argc != 2) { ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n"); return 0; } AST_NONSTANDARD_RAW_ARGS(label, cond.labels, ':'); if (pbx_checkcondition(cond.ition)) { if (!ast_strlen_zero(label.iftrue)) res = gosub_exec(chan, label.iftrue); } else if (!ast_strlen_zero(label.iffalse)) { res = gosub_exec(chan, label.iffalse); } return res; }
static int handle_gosub | ( | struct ast_channel * | chan, |
AGI * | agi, | ||
int | argc, | ||
char ** | argv | ||
) | [static] |
Definition at line 561 of file app_stack.c.
References asprintf, ast_agi_send(), ast_channel_datastore_find(), ast_copy_string(), ast_debug, ast_exists_extension(), ast_findlabel_extension(), ast_free, AST_LIST_FIRST, AST_LIST_HEAD, ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_pbx_run_args(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_datastore::data, errno, ast_channel::exten, agi_state::fd, gosub_stack_frame::is_agi, LOG_ERROR, LOG_WARNING, ast_pbx_args::no_hangup_chan, ast_channel::pbx, pbx_exec(), pbx_findapp(), ast_channel::priority, gosub_stack_frame::priority, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
{ int old_priority, priority; char old_context[AST_MAX_CONTEXT], old_extension[AST_MAX_EXTENSION]; struct ast_app *theapp; char *gosub_args; if (argc < 4 || argc > 5) { return RESULT_SHOWUSAGE; } 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] : ""); if (sscanf(argv[3], "%30d", &priority) != 1 || priority < 1) { /* Lookup the priority label */ if ((priority = ast_findlabel_extension(chan, argv[1], argv[2], argv[3], chan->cid.cid_num)) < 0) { ast_log(LOG_ERROR, "Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]); ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n"); return RESULT_FAILURE; } } else if (!ast_exists_extension(chan, argv[1], argv[2], priority, chan->cid.cid_num)) { ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n"); return RESULT_FAILURE; } /* Save previous location, since we're going to change it */ ast_copy_string(old_context, chan->context, sizeof(old_context)); ast_copy_string(old_extension, chan->exten, sizeof(old_extension)); old_priority = chan->priority; if (!(theapp = pbx_findapp("Gosub"))) { ast_log(LOG_ERROR, "Gosub() cannot be found in the list of loaded applications\n"); ast_agi_send(agi->fd, chan, "503 result=-2 Gosub is not loaded\n"); return RESULT_FAILURE; } /* Apparently, if you run ast_pbx_run on a channel that already has a pbx * structure, you need to add 1 to the priority to get it to go to the * right place. But if it doesn't have a pbx structure, then leaving off * the 1 is the right thing to do. See how this code differs when we * call a Gosub for the CALLEE channel in Dial or Queue. */ if (argc == 5) { if (asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority + (chan->pbx ? 1 : 0), argv[4]) < 0) { ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); gosub_args = NULL; } } else { if (asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority + (chan->pbx ? 1 : 0)) < 0) { ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); gosub_args = NULL; } } if (gosub_args) { int res; ast_debug(1, "Trying gosub with arguments '%s'\n", gosub_args); if ((res = pbx_exec(chan, theapp, gosub_args)) == 0) { struct ast_pbx *pbx = chan->pbx; struct ast_pbx_args args; struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); AST_LIST_HEAD(, gosub_stack_frame) *oldlist = stack_store->data; struct gosub_stack_frame *cur = AST_LIST_FIRST(oldlist); cur->is_agi = 1; memset(&args, 0, sizeof(args)); args.no_hangup_chan = 1; /* Suppress warning about PBX already existing */ chan->pbx = NULL; ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n"); ast_pbx_run_args(chan, &args); ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete\n"); if (chan->pbx) { ast_free(chan->pbx); } chan->pbx = pbx; } else { ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res); } ast_free(gosub_args); } else { ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n"); return RESULT_FAILURE; } /* Restore previous location */ ast_copy_string(chan->context, old_context, sizeof(chan->context)); ast_copy_string(chan->exten, old_extension, sizeof(chan->exten)); chan->priority = old_priority; return RESULT_SUCCESS; }
static int load_module | ( | void | ) | [static] |
Definition at line 680 of file app_stack.c.
References ast_agi_register(), ast_custom_function_register, ast_register_application_xml, gosub_agi_command, gosub_exec(), gosubif_exec(), local_function, peek_function, pop_exec(), return_exec(), and ast_module_info::self.
{ if (ast_agi_register) { ast_agi_register(ast_module_info->self, &gosub_agi_command); } ast_register_application_xml(app_pop, pop_exec); ast_register_application_xml(app_return, return_exec); ast_register_application_xml(app_gosubif, gosubif_exec); ast_register_application_xml(app_gosub, gosub_exec); ast_custom_function_register(&local_function); ast_custom_function_register(&peek_function); return 0; }
static int local_read | ( | struct ast_channel * | chan, |
const char * | cmd, | ||
char * | data, | ||
char * | buf, | ||
size_t | len | ||
) | [static] |
Definition at line 466 of file app_stack.c.
References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_LIST_FIRST, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_var_name(), ast_datastore::data, gosub_stack_frame::entries, pbx_builtin_getvar_helper(), S_OR, and gosub_stack_frame::varshead.
{ struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); AST_LIST_HEAD(, gosub_stack_frame) *oldlist; struct gosub_stack_frame *frame; struct ast_var_t *variables; if (!stack_store) return -1; oldlist = stack_store->data; AST_LIST_LOCK(oldlist); if (!(frame = AST_LIST_FIRST(oldlist))) { /* Not within a Gosub routine */ AST_LIST_UNLOCK(oldlist); return -1; } AST_LIST_TRAVERSE(&frame->varshead, variables, entries) { if (!strcmp(data, ast_var_name(variables))) { const char *tmp; ast_channel_lock(chan); tmp = pbx_builtin_getvar_helper(chan, data); ast_copy_string(buf, S_OR(tmp, ""), len); ast_channel_unlock(chan); break; } } AST_LIST_UNLOCK(oldlist); return 0; }
static int local_write | ( | struct ast_channel * | chan, |
const char * | cmd, | ||
char * | var, | ||
const char * | value | ||
) | [static] |
Definition at line 498 of file app_stack.c.
References ast_channel_datastore_find(), AST_LIST_FIRST, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_datastore::data, frame_set_var(), and LOG_ERROR.
{ struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); AST_LIST_HEAD(, gosub_stack_frame) *oldlist; struct gosub_stack_frame *frame; if (!stack_store) { ast_log(LOG_ERROR, "Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var); return -1; } oldlist = stack_store->data; AST_LIST_LOCK(oldlist); frame = AST_LIST_FIRST(oldlist); if (frame) frame_set_var(chan, frame, var, value); AST_LIST_UNLOCK(oldlist); return 0; }
static int peek_read | ( | struct ast_channel * | chan, |
const char * | cmd, | ||
char * | data, | ||
char * | buf, | ||
size_t | len | ||
) | [static] |
Definition at line 527 of file app_stack.c.
References AST_APP_ARG, ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_LIST_TRAVERSE, ast_log(), AST_STANDARD_RAW_ARGS, ast_var_name(), ast_var_value(), gosub_stack_frame::entries, LOG_ERROR, name, and ast_channel::varshead.
{ int found = 0, n; struct ast_var_t *variables; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(n); AST_APP_ARG(name); ); if (!chan) { ast_log(LOG_ERROR, "LOCAL_PEEK must be called on an active channel\n"); return -1; } AST_STANDARD_RAW_ARGS(args, data); n = atoi(args.n); *buf = '\0'; ast_channel_lock(chan); AST_LIST_TRAVERSE(&chan->varshead, variables, entries) { if (!strcmp(args.name, ast_var_name(variables)) && ++found > n) { ast_copy_string(buf, ast_var_value(variables), len); break; } } ast_channel_unlock(chan); return 0; }
static int pop_exec | ( | struct ast_channel * | chan, |
void * | data | ||
) | [static] |
Definition at line 270 of file app_stack.c.
References ast_channel_datastore_find(), ast_debug, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log(), ast_datastore::data, gosub_stack_frame::entries, gosub_release_frame(), and LOG_WARNING.
Referenced by load_module().
{ struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); struct gosub_stack_frame *oldframe; AST_LIST_HEAD(, gosub_stack_frame) *oldlist; if (!stack_store) { ast_log(LOG_WARNING, "%s called with no gosub stack allocated.\n", app_pop); return 0; } oldlist = stack_store->data; AST_LIST_LOCK(oldlist); oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries); AST_LIST_UNLOCK(oldlist); if (oldframe) { gosub_release_frame(chan, oldframe); } else { ast_debug(1, "%s called with an empty gosub stack\n", app_pop); } return 0; }
static int return_exec | ( | struct ast_channel * | chan, |
void * | data | ||
) | [static] |
Definition at line 294 of file app_stack.c.
References ast_channel_datastore_find(), ast_explicit_goto(), AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log(), gosub_stack_frame::context, ast_datastore::data, gosub_stack_frame::entries, gosub_stack_frame::extension, gosub_release_frame(), gosub_stack_frame::is_agi, LOG_ERROR, pbx_builtin_setvar_helper(), gosub_stack_frame::priority, and S_OR.
Referenced by load_module().
{ struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); struct gosub_stack_frame *oldframe; AST_LIST_HEAD(, gosub_stack_frame) *oldlist; char *retval = data; int res = 0; if (!stack_store) { ast_log(LOG_ERROR, "Return without Gosub: stack is unallocated\n"); return -1; } oldlist = stack_store->data; AST_LIST_LOCK(oldlist); oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries); AST_LIST_UNLOCK(oldlist); if (!oldframe) { ast_log(LOG_ERROR, "Return without Gosub: stack is empty\n"); return -1; } else if (oldframe->is_agi) { /* Exit from AGI */ res = -1; } ast_explicit_goto(chan, oldframe->context, oldframe->extension, oldframe->priority); gosub_release_frame(chan, oldframe); /* Set a return value, if any */ pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", S_OR(retval, "")); return res; }
static int unload_module | ( | void | ) | [static] |
Definition at line 664 of file app_stack.c.
References ast_agi_unregister(), ast_custom_function_unregister(), ast_unregister_application(), gosub_agi_command, local_function, peek_function, and ast_module_info::self.
{ if (ast_agi_unregister) { ast_agi_unregister(ast_module_info->self, &gosub_agi_command); } ast_unregister_application(app_return); ast_unregister_application(app_pop); ast_unregister_application(app_gosubif); ast_unregister_application(app_gosub); ast_custom_function_unregister(&local_function); ast_custom_function_unregister(&peek_function); return 0; }
struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Dialplan subroutines (Gosub, Return, etc)" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } [static] |
Definition at line 696 of file app_stack.c.
const char* app_gosub = "Gosub" [static] |
Definition at line 169 of file app_stack.c.
const char* app_gosubif = "GosubIf" [static] |
Definition at line 170 of file app_stack.c.
const char* app_pop = "StackPop" [static] |
Definition at line 172 of file app_stack.c.
const char* app_return = "Return" [static] |
Definition at line 171 of file app_stack.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 696 of file app_stack.c.
struct agi_command gosub_agi_command |
{ { "gosub", NULL }, handle_gosub, "Execute a dialplan subroutine", usage_gosub , 0 }
Definition at line 661 of file app_stack.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function local_function [static] |
{ .name = "LOCAL", .write = local_write, .read = local_read, }
Definition at line 521 of file app_stack.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function peek_function [static] |
{ .name = "LOCAL_PEEK", .read = peek_read, }
Definition at line 556 of file app_stack.c.
Referenced by load_module(), and unload_module().
struct ast_datastore_info stack_info [static] |
{ .type = "GOSUB", .destroy = gosub_free, }
Definition at line 176 of file app_stack.c.
char usage_gosub[] = " to the dialplan with execution of a Return()\n" [static] |
Definition at line 656 of file app_stack.c.