#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 |
Defines | |
#define | ASTERISK_AGI_OPTIONAL |
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 | 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 | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .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 = "068e67f60f50dd9ee86464c05884a49d" , .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 const struct ast_module_info * | ast_module_info = &__mod_info |
agi_command | gosub_agi_command |
static const char * | gosub_descrip |
static const char * | gosub_synopsis = "Jump to label, saving return address" |
static const char * | gosubif_descrip |
static const char * | gosubif_synopsis = "Conditionally jump to label, saving return address" |
static struct ast_custom_function | local_function |
static const char * | pop_descrip |
static const char * | pop_synopsis = "Remove one address from gosub stack" |
static const char * | return_descrip |
static const char * | return_synopsis = "Return from gosub routine" |
static struct ast_datastore_info | stack_info |
static char | usage_gosub [] |
Definition in file app_stack.c.
#define ASTERISK_AGI_OPTIONAL |
Definition at line 43 of file app_stack.c.
static void __reg_module | ( | void | ) | [static] |
Definition at line 536 of file app_stack.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 536 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 90 of file app_stack.c.
References AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_var_assign(), ast_var_name(), gosub_stack_frame::entries, EVENT_FLAG_DIALPLAN, manager_event, pbx_builtin_pushvar_helper(), and pbx_builtin_setvar_helper().
Referenced by gosub_exec(), and local_write().
00091 { 00092 struct ast_var_t *variables; 00093 int found = 0; 00094 00095 /* Does this variable already exist? */ 00096 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) { 00097 if (!strcmp(var, ast_var_name(variables))) { 00098 found = 1; 00099 break; 00100 } 00101 } 00102 00103 if (!found) { 00104 variables = ast_var_assign(var, ""); 00105 AST_LIST_INSERT_HEAD(&frame->varshead, variables, entries); 00106 pbx_builtin_pushvar_helper(chan, var, value); 00107 } else { 00108 pbx_builtin_setvar_helper(chan, var, value); 00109 } 00110 00111 manager_event(EVENT_FLAG_DIALPLAN, "VarSet", 00112 "Channel: %s\r\n" 00113 "Variable: LOCAL(%s)\r\n" 00114 "Value: %s\r\n" 00115 "Uniqueid: %s\r\n", 00116 chan->name, var, value, chan->uniqueid); 00117 return 0; 00118 }
static struct gosub_stack_frame* gosub_allocate_frame | ( | const char * | context, | |
const char * | extension, | |||
int | priority, | |||
unsigned char | arguments | |||
) | [static] |
Definition at line 139 of file app_stack.c.
References ast_calloc, and AST_LIST_HEAD_INIT_NOLOCK.
Referenced by gosub_exec().
00140 { 00141 struct gosub_stack_frame *new = NULL; 00142 int len_extension = strlen(extension), len_context = strlen(context); 00143 00144 if ((new = ast_calloc(1, sizeof(*new) + 2 + len_extension + len_context))) { 00145 AST_LIST_HEAD_INIT_NOLOCK(&new->varshead); 00146 strcpy(new->extension, extension); 00147 new->context = new->extension + len_extension + 1; 00148 strcpy(new->context, context); 00149 new->priority = priority; 00150 new->arguments = arguments; 00151 } 00152 return new; 00153 }
static int gosub_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 222 of file app_stack.c.
References AST_APP_ARG, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_alloc(), ast_channel_datastore_find(), ast_channel_datastore_free(), ast_copy_string(), ast_debug, AST_DECLARE_APP_ARGS, ast_exists_extension(), AST_FLAG_IN_AUTOLOOP, ast_free, AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_parseable_goto(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, chan, 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, stack_info, and strsep().
Referenced by gosubif_exec(), and load_module().
00223 { 00224 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00225 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00226 struct gosub_stack_frame *newframe; 00227 char argname[15], *tmp = ast_strdupa(data), *label, *endparen; 00228 int i; 00229 AST_DECLARE_APP_ARGS(args2, 00230 AST_APP_ARG(argval)[100]; 00231 ); 00232 00233 if (ast_strlen_zero(data)) { 00234 ast_log(LOG_ERROR, "%s requires an argument: %s([[context,]exten,]priority[(arg1[,...][,argN])])\n", app_gosub, app_gosub); 00235 return -1; 00236 } 00237 00238 if (!stack_store) { 00239 ast_debug(1, "Channel %s has no datastore, so we're allocating one.\n", chan->name); 00240 stack_store = ast_channel_datastore_alloc(&stack_info, NULL); 00241 if (!stack_store) { 00242 ast_log(LOG_ERROR, "Unable to allocate new datastore. Gosub will fail.\n"); 00243 return -1; 00244 } 00245 00246 oldlist = ast_calloc(1, sizeof(*oldlist)); 00247 if (!oldlist) { 00248 ast_log(LOG_ERROR, "Unable to allocate datastore list head. Gosub will fail.\n"); 00249 ast_channel_datastore_free(stack_store); 00250 return -1; 00251 } 00252 00253 stack_store->data = oldlist; 00254 AST_LIST_HEAD_INIT(oldlist); 00255 ast_channel_datastore_add(chan, stack_store); 00256 } 00257 00258 /* Separate the arguments from the label */ 00259 /* NOTE: you cannot use ast_app_separate_args for this, because '(' cannot be used as a delimiter. */ 00260 label = strsep(&tmp, "("); 00261 if (tmp) { 00262 endparen = strrchr(tmp, ')'); 00263 if (endparen) 00264 *endparen = '\0'; 00265 else 00266 ast_log(LOG_WARNING, "Ouch. No closing paren: '%s'?\n", (char *)data); 00267 AST_STANDARD_APP_ARGS(args2, tmp); 00268 } else 00269 args2.argc = 0; 00270 00271 /* Create the return address, but don't save it until we know that the Gosub destination exists */ 00272 newframe = gosub_allocate_frame(chan->context, chan->exten, chan->priority + 1, args2.argc); 00273 00274 if (!newframe) { 00275 return -1; 00276 } 00277 00278 if (ast_parseable_goto(chan, label)) { 00279 ast_log(LOG_ERROR, "Gosub address is invalid: '%s'\n", (char *)data); 00280 ast_free(newframe); 00281 return -1; 00282 } 00283 00284 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)) { 00285 ast_log(LOG_ERROR, "Attempt to reach a non-existent destination for gosub: (Context:%s, Extension:%s, Priority:%d)\n", 00286 chan->context, chan->exten, chan->priority); 00287 ast_copy_string(chan->context, newframe->context, sizeof(chan->context)); 00288 ast_copy_string(chan->exten, newframe->extension, sizeof(chan->exten)); 00289 chan->priority = newframe->priority; 00290 ast_free(newframe); 00291 return -1; 00292 } 00293 00294 /* Now that we know for certain that we're going to a new location, set our arguments */ 00295 for (i = 0; i < args2.argc; i++) { 00296 snprintf(argname, sizeof(argname), "ARG%d", i + 1); 00297 frame_set_var(chan, newframe, argname, args2.argval[i]); 00298 ast_debug(1, "Setting '%s' to '%s'\n", argname, args2.argval[i]); 00299 } 00300 00301 /* And finally, save our return address */ 00302 oldlist = stack_store->data; 00303 AST_LIST_LOCK(oldlist); 00304 AST_LIST_INSERT_HEAD(oldlist, newframe, entries); 00305 AST_LIST_UNLOCK(oldlist); 00306 00307 return 0; 00308 }
static void gosub_free | ( | void * | data | ) | [static] |
Definition at line 155 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().
00156 { 00157 AST_LIST_HEAD(, gosub_stack_frame) *oldlist = data; 00158 struct gosub_stack_frame *oldframe; 00159 AST_LIST_LOCK(oldlist); 00160 while ((oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries))) { 00161 gosub_release_frame(NULL, oldframe); 00162 } 00163 AST_LIST_UNLOCK(oldlist); 00164 AST_LIST_HEAD_DESTROY(oldlist); 00165 ast_free(oldlist); 00166 }
static void gosub_release_frame | ( | struct ast_channel * | chan, | |
struct gosub_stack_frame * | frame | |||
) | [static] |
Definition at line 120 of file app_stack.c.
References ast_free, AST_LIST_REMOVE_HEAD, ast_var_delete(), ast_var_name(), chan, gosub_stack_frame::entries, pbx_builtin_setvar_helper(), and gosub_stack_frame::varshead.
Referenced by gosub_free(), pop_exec(), and return_exec().
00121 { 00122 struct ast_var_t *vardata; 00123 00124 /* If chan is not defined, then we're calling it as part of gosub_free, 00125 * and the channel variables will be deallocated anyway. Otherwise, we're 00126 * just releasing a single frame, so we need to clean up the arguments for 00127 * that frame, so that we re-expose the variables from the previous frame 00128 * that were hidden by this one. 00129 */ 00130 while ((vardata = AST_LIST_REMOVE_HEAD(&frame->varshead, entries))) { 00131 if (chan) 00132 pbx_builtin_setvar_helper(chan, ast_var_name(vardata), NULL); 00133 ast_var_delete(vardata); 00134 } 00135 00136 ast_free(frame); 00137 }
static int gosubif_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 310 of file app_stack.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), chan, cond, gosub_exec(), LOG_WARNING, and pbx_checkcondition().
Referenced by load_module().
00311 { 00312 char *args; 00313 int res=0; 00314 AST_DECLARE_APP_ARGS(cond, 00315 AST_APP_ARG(ition); 00316 AST_APP_ARG(labels); 00317 ); 00318 AST_DECLARE_APP_ARGS(label, 00319 AST_APP_ARG(iftrue); 00320 AST_APP_ARG(iffalse); 00321 ); 00322 00323 if (ast_strlen_zero(data)) { 00324 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n"); 00325 return 0; 00326 } 00327 00328 args = ast_strdupa(data); 00329 AST_NONSTANDARD_APP_ARGS(cond, args, '?'); 00330 if (cond.argc != 2) { 00331 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n"); 00332 return 0; 00333 } 00334 00335 AST_NONSTANDARD_APP_ARGS(label, cond.labels, ':'); 00336 00337 if (pbx_checkcondition(cond.ition)) { 00338 if (!ast_strlen_zero(label.iftrue)) 00339 res = gosub_exec(chan, label.iftrue); 00340 } else if (!ast_strlen_zero(label.iffalse)) { 00341 res = gosub_exec(chan, label.iffalse); 00342 } 00343 00344 return res; 00345 }
static int handle_gosub | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 402 of file app_stack.c.
References asprintf, ast_agi_send(), ast_copy_string(), ast_debug, ast_exists_extension(), ast_findlabel_extension(), ast_free, ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_pbx_run_args(), chan, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, errno, ast_channel::exten, agi_state::fd, LOG_ERROR, LOG_WARNING, ast_channel::pbx, pbx_exec(), pbx_findapp(), ast_channel::priority, gosub_stack_frame::priority, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00403 { 00404 int old_priority, priority; 00405 char old_context[AST_MAX_CONTEXT], old_extension[AST_MAX_EXTENSION]; 00406 struct ast_app *theapp; 00407 char *gosub_args; 00408 00409 if (argc < 4 || argc > 5) { 00410 return RESULT_SHOWUSAGE; 00411 } 00412 00413 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] : ""); 00414 00415 if (sscanf(argv[3], "%d", &priority) != 1 || priority < 1) { 00416 /* Lookup the priority label */ 00417 if ((priority = ast_findlabel_extension(chan, argv[1], argv[2], argv[3], chan->cid.cid_num)) < 0) { 00418 ast_log(LOG_ERROR, "Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]); 00419 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n"); 00420 return RESULT_FAILURE; 00421 } 00422 } else if (!ast_exists_extension(chan, argv[1], argv[2], priority, chan->cid.cid_num)) { 00423 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n"); 00424 return RESULT_FAILURE; 00425 } 00426 00427 /* Save previous location, since we're going to change it */ 00428 ast_copy_string(old_context, chan->context, sizeof(old_context)); 00429 ast_copy_string(old_extension, chan->exten, sizeof(old_extension)); 00430 old_priority = chan->priority; 00431 00432 if (!(theapp = pbx_findapp("Gosub"))) { 00433 ast_log(LOG_ERROR, "Gosub() cannot be found in the list of loaded applications\n"); 00434 ast_agi_send(agi->fd, chan, "503 result=-2 Gosub is not loaded\n"); 00435 return RESULT_FAILURE; 00436 } 00437 00438 /* Apparently, if you run ast_pbx_run on a channel that already has a pbx 00439 * structure, you need to add 1 to the priority to get it to go to the 00440 * right place. But if it doesn't have a pbx structure, then leaving off 00441 * the 1 is the right thing to do. See how this code differs when we 00442 * call a Gosub for the CALLEE channel in Dial or Queue. 00443 */ 00444 if (argc == 5) { 00445 if (asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority + 1, argv[4]) < 0) { 00446 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00447 gosub_args = NULL; 00448 } 00449 } else { 00450 if (asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority + 1) < 0) { 00451 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00452 gosub_args = NULL; 00453 } 00454 } 00455 00456 if (gosub_args) { 00457 int res; 00458 00459 ast_debug(1, "Trying gosub with arguments '%s'\n", gosub_args); 00460 ast_copy_string(chan->context, "app_stack_gosub_virtual_context", sizeof(chan->context)); 00461 ast_copy_string(chan->exten, "s", sizeof(chan->exten)); 00462 chan->priority = 0; 00463 00464 if ((res = pbx_exec(chan, theapp, gosub_args)) == 0) { 00465 struct ast_pbx *pbx = chan->pbx; 00466 struct ast_pbx_args args; 00467 memset(&args, 0, sizeof(args)); 00468 args.no_hangup_chan = 1; 00469 /* Suppress warning about PBX already existing */ 00470 chan->pbx = NULL; 00471 ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n"); 00472 ast_pbx_run_args(chan, &args); 00473 ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete\n"); 00474 if (chan->pbx) { 00475 ast_free(chan->pbx); 00476 } 00477 chan->pbx = pbx; 00478 } else { 00479 ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res); 00480 } 00481 ast_free(gosub_args); 00482 } else { 00483 ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n"); 00484 return RESULT_FAILURE; 00485 } 00486 00487 /* Restore previous location */ 00488 ast_copy_string(chan->context, old_context, sizeof(chan->context)); 00489 ast_copy_string(chan->exten, old_extension, sizeof(chan->exten)); 00490 chan->priority = old_priority; 00491 00492 return RESULT_SUCCESS; 00493 }
static int load_module | ( | void | ) | [static] |
Definition at line 518 of file app_stack.c.
References ast_agi_register(), ast_custom_function_register, ast_register_application, gosub_agi_command, gosub_exec(), gosubif_exec(), local_function, pop_exec(), and return_exec().
00519 { 00520 /* usage of AGI is optional, so check to see if the ast_agi_register() 00521 function is available; if so, use it. 00522 */ 00523 if (ast_agi_register) { 00524 ast_agi_register(ast_module_info->self, &gosub_agi_command); 00525 } 00526 00527 ast_register_application(app_pop, pop_exec, pop_synopsis, pop_descrip); 00528 ast_register_application(app_return, return_exec, return_synopsis, return_descrip); 00529 ast_register_application(app_gosubif, gosubif_exec, gosubif_synopsis, gosubif_descrip); 00530 ast_register_application(app_gosub, gosub_exec, gosub_synopsis, gosub_descrip); 00531 ast_custom_function_register(&local_function); 00532 00533 return 0; 00534 }
static int local_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 347 of file app_stack.c.
References ast_channel_datastore_find(), ast_copy_string(), AST_LIST_FIRST, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_var_name(), chan, ast_datastore::data, gosub_stack_frame::entries, pbx_builtin_getvar_helper(), S_OR, stack_info, and gosub_stack_frame::varshead.
00348 { 00349 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00350 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00351 struct gosub_stack_frame *frame; 00352 struct ast_var_t *variables; 00353 00354 if (!stack_store) 00355 return -1; 00356 00357 oldlist = stack_store->data; 00358 AST_LIST_LOCK(oldlist); 00359 frame = AST_LIST_FIRST(oldlist); 00360 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) { 00361 if (!strcmp(data, ast_var_name(variables))) { 00362 const char *tmp = pbx_builtin_getvar_helper(chan, data); 00363 ast_copy_string(buf, S_OR(tmp, ""), len); 00364 break; 00365 } 00366 } 00367 AST_LIST_UNLOCK(oldlist); 00368 return 0; 00369 }
static int local_write | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | var, | |||
const char * | value | |||
) | [static] |
Definition at line 371 of file app_stack.c.
References ast_channel_datastore_find(), AST_LIST_FIRST, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), chan, ast_datastore::data, frame_set_var(), LOG_ERROR, and stack_info.
00372 { 00373 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00374 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00375 struct gosub_stack_frame *frame; 00376 00377 if (!stack_store) { 00378 ast_log(LOG_ERROR, "Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var); 00379 return -1; 00380 } 00381 00382 oldlist = stack_store->data; 00383 AST_LIST_LOCK(oldlist); 00384 frame = AST_LIST_FIRST(oldlist); 00385 00386 if (frame) 00387 frame_set_var(chan, frame, var, value); 00388 00389 AST_LIST_UNLOCK(oldlist); 00390 00391 return 0; 00392 }
static int pop_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 168 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(), chan, ast_datastore::data, gosub_stack_frame::entries, gosub_release_frame(), LOG_WARNING, and stack_info.
Referenced by load_module().
00169 { 00170 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00171 struct gosub_stack_frame *oldframe; 00172 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00173 00174 if (!stack_store) { 00175 ast_log(LOG_WARNING, "%s called with no gosub stack allocated.\n", app_pop); 00176 return 0; 00177 } 00178 00179 oldlist = stack_store->data; 00180 AST_LIST_LOCK(oldlist); 00181 oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries); 00182 AST_LIST_UNLOCK(oldlist); 00183 00184 if (oldframe) { 00185 gosub_release_frame(chan, oldframe); 00186 } else { 00187 ast_debug(1, "%s called with an empty gosub stack\n", app_pop); 00188 } 00189 return 0; 00190 }
static int return_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 192 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(), chan, gosub_stack_frame::context, ast_datastore::data, gosub_stack_frame::entries, gosub_stack_frame::extension, gosub_release_frame(), LOG_ERROR, pbx_builtin_setvar_helper(), gosub_stack_frame::priority, S_OR, and stack_info.
Referenced by load_module().
00193 { 00194 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00195 struct gosub_stack_frame *oldframe; 00196 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00197 char *retval = data; 00198 00199 if (!stack_store) { 00200 ast_log(LOG_ERROR, "Return without Gosub: stack is unallocated\n"); 00201 return -1; 00202 } 00203 00204 oldlist = stack_store->data; 00205 AST_LIST_LOCK(oldlist); 00206 oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries); 00207 AST_LIST_UNLOCK(oldlist); 00208 00209 if (!oldframe) { 00210 ast_log(LOG_ERROR, "Return without Gosub: stack is empty\n"); 00211 return -1; 00212 } 00213 00214 ast_explicit_goto(chan, oldframe->context, oldframe->extension, oldframe->priority); 00215 gosub_release_frame(chan, oldframe); 00216 00217 /* Set a return value, if any */ 00218 pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", S_OR(retval, "")); 00219 return 0; 00220 }
static int unload_module | ( | void | ) | [static] |
Definition at line 503 of file app_stack.c.
References ast_agi_unregister(), ast_custom_function_unregister(), ast_unregister_application(), gosub_agi_command, and local_function.
00504 { 00505 if (ast_agi_unregister) { 00506 ast_agi_unregister(ast_module_info->self, &gosub_agi_command); 00507 } 00508 00509 ast_unregister_application(app_return); 00510 ast_unregister_application(app_pop); 00511 ast_unregister_application(app_gosubif); 00512 ast_unregister_application(app_gosub); 00513 ast_custom_function_unregister(&local_function); 00514 00515 return 0; 00516 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 536 of file app_stack.c.
const char* app_gosub = "Gosub" [static] |
Definition at line 47 of file app_stack.c.
const char* app_gosubif = "GosubIf" [static] |
Definition at line 48 of file app_stack.c.
const char* app_pop = "StackPop" [static] |
Definition at line 50 of file app_stack.c.
const char* app_return = "Return" [static] |
Definition at line 49 of file app_stack.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 536 of file app_stack.c.
struct agi_command gosub_agi_command |
Initial value:
{ { "gosub", NULL }, handle_gosub, "Execute a dialplan subroutine", usage_gosub , 0 }
Definition at line 500 of file app_stack.c.
Referenced by load_module(), and unload_module().
const char* gosub_descrip [static] |
Initial value:
" Gosub([[context,]exten,]priority[(arg1[,...][,argN])]):\n" "Jumps to the label specified, saving the return address.\n"
Definition at line 57 of file app_stack.c.
const char* gosub_synopsis = "Jump to label, saving return address" [static] |
Definition at line 52 of file app_stack.c.
const char* gosubif_descrip [static] |
Initial value:
" GosubIf(condition?labeliftrue[(arg1[,...])][:labeliffalse[(arg1[,...])]]):\n" "If the condition is true, then jump to labeliftrue. If false, jumps to\n" "labeliffalse, if specified. In either case, a jump saves the return point\n" "in the dialplan, to be returned to with a Return.\n"
Definition at line 60 of file app_stack.c.
const char* gosubif_synopsis = "Conditionally jump to label, saving return address" [static] |
Definition at line 53 of file app_stack.c.
struct ast_custom_function local_function [static] |
const char* pop_descrip [static] |
Initial value:
" StackPop():\n" "Removes last label on the stack, discarding it.\n"
Definition at line 69 of file app_stack.c.
const char* pop_synopsis = "Remove one address from gosub stack" [static] |
Definition at line 55 of file app_stack.c.
const char* return_descrip [static] |
Initial value:
" Return([return-value]):\n" "Jumps to the last label on the stack, removing it. The return value, if\n" "any, is saved in the channel variable GOSUB_RETVAL.\n"
Definition at line 65 of file app_stack.c.
const char* return_synopsis = "Return from gosub routine" [static] |
Definition at line 54 of file app_stack.c.
struct ast_datastore_info stack_info [static] |
Initial value:
{ .type = "GOSUB", .destroy = gosub_free, }
Definition at line 75 of file app_stack.c.
Referenced by gosub_exec(), local_read(), local_write(), pop_exec(), and return_exec().
char usage_gosub[] [static] |
Initial value:
" Usage: GOSUB <context> <extension> <priority> [<optional-argument>]\n" " Cause the channel to execute the specified dialplan subroutine, returning\n" " to the dialplan with execution of a Return()\n"
Definition at line 495 of file app_stack.c.