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 551 of file app_stack.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 551 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 91 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().
00092 { 00093 struct ast_var_t *variables; 00094 int found = 0; 00095 00096 /* Does this variable already exist? */ 00097 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) { 00098 if (!strcmp(var, ast_var_name(variables))) { 00099 found = 1; 00100 break; 00101 } 00102 } 00103 00104 if (!found) { 00105 variables = ast_var_assign(var, ""); 00106 AST_LIST_INSERT_HEAD(&frame->varshead, variables, entries); 00107 pbx_builtin_pushvar_helper(chan, var, value); 00108 } else { 00109 pbx_builtin_setvar_helper(chan, var, value); 00110 } 00111 00112 manager_event(EVENT_FLAG_DIALPLAN, "VarSet", 00113 "Channel: %s\r\n" 00114 "Variable: LOCAL(%s)\r\n" 00115 "Value: %s\r\n" 00116 "Uniqueid: %s\r\n", 00117 chan->name, var, value, chan->uniqueid); 00118 return 0; 00119 }
| static struct gosub_stack_frame* gosub_allocate_frame | ( | const char * | context, | |
| const char * | extension, | |||
| int | priority, | |||
| unsigned char | arguments | |||
| ) | [static, read] |
Definition at line 140 of file app_stack.c.
References ast_calloc, and AST_LIST_HEAD_INIT_NOLOCK.
Referenced by gosub_exec().
00141 { 00142 struct gosub_stack_frame *new = NULL; 00143 int len_extension = strlen(extension), len_context = strlen(context); 00144 00145 if ((new = ast_calloc(1, sizeof(*new) + 2 + len_extension + len_context))) { 00146 AST_LIST_HEAD_INIT_NOLOCK(&new->varshead); 00147 strcpy(new->extension, extension); 00148 new->context = new->extension + len_extension + 1; 00149 strcpy(new->context, context); 00150 new->priority = priority; 00151 new->arguments = arguments; 00152 } 00153 return new; 00154 }
| static int gosub_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 227 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().
00228 { 00229 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00230 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00231 struct gosub_stack_frame *newframe; 00232 char argname[15], *tmp = ast_strdupa(data), *label, *endparen; 00233 int i; 00234 AST_DECLARE_APP_ARGS(args2, 00235 AST_APP_ARG(argval)[100]; 00236 ); 00237 00238 if (ast_strlen_zero(data)) { 00239 ast_log(LOG_ERROR, "%s requires an argument: %s([[context,]exten,]priority[(arg1[,...][,argN])])\n", app_gosub, app_gosub); 00240 return -1; 00241 } 00242 00243 if (!stack_store) { 00244 ast_debug(1, "Channel %s has no datastore, so we're allocating one.\n", chan->name); 00245 stack_store = ast_datastore_alloc(&stack_info, NULL); 00246 if (!stack_store) { 00247 ast_log(LOG_ERROR, "Unable to allocate new datastore. Gosub will fail.\n"); 00248 return -1; 00249 } 00250 00251 oldlist = ast_calloc(1, sizeof(*oldlist)); 00252 if (!oldlist) { 00253 ast_log(LOG_ERROR, "Unable to allocate datastore list head. Gosub will fail.\n"); 00254 ast_datastore_free(stack_store); 00255 return -1; 00256 } 00257 00258 stack_store->data = oldlist; 00259 AST_LIST_HEAD_INIT(oldlist); 00260 ast_channel_datastore_add(chan, stack_store); 00261 } 00262 00263 /* Separate the arguments from the label */ 00264 /* NOTE: you cannot use ast_app_separate_args for this, because '(' cannot be used as a delimiter. */ 00265 label = strsep(&tmp, "("); 00266 if (tmp) { 00267 endparen = strrchr(tmp, ')'); 00268 if (endparen) 00269 *endparen = '\0'; 00270 else 00271 ast_log(LOG_WARNING, "Ouch. No closing paren: '%s'?\n", (char *)data); 00272 AST_STANDARD_RAW_ARGS(args2, tmp); 00273 } else 00274 args2.argc = 0; 00275 00276 /* Create the return address, but don't save it until we know that the Gosub destination exists */ 00277 newframe = gosub_allocate_frame(chan->context, chan->exten, chan->priority + 1, args2.argc); 00278 00279 if (!newframe) { 00280 return -1; 00281 } 00282 00283 if (ast_parseable_goto(chan, label)) { 00284 ast_log(LOG_ERROR, "Gosub address is invalid: '%s'\n", (char *)data); 00285 ast_free(newframe); 00286 return -1; 00287 } 00288 00289 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)) { 00290 ast_log(LOG_ERROR, "Attempt to reach a non-existent destination for gosub: (Context:%s, Extension:%s, Priority:%d)\n", 00291 chan->context, chan->exten, chan->priority); 00292 ast_copy_string(chan->context, newframe->context, sizeof(chan->context)); 00293 ast_copy_string(chan->exten, newframe->extension, sizeof(chan->exten)); 00294 chan->priority = newframe->priority; 00295 ast_free(newframe); 00296 return -1; 00297 } 00298 00299 /* Now that we know for certain that we're going to a new location, set our arguments */ 00300 for (i = 0; i < args2.argc; i++) { 00301 snprintf(argname, sizeof(argname), "ARG%d", i + 1); 00302 frame_set_var(chan, newframe, argname, args2.argval[i]); 00303 ast_debug(1, "Setting '%s' to '%s'\n", argname, args2.argval[i]); 00304 } 00305 00306 /* And finally, save our return address */ 00307 oldlist = stack_store->data; 00308 AST_LIST_LOCK(oldlist); 00309 AST_LIST_INSERT_HEAD(oldlist, newframe, entries); 00310 AST_LIST_UNLOCK(oldlist); 00311 00312 return 0; 00313 }
| static void gosub_free | ( | void * | data | ) | [static] |
Definition at line 156 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().
00157 { 00158 AST_LIST_HEAD(, gosub_stack_frame) *oldlist = data; 00159 struct gosub_stack_frame *oldframe; 00160 AST_LIST_LOCK(oldlist); 00161 while ((oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries))) { 00162 gosub_release_frame(NULL, oldframe); 00163 } 00164 AST_LIST_UNLOCK(oldlist); 00165 AST_LIST_HEAD_DESTROY(oldlist); 00166 ast_free(oldlist); 00167 }
| static void gosub_release_frame | ( | struct ast_channel * | chan, | |
| struct gosub_stack_frame * | frame | |||
| ) | [static] |
Definition at line 121 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().
00122 { 00123 struct ast_var_t *vardata; 00124 00125 /* If chan is not defined, then we're calling it as part of gosub_free, 00126 * and the channel variables will be deallocated anyway. Otherwise, we're 00127 * just releasing a single frame, so we need to clean up the arguments for 00128 * that frame, so that we re-expose the variables from the previous frame 00129 * that were hidden by this one. 00130 */ 00131 while ((vardata = AST_LIST_REMOVE_HEAD(&frame->varshead, entries))) { 00132 if (chan) 00133 pbx_builtin_setvar_helper(chan, ast_var_name(vardata), NULL); 00134 ast_var_delete(vardata); 00135 } 00136 00137 ast_free(frame); 00138 }
| static int gosubif_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 315 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().
00316 { 00317 char *args; 00318 int res=0; 00319 AST_DECLARE_APP_ARGS(cond, 00320 AST_APP_ARG(ition); 00321 AST_APP_ARG(labels); 00322 ); 00323 AST_DECLARE_APP_ARGS(label, 00324 AST_APP_ARG(iftrue); 00325 AST_APP_ARG(iffalse); 00326 ); 00327 00328 if (ast_strlen_zero(data)) { 00329 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n"); 00330 return 0; 00331 } 00332 00333 args = ast_strdupa(data); 00334 AST_NONSTANDARD_RAW_ARGS(cond, args, '?'); 00335 if (cond.argc != 2) { 00336 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n"); 00337 return 0; 00338 } 00339 00340 AST_NONSTANDARD_RAW_ARGS(label, cond.labels, ':'); 00341 00342 if (pbx_checkcondition(cond.ition)) { 00343 if (!ast_strlen_zero(label.iftrue)) 00344 res = gosub_exec(chan, label.iftrue); 00345 } else if (!ast_strlen_zero(label.iffalse)) { 00346 res = gosub_exec(chan, label.iffalse); 00347 } 00348 00349 return res; 00350 }
| static int handle_gosub | ( | struct ast_channel * | chan, | |
| AGI * | agi, | |||
| int | argc, | |||
| char ** | argv | |||
| ) | [static] |
Definition at line 415 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.
00416 { 00417 int old_priority, priority; 00418 char old_context[AST_MAX_CONTEXT], old_extension[AST_MAX_EXTENSION]; 00419 struct ast_app *theapp; 00420 char *gosub_args; 00421 00422 if (argc < 4 || argc > 5) { 00423 return RESULT_SHOWUSAGE; 00424 } 00425 00426 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] : ""); 00427 00428 if (sscanf(argv[3], "%30d", &priority) != 1 || priority < 1) { 00429 /* Lookup the priority label */ 00430 if ((priority = ast_findlabel_extension(chan, argv[1], argv[2], argv[3], chan->cid.cid_num)) < 0) { 00431 ast_log(LOG_ERROR, "Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]); 00432 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n"); 00433 return RESULT_FAILURE; 00434 } 00435 } else if (!ast_exists_extension(chan, argv[1], argv[2], priority, chan->cid.cid_num)) { 00436 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n"); 00437 return RESULT_FAILURE; 00438 } 00439 00440 /* Save previous location, since we're going to change it */ 00441 ast_copy_string(old_context, chan->context, sizeof(old_context)); 00442 ast_copy_string(old_extension, chan->exten, sizeof(old_extension)); 00443 old_priority = chan->priority; 00444 00445 if (!(theapp = pbx_findapp("Gosub"))) { 00446 ast_log(LOG_ERROR, "Gosub() cannot be found in the list of loaded applications\n"); 00447 ast_agi_send(agi->fd, chan, "503 result=-2 Gosub is not loaded\n"); 00448 return RESULT_FAILURE; 00449 } 00450 00451 /* Apparently, if you run ast_pbx_run on a channel that already has a pbx 00452 * structure, you need to add 1 to the priority to get it to go to the 00453 * right place. But if it doesn't have a pbx structure, then leaving off 00454 * the 1 is the right thing to do. See how this code differs when we 00455 * call a Gosub for the CALLEE channel in Dial or Queue. 00456 */ 00457 if (argc == 5) { 00458 if (asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority + (chan->pbx ? 1 : 0), argv[4]) < 0) { 00459 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00460 gosub_args = NULL; 00461 } 00462 } else { 00463 if (asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority + (chan->pbx ? 1 : 0)) < 0) { 00464 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00465 gosub_args = NULL; 00466 } 00467 } 00468 00469 if (gosub_args) { 00470 int res; 00471 00472 ast_debug(1, "Trying gosub with arguments '%s'\n", gosub_args); 00473 00474 if ((res = pbx_exec(chan, theapp, gosub_args)) == 0) { 00475 struct ast_pbx *pbx = chan->pbx; 00476 struct ast_pbx_args args; 00477 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00478 AST_LIST_HEAD(, gosub_stack_frame) *oldlist = stack_store->data; 00479 struct gosub_stack_frame *cur = AST_LIST_FIRST(oldlist); 00480 cur->is_agi = 1; 00481 00482 memset(&args, 0, sizeof(args)); 00483 args.no_hangup_chan = 1; 00484 /* Suppress warning about PBX already existing */ 00485 chan->pbx = NULL; 00486 ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n"); 00487 ast_pbx_run_args(chan, &args); 00488 ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete\n"); 00489 if (chan->pbx) { 00490 ast_free(chan->pbx); 00491 } 00492 chan->pbx = pbx; 00493 } else { 00494 ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res); 00495 } 00496 ast_free(gosub_args); 00497 } else { 00498 ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n"); 00499 return RESULT_FAILURE; 00500 } 00501 00502 /* Restore previous location */ 00503 ast_copy_string(chan->context, old_context, sizeof(chan->context)); 00504 ast_copy_string(chan->exten, old_extension, sizeof(chan->exten)); 00505 chan->priority = old_priority; 00506 00507 return RESULT_SUCCESS; 00508 }
| static int load_module | ( | void | ) | [static] |
Definition at line 533 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().
00534 { 00535 /* usage of AGI is optional, so check to see if the ast_agi_register() 00536 function is available; if so, use it. 00537 */ 00538 if (ast_agi_register) { 00539 ast_agi_register(ast_module_info->self, &gosub_agi_command); 00540 } 00541 00542 ast_register_application(app_pop, pop_exec, pop_synopsis, pop_descrip); 00543 ast_register_application(app_return, return_exec, return_synopsis, return_descrip); 00544 ast_register_application(app_gosubif, gosubif_exec, gosubif_synopsis, gosubif_descrip); 00545 ast_register_application(app_gosub, gosub_exec, gosub_synopsis, gosub_descrip); 00546 ast_custom_function_register(&local_function); 00547 00548 return 0; 00549 }
| static int local_read | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | data, | |||
| char * | buf, | |||
| size_t | len | |||
| ) | [static] |
Definition at line 352 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.
00353 { 00354 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00355 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00356 struct gosub_stack_frame *frame; 00357 struct ast_var_t *variables; 00358 00359 if (!stack_store) 00360 return -1; 00361 00362 oldlist = stack_store->data; 00363 AST_LIST_LOCK(oldlist); 00364 if (!(frame = AST_LIST_FIRST(oldlist))) { 00365 /* Not within a Gosub routine */ 00366 AST_LIST_UNLOCK(oldlist); 00367 return -1; 00368 } 00369 00370 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) { 00371 if (!strcmp(data, ast_var_name(variables))) { 00372 const char *tmp; 00373 ast_channel_lock(chan); 00374 tmp = pbx_builtin_getvar_helper(chan, data); 00375 ast_copy_string(buf, S_OR(tmp, ""), len); 00376 ast_channel_unlock(chan); 00377 break; 00378 } 00379 } 00380 AST_LIST_UNLOCK(oldlist); 00381 return 0; 00382 }
| static int local_write | ( | struct ast_channel * | chan, | |
| const char * | cmd, | |||
| char * | var, | |||
| const char * | value | |||
| ) | [static] |
Definition at line 384 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.
00385 { 00386 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00387 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00388 struct gosub_stack_frame *frame; 00389 00390 if (!stack_store) { 00391 ast_log(LOG_ERROR, "Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var); 00392 return -1; 00393 } 00394 00395 oldlist = stack_store->data; 00396 AST_LIST_LOCK(oldlist); 00397 frame = AST_LIST_FIRST(oldlist); 00398 00399 if (frame) 00400 frame_set_var(chan, frame, var, value); 00401 00402 AST_LIST_UNLOCK(oldlist); 00403 00404 return 0; 00405 }
| static int pop_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 169 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().
00170 { 00171 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00172 struct gosub_stack_frame *oldframe; 00173 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00174 00175 if (!stack_store) { 00176 ast_log(LOG_WARNING, "%s called with no gosub stack allocated.\n", app_pop); 00177 return 0; 00178 } 00179 00180 oldlist = stack_store->data; 00181 AST_LIST_LOCK(oldlist); 00182 oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries); 00183 AST_LIST_UNLOCK(oldlist); 00184 00185 if (oldframe) { 00186 gosub_release_frame(chan, oldframe); 00187 } else { 00188 ast_debug(1, "%s called with an empty gosub stack\n", app_pop); 00189 } 00190 return 0; 00191 }
| static int return_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 193 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().
00194 { 00195 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00196 struct gosub_stack_frame *oldframe; 00197 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00198 char *retval = data; 00199 int res = 0; 00200 00201 if (!stack_store) { 00202 ast_log(LOG_ERROR, "Return without Gosub: stack is unallocated\n"); 00203 return -1; 00204 } 00205 00206 oldlist = stack_store->data; 00207 AST_LIST_LOCK(oldlist); 00208 oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries); 00209 AST_LIST_UNLOCK(oldlist); 00210 00211 if (!oldframe) { 00212 ast_log(LOG_ERROR, "Return without Gosub: stack is empty\n"); 00213 return -1; 00214 } else if (oldframe->is_agi) { 00215 /* Exit from AGI */ 00216 res = -1; 00217 } 00218 00219 ast_explicit_goto(chan, oldframe->context, oldframe->extension, oldframe->priority); 00220 gosub_release_frame(chan, oldframe); 00221 00222 /* Set a return value, if any */ 00223 pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", S_OR(retval, "")); 00224 return res; 00225 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 518 of file app_stack.c.
References ast_agi_unregister(), ast_custom_function_unregister(), ast_unregister_application(), gosub_agi_command, and local_function.
00519 { 00520 if (ast_agi_unregister) { 00521 ast_agi_unregister(ast_module_info->self, &gosub_agi_command); 00522 } 00523 00524 ast_unregister_application(app_return); 00525 ast_unregister_application(app_pop); 00526 ast_unregister_application(app_gosubif); 00527 ast_unregister_application(app_gosub); 00528 ast_custom_function_unregister(&local_function); 00529 00530 return 0; 00531 }
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 551 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 551 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 515 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 407 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 510 of file app_stack.c.
1.6.1