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