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