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