#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 |
Defines | |
#define | ASTERISK_AGI_OPTIONAL |
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 | 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 = "a9c98e5d177805051735cb5b0b16b0a0" , .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 |
agi_command | gosub_agi_command |
static const char * | gosub_descrip |
static const char * | gosub_synopsis = "Jump to label, saving return address" |
static const char * | gosubif_descrip |
static const char * | gosubif_synopsis = "Conditionally jump to label, saving return address" |
static struct ast_custom_function | local_function |
static const char * | pop_descrip |
static const char * | pop_synopsis = "Remove one address from gosub stack" |
static const char * | return_descrip |
static const char * | return_synopsis = "Return from gosub routine" |
static struct ast_datastore_info | stack_info |
static char | usage_gosub [] |
Definition in file app_stack.c.
#define ASTERISK_AGI_OPTIONAL |
Definition at line 43 of file app_stack.c.
static void __reg_module | ( | void | ) | [static] |
Definition at line 537 of file app_stack.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 537 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 90 of file app_stack.c.
References AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_strlen_zero(), 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().
00091 { 00092 struct ast_var_t *variables; 00093 int found = 0; 00094 00095 /* Does this variable already exist? */ 00096 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) { 00097 if (!strcmp(var, ast_var_name(variables))) { 00098 found = 1; 00099 break; 00100 } 00101 } 00102 00103 if (!ast_strlen_zero(value)) { 00104 if (!found) { 00105 variables = ast_var_assign(var, ""); 00106 AST_LIST_INSERT_HEAD(&frame->varshead, variables, entries); 00107 pbx_builtin_pushvar_helper(chan, var, value); 00108 } else 00109 pbx_builtin_setvar_helper(chan, var, value); 00110 00111 manager_event(EVENT_FLAG_DIALPLAN, "VarSet", 00112 "Channel: %s\r\n" 00113 "Variable: LOCAL(%s)\r\n" 00114 "Value: %s\r\n" 00115 "Uniqueid: %s\r\n", 00116 chan->name, var, value, chan->uniqueid); 00117 } 00118 return 0; 00119 }
static struct gosub_stack_frame* gosub_allocate_frame | ( | const char * | context, | |
const char * | extension, | |||
int | priority, | |||
unsigned char | arguments | |||
) | [static] |
Definition at line 140 of file app_stack.c.
References ast_calloc, and AST_LIST_HEAD_INIT_NOLOCK.
Referenced by gosub_exec().
00141 { 00142 struct gosub_stack_frame *new = NULL; 00143 int len_extension = strlen(extension), len_context = strlen(context); 00144 00145 if ((new = ast_calloc(1, sizeof(*new) + 2 + len_extension + len_context))) { 00146 AST_LIST_HEAD_INIT_NOLOCK(&new->varshead); 00147 strcpy(new->extension, extension); 00148 new->context = new->extension + len_extension + 1; 00149 strcpy(new->context, context); 00150 new->priority = priority; 00151 new->arguments = arguments; 00152 } 00153 return new; 00154 }
static int gosub_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 223 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_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, chan, 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, ast_channel::priority, stack_info, and strsep().
Referenced by gosubif_exec(), and load_module().
00224 { 00225 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00226 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00227 struct gosub_stack_frame *newframe; 00228 char argname[15], *tmp = ast_strdupa(data), *label, *endparen; 00229 int i; 00230 AST_DECLARE_APP_ARGS(args2, 00231 AST_APP_ARG(argval)[100]; 00232 ); 00233 00234 if (ast_strlen_zero(data)) { 00235 ast_log(LOG_ERROR, "%s requires an argument: %s([[context,]exten,]priority[(arg1[,...][,argN])])\n", app_gosub, app_gosub); 00236 return -1; 00237 } 00238 00239 if (!stack_store) { 00240 ast_debug(1, "Channel %s has no datastore, so we're allocating one.\n", chan->name); 00241 stack_store = ast_datastore_alloc(&stack_info, NULL); 00242 if (!stack_store) { 00243 ast_log(LOG_ERROR, "Unable to allocate new datastore. Gosub will fail.\n"); 00244 return -1; 00245 } 00246 00247 oldlist = ast_calloc(1, sizeof(*oldlist)); 00248 if (!oldlist) { 00249 ast_log(LOG_ERROR, "Unable to allocate datastore list head. Gosub will fail.\n"); 00250 ast_datastore_free(stack_store); 00251 return -1; 00252 } 00253 00254 stack_store->data = oldlist; 00255 AST_LIST_HEAD_INIT(oldlist); 00256 ast_channel_datastore_add(chan, stack_store); 00257 } 00258 00259 /* Separate the arguments from the label */ 00260 /* NOTE: you cannot use ast_app_separate_args for this, because '(' cannot be used as a delimiter. */ 00261 label = strsep(&tmp, "("); 00262 if (tmp) { 00263 endparen = strrchr(tmp, ')'); 00264 if (endparen) 00265 *endparen = '\0'; 00266 else 00267 ast_log(LOG_WARNING, "Ouch. No closing paren: '%s'?\n", (char *)data); 00268 AST_STANDARD_APP_ARGS(args2, tmp); 00269 } else 00270 args2.argc = 0; 00271 00272 /* Create the return address, but don't save it until we know that the Gosub destination exists */ 00273 newframe = gosub_allocate_frame(chan->context, chan->exten, chan->priority + 1, args2.argc); 00274 00275 if (!newframe) { 00276 return -1; 00277 } 00278 00279 if (ast_parseable_goto(chan, label)) { 00280 ast_log(LOG_ERROR, "Gosub address is invalid: '%s'\n", (char *)data); 00281 ast_free(newframe); 00282 return -1; 00283 } 00284 00285 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)) { 00286 ast_log(LOG_ERROR, "Attempt to reach a non-existent destination for gosub: (Context:%s, Extension:%s, Priority:%d)\n", 00287 chan->context, chan->exten, chan->priority); 00288 ast_copy_string(chan->context, newframe->context, sizeof(chan->context)); 00289 ast_copy_string(chan->exten, newframe->extension, sizeof(chan->exten)); 00290 chan->priority = newframe->priority; 00291 ast_free(newframe); 00292 return -1; 00293 } 00294 00295 /* Now that we know for certain that we're going to a new location, set our arguments */ 00296 for (i = 0; i < args2.argc; i++) { 00297 snprintf(argname, sizeof(argname), "ARG%d", i + 1); 00298 frame_set_var(chan, newframe, argname, args2.argval[i]); 00299 ast_debug(1, "Setting '%s' to '%s'\n", argname, args2.argval[i]); 00300 } 00301 00302 /* And finally, save our return address */ 00303 oldlist = stack_store->data; 00304 AST_LIST_LOCK(oldlist); 00305 AST_LIST_INSERT_HEAD(oldlist, newframe, entries); 00306 AST_LIST_UNLOCK(oldlist); 00307 00308 return 0; 00309 }
static void gosub_free | ( | void * | data | ) | [static] |
Definition at line 156 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().
00157 { 00158 AST_LIST_HEAD(, gosub_stack_frame) *oldlist = data; 00159 struct gosub_stack_frame *oldframe; 00160 AST_LIST_LOCK(oldlist); 00161 while ((oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries))) { 00162 gosub_release_frame(NULL, oldframe); 00163 } 00164 AST_LIST_UNLOCK(oldlist); 00165 AST_LIST_HEAD_DESTROY(oldlist); 00166 ast_free(oldlist); 00167 }
static void gosub_release_frame | ( | struct ast_channel * | chan, | |
struct gosub_stack_frame * | frame | |||
) | [static] |
Definition at line 121 of file app_stack.c.
References ast_free, AST_LIST_REMOVE_HEAD, ast_var_delete(), ast_var_name(), chan, gosub_stack_frame::entries, pbx_builtin_setvar_helper(), and gosub_stack_frame::varshead.
Referenced by gosub_free(), pop_exec(), and return_exec().
00122 { 00123 struct ast_var_t *vardata; 00124 00125 /* If chan is not defined, then we're calling it as part of gosub_free, 00126 * and the channel variables will be deallocated anyway. Otherwise, we're 00127 * just releasing a single frame, so we need to clean up the arguments for 00128 * that frame, so that we re-expose the variables from the previous frame 00129 * that were hidden by this one. 00130 */ 00131 while ((vardata = AST_LIST_REMOVE_HEAD(&frame->varshead, entries))) { 00132 if (chan) 00133 pbx_builtin_setvar_helper(chan, ast_var_name(vardata), NULL); 00134 ast_var_delete(vardata); 00135 } 00136 00137 ast_free(frame); 00138 }
static int gosubif_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 311 of file app_stack.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_NONSTANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), chan, cond, gosub_exec(), LOG_WARNING, and pbx_checkcondition().
Referenced by load_module().
00312 { 00313 char *args; 00314 int res=0; 00315 AST_DECLARE_APP_ARGS(cond, 00316 AST_APP_ARG(ition); 00317 AST_APP_ARG(labels); 00318 ); 00319 AST_DECLARE_APP_ARGS(label, 00320 AST_APP_ARG(iftrue); 00321 AST_APP_ARG(iffalse); 00322 ); 00323 00324 if (ast_strlen_zero(data)) { 00325 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n"); 00326 return 0; 00327 } 00328 00329 args = ast_strdupa(data); 00330 AST_NONSTANDARD_APP_ARGS(cond, args, '?'); 00331 if (cond.argc != 2) { 00332 ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n"); 00333 return 0; 00334 } 00335 00336 AST_NONSTANDARD_APP_ARGS(label, cond.labels, ':'); 00337 00338 if (pbx_checkcondition(cond.ition)) { 00339 if (!ast_strlen_zero(label.iftrue)) 00340 res = gosub_exec(chan, label.iftrue); 00341 } else if (!ast_strlen_zero(label.iffalse)) { 00342 res = gosub_exec(chan, label.iffalse); 00343 } 00344 00345 return res; 00346 }
static int handle_gosub | ( | struct ast_channel * | chan, | |
AGI * | agi, | |||
int | argc, | |||
char ** | argv | |||
) | [static] |
Definition at line 406 of file app_stack.c.
References asprintf, ast_agi_send(), ast_copy_string(), ast_debug, ast_exists_extension(), ast_findlabel_extension(), ast_free, ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_pbx_run_args(), chan, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, errno, ast_channel::exten, agi_state::fd, LOG_ERROR, LOG_WARNING, ast_channel::pbx, pbx_exec(), pbx_findapp(), ast_channel::priority, gosub_stack_frame::priority, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.
00407 { 00408 int old_priority, priority; 00409 char old_context[AST_MAX_CONTEXT], old_extension[AST_MAX_EXTENSION]; 00410 struct ast_app *theapp; 00411 char *gosub_args; 00412 00413 if (argc < 4 || argc > 5) { 00414 return RESULT_SHOWUSAGE; 00415 } 00416 00417 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] : ""); 00418 00419 if (sscanf(argv[3], "%d", &priority) != 1 || priority < 1) { 00420 /* Lookup the priority label */ 00421 if ((priority = ast_findlabel_extension(chan, argv[1], argv[2], argv[3], chan->cid.cid_num)) < 0) { 00422 ast_log(LOG_ERROR, "Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]); 00423 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n"); 00424 return RESULT_FAILURE; 00425 } 00426 } else if (!ast_exists_extension(chan, argv[1], argv[2], priority, chan->cid.cid_num)) { 00427 ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n"); 00428 return RESULT_FAILURE; 00429 } 00430 00431 /* Save previous location, since we're going to change it */ 00432 ast_copy_string(old_context, chan->context, sizeof(old_context)); 00433 ast_copy_string(old_extension, chan->exten, sizeof(old_extension)); 00434 old_priority = chan->priority; 00435 00436 if (!(theapp = pbx_findapp("Gosub"))) { 00437 ast_log(LOG_ERROR, "Gosub() cannot be found in the list of loaded applications\n"); 00438 ast_agi_send(agi->fd, chan, "503 result=-2 Gosub is not loaded\n"); 00439 return RESULT_FAILURE; 00440 } 00441 00442 /* Apparently, if you run ast_pbx_run on a channel that already has a pbx 00443 * structure, you need to add 1 to the priority to get it to go to the 00444 * right place. But if it doesn't have a pbx structure, then leaving off 00445 * the 1 is the right thing to do. See how this code differs when we 00446 * call a Gosub for the CALLEE channel in Dial or Queue. 00447 */ 00448 if (argc == 5) { 00449 if (asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority + 1, argv[4]) < 0) { 00450 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00451 gosub_args = NULL; 00452 } 00453 } else { 00454 if (asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority + 1) < 0) { 00455 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); 00456 gosub_args = NULL; 00457 } 00458 } 00459 00460 if (gosub_args) { 00461 int res; 00462 00463 ast_debug(1, "Trying gosub with arguments '%s'\n", gosub_args); 00464 00465 if ((res = pbx_exec(chan, theapp, gosub_args)) == 0) { 00466 struct ast_pbx *pbx = chan->pbx; 00467 struct ast_pbx_args args; 00468 memset(&args, 0, sizeof(args)); 00469 args.no_hangup_chan = 1; 00470 /* Suppress warning about PBX already existing */ 00471 chan->pbx = NULL; 00472 ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n"); 00473 ast_pbx_run_args(chan, &args); 00474 ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete\n"); 00475 if (chan->pbx) { 00476 ast_free(chan->pbx); 00477 } 00478 chan->pbx = pbx; 00479 } else { 00480 ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res); 00481 } 00482 ast_free(gosub_args); 00483 } else { 00484 ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n"); 00485 return RESULT_FAILURE; 00486 } 00487 00488 /* Restore previous location */ 00489 ast_copy_string(chan->context, old_context, sizeof(chan->context)); 00490 ast_copy_string(chan->exten, old_extension, sizeof(chan->exten)); 00491 chan->priority = old_priority; 00492 00493 return RESULT_SUCCESS; 00494 }
static int load_module | ( | void | ) | [static] |
Definition at line 519 of file app_stack.c.
References ast_agi_register(), ast_custom_function_register, ast_register_application, gosub_agi_command, gosub_exec(), gosubif_exec(), local_function, pop_exec(), and return_exec().
00520 { 00521 /* usage of AGI is optional, so check to see if the ast_agi_register() 00522 function is available; if so, use it. 00523 */ 00524 if (ast_agi_register) { 00525 ast_agi_register(ast_module_info->self, &gosub_agi_command); 00526 } 00527 00528 ast_register_application(app_pop, pop_exec, pop_synopsis, pop_descrip); 00529 ast_register_application(app_return, return_exec, return_synopsis, return_descrip); 00530 ast_register_application(app_gosubif, gosubif_exec, gosubif_synopsis, gosubif_descrip); 00531 ast_register_application(app_gosub, gosub_exec, gosub_synopsis, gosub_descrip); 00532 ast_custom_function_register(&local_function); 00533 00534 return 0; 00535 }
static int local_read | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | data, | |||
char * | buf, | |||
size_t | len | |||
) | [static] |
Definition at line 348 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(), chan, ast_datastore::data, gosub_stack_frame::entries, pbx_builtin_getvar_helper(), S_OR, stack_info, and gosub_stack_frame::varshead.
00349 { 00350 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00351 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00352 struct gosub_stack_frame *frame; 00353 struct ast_var_t *variables; 00354 00355 if (!stack_store) 00356 return -1; 00357 00358 oldlist = stack_store->data; 00359 AST_LIST_LOCK(oldlist); 00360 frame = AST_LIST_FIRST(oldlist); 00361 AST_LIST_TRAVERSE(&frame->varshead, variables, entries) { 00362 if (!strcmp(data, ast_var_name(variables))) { 00363 const char *tmp; 00364 ast_channel_lock(chan); 00365 tmp = pbx_builtin_getvar_helper(chan, data); 00366 ast_copy_string(buf, S_OR(tmp, ""), len); 00367 ast_channel_unlock(chan); 00368 break; 00369 } 00370 } 00371 AST_LIST_UNLOCK(oldlist); 00372 return 0; 00373 }
static int local_write | ( | struct ast_channel * | chan, | |
const char * | cmd, | |||
char * | var, | |||
const char * | value | |||
) | [static] |
Definition at line 375 of file app_stack.c.
References ast_channel_datastore_find(), AST_LIST_FIRST, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), chan, ast_datastore::data, frame_set_var(), LOG_ERROR, and stack_info.
00376 { 00377 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00378 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00379 struct gosub_stack_frame *frame; 00380 00381 if (!stack_store) { 00382 ast_log(LOG_ERROR, "Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var); 00383 return -1; 00384 } 00385 00386 oldlist = stack_store->data; 00387 AST_LIST_LOCK(oldlist); 00388 frame = AST_LIST_FIRST(oldlist); 00389 00390 if (frame) 00391 frame_set_var(chan, frame, var, value); 00392 00393 AST_LIST_UNLOCK(oldlist); 00394 00395 return 0; 00396 }
static int pop_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 169 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(), chan, ast_datastore::data, gosub_stack_frame::entries, gosub_release_frame(), LOG_WARNING, and stack_info.
Referenced by load_module().
00170 { 00171 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00172 struct gosub_stack_frame *oldframe; 00173 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00174 00175 if (!stack_store) { 00176 ast_log(LOG_WARNING, "%s called with no gosub stack allocated.\n", app_pop); 00177 return 0; 00178 } 00179 00180 oldlist = stack_store->data; 00181 AST_LIST_LOCK(oldlist); 00182 oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries); 00183 AST_LIST_UNLOCK(oldlist); 00184 00185 if (oldframe) { 00186 gosub_release_frame(chan, oldframe); 00187 } else { 00188 ast_debug(1, "%s called with an empty gosub stack\n", app_pop); 00189 } 00190 return 0; 00191 }
static int return_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 193 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(), chan, gosub_stack_frame::context, ast_datastore::data, gosub_stack_frame::entries, gosub_stack_frame::extension, gosub_release_frame(), LOG_ERROR, pbx_builtin_setvar_helper(), gosub_stack_frame::priority, S_OR, and stack_info.
Referenced by load_module().
00194 { 00195 struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL); 00196 struct gosub_stack_frame *oldframe; 00197 AST_LIST_HEAD(, gosub_stack_frame) *oldlist; 00198 char *retval = data; 00199 00200 if (!stack_store) { 00201 ast_log(LOG_ERROR, "Return without Gosub: stack is unallocated\n"); 00202 return -1; 00203 } 00204 00205 oldlist = stack_store->data; 00206 AST_LIST_LOCK(oldlist); 00207 oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries); 00208 AST_LIST_UNLOCK(oldlist); 00209 00210 if (!oldframe) { 00211 ast_log(LOG_ERROR, "Return without Gosub: stack is empty\n"); 00212 return -1; 00213 } 00214 00215 ast_explicit_goto(chan, oldframe->context, oldframe->extension, oldframe->priority); 00216 gosub_release_frame(chan, oldframe); 00217 00218 /* Set a return value, if any */ 00219 pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", S_OR(retval, "")); 00220 return 0; 00221 }
static int unload_module | ( | void | ) | [static] |
Definition at line 504 of file app_stack.c.
References ast_agi_unregister(), ast_custom_function_unregister(), ast_unregister_application(), gosub_agi_command, and local_function.
00505 { 00506 if (ast_agi_unregister) { 00507 ast_agi_unregister(ast_module_info->self, &gosub_agi_command); 00508 } 00509 00510 ast_unregister_application(app_return); 00511 ast_unregister_application(app_pop); 00512 ast_unregister_application(app_gosubif); 00513 ast_unregister_application(app_gosub); 00514 ast_custom_function_unregister(&local_function); 00515 00516 return 0; 00517 }
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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 537 of file app_stack.c.
const char* app_gosub = "Gosub" [static] |
Definition at line 47 of file app_stack.c.
const char* app_gosubif = "GosubIf" [static] |
Definition at line 48 of file app_stack.c.
const char* app_pop = "StackPop" [static] |
Definition at line 50 of file app_stack.c.
const char* app_return = "Return" [static] |
Definition at line 49 of file app_stack.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 537 of file app_stack.c.
struct agi_command gosub_agi_command |
Initial value:
{ { "gosub", NULL }, handle_gosub, "Execute a dialplan subroutine", usage_gosub , 0 }
Definition at line 501 of file app_stack.c.
Referenced by load_module(), and unload_module().
const char* gosub_descrip [static] |
Initial value:
" Gosub([[context,]exten,]priority[(arg1[,...][,argN])]):\n" "Jumps to the label specified, saving the return address.\n"
Definition at line 57 of file app_stack.c.
const char* gosub_synopsis = "Jump to label, saving return address" [static] |
Definition at line 52 of file app_stack.c.
const char* gosubif_descrip [static] |
Initial value:
" GosubIf(condition?labeliftrue[(arg1[,...])][:labeliffalse[(arg1[,...])]]):\n" "If the condition is true, then jump to labeliftrue. If false, jumps to\n" "labeliffalse, if specified. In either case, a jump saves the return point\n" "in the dialplan, to be returned to with a Return.\n"
Definition at line 60 of file app_stack.c.
const char* gosubif_synopsis = "Conditionally jump to label, saving return address" [static] |
Definition at line 53 of file app_stack.c.
struct ast_custom_function local_function [static] |
const char* pop_descrip [static] |
Initial value:
" StackPop():\n" "Removes last label on the stack, discarding it.\n"
Definition at line 69 of file app_stack.c.
const char* pop_synopsis = "Remove one address from gosub stack" [static] |
Definition at line 55 of file app_stack.c.
const char* return_descrip [static] |
Initial value:
" Return([return-value]):\n" "Jumps to the last label on the stack, removing it. The return value, if\n" "any, is saved in the channel variable GOSUB_RETVAL.\n"
Definition at line 65 of file app_stack.c.
const char* return_synopsis = "Return from gosub routine" [static] |
Definition at line 54 of file app_stack.c.
struct ast_datastore_info stack_info [static] |
Initial value:
{ .type = "GOSUB", .destroy = gosub_free, }
Definition at line 75 of file app_stack.c.
Referenced by gosub_exec(), local_read(), local_write(), pop_exec(), and return_exec().
char usage_gosub[] [static] |
Initial value:
" 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 496 of file app_stack.c.