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 |
Functions | |
AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT|AST_MODFLAG_LOAD_ORDER,"Dialplan subroutines (Gosub, Return, etc)",.load=load_module,.unload=unload_module,.load_pri=AST_MODPRI_APP_DEPEND,.nonoptreq="res_agi",) | |
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 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 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 |
Stack applications Gosub, Return, etc.
Definition in file app_stack.c.
AST_MODULE_INFO | ( | ASTERISK_GPL_KEY | , | |
AST_MODFLAG_DEFAULT| | AST_MODFLAG_LOAD_ORDER, | |||
"Dialplan subroutines (Gosub, Return, etc)" | , | |||
. | load = load_module , |
|||
. | unload = unload_module , |
|||
. | load_pri = AST_MODPRI_APP_DEPEND , |
|||
. | nonoptreq = "res_agi" | |||
) |
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(), 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, read] |
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 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, ast_channel::exten, frame_set_var(), gosub_allocate_frame(), ast_party_caller::id, LOG_ERROR, LOG_WARNING, ast_party_id::number, orig_exten(), parse(), ast_channel::priority, S_COR, ast_party_number::str, 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, 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(), and pbx_builtin_setvar_helper().
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 ast_agi_send(), ast_asprintf, 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, ast_channel::exten, agi_state::fd, ast_party_caller::id, LOG_ERROR, LOG_WARNING, ast_pbx_args::no_hangup_chan, ast_party_id::number, ast_channel::pbx, pbx_exec(), pbx_findapp(), ast_channel::priority, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, S_COR, 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 (ast_asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority + (chan->pbx ? 1 : 0), argv[4]) < 0) { 00796 gosub_args = NULL; 00797 } 00798 } else { 00799 if (ast_asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority + (chan->pbx ? 1 : 0)) < 0) { 00800 gosub_args = NULL; 00801 } 00802 } 00803 00804 if (gosub_args) { 00805 int res; 00806 00807 ast_debug(1, "Trying gosub with arguments '%s'\n", gosub_args); 00808 00809 if ((res = pbx_exec(chan, theapp, gosub_args)) == 0) { 00810 struct ast_pbx *pbx = chan->pbx; 00811 struct ast_pbx_args args; 00812 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00813 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00814 struct gosub_stack_frame *cur; 00815 if (!stack_store) { 00816 ast_log(LOG_WARNING, "No GoSub stack remaining after AGI GoSub execution.\n"); 00817 ast_free(gosub_args); 00818 return RESULT_FAILURE; 00819 } 00820 oldlist = stack_store->data; 00821 cur = AST_LIST_FIRST(oldlist); 00822 cur->is_agi = 1; 00823 00824 memset(&args, 0, sizeof(args)); 00825 args.no_hangup_chan = 1; 00826 /* Suppress warning about PBX already existing */ 00827 chan->pbx = NULL; 00828 ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n"); 00829 ast_pbx_run_args(chan, &args); 00830 ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete\n"); 00831 if (chan->pbx) { 00832 ast_free(chan->pbx); 00833 } 00834 chan->pbx = pbx; 00835 } else { 00836 ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res); 00837 } 00838 ast_free(gosub_args); 00839 } else { 00840 ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n"); 00841 return RESULT_FAILURE; 00842 } 00843 00844 /* Restore previous location */ 00845 ast_copy_string(chan->context, old_context, sizeof(chan->context)); 00846 ast_copy_string(chan->exten, old_extension, sizeof(chan->exten)); 00847 chan->priority = old_priority; 00848 00849 return RESULT_SUCCESS; 00850 }
static int load_module | ( | void | ) | [static] |
Definition at line 870 of file app_stack.c.
References ast_agi_register(), ast_custom_function_register, ast_register_application_xml, gosub_exec(), gosubif_exec(), pop_exec(), and return_exec().
00871 { 00872 ast_agi_register(ast_module_info->self, &gosub_agi_command); 00873 00874 ast_register_application_xml(app_pop, pop_exec); 00875 ast_register_application_xml(app_return, return_exec); 00876 ast_register_application_xml(app_gosubif, gosubif_exec); 00877 ast_register_application_xml(app_gosub, gosub_exec); 00878 ast_custom_function_register(&local_function); 00879 ast_custom_function_register(&peek_function); 00880 ast_custom_function_register(&stackpeek_function); 00881 00882 return 0; 00883 }
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, pbx_builtin_getvar_helper(), and S_OR.
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(), and LOG_ERROR.
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(), 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_release_frame(), and LOG_WARNING.
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(), ast_datastore::data, gosub_release_frame(), LOG_ERROR, pbx_builtin_setvar_helper(), and S_OR.
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(), ast_datastore::data, and LOG_ERROR.
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 855 of file app_stack.c.
References ast_agi_unregister(), ast_custom_function_unregister(), and ast_unregister_application().
00856 { 00857 ast_agi_unregister(ast_module_info->self, &gosub_agi_command); 00858 00859 ast_unregister_application(app_return); 00860 ast_unregister_application(app_pop); 00861 ast_unregister_application(app_gosubif); 00862 ast_unregister_application(app_gosub); 00863 ast_custom_function_unregister(&local_function); 00864 ast_custom_function_unregister(&peek_function); 00865 ast_custom_function_unregister(&stackpeek_function); 00866 00867 return 0; 00868 }
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 agi_command gosub_agi_command [static] |
{ { "gosub", NULL }, handle_gosub, NULL, NULL, 0 }
Definition at line 852 of file app_stack.c.
struct ast_custom_function local_function [static] |
{ .name = "LOCAL", .write = local_write, .read = local_read, }
Definition at line 626 of file app_stack.c.
struct ast_custom_function peek_function [static] |
{ .name = "LOCAL_PEEK", .read = peek_read, }
Definition at line 661 of file app_stack.c.
struct ast_datastore_info stack_info [static] |
{ .type = "GOSUB", .destroy = gosub_free, }
Definition at line 215 of file app_stack.c.
struct ast_custom_function stackpeek_function [static] |
{ .name = "STACK_PEEK", .read2 = stackpeek_read, }
Definition at line 744 of file app_stack.c.