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 |
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 = "a9c98e5d177805051735cb5b0b16b0a0" , .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 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 [] |
Stack applications Gosub, Return, etc.
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 541 of file app_stack.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 541 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(), 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, read] |
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_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_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, gosub_stack_frame::priority, ast_channel::priority, 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_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_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_RAW_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(), 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_RAW_ARGS, ast_strdupa, ast_strlen_zero(), 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_RAW_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_RAW_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 410 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(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, errno, ast_channel::exten, agi_state::fd, 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.
00411 { 00412 int old_priority, priority; 00413 char old_context[AST_MAX_CONTEXT], old_extension[AST_MAX_EXTENSION]; 00414 struct ast_app *theapp; 00415 char *gosub_args; 00416 00417 if (argc < 4 || argc > 5) { 00418 return RESULT_SHOWUSAGE; 00419 } 00420 00421 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] : ""); 00422 00423 if (sscanf(argv[3], "%30d", &priority) != 1 || priority < 1) { 00424 /* Lookup the priority label */ 00425 if ((priority = ast_findlabel_extension(chan, argv[1], argv[2], argv[3], chan->cid.cid_num)) < 0) { 00426 ast_log(LOG_ERROR, "Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]); 00427 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n"); 00428 return RESULT_FAILURE; 00429 } 00430 } else if (!ast_exists_extension(chan, argv[1], argv[2], priority, chan->cid.cid_num)) { 00431 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n"); 00432 return RESULT_FAILURE; 00433 } 00434 00435 /* Save previous location, since we're going to change it */ 00436 ast_copy_string(old_context, chan->context, sizeof(old_context)); 00437 ast_copy_string(old_extension, chan->exten, sizeof(old_extension)); 00438 old_priority = chan->priority; 00439 00440 if (!(theapp = pbx_findapp("Gosub"))) { 00441 ast_log(LOG_ERROR, "Gosub() cannot be found in the list of loaded applications\n"); 00442 ast_agi_send(agi->fd, chan, "503 result=-2 Gosub is not loaded\n"); 00443 return RESULT_FAILURE; 00444 } 00445 00446 /* Apparently, if you run ast_pbx_run on a channel that already has a pbx 00447 * structure, you need to add 1 to the priority to get it to go to the 00448 * right place. But if it doesn't have a pbx structure, then leaving off 00449 * the 1 is the right thing to do. See how this code differs when we 00450 * call a Gosub for the CALLEE channel in Dial or Queue. 00451 */ 00452 if (argc == 5) { 00453 if (asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority + 1, argv[4]) < 0) { 00454 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00455 gosub_args = NULL; 00456 } 00457 } else { 00458 if (asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority + 1) < 0) { 00459 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00460 gosub_args = NULL; 00461 } 00462 } 00463 00464 if (gosub_args) { 00465 int res; 00466 00467 ast_debug(1, "Trying gosub with arguments '%s'\n", gosub_args); 00468 00469 if ((res = pbx_exec(chan, theapp, gosub_args)) == 0) { 00470 struct ast_pbx *pbx = chan->pbx; 00471 struct ast_pbx_args args; 00472 memset(&args, 0, sizeof(args)); 00473 args.no_hangup_chan = 1; 00474 /* Suppress warning about PBX already existing */ 00475 chan->pbx = NULL; 00476 ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n"); 00477 ast_pbx_run_args(chan, &args); 00478 ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete\n"); 00479 if (chan->pbx) { 00480 ast_free(chan->pbx); 00481 } 00482 chan->pbx = pbx; 00483 } else { 00484 ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res); 00485 } 00486 ast_free(gosub_args); 00487 } else { 00488 ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n"); 00489 return RESULT_FAILURE; 00490 } 00491 00492 /* Restore previous location */ 00493 ast_copy_string(chan->context, old_context, sizeof(chan->context)); 00494 ast_copy_string(chan->exten, old_extension, sizeof(chan->exten)); 00495 chan->priority = old_priority; 00496 00497 return RESULT_SUCCESS; 00498 }
| static int load_module | ( | void | ) | [static] |
Definition at line 523 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().
00524 { 00525 /* usage of AGI is optional, so check to see if the ast_agi_register() 00526 function is available; if so, use it. 00527 */ 00528 if (ast_agi_register) { 00529 ast_agi_register(ast_module_info->self, &gosub_agi_command); 00530 } 00531 00532 ast_register_application(app_pop, pop_exec, pop_synopsis, pop_descrip); 00533 ast_register_application(app_return, return_exec, return_synopsis, return_descrip); 00534 ast_register_application(app_gosubif, gosubif_exec, gosubif_synopsis, gosubif_descrip); 00535 ast_register_application(app_gosub, gosub_exec, gosub_synopsis, gosub_descrip); 00536 ast_custom_function_register(&local_function); 00537 00538 return 0; 00539 }
| 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_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.
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 if (!(frame = AST_LIST_FIRST(oldlist))) { 00360 /* Not within a Gosub routine */ 00361 AST_LIST_UNLOCK(oldlist); 00362 return -1; 00363 } 00364 00365 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) { 00366 if (!strcmp(data, ast_var_name(variables))) { 00367 const char *tmp; 00368 ast_channel_lock(chan); 00369 tmp = pbx_builtin_getvar_helper(chan, data); 00370 ast_copy_string(buf, S_OR(tmp, ""), len); 00371 ast_channel_unlock(chan); 00372 break; 00373 } 00374 } 00375 AST_LIST_UNLOCK(oldlist); 00376 return 0; 00377 }
| static int local_write | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | var, | |||
| const char * | value | |||
| ) | [static] |
Definition at line 379 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.
00380 { 00381 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00382 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00383 struct gosub_stack_frame *frame; 00384 00385 if (!stack_store) { 00386 ast_log(LOG_ERROR, "Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var); 00387 return -1; 00388 } 00389 00390 oldlist = stack_store->data; 00391 AST_LIST_LOCK(oldlist); 00392 frame = AST_LIST_FIRST(oldlist); 00393 00394 if (frame) 00395 frame_set_var(chan, frame, var, value); 00396 00397 AST_LIST_UNLOCK(oldlist); 00398 00399 return 0; 00400 }
| 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(), ast_datastore::data, gosub_stack_frame::entries, gosub_release_frame(), and LOG_WARNING.
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(), 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, and S_OR.
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 508 of file app_stack.c.
References ast_agi_unregister(), ast_custom_function_unregister(), ast_unregister_application(), gosub_agi_command, and local_function.
00509 { 00510 if (ast_agi_unregister) { 00511 ast_agi_unregister(ast_module_info->self, &gosub_agi_command); 00512 } 00513 00514 ast_unregister_application(app_return); 00515 ast_unregister_application(app_pop); 00516 ast_unregister_application(app_gosubif); 00517 ast_unregister_application(app_gosub); 00518 ast_custom_function_unregister(&local_function); 00519 00520 return 0; 00521 }
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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 541 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.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 541 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 505 of file app_stack.c.
Referenced by load_module(), and unload_module().
const char* gosub_descrip [static] |
" 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] |
" 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] |
Definition at line 402 of file app_stack.c.
Referenced by load_module(), and unload_module().
const char* pop_descrip [static] |
" 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] |
" 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] |
{
.type = "GOSUB",
.destroy = gosub_free,
}
Definition at line 75 of file app_stack.c.
char usage_gosub[] [static] |
" 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 500 of file app_stack.c.
1.6.1