#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 |
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 562 of file app_stack.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 562 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(), 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().
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] |
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 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, 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().
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, *lastframe; 00232 char argname[15], *tmp = ast_strdupa(data), *label, *endparen; 00233 int i, max_argc = 0; 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 } else { 00262 oldlist = stack_store->data; 00263 } 00264 00265 if ((lastframe = AST_LIST_FIRST(oldlist))) { 00266 max_argc = lastframe->arguments; 00267 } 00268 00269 /* Separate the arguments from the label */ 00270 /* NOTE: you cannot use ast_app_separate_args for this, because '(' cannot be used as a delimiter. */ 00271 label = strsep(&tmp, "("); 00272 if (tmp) { 00273 endparen = strrchr(tmp, ')'); 00274 if (endparen) 00275 *endparen = '\0'; 00276 else 00277 ast_log(LOG_WARNING, "Ouch. No closing paren: '%s'?\n", (char *)data); 00278 AST_STANDARD_RAW_ARGS(args2, tmp); 00279 } else 00280 args2.argc = 0; 00281 00282 /* Mask out previous arguments in this invocation */ 00283 if (args2.argc > max_argc) { 00284 max_argc = args2.argc; 00285 } 00286 00287 /* Create the return address, but don't save it until we know that the Gosub destination exists */ 00288 newframe = gosub_allocate_frame(chan->context, chan->exten, chan->priority + 1, max_argc); 00289 00290 if (!newframe) { 00291 return -1; 00292 } 00293 00294 if (ast_parseable_goto(chan, label)) { 00295 ast_log(LOG_ERROR, "Gosub address is invalid: '%s'\n", (char *)data); 00296 ast_free(newframe); 00297 return -1; 00298 } 00299 00300 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)) { 00301 ast_log(LOG_ERROR, "Attempt to reach a non-existent destination for gosub: (Context:%s, Extension:%s, Priority:%d)\n", 00302 chan->context, chan->exten, chan->priority); 00303 ast_copy_string(chan->context, newframe->context, sizeof(chan->context)); 00304 ast_copy_string(chan->exten, newframe->extension, sizeof(chan->exten)); 00305 chan->priority = newframe->priority; 00306 ast_free(newframe); 00307 return -1; 00308 } 00309 00310 /* Now that we know for certain that we're going to a new location, set our arguments */ 00311 for (i = 0; i < max_argc; i++) { 00312 snprintf(argname, sizeof(argname), "ARG%d", i + 1); 00313 frame_set_var(chan, newframe, argname, i < args2.argc ? args2.argval[i] : ""); 00314 ast_debug(1, "Setting '%s' to '%s'\n", argname, i < args2.argc ? args2.argval[i] : ""); 00315 } 00316 00317 /* And finally, save our return address */ 00318 oldlist = stack_store->data; 00319 AST_LIST_LOCK(oldlist); 00320 AST_LIST_INSERT_HEAD(oldlist, newframe, entries); 00321 AST_LIST_UNLOCK(oldlist); 00322 00323 return 0; 00324 }
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(), chan, 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 326 of file app_stack.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_NONSTANDARD_RAW_ARGS, ast_strdupa, ast_strlen_zero(), chan, cond, gosub_exec(), LOG_WARNING, and pbx_checkcondition().
Referenced by load_module().
00327 { 00328 char *args; 00329 int res=0; 00330 AST_DECLARE_APP_ARGS(cond, 00331 AST_APP_ARG(ition); 00332 AST_APP_ARG(labels); 00333 ); 00334 AST_DECLARE_APP_ARGS(label, 00335 AST_APP_ARG(iftrue); 00336 AST_APP_ARG(iffalse); 00337 ); 00338 00339 if (ast_strlen_zero(data)) { 00340 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n"); 00341 return 0; 00342 } 00343 00344 args = ast_strdupa(data); 00345 AST_NONSTANDARD_RAW_ARGS(cond, args, '?'); 00346 if (cond.argc != 2) { 00347 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n"); 00348 return 0; 00349 } 00350 00351 AST_NONSTANDARD_RAW_ARGS(label, cond.labels, ':'); 00352 00353 if (pbx_checkcondition(cond.ition)) { 00354 if (!ast_strlen_zero(label.iftrue)) 00355 res = gosub_exec(chan, label.iftrue); 00356 } else if (!ast_strlen_zero(label.iffalse)) { 00357 res = gosub_exec(chan, label.iffalse); 00358 } 00359 00360 return res; 00361 }
static int handle_gosub | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 426 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(), chan, 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_channel::pbx, pbx_exec(), pbx_findapp(), ast_channel::priority, gosub_stack_frame::priority, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, and stack_info.
00427 { 00428 int old_priority, priority; 00429 char old_context[AST_MAX_CONTEXT], old_extension[AST_MAX_EXTENSION]; 00430 struct ast_app *theapp; 00431 char *gosub_args; 00432 00433 if (argc < 4 || argc > 5) { 00434 return RESULT_SHOWUSAGE; 00435 } 00436 00437 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] : ""); 00438 00439 if (sscanf(argv[3], "%30d", &priority) != 1 || priority < 1) { 00440 /* Lookup the priority label */ 00441 if ((priority = ast_findlabel_extension(chan, argv[1], argv[2], argv[3], chan->cid.cid_num)) < 0) { 00442 ast_log(LOG_ERROR, "Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]); 00443 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n"); 00444 return RESULT_FAILURE; 00445 } 00446 } else if (!ast_exists_extension(chan, argv[1], argv[2], priority, chan->cid.cid_num)) { 00447 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n"); 00448 return RESULT_FAILURE; 00449 } 00450 00451 /* Save previous location, since we're going to change it */ 00452 ast_copy_string(old_context, chan->context, sizeof(old_context)); 00453 ast_copy_string(old_extension, chan->exten, sizeof(old_extension)); 00454 old_priority = chan->priority; 00455 00456 if (!(theapp = pbx_findapp("Gosub"))) { 00457 ast_log(LOG_ERROR, "Gosub() cannot be found in the list of loaded applications\n"); 00458 ast_agi_send(agi->fd, chan, "503 result=-2 Gosub is not loaded\n"); 00459 return RESULT_FAILURE; 00460 } 00461 00462 /* Apparently, if you run ast_pbx_run on a channel that already has a pbx 00463 * structure, you need to add 1 to the priority to get it to go to the 00464 * right place. But if it doesn't have a pbx structure, then leaving off 00465 * the 1 is the right thing to do. See how this code differs when we 00466 * call a Gosub for the CALLEE channel in Dial or Queue. 00467 */ 00468 if (argc == 5) { 00469 if (asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority + (chan->pbx ? 1 : 0), argv[4]) < 0) { 00470 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00471 gosub_args = NULL; 00472 } 00473 } else { 00474 if (asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority + (chan->pbx ? 1 : 0)) < 0) { 00475 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00476 gosub_args = NULL; 00477 } 00478 } 00479 00480 if (gosub_args) { 00481 int res; 00482 00483 ast_debug(1, "Trying gosub with arguments '%s'\n", gosub_args); 00484 00485 if ((res = pbx_exec(chan, theapp, gosub_args)) == 0) { 00486 struct ast_pbx *pbx = chan->pbx; 00487 struct ast_pbx_args args; 00488 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00489 AST_LIST_HEAD(, gosub_stack_frame) *oldlist = stack_store->data; 00490 struct gosub_stack_frame *cur = AST_LIST_FIRST(oldlist); 00491 cur->is_agi = 1; 00492 00493 memset(&args, 0, sizeof(args)); 00494 args.no_hangup_chan = 1; 00495 /* Suppress warning about PBX already existing */ 00496 chan->pbx = NULL; 00497 ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n"); 00498 ast_pbx_run_args(chan, &args); 00499 ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete\n"); 00500 if (chan->pbx) { 00501 ast_free(chan->pbx); 00502 } 00503 chan->pbx = pbx; 00504 } else { 00505 ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res); 00506 } 00507 ast_free(gosub_args); 00508 } else { 00509 ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n"); 00510 return RESULT_FAILURE; 00511 } 00512 00513 /* Restore previous location */ 00514 ast_copy_string(chan->context, old_context, sizeof(chan->context)); 00515 ast_copy_string(chan->exten, old_extension, sizeof(chan->exten)); 00516 chan->priority = old_priority; 00517 00518 return RESULT_SUCCESS; 00519 }
static int load_module | ( | void | ) | [static] |
Definition at line 544 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().
00545 { 00546 /* usage of AGI is optional, so check to see if the ast_agi_register() 00547 function is available; if so, use it. 00548 */ 00549 if (ast_agi_register) { 00550 ast_agi_register(ast_module_info->self, &gosub_agi_command); 00551 } 00552 00553 ast_register_application(app_pop, pop_exec, pop_synopsis, pop_descrip); 00554 ast_register_application(app_return, return_exec, return_synopsis, return_descrip); 00555 ast_register_application(app_gosubif, gosubif_exec, gosubif_synopsis, gosubif_descrip); 00556 ast_register_application(app_gosub, gosub_exec, gosub_synopsis, gosub_descrip); 00557 ast_custom_function_register(&local_function); 00558 00559 return 0; 00560 }
static int local_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 363 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(), chan, ast_datastore::data, gosub_stack_frame::entries, pbx_builtin_getvar_helper(), S_OR, stack_info, and gosub_stack_frame::varshead.
00364 { 00365 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00366 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00367 struct gosub_stack_frame *frame; 00368 struct ast_var_t *variables; 00369 00370 if (!stack_store) 00371 return -1; 00372 00373 oldlist = stack_store->data; 00374 AST_LIST_LOCK(oldlist); 00375 if (!(frame = AST_LIST_FIRST(oldlist))) { 00376 /* Not within a Gosub routine */ 00377 AST_LIST_UNLOCK(oldlist); 00378 return -1; 00379 } 00380 00381 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) { 00382 if (!strcmp(data, ast_var_name(variables))) { 00383 const char *tmp; 00384 ast_channel_lock(chan); 00385 tmp = pbx_builtin_getvar_helper(chan, data); 00386 ast_copy_string(buf, S_OR(tmp, ""), len); 00387 ast_channel_unlock(chan); 00388 break; 00389 } 00390 } 00391 AST_LIST_UNLOCK(oldlist); 00392 return 0; 00393 }
static int local_write | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | var, | |||
const char * | value | |||
) | [static] |
Definition at line 395 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.
00396 { 00397 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00398 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00399 struct gosub_stack_frame *frame; 00400 00401 if (!stack_store) { 00402 ast_log(LOG_ERROR, "Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var); 00403 return -1; 00404 } 00405 00406 oldlist = stack_store->data; 00407 AST_LIST_LOCK(oldlist); 00408 frame = AST_LIST_FIRST(oldlist); 00409 00410 if (frame) 00411 frame_set_var(chan, frame, var, value); 00412 00413 AST_LIST_UNLOCK(oldlist); 00414 00415 return 0; 00416 }
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(), chan, ast_datastore::data, gosub_stack_frame::entries, gosub_release_frame(), LOG_WARNING, and stack_info.
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(), chan, 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, S_OR, and stack_info.
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 529 of file app_stack.c.
References ast_agi_unregister(), ast_custom_function_unregister(), ast_unregister_application(), gosub_agi_command, and local_function.
00530 { 00531 if (ast_agi_unregister) { 00532 ast_agi_unregister(ast_module_info->self, &gosub_agi_command); 00533 } 00534 00535 ast_unregister_application(app_return); 00536 ast_unregister_application(app_pop); 00537 ast_unregister_application(app_gosubif); 00538 ast_unregister_application(app_gosub); 00539 ast_custom_function_unregister(&local_function); 00540 00541 return 0; 00542 }
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 562 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 562 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 526 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(), handle_gosub(), 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 521 of file app_stack.c.