#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 | stackpeek_read (struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_LOAD_ORDER , .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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .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 |
static struct ast_custom_function | stackpeek_function |
Definition in file app_stack.c.
static void __reg_module | ( | void | ) | [static] |
Definition at line 892 of file app_stack.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 892 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 231 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().
00232 { 00233 struct ast_var_t *variables; 00234 int found = 0; 00235 00236 /* Does this variable already exist? */ 00237 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) { 00238 if (!strcmp(var, ast_var_name(variables))) { 00239 found = 1; 00240 break; 00241 } 00242 } 00243 00244 if (!found) { 00245 variables = ast_var_assign(var, ""); 00246 AST_LIST_INSERT_HEAD(&frame->varshead, variables, entries); 00247 pbx_builtin_pushvar_helper(chan, var, value); 00248 } else { 00249 pbx_builtin_setvar_helper(chan, var, value); 00250 } 00251 00252 manager_event(EVENT_FLAG_DIALPLAN, "VarSet", 00253 "Channel: %s\r\n" 00254 "Variable: LOCAL(%s)\r\n" 00255 "Value: %s\r\n" 00256 "Uniqueid: %s\r\n", 00257 chan->name, var, value, chan->uniqueid); 00258 return 0; 00259 }
static struct gosub_stack_frame* gosub_allocate_frame | ( | const char * | context, | |
const char * | extension, | |||
int | priority, | |||
unsigned char | arguments | |||
) | [static] |
Definition at line 280 of file app_stack.c.
References ast_calloc, and AST_LIST_HEAD_INIT_NOLOCK.
Referenced by gosub_exec().
00281 { 00282 struct gosub_stack_frame *new = NULL; 00283 int len_extension = strlen(extension), len_context = strlen(context); 00284 00285 if ((new = ast_calloc(1, sizeof(*new) + 2 + len_extension + len_context))) { 00286 AST_LIST_HEAD_INIT_NOLOCK(&new->varshead); 00287 strcpy(new->extension, extension); 00288 new->context = new->extension + len_extension + 1; 00289 strcpy(new->context, context); 00290 new->priority = priority; 00291 new->arguments = arguments; 00292 } 00293 return new; 00294 }
static int gosub_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 374 of file app_stack.c.
References gosub_stack_frame::arguments, AST_APP_ARG, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_datastore_alloc, ast_datastore_free(), ast_debug, AST_DECLARE_APP_ARGS, ast_exists_extension(), AST_FLAG_IN_AUTOLOOP, 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, ast_channel::context, ast_datastore::data, gosub_stack_frame::entries, ast_channel::exten, frame_set_var(), gosub_allocate_frame(), ast_party_caller::id, LOG_ERROR, LOG_WARNING, ast_channel::name, ast_party_id::number, orig_exten(), parse(), ast_channel::priority, S_COR, stack_info, ast_party_number::str, strsep(), and ast_party_number::valid.
Referenced by gosubif_exec(), and load_module().
00375 { 00376 struct ast_datastore *stack_store; 00377 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00378 struct gosub_stack_frame *newframe; 00379 struct gosub_stack_frame *lastframe; 00380 char argname[15]; 00381 char *parse; 00382 char *label; 00383 char *caller_id; 00384 char *orig_context; 00385 char *orig_exten; 00386 char *dest_context; 00387 char *dest_exten; 00388 int orig_priority; 00389 int dest_priority; 00390 int i; 00391 int max_argc = 0; 00392 AST_DECLARE_APP_ARGS(args2, 00393 AST_APP_ARG(argval)[100]; 00394 ); 00395 00396 if (ast_strlen_zero(data)) { 00397 ast_log(LOG_ERROR, "%s requires an argument: %s([[context,]exten,]priority[(arg1[,...][,argN])])\n", app_gosub, app_gosub); 00398 return -1; 00399 } 00400 00401 /* 00402 * Separate the arguments from the label 00403 * 00404 * NOTE: You cannot use ast_app_separate_args for this, because 00405 * '(' cannot be used as a delimiter. 00406 */ 00407 parse = ast_strdupa(data); 00408 label = strsep(&parse, "("); 00409 if (parse) { 00410 char *endparen; 00411 00412 endparen = strrchr(parse, ')'); 00413 if (endparen) { 00414 *endparen = '\0'; 00415 } else { 00416 ast_log(LOG_WARNING, "Ouch. No closing paren: '%s'?\n", data); 00417 } 00418 AST_STANDARD_RAW_ARGS(args2, parse); 00419 } else { 00420 args2.argc = 0; 00421 } 00422 00423 ast_channel_lock(chan); 00424 orig_context = ast_strdupa(chan->context); 00425 orig_exten = ast_strdupa(chan->exten); 00426 orig_priority = chan->priority; 00427 ast_channel_unlock(chan); 00428 00429 if (ast_parseable_goto(chan, label)) { 00430 ast_log(LOG_ERROR, "%s address is invalid: '%s'\n", app_gosub, data); 00431 goto error_exit; 00432 } 00433 00434 ast_channel_lock(chan); 00435 dest_context = ast_strdupa(chan->context); 00436 dest_exten = ast_strdupa(chan->exten); 00437 dest_priority = chan->priority; 00438 if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP)) { 00439 ++dest_priority; 00440 } 00441 caller_id = S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL); 00442 if (caller_id) { 00443 caller_id = ast_strdupa(caller_id); 00444 } 00445 ast_channel_unlock(chan); 00446 00447 if (!ast_exists_extension(chan, dest_context, dest_exten, dest_priority, caller_id)) { 00448 ast_log(LOG_ERROR, "Attempt to reach a non-existent destination for %s: (Context:%s, Extension:%s, Priority:%d)\n", 00449 app_gosub, dest_context, dest_exten, dest_priority); 00450 goto error_exit; 00451 } 00452 00453 /* Now we know that we're going to a new location */ 00454 00455 ast_channel_lock(chan); 00456 00457 /* Find stack datastore return list. */ 00458 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) { 00459 ast_debug(1, "Channel %s has no datastore, so we're allocating one.\n", 00460 chan->name); 00461 stack_store = ast_datastore_alloc(&stack_info, NULL); 00462 if (!stack_store) { 00463 ast_log(LOG_ERROR, "Unable to allocate new datastore. %s failed.\n", 00464 app_gosub); 00465 goto error_exit_locked; 00466 } 00467 00468 oldlist = ast_calloc(1, sizeof(*oldlist)); 00469 if (!oldlist) { 00470 ast_log(LOG_ERROR, "Unable to allocate datastore list head. %s failed.\n", 00471 app_gosub); 00472 ast_datastore_free(stack_store); 00473 goto error_exit_locked; 00474 } 00475 AST_LIST_HEAD_INIT(oldlist); 00476 00477 stack_store->data = oldlist; 00478 ast_channel_datastore_add(chan, stack_store); 00479 } else { 00480 oldlist = stack_store->data; 00481 } 00482 00483 if ((lastframe = AST_LIST_FIRST(oldlist))) { 00484 max_argc = lastframe->arguments; 00485 } 00486 00487 /* Mask out previous Gosub arguments in this invocation */ 00488 if (args2.argc > max_argc) { 00489 max_argc = args2.argc; 00490 } 00491 00492 /* Create the return address */ 00493 newframe = gosub_allocate_frame(orig_context, orig_exten, orig_priority + 1, max_argc); 00494 if (!newframe) { 00495 goto error_exit_locked; 00496 } 00497 00498 /* Set our arguments */ 00499 for (i = 0; i < max_argc; i++) { 00500 snprintf(argname, sizeof(argname), "ARG%d", i + 1); 00501 frame_set_var(chan, newframe, argname, i < args2.argc ? args2.argval[i] : ""); 00502 ast_debug(1, "Setting '%s' to '%s'\n", argname, i < args2.argc ? args2.argval[i] : ""); 00503 } 00504 snprintf(argname, sizeof(argname), "%d", args2.argc); 00505 frame_set_var(chan, newframe, "ARGC", argname); 00506 00507 /* And finally, save our return address */ 00508 AST_LIST_LOCK(oldlist); 00509 AST_LIST_INSERT_HEAD(oldlist, newframe, entries); 00510 AST_LIST_UNLOCK(oldlist); 00511 ast_channel_unlock(chan); 00512 00513 return 0; 00514 00515 error_exit: 00516 ast_channel_lock(chan); 00517 00518 error_exit_locked: 00519 /* Restore the original dialplan location. */ 00520 ast_copy_string(chan->context, orig_context, sizeof(chan->context)); 00521 ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten)); 00522 chan->priority = orig_priority; 00523 ast_channel_unlock(chan); 00524 return -1; 00525 }
static void gosub_free | ( | void * | data | ) | [static] |
Definition at line 296 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().
00297 { 00298 AST_LIST_HEAD(, gosub_stack_frame) *oldlist = data; 00299 struct gosub_stack_frame *oldframe; 00300 AST_LIST_LOCK(oldlist); 00301 while ((oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries))) { 00302 gosub_release_frame(NULL, oldframe); 00303 } 00304 AST_LIST_UNLOCK(oldlist); 00305 AST_LIST_HEAD_DESTROY(oldlist); 00306 ast_free(oldlist); 00307 }
static void gosub_release_frame | ( | struct ast_channel * | chan, | |
struct gosub_stack_frame * | frame | |||
) | [static] |
Definition at line 261 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().
00262 { 00263 struct ast_var_t *vardata; 00264 00265 /* If chan is not defined, then we're calling it as part of gosub_free, 00266 * and the channel variables will be deallocated anyway. Otherwise, we're 00267 * just releasing a single frame, so we need to clean up the arguments for 00268 * that frame, so that we re-expose the variables from the previous frame 00269 * that were hidden by this one. 00270 */ 00271 while ((vardata = AST_LIST_REMOVE_HEAD(&frame->varshead, entries))) { 00272 if (chan) 00273 pbx_builtin_setvar_helper(chan, ast_var_name(vardata), NULL); 00274 ast_var_delete(vardata); 00275 } 00276 00277 ast_free(frame); 00278 }
static int gosubif_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 527 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().
00528 { 00529 char *args; 00530 int res=0; 00531 AST_DECLARE_APP_ARGS(cond, 00532 AST_APP_ARG(ition); 00533 AST_APP_ARG(labels); 00534 ); 00535 AST_DECLARE_APP_ARGS(label, 00536 AST_APP_ARG(iftrue); 00537 AST_APP_ARG(iffalse); 00538 ); 00539 00540 if (ast_strlen_zero(data)) { 00541 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n"); 00542 return 0; 00543 } 00544 00545 args = ast_strdupa(data); 00546 AST_NONSTANDARD_RAW_ARGS(cond, args, '?'); 00547 if (cond.argc != 2) { 00548 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n"); 00549 return 0; 00550 } 00551 00552 AST_NONSTANDARD_RAW_ARGS(label, cond.labels, ':'); 00553 00554 if (pbx_checkcondition(cond.ition)) { 00555 if (!ast_strlen_zero(label.iftrue)) 00556 res = gosub_exec(chan, label.iftrue); 00557 } else if (!ast_strlen_zero(label.iffalse)) { 00558 res = gosub_exec(chan, label.iffalse); 00559 } 00560 00561 return res; 00562 }
static int handle_gosub | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
const char *const * | argv | |||
) | [static] |
Definition at line 749 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.
00750 { 00751 int old_priority, priority; 00752 char old_context[AST_MAX_CONTEXT], old_extension[AST_MAX_EXTENSION]; 00753 struct ast_app *theapp; 00754 char *gosub_args; 00755 00756 if (argc < 4 || argc > 5) { 00757 return RESULT_SHOWUSAGE; 00758 } 00759 00760 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] : ""); 00761 00762 if (sscanf(argv[3], "%30d", &priority) != 1 || priority < 1) { 00763 /* Lookup the priority label */ 00764 priority = ast_findlabel_extension(chan, argv[1], argv[2], argv[3], 00765 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL)); 00766 if (priority < 0) { 00767 ast_log(LOG_ERROR, "Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]); 00768 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n"); 00769 return RESULT_FAILURE; 00770 } 00771 } else if (!ast_exists_extension(chan, argv[1], argv[2], priority, 00772 S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) { 00773 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n"); 00774 return RESULT_FAILURE; 00775 } 00776 00777 /* Save previous location, since we're going to change it */ 00778 ast_copy_string(old_context, chan->context, sizeof(old_context)); 00779 ast_copy_string(old_extension, chan->exten, sizeof(old_extension)); 00780 old_priority = chan->priority; 00781 00782 if (!(theapp = pbx_findapp("Gosub"))) { 00783 ast_log(LOG_ERROR, "Gosub() cannot be found in the list of loaded applications\n"); 00784 ast_agi_send(agi->fd, chan, "503 result=-2 Gosub is not loaded\n"); 00785 return RESULT_FAILURE; 00786 } 00787 00788 /* Apparently, if you run ast_pbx_run on a channel that already has a pbx 00789 * structure, you need to add 1 to the priority to get it to go to the 00790 * right place. But if it doesn't have a pbx structure, then leaving off 00791 * the 1 is the right thing to do. See how this code differs when we 00792 * call a Gosub for the CALLEE channel in Dial or Queue. 00793 */ 00794 if (argc == 5) { 00795 if (asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority + (chan->pbx ? 1 : 0), argv[4]) < 0) { 00796 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00797 gosub_args = NULL; 00798 } 00799 } else { 00800 if (asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority + (chan->pbx ? 1 : 0)) < 0) { 00801 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00802 gosub_args = NULL; 00803 } 00804 } 00805 00806 if (gosub_args) { 00807 int res; 00808 00809 ast_debug(1, "Trying gosub with arguments '%s'\n", gosub_args); 00810 00811 if ((res = pbx_exec(chan, theapp, gosub_args)) == 0) { 00812 struct ast_pbx *pbx = chan->pbx; 00813 struct ast_pbx_args args; 00814 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00815 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00816 struct gosub_stack_frame *cur; 00817 if (!stack_store) { 00818 ast_log(LOG_WARNING, "No GoSub stack remaining after AGI GoSub execution.\n"); 00819 ast_free(gosub_args); 00820 return RESULT_FAILURE; 00821 } 00822 oldlist = stack_store->data; 00823 cur = AST_LIST_FIRST(oldlist); 00824 cur->is_agi = 1; 00825 00826 memset(&args, 0, sizeof(args)); 00827 args.no_hangup_chan = 1; 00828 /* Suppress warning about PBX already existing */ 00829 chan->pbx = NULL; 00830 ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n"); 00831 ast_pbx_run_args(chan, &args); 00832 ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete\n"); 00833 if (chan->pbx) { 00834 ast_free(chan->pbx); 00835 } 00836 chan->pbx = pbx; 00837 } else { 00838 ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res); 00839 } 00840 ast_free(gosub_args); 00841 } else { 00842 ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n"); 00843 return RESULT_FAILURE; 00844 } 00845 00846 /* Restore previous location */ 00847 ast_copy_string(chan->context, old_context, sizeof(chan->context)); 00848 ast_copy_string(chan->exten, old_extension, sizeof(chan->exten)); 00849 chan->priority = old_priority; 00850 00851 return RESULT_SUCCESS; 00852 }
static int load_module | ( | void | ) | [static] |
Definition at line 872 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(), return_exec(), and stackpeek_function.
00873 { 00874 ast_agi_register(ast_module_info->self, &gosub_agi_command); 00875 00876 ast_register_application_xml(app_pop, pop_exec); 00877 ast_register_application_xml(app_return, return_exec); 00878 ast_register_application_xml(app_gosubif, gosubif_exec); 00879 ast_register_application_xml(app_gosub, gosub_exec); 00880 ast_custom_function_register(&local_function); 00881 ast_custom_function_register(&peek_function); 00882 ast_custom_function_register(&stackpeek_function); 00883 00884 return 0; 00885 }
static int local_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 564 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.
00565 { 00566 struct ast_datastore *stack_store; 00567 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00568 struct gosub_stack_frame *frame; 00569 struct ast_var_t *variables; 00570 00571 ast_channel_lock(chan); 00572 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) { 00573 ast_channel_unlock(chan); 00574 return -1; 00575 } 00576 00577 oldlist = stack_store->data; 00578 AST_LIST_LOCK(oldlist); 00579 if (!(frame = AST_LIST_FIRST(oldlist))) { 00580 /* Not within a Gosub routine */ 00581 AST_LIST_UNLOCK(oldlist); 00582 ast_channel_unlock(chan); 00583 return -1; 00584 } 00585 00586 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) { 00587 if (!strcmp(data, ast_var_name(variables))) { 00588 const char *tmp; 00589 tmp = pbx_builtin_getvar_helper(chan, data); 00590 ast_copy_string(buf, S_OR(tmp, ""), len); 00591 break; 00592 } 00593 } 00594 AST_LIST_UNLOCK(oldlist); 00595 ast_channel_unlock(chan); 00596 return 0; 00597 }
static int local_write | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | var, | |||
const char * | value | |||
) | [static] |
Definition at line 599 of file app_stack.c.
References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, 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.
00600 { 00601 struct ast_datastore *stack_store; 00602 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00603 struct gosub_stack_frame *frame; 00604 00605 ast_channel_lock(chan); 00606 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) { 00607 ast_log(LOG_ERROR, "Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var); 00608 ast_channel_unlock(chan); 00609 return -1; 00610 } 00611 00612 oldlist = stack_store->data; 00613 AST_LIST_LOCK(oldlist); 00614 frame = AST_LIST_FIRST(oldlist); 00615 00616 if (frame) { 00617 frame_set_var(chan, frame, var, value); 00618 } 00619 00620 AST_LIST_UNLOCK(oldlist); 00621 ast_channel_unlock(chan); 00622 00623 return 0; 00624 }
static int peek_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 632 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.
00633 { 00634 int found = 0, n; 00635 struct ast_var_t *variables; 00636 AST_DECLARE_APP_ARGS(args, 00637 AST_APP_ARG(n); 00638 AST_APP_ARG(name); 00639 ); 00640 00641 if (!chan) { 00642 ast_log(LOG_ERROR, "LOCAL_PEEK must be called on an active channel\n"); 00643 return -1; 00644 } 00645 00646 AST_STANDARD_RAW_ARGS(args, data); 00647 n = atoi(args.n); 00648 *buf = '\0'; 00649 00650 ast_channel_lock(chan); 00651 AST_LIST_TRAVERSE(&chan->varshead, variables, entries) { 00652 if (!strcmp(args.name, ast_var_name(variables)) && ++found > n) { 00653 ast_copy_string(buf, ast_var_value(variables), len); 00654 break; 00655 } 00656 } 00657 ast_channel_unlock(chan); 00658 return 0; 00659 }
static int pop_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 309 of file app_stack.c.
References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, 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().
00310 { 00311 struct ast_datastore *stack_store; 00312 struct gosub_stack_frame *oldframe; 00313 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00314 00315 ast_channel_lock(chan); 00316 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) { 00317 ast_log(LOG_WARNING, "%s called with no gosub stack allocated.\n", app_pop); 00318 ast_channel_unlock(chan); 00319 return 0; 00320 } 00321 00322 oldlist = stack_store->data; 00323 AST_LIST_LOCK(oldlist); 00324 oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries); 00325 AST_LIST_UNLOCK(oldlist); 00326 00327 if (oldframe) { 00328 gosub_release_frame(chan, oldframe); 00329 } else { 00330 ast_debug(1, "%s called with an empty gosub stack\n", app_pop); 00331 } 00332 ast_channel_unlock(chan); 00333 return 0; 00334 }
static int return_exec | ( | struct ast_channel * | chan, | |
const char * | data | |||
) | [static] |
Definition at line 336 of file app_stack.c.
References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, 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().
00337 { 00338 struct ast_datastore *stack_store; 00339 struct gosub_stack_frame *oldframe; 00340 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00341 const char *retval = data; 00342 int res = 0; 00343 00344 ast_channel_lock(chan); 00345 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) { 00346 ast_log(LOG_ERROR, "Return without Gosub: stack is unallocated\n"); 00347 ast_channel_unlock(chan); 00348 return -1; 00349 } 00350 00351 oldlist = stack_store->data; 00352 AST_LIST_LOCK(oldlist); 00353 oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries); 00354 AST_LIST_UNLOCK(oldlist); 00355 00356 if (!oldframe) { 00357 ast_log(LOG_ERROR, "Return without Gosub: stack is empty\n"); 00358 ast_channel_unlock(chan); 00359 return -1; 00360 } else if (oldframe->is_agi) { 00361 /* Exit from AGI */ 00362 res = -1; 00363 } 00364 00365 ast_explicit_goto(chan, oldframe->context, oldframe->extension, oldframe->priority); 00366 gosub_release_frame(chan, oldframe); 00367 00368 /* Set a return value, if any */ 00369 pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", S_OR(retval, "")); 00370 ast_channel_unlock(chan); 00371 return res; 00372 }
static int stackpeek_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
struct ast_str ** | str, | |||
ssize_t | len | |||
) | [static] |
Definition at line 666 of file app_stack.c.
References args, AST_APP_ARG, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_DECLARE_APP_ARGS, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_skip_blanks(), AST_STANDARD_APP_ARGS, ast_str_set(), ast_strdupa, ast_true(), gosub_stack_frame::context, ast_datastore::data, gosub_stack_frame::entries, gosub_stack_frame::extension, LOG_ERROR, gosub_stack_frame::priority, stack_info, and str.
00667 { 00668 struct ast_datastore *stack_store; 00669 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00670 struct gosub_stack_frame *frame; 00671 int n; 00672 AST_DECLARE_APP_ARGS(args, 00673 AST_APP_ARG(n); 00674 AST_APP_ARG(which); 00675 AST_APP_ARG(suppress); 00676 ); 00677 00678 if (!chan) { 00679 ast_log(LOG_ERROR, "STACK_PEEK must be called on an active channel\n"); 00680 return -1; 00681 } 00682 00683 data = ast_strdupa(data); 00684 AST_STANDARD_APP_ARGS(args, data); 00685 00686 n = atoi(args.n); 00687 if (n <= 0) { 00688 ast_log(LOG_ERROR, "STACK_PEEK must be called with a positive peek value\n"); 00689 return -1; 00690 } 00691 00692 ast_channel_lock(chan); 00693 if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) { 00694 if (!ast_true(args.suppress)) { 00695 ast_log(LOG_ERROR, "STACK_PEEK called on a channel without a gosub stack\n"); 00696 } 00697 ast_channel_unlock(chan); 00698 return -1; 00699 } 00700 00701 oldlist = stack_store->data; 00702 00703 AST_LIST_LOCK(oldlist); 00704 AST_LIST_TRAVERSE(oldlist, frame, entries) { 00705 if (--n == 0) { 00706 break; 00707 } 00708 } 00709 00710 if (!frame) { 00711 /* Too deep */ 00712 if (!ast_true(args.suppress)) { 00713 ast_log(LOG_ERROR, "Stack peek of '%s' is more stack frames than I have\n", args.n); 00714 } 00715 ast_channel_unlock(chan); 00716 return -1; 00717 } 00718 00719 args.which = ast_skip_blanks(args.which); 00720 00721 switch (args.which[0]) { 00722 case 'l': /* label */ 00723 ast_str_set(str, len, "%s,%s,%d", frame->context, frame->extension, frame->priority - 1); 00724 break; 00725 case 'c': /* context */ 00726 ast_str_set(str, len, "%s", frame->context); 00727 break; 00728 case 'e': /* extension */ 00729 ast_str_set(str, len, "%s", frame->extension); 00730 break; 00731 case 'p': /* priority */ 00732 ast_str_set(str, len, "%d", frame->priority - 1); 00733 break; 00734 default: 00735 ast_log(LOG_ERROR, "Unknown argument '%s' to STACK_PEEK\n", args.which); 00736 } 00737 00738 AST_LIST_UNLOCK(oldlist); 00739 ast_channel_unlock(chan); 00740 00741 return 0; 00742 }
static int unload_module | ( | void | ) | [static] |
Definition at line 857 of file app_stack.c.
References ast_agi_unregister(), ast_custom_function_unregister(), ast_unregister_application(), gosub_agi_command, local_function, peek_function, and stackpeek_function.
00858 { 00859 ast_agi_unregister(ast_module_info->self, &gosub_agi_command); 00860 00861 ast_unregister_application(app_return); 00862 ast_unregister_application(app_pop); 00863 ast_unregister_application(app_gosubif); 00864 ast_unregister_application(app_gosub); 00865 ast_custom_function_unregister(&local_function); 00866 ast_custom_function_unregister(&peek_function); 00867 ast_custom_function_unregister(&stackpeek_function); 00868 00869 return 0; 00870 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_LOAD_ORDER , .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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .nonoptreq = "res_agi", } [static] |
Definition at line 892 of file app_stack.c.
const char* const app_gosub = "Gosub" [static] |
Definition at line 208 of file app_stack.c.
const char* const app_gosubif = "GosubIf" [static] |
Definition at line 209 of file app_stack.c.
const char* const app_pop = "StackPop" [static] |
Definition at line 211 of file app_stack.c.
const char* const app_return = "Return" [static] |
Definition at line 210 of file app_stack.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 892 of file app_stack.c.
struct agi_command gosub_agi_command [static] |
Initial value:
{ { "gosub", NULL }, handle_gosub, NULL, NULL, 0 }
Definition at line 854 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 626 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 661 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 215 of file app_stack.c.
Referenced by gosub_exec(), handle_gosub(), local_read(), local_write(), pop_exec(), return_exec(), and stackpeek_read().
struct ast_custom_function stackpeek_function [static] |
Initial value:
{ .name = "STACK_PEEK", .read2 = stackpeek_read, }
Definition at line 744 of file app_stack.c.
Referenced by load_module(), and unload_module().