#include "asterisk.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/app.h"
#include "asterisk/manager.h"
#include "asterisk/channel.h"
#include "asterisk/agi.h"
Go to the source code of this file.
Data Structures | |
struct | gosub_stack_frame |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | frame_set_var (struct ast_channel *chan, struct gosub_stack_frame *frame, const char *var, const char *value) |
static struct gosub_stack_frame * | gosub_allocate_frame (const char *context, const char *extension, int priority, unsigned char arguments) |
static int | gosub_exec (struct ast_channel *chan, const char *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, const char *data) |
static int | handle_gosub (struct ast_channel *chan, AGI *agi, int argc, const char *const *argv) |
static int | load_module (void) |
static int | local_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
static int | local_write (struct ast_channel *chan, const char *cmd, char *var, const char *value) |
static int | peek_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) |
static int | pop_exec (struct ast_channel *chan, const char *data) |
static int | return_exec (struct ast_channel *chan, const char *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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .nonoptreq = "res_agi", } |
static const char *const | app_gosub = "Gosub" |
static const char *const | app_gosubif = "GosubIf" |
static const char *const | app_pop = "StackPop" |
static const char *const | app_return = "Return" |
static struct ast_module_info * | ast_module_info = &__mod_info |
static struct agi_command | gosub_agi_command |
static struct ast_custom_function | local_function |
static struct ast_custom_function | peek_function |
static struct ast_datastore_info | stack_info |
Definition in file app_stack.c.
static void __reg_module | ( | void | ) | [static] |
Definition at line 712 of file app_stack.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 712 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 208 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().
00209 { 00210 struct ast_var_t *variables; 00211 int found = 0; 00212 00213 /* Does this variable already exist? */ 00214 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) { 00215 if (!strcmp(var, ast_var_name(variables))) { 00216 found = 1; 00217 break; 00218 } 00219 } 00220 00221 if (!found) { 00222 variables = ast_var_assign(var, ""); 00223 AST_LIST_INSERT_HEAD(&frame->varshead, variables, entries); 00224 pbx_builtin_pushvar_helper(chan, var, value); 00225 } else { 00226 pbx_builtin_setvar_helper(chan, var, value); 00227 } 00228 00229 manager_event(EVENT_FLAG_DIALPLAN, "VarSet", 00230 "Channel: %s\r\n" 00231 "Variable: LOCAL(%s)\r\n" 00232 "Value: %s\r\n" 00233 "Uniqueid: %s\r\n", 00234 chan->name, var, value, chan->uniqueid); 00235 return 0; 00236 }
static struct gosub_stack_frame* gosub_allocate_frame | ( | const char * | context, | |
const char * | extension, | |||
int | priority, | |||
unsigned char | arguments | |||
) | [static] |
Definition at line 257 of file app_stack.c.
References ast_calloc, and AST_LIST_HEAD_INIT_NOLOCK.
Referenced by gosub_exec().
00258 { 00259 struct gosub_stack_frame *new = NULL; 00260 int len_extension = strlen(extension), len_context = strlen(context); 00261 00262 if ((new = ast_calloc(1, sizeof(*new) + 2 + len_extension + len_context))) { 00263 AST_LIST_HEAD_INIT_NOLOCK(&new->varshead); 00264 strcpy(new->extension, extension); 00265 new->context = new->extension + len_extension + 1; 00266 strcpy(new->context, context); 00267 new->priority = priority; 00268 new->arguments = arguments; 00269 } 00270 return new; 00271 }
static int gosub_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 344 of file app_stack.c.
References gosub_stack_frame::arguments, AST_APP_ARG, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_copy_string(), ast_datastore_alloc, ast_datastore_free(), ast_debug, AST_DECLARE_APP_ARGS, ast_exists_extension(), AST_FLAG_IN_AUTOLOOP, ast_free, AST_LIST_FIRST, AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_parseable_goto(), AST_STANDARD_RAW_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_channel::caller, 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(), ast_party_caller::id, LOG_ERROR, LOG_WARNING, ast_channel::name, ast_party_id::number, gosub_stack_frame::priority, ast_channel::priority, S_COR, stack_info, ast_party_number::str, strsep(), and ast_party_number::valid.
Referenced by gosubif_exec(), and load_module().
00345 { 00346 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00347 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00348 struct gosub_stack_frame *newframe, *lastframe; 00349 char argname[15], *tmp = ast_strdupa(data), *label, *endparen; 00350 int i, max_argc = 0; 00351 AST_DECLARE_APP_ARGS(args2, 00352 AST_APP_ARG(argval)[100]; 00353 ); 00354 00355 if (ast_strlen_zero(data)) { 00356 ast_log(LOG_ERROR, "%s requires an argument: %s([[context,]exten,]priority[(arg1[,...][,argN])])\n", app_gosub, app_gosub); 00357 return -1; 00358 } 00359 00360 if (!stack_store) { 00361 ast_debug(1, "Channel %s has no datastore, so we're allocating one.\n", chan->name); 00362 stack_store = ast_datastore_alloc(&stack_info, NULL); 00363 if (!stack_store) { 00364 ast_log(LOG_ERROR, "Unable to allocate new datastore. Gosub will fail.\n"); 00365 return -1; 00366 } 00367 00368 oldlist = ast_calloc(1, sizeof(*oldlist)); 00369 if (!oldlist) { 00370 ast_log(LOG_ERROR, "Unable to allocate datastore list head. Gosub will fail.\n"); 00371 ast_datastore_free(stack_store); 00372 return -1; 00373 } 00374 00375 stack_store->data = oldlist; 00376 AST_LIST_HEAD_INIT(oldlist); 00377 ast_channel_datastore_add(chan, stack_store); 00378 } else { 00379 oldlist = stack_store->data; 00380 } 00381 00382 if ((lastframe = AST_LIST_FIRST(oldlist))) { 00383 max_argc = lastframe->arguments; 00384 } 00385 00386 /* Separate the arguments from the label */ 00387 /* NOTE: you cannot use ast_app_separate_args for this, because '(' cannot be used as a delimiter. */ 00388 label = strsep(&tmp, "("); 00389 if (tmp) { 00390 endparen = strrchr(tmp, ')'); 00391 if (endparen) 00392 *endparen = '\0'; 00393 else 00394 ast_log(LOG_WARNING, "Ouch. No closing paren: '%s'?\n", (char *)data); 00395 AST_STANDARD_RAW_ARGS(args2, tmp); 00396 } else 00397 args2.argc = 0; 00398 00399 /* Mask out previous arguments in this invocation */ 00400 if (args2.argc > max_argc) { 00401 max_argc = args2.argc; 00402 } 00403 00404 /* Create the return address, but don't save it until we know that the Gosub destination exists */ 00405 newframe = gosub_allocate_frame(chan->context, chan->exten, chan->priority + 1, max_argc); 00406 00407 if (!newframe) { 00408 return -1; 00409 } 00410 00411 if (ast_parseable_goto(chan, label)) { 00412 ast_log(LOG_ERROR, "Gosub address is invalid: '%s'\n", (char *)data); 00413 ast_free(newframe); 00414 return -1; 00415 } 00416 00417 if (!ast_exists_extension(chan, chan->context, chan->exten, 00418 ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP) ? chan->priority + 1 : chan->priority, 00419 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 00420 ast_log(LOG_ERROR, "Attempt to reach a non-existent destination for gosub: (Context:%s, Extension:%s, Priority:%d)\n", 00421 chan->context, chan->exten, ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP) ? chan->priority + 1 : chan->priority); 00422 ast_copy_string(chan->context, newframe->context, sizeof(chan->context)); 00423 ast_copy_string(chan->exten, newframe->extension, sizeof(chan->exten)); 00424 chan->priority = newframe->priority; 00425 ast_free(newframe); 00426 return -1; 00427 } 00428 00429 /* Now that we know for certain that we're going to a new location, set our arguments */ 00430 for (i = 0; i < max_argc; i++) { 00431 snprintf(argname, sizeof(argname), "ARG%d", i + 1); 00432 frame_set_var(chan, newframe, argname, i < args2.argc ? args2.argval[i] : ""); 00433 ast_debug(1, "Setting '%s' to '%s'\n", argname, i < args2.argc ? args2.argval[i] : ""); 00434 } 00435 snprintf(argname, sizeof(argname), "%d", args2.argc); 00436 frame_set_var(chan, newframe, "ARGC", argname); 00437 00438 /* And finally, save our return address */ 00439 oldlist = stack_store->data; 00440 AST_LIST_LOCK(oldlist); 00441 AST_LIST_INSERT_HEAD(oldlist, newframe, entries); 00442 AST_LIST_UNLOCK(oldlist); 00443 00444 return 0; 00445 }
static void gosub_free | ( | void * | data | ) | [static] |
Definition at line 273 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().
00274 { 00275 AST_LIST_HEAD(, gosub_stack_frame) *oldlist = data; 00276 struct gosub_stack_frame *oldframe; 00277 AST_LIST_LOCK(oldlist); 00278 while ((oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries))) { 00279 gosub_release_frame(NULL, oldframe); 00280 } 00281 AST_LIST_UNLOCK(oldlist); 00282 AST_LIST_HEAD_DESTROY(oldlist); 00283 ast_free(oldlist); 00284 }
static void gosub_release_frame | ( | struct ast_channel * | chan, | |
struct gosub_stack_frame * | frame | |||
) | [static] |
Definition at line 238 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().
00239 { 00240 struct ast_var_t *vardata; 00241 00242 /* If chan is not defined, then we're calling it as part of gosub_free, 00243 * and the channel variables will be deallocated anyway. Otherwise, we're 00244 * just releasing a single frame, so we need to clean up the arguments for 00245 * that frame, so that we re-expose the variables from the previous frame 00246 * that were hidden by this one. 00247 */ 00248 while ((vardata = AST_LIST_REMOVE_HEAD(&frame->varshead, entries))) { 00249 if (chan) 00250 pbx_builtin_setvar_helper(chan, ast_var_name(vardata), NULL); 00251 ast_var_delete(vardata); 00252 } 00253 00254 ast_free(frame); 00255 }
static int gosubif_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 447 of file app_stack.c.
References args, 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().
00448 { 00449 char *args; 00450 int res=0; 00451 AST_DECLARE_APP_ARGS(cond, 00452 AST_APP_ARG(ition); 00453 AST_APP_ARG(labels); 00454 ); 00455 AST_DECLARE_APP_ARGS(label, 00456 AST_APP_ARG(iftrue); 00457 AST_APP_ARG(iffalse); 00458 ); 00459 00460 if (ast_strlen_zero(data)) { 00461 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n"); 00462 return 0; 00463 } 00464 00465 args = ast_strdupa(data); 00466 AST_NONSTANDARD_RAW_ARGS(cond, args, '?'); 00467 if (cond.argc != 2) { 00468 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n"); 00469 return 0; 00470 } 00471 00472 AST_NONSTANDARD_RAW_ARGS(label, cond.labels, ':'); 00473 00474 if (pbx_checkcondition(cond.ition)) { 00475 if (!ast_strlen_zero(label.iftrue)) 00476 res = gosub_exec(chan, label.iftrue); 00477 } else if (!ast_strlen_zero(label.iffalse)) { 00478 res = gosub_exec(chan, label.iffalse); 00479 } 00480 00481 return res; 00482 }
static int handle_gosub | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const * | argv | |||
) | [static] |
Definition at line 579 of file app_stack.c.
References args, 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::caller, ast_channel::context, ast_datastore::data, errno, ast_channel::exten, agi_state::fd, ast_party_caller::id, gosub_stack_frame::is_agi, LOG_ERROR, LOG_WARNING, ast_party_id::number, ast_channel::pbx, pbx_exec(), pbx_findapp(), ast_channel::priority, gosub_stack_frame::priority, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, S_COR, stack_info, ast_party_number::str, and ast_party_number::valid.
00580 { 00581 int old_priority, priority; 00582 char old_context[AST_MAX_CONTEXT], old_extension[AST_MAX_EXTENSION]; 00583 struct ast_app *theapp; 00584 char *gosub_args; 00585 00586 if (argc < 4 || argc > 5) { 00587 return RESULT_SHOWUSAGE; 00588 } 00589 00590 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] : ""); 00591 00592 if (sscanf(argv[3], "%30d", &priority) != 1 || priority < 1) { 00593 /* Lookup the priority label */ 00594 priority = ast_findlabel_extension(chan, argv[1], argv[2], argv[3], 00595 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL)); 00596 if (priority < 0) { 00597 ast_log(LOG_ERROR, "Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]); 00598 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n"); 00599 return RESULT_FAILURE; 00600 } 00601 } else if (!ast_exists_extension(chan, argv[1], argv[2], priority, 00602 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 00603 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n"); 00604 return RESULT_FAILURE; 00605 } 00606 00607 /* Save previous location, since we're going to change it */ 00608 ast_copy_string(old_context, chan->context, sizeof(old_context)); 00609 ast_copy_string(old_extension, chan->exten, sizeof(old_extension)); 00610 old_priority = chan->priority; 00611 00612 if (!(theapp = pbx_findapp("Gosub"))) { 00613 ast_log(LOG_ERROR, "Gosub() cannot be found in the list of loaded applications\n"); 00614 ast_agi_send(agi->fd, chan, "503 result=-2 Gosub is not loaded\n"); 00615 return RESULT_FAILURE; 00616 } 00617 00618 /* Apparently, if you run ast_pbx_run on a channel that already has a pbx 00619 * structure, you need to add 1 to the priority to get it to go to the 00620 * right place. But if it doesn't have a pbx structure, then leaving off 00621 * the 1 is the right thing to do. See how this code differs when we 00622 * call a Gosub for the CALLEE channel in Dial or Queue. 00623 */ 00624 if (argc == 5) { 00625 if (asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority + (chan->pbx ? 1 : 0), argv[4]) < 0) { 00626 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00627 gosub_args = NULL; 00628 } 00629 } else { 00630 if (asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority + (chan->pbx ? 1 : 0)) < 0) { 00631 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00632 gosub_args = NULL; 00633 } 00634 } 00635 00636 if (gosub_args) { 00637 int res; 00638 00639 ast_debug(1, "Trying gosub with arguments '%s'\n", gosub_args); 00640 00641 if ((res = pbx_exec(chan, theapp, gosub_args)) == 0) { 00642 struct ast_pbx *pbx = chan->pbx; 00643 struct ast_pbx_args args; 00644 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00645 AST_LIST_HEAD(, gosub_stack_frame) *oldlist = stack_store->data; 00646 struct gosub_stack_frame *cur = AST_LIST_FIRST(oldlist); 00647 cur->is_agi = 1; 00648 00649 memset(&args, 0, sizeof(args)); 00650 args.no_hangup_chan = 1; 00651 /* Suppress warning about PBX already existing */ 00652 chan->pbx = NULL; 00653 ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n"); 00654 ast_pbx_run_args(chan, &args); 00655 ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete\n"); 00656 if (chan->pbx) { 00657 ast_free(chan->pbx); 00658 } 00659 chan->pbx = pbx; 00660 } else { 00661 ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res); 00662 } 00663 ast_free(gosub_args); 00664 } else { 00665 ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n"); 00666 return RESULT_FAILURE; 00667 } 00668 00669 /* Restore previous location */ 00670 ast_copy_string(chan->context, old_context, sizeof(chan->context)); 00671 ast_copy_string(chan->exten, old_extension, sizeof(chan->exten)); 00672 chan->priority = old_priority; 00673 00674 return RESULT_SUCCESS; 00675 }
static int load_module | ( | void | ) | [static] |
Definition at line 694 of file app_stack.c.
References ast_agi_register(), ast_custom_function_register, ast_register_application_xml, gosub_agi_command, gosub_exec(), gosubif_exec(), local_function, peek_function, pop_exec(), and return_exec().
00695 { 00696 ast_agi_register(ast_module_info->self, &gosub_agi_command); 00697 00698 ast_register_application_xml(app_pop, pop_exec); 00699 ast_register_application_xml(app_return, return_exec); 00700 ast_register_application_xml(app_gosubif, gosubif_exec); 00701 ast_register_application_xml(app_gosub, gosub_exec); 00702 ast_custom_function_register(&local_function); 00703 ast_custom_function_register(&peek_function); 00704 00705 return 0; 00706 }
static int local_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 484 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, stack_info, and gosub_stack_frame::varshead.
00485 { 00486 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00487 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00488 struct gosub_stack_frame *frame; 00489 struct ast_var_t *variables; 00490 00491 if (!stack_store) 00492 return -1; 00493 00494 oldlist = stack_store->data; 00495 AST_LIST_LOCK(oldlist); 00496 if (!(frame = AST_LIST_FIRST(oldlist))) { 00497 /* Not within a Gosub routine */ 00498 AST_LIST_UNLOCK(oldlist); 00499 return -1; 00500 } 00501 00502 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) { 00503 if (!strcmp(data, ast_var_name(variables))) { 00504 const char *tmp; 00505 ast_channel_lock(chan); 00506 tmp = pbx_builtin_getvar_helper(chan, data); 00507 ast_copy_string(buf, S_OR(tmp, ""), len); 00508 ast_channel_unlock(chan); 00509 break; 00510 } 00511 } 00512 AST_LIST_UNLOCK(oldlist); 00513 return 0; 00514 }
static int local_write | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | var, | |||
const char * | value | |||
) | [static] |
Definition at line 516 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(), LOG_ERROR, and stack_info.
00517 { 00518 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00519 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00520 struct gosub_stack_frame *frame; 00521 00522 if (!stack_store) { 00523 ast_log(LOG_ERROR, "Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var); 00524 return -1; 00525 } 00526 00527 oldlist = stack_store->data; 00528 AST_LIST_LOCK(oldlist); 00529 frame = AST_LIST_FIRST(oldlist); 00530 00531 if (frame) 00532 frame_set_var(chan, frame, var, value); 00533 00534 AST_LIST_UNLOCK(oldlist); 00535 00536 return 0; 00537 }
static int peek_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 545 of file app_stack.c.
References args, AST_APP_ARG, ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_LIST_TRAVERSE, ast_log(), AST_STANDARD_RAW_ARGS, ast_var_name(), ast_var_value(), gosub_stack_frame::entries, LOG_ERROR, name, and ast_channel::varshead.
00546 { 00547 int found = 0, n; 00548 struct ast_var_t *variables; 00549 AST_DECLARE_APP_ARGS(args, 00550 AST_APP_ARG(n); 00551 AST_APP_ARG(name); 00552 ); 00553 00554 if (!chan) { 00555 ast_log(LOG_ERROR, "LOCAL_PEEK must be called on an active channel\n"); 00556 return -1; 00557 } 00558 00559 AST_STANDARD_RAW_ARGS(args, data); 00560 n = atoi(args.n); 00561 *buf = '\0'; 00562 00563 ast_channel_lock(chan); 00564 AST_LIST_TRAVERSE(&chan->varshead, variables, entries) { 00565 if (!strcmp(args.name, ast_var_name(variables)) && ++found > n) { 00566 ast_copy_string(buf, ast_var_value(variables), len); 00567 break; 00568 } 00569 } 00570 ast_channel_unlock(chan); 00571 return 0; 00572 }
static int pop_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 286 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(), LOG_WARNING, and stack_info.
Referenced by load_module().
00287 { 00288 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00289 struct gosub_stack_frame *oldframe; 00290 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00291 00292 if (!stack_store) { 00293 ast_log(LOG_WARNING, "%s called with no gosub stack allocated.\n", app_pop); 00294 return 0; 00295 } 00296 00297 oldlist = stack_store->data; 00298 AST_LIST_LOCK(oldlist); 00299 oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries); 00300 AST_LIST_UNLOCK(oldlist); 00301 00302 if (oldframe) { 00303 gosub_release_frame(chan, oldframe); 00304 } else { 00305 ast_debug(1, "%s called with an empty gosub stack\n", app_pop); 00306 } 00307 return 0; 00308 }
static int return_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 310 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, S_OR, and stack_info.
Referenced by load_module().
00311 { 00312 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00313 struct gosub_stack_frame *oldframe; 00314 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00315 const char *retval = data; 00316 int res = 0; 00317 00318 if (!stack_store) { 00319 ast_log(LOG_ERROR, "Return without Gosub: stack is unallocated\n"); 00320 return -1; 00321 } 00322 00323 oldlist = stack_store->data; 00324 AST_LIST_LOCK(oldlist); 00325 oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries); 00326 AST_LIST_UNLOCK(oldlist); 00327 00328 if (!oldframe) { 00329 ast_log(LOG_ERROR, "Return without Gosub: stack is empty\n"); 00330 return -1; 00331 } else if (oldframe->is_agi) { 00332 /* Exit from AGI */ 00333 res = -1; 00334 } 00335 00336 ast_explicit_goto(chan, oldframe->context, oldframe->extension, oldframe->priority); 00337 gosub_release_frame(chan, oldframe); 00338 00339 /* Set a return value, if any */ 00340 pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", S_OR(retval, "")); 00341 return res; 00342 }
static int unload_module | ( | void | ) | [static] |
Definition at line 680 of file app_stack.c.
References ast_agi_unregister(), ast_custom_function_unregister(), ast_unregister_application(), gosub_agi_command, local_function, and peek_function.
00681 { 00682 ast_agi_unregister(ast_module_info->self, &gosub_agi_command); 00683 00684 ast_unregister_application(app_return); 00685 ast_unregister_application(app_pop); 00686 ast_unregister_application(app_gosubif); 00687 ast_unregister_application(app_gosub); 00688 ast_custom_function_unregister(&local_function); 00689 ast_custom_function_unregister(&peek_function); 00690 00691 return 0; 00692 }
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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .nonoptreq = "res_agi", } [static] |
Definition at line 712 of file app_stack.c.
const char* const app_gosub = "Gosub" [static] |
Definition at line 185 of file app_stack.c.
const char* const app_gosubif = "GosubIf" [static] |
Definition at line 186 of file app_stack.c.
const char* const app_pop = "StackPop" [static] |
Definition at line 188 of file app_stack.c.
const char* const app_return = "Return" [static] |
Definition at line 187 of file app_stack.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 712 of file app_stack.c.
struct agi_command gosub_agi_command [static] |
Initial value:
{ { "gosub", NULL }, handle_gosub, NULL, NULL, 0 }
Definition at line 677 of file app_stack.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function local_function [static] |
Initial value:
{ .name = "LOCAL", .write = local_write, .read = local_read, }
Definition at line 539 of file app_stack.c.
Referenced by load_module(), and unload_module().
struct ast_custom_function peek_function [static] |
Initial value:
{ .name = "LOCAL_PEEK", .read = peek_read, }
Definition at line 574 of file app_stack.c.
Referenced by load_module(), and unload_module().
struct ast_datastore_info stack_info [static] |
Initial value:
{ .type = "GOSUB", .destroy = gosub_free, }
Definition at line 192 of file app_stack.c.
Referenced by gosub_exec(), handle_gosub(), local_read(), local_write(), pop_exec(), and return_exec().