Thu Jul 9 13:40:49 2009

Asterisk developer's documentation


app_stack.c File Reference

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

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_framegosub_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 = "068e67f60f50dd9ee86464c05884a49d" , .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 const struct ast_module_infoast_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 []


Detailed Description

Stack applications Gosub, Return, etc.

Author:
Tilghman Lesher <app_stack_v003@the-tilghman.com>

Definition in file app_stack.c.


Define Documentation

#define ASTERISK_AGI_OPTIONAL

Definition at line 43 of file app_stack.c.


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 536 of file app_stack.c.

static void __unreg_module ( void   )  [static]

Definition at line 536 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_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 (!found) {
00104       variables = ast_var_assign(var, "");
00105       AST_LIST_INSERT_HEAD(&frame->varshead, variables, entries);
00106       pbx_builtin_pushvar_helper(chan, var, value);
00107    } else {
00108       pbx_builtin_setvar_helper(chan, var, value);
00109    }
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    return 0;
00118 }

static struct gosub_stack_frame* gosub_allocate_frame ( const char *  context,
const char *  extension,
int  priority,
unsigned char  arguments 
) [static]

Definition at line 139 of file app_stack.c.

References ast_calloc, and AST_LIST_HEAD_INIT_NOLOCK.

Referenced by gosub_exec().

00140 {
00141    struct gosub_stack_frame *new = NULL;
00142    int len_extension = strlen(extension), len_context = strlen(context);
00143 
00144    if ((new = ast_calloc(1, sizeof(*new) + 2 + len_extension + len_context))) {
00145       AST_LIST_HEAD_INIT_NOLOCK(&new->varshead);
00146       strcpy(new->extension, extension);
00147       new->context = new->extension + len_extension + 1;
00148       strcpy(new->context, context);
00149       new->priority = priority;
00150       new->arguments = arguments;
00151    }
00152    return new;
00153 }

static int gosub_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 222 of file app_stack.c.

References AST_APP_ARG, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_alloc(), ast_channel_datastore_find(), ast_channel_datastore_free(), ast_copy_string(), 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().

00223 {
00224    struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00225    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00226    struct gosub_stack_frame *newframe;
00227    char argname[15], *tmp = ast_strdupa(data), *label, *endparen;
00228    int i;
00229    AST_DECLARE_APP_ARGS(args2,
00230       AST_APP_ARG(argval)[100];
00231    );
00232 
00233    if (ast_strlen_zero(data)) {
00234       ast_log(LOG_ERROR, "%s requires an argument: %s([[context,]exten,]priority[(arg1[,...][,argN])])\n", app_gosub, app_gosub);
00235       return -1;
00236    }
00237 
00238    if (!stack_store) {
00239       ast_debug(1, "Channel %s has no datastore, so we're allocating one.\n", chan->name);
00240       stack_store = ast_channel_datastore_alloc(&stack_info, NULL);
00241       if (!stack_store) {
00242          ast_log(LOG_ERROR, "Unable to allocate new datastore.  Gosub will fail.\n");
00243          return -1;
00244       }
00245 
00246       oldlist = ast_calloc(1, sizeof(*oldlist));
00247       if (!oldlist) {
00248          ast_log(LOG_ERROR, "Unable to allocate datastore list head.  Gosub will fail.\n");
00249          ast_channel_datastore_free(stack_store);
00250          return -1;
00251       }
00252 
00253       stack_store->data = oldlist;
00254       AST_LIST_HEAD_INIT(oldlist);
00255       ast_channel_datastore_add(chan, stack_store);
00256    }
00257 
00258    /* Separate the arguments from the label */
00259    /* NOTE:  you cannot use ast_app_separate_args for this, because '(' cannot be used as a delimiter. */
00260    label = strsep(&tmp, "(");
00261    if (tmp) {
00262       endparen = strrchr(tmp, ')');
00263       if (endparen)
00264          *endparen = '\0';
00265       else
00266          ast_log(LOG_WARNING, "Ouch.  No closing paren: '%s'?\n", (char *)data);
00267       AST_STANDARD_APP_ARGS(args2, tmp);
00268    } else
00269       args2.argc = 0;
00270 
00271    /* Create the return address, but don't save it until we know that the Gosub destination exists */
00272    newframe = gosub_allocate_frame(chan->context, chan->exten, chan->priority + 1, args2.argc);
00273 
00274    if (!newframe) {
00275       return -1;
00276    }
00277 
00278    if (ast_parseable_goto(chan, label)) {
00279       ast_log(LOG_ERROR, "Gosub address is invalid: '%s'\n", (char *)data);
00280       ast_free(newframe);
00281       return -1;
00282    }
00283 
00284    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)) {
00285       ast_log(LOG_ERROR, "Attempt to reach a non-existent destination for gosub: (Context:%s, Extension:%s, Priority:%d)\n",
00286             chan->context, chan->exten, chan->priority);
00287       ast_copy_string(chan->context, newframe->context, sizeof(chan->context));
00288       ast_copy_string(chan->exten, newframe->extension, sizeof(chan->exten));
00289       chan->priority = newframe->priority;
00290       ast_free(newframe);
00291       return -1;
00292    }
00293 
00294    /* Now that we know for certain that we're going to a new location, set our arguments */
00295    for (i = 0; i < args2.argc; i++) {
00296       snprintf(argname, sizeof(argname), "ARG%d", i + 1);
00297       frame_set_var(chan, newframe, argname, args2.argval[i]);
00298       ast_debug(1, "Setting '%s' to '%s'\n", argname, args2.argval[i]);
00299    }
00300 
00301    /* And finally, save our return address */
00302    oldlist = stack_store->data;
00303    AST_LIST_LOCK(oldlist);
00304    AST_LIST_INSERT_HEAD(oldlist, newframe, entries);
00305    AST_LIST_UNLOCK(oldlist);
00306 
00307    return 0;
00308 }

static void gosub_free ( void *  data  )  [static]

Definition at line 155 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().

00156 {
00157    AST_LIST_HEAD(, gosub_stack_frame) *oldlist = data;
00158    struct gosub_stack_frame *oldframe;
00159    AST_LIST_LOCK(oldlist);
00160    while ((oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries))) {
00161       gosub_release_frame(NULL, oldframe);
00162    }
00163    AST_LIST_UNLOCK(oldlist);
00164    AST_LIST_HEAD_DESTROY(oldlist);
00165    ast_free(oldlist);
00166 }

static void gosub_release_frame ( struct ast_channel chan,
struct gosub_stack_frame frame 
) [static]

Definition at line 120 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().

00121 {
00122    struct ast_var_t *vardata;
00123 
00124    /* If chan is not defined, then we're calling it as part of gosub_free,
00125     * and the channel variables will be deallocated anyway.  Otherwise, we're
00126     * just releasing a single frame, so we need to clean up the arguments for
00127     * that frame, so that we re-expose the variables from the previous frame
00128     * that were hidden by this one.
00129     */
00130    while ((vardata = AST_LIST_REMOVE_HEAD(&frame->varshead, entries))) {
00131       if (chan)
00132          pbx_builtin_setvar_helper(chan, ast_var_name(vardata), NULL);  
00133       ast_var_delete(vardata);
00134    }
00135 
00136    ast_free(frame);
00137 }

static int gosubif_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 310 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().

00311 {
00312    char *args;
00313    int res=0;
00314    AST_DECLARE_APP_ARGS(cond,
00315       AST_APP_ARG(ition);
00316       AST_APP_ARG(labels);
00317    );
00318    AST_DECLARE_APP_ARGS(label,
00319       AST_APP_ARG(iftrue);
00320       AST_APP_ARG(iffalse);
00321    );
00322 
00323    if (ast_strlen_zero(data)) {
00324       ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
00325       return 0;
00326    }
00327 
00328    args = ast_strdupa(data);
00329    AST_NONSTANDARD_APP_ARGS(cond, args, '?');
00330    if (cond.argc != 2) {
00331       ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
00332       return 0;
00333    }
00334 
00335    AST_NONSTANDARD_APP_ARGS(label, cond.labels, ':');
00336 
00337    if (pbx_checkcondition(cond.ition)) {
00338       if (!ast_strlen_zero(label.iftrue))
00339          res = gosub_exec(chan, label.iftrue);
00340    } else if (!ast_strlen_zero(label.iffalse)) {
00341       res = gosub_exec(chan, label.iffalse);
00342    }
00343 
00344    return res;
00345 }

static int handle_gosub ( struct ast_channel chan,
AGI agi,
int  argc,
char **  argv 
) [static]

Definition at line 402 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.

00403 {
00404    int old_priority, priority;
00405    char old_context[AST_MAX_CONTEXT], old_extension[AST_MAX_EXTENSION];
00406    struct ast_app *theapp;
00407    char *gosub_args;
00408 
00409    if (argc < 4 || argc > 5) {
00410       return RESULT_SHOWUSAGE;
00411    }
00412 
00413    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] : "");
00414 
00415    if (sscanf(argv[3], "%d", &priority) != 1 || priority < 1) {
00416       /* Lookup the priority label */
00417       if ((priority = ast_findlabel_extension(chan, argv[1], argv[2], argv[3], chan->cid.cid_num)) < 0) {
00418          ast_log(LOG_ERROR, "Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]);
00419          ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
00420          return RESULT_FAILURE;
00421       }
00422    } else if (!ast_exists_extension(chan, argv[1], argv[2], priority, chan->cid.cid_num)) {
00423       ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
00424       return RESULT_FAILURE;
00425    }
00426 
00427    /* Save previous location, since we're going to change it */
00428    ast_copy_string(old_context, chan->context, sizeof(old_context));
00429    ast_copy_string(old_extension, chan->exten, sizeof(old_extension));
00430    old_priority = chan->priority;
00431 
00432    if (!(theapp = pbx_findapp("Gosub"))) {
00433       ast_log(LOG_ERROR, "Gosub() cannot be found in the list of loaded applications\n");
00434       ast_agi_send(agi->fd, chan, "503 result=-2 Gosub is not loaded\n");
00435       return RESULT_FAILURE;
00436    }
00437 
00438    /* Apparently, if you run ast_pbx_run on a channel that already has a pbx
00439     * structure, you need to add 1 to the priority to get it to go to the
00440     * right place.  But if it doesn't have a pbx structure, then leaving off
00441     * the 1 is the right thing to do.  See how this code differs when we
00442     * call a Gosub for the CALLEE channel in Dial or Queue.
00443     */
00444    if (argc == 5) {
00445       if (asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority + 1, argv[4]) < 0) {
00446          ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00447          gosub_args = NULL;
00448       }
00449    } else {
00450       if (asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority + 1) < 0) {
00451          ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00452          gosub_args = NULL;
00453       }
00454    }
00455 
00456    if (gosub_args) {
00457       int res;
00458 
00459       ast_debug(1, "Trying gosub with arguments '%s'\n", gosub_args);
00460       ast_copy_string(chan->context, "app_stack_gosub_virtual_context", sizeof(chan->context));
00461       ast_copy_string(chan->exten, "s", sizeof(chan->exten));
00462       chan->priority = 0;
00463 
00464       if ((res = pbx_exec(chan, theapp, gosub_args)) == 0) {
00465          struct ast_pbx *pbx = chan->pbx;
00466          struct ast_pbx_args args;
00467          memset(&args, 0, sizeof(args));
00468          args.no_hangup_chan = 1;
00469          /* Suppress warning about PBX already existing */
00470          chan->pbx = NULL;
00471          ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n");
00472          ast_pbx_run_args(chan, &args);
00473          ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete\n");
00474          if (chan->pbx) {
00475             ast_free(chan->pbx);
00476          }
00477          chan->pbx = pbx;
00478       } else {
00479          ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res);
00480       }
00481       ast_free(gosub_args);
00482    } else {
00483       ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n");
00484       return RESULT_FAILURE;
00485    }
00486 
00487    /* Restore previous location */
00488    ast_copy_string(chan->context, old_context, sizeof(chan->context));
00489    ast_copy_string(chan->exten, old_extension, sizeof(chan->exten));
00490    chan->priority = old_priority;
00491 
00492    return RESULT_SUCCESS;
00493 }

static int load_module ( void   )  [static]

Definition at line 518 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().

00519 {
00520    /* usage of AGI is optional, so check to see if the ast_agi_register()
00521       function is available; if so, use it.
00522    */
00523    if (ast_agi_register) {
00524       ast_agi_register(ast_module_info->self, &gosub_agi_command);
00525    }
00526 
00527    ast_register_application(app_pop, pop_exec, pop_synopsis, pop_descrip);
00528    ast_register_application(app_return, return_exec, return_synopsis, return_descrip);
00529    ast_register_application(app_gosubif, gosubif_exec, gosubif_synopsis, gosubif_descrip);
00530    ast_register_application(app_gosub, gosub_exec, gosub_synopsis, gosub_descrip);
00531    ast_custom_function_register(&local_function);
00532 
00533    return 0;
00534 }

static int local_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Definition at line 347 of file app_stack.c.

References ast_channel_datastore_find(), 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.

00348 {
00349    struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00350    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00351    struct gosub_stack_frame *frame;
00352    struct ast_var_t *variables;
00353 
00354    if (!stack_store)
00355       return -1;
00356 
00357    oldlist = stack_store->data;
00358    AST_LIST_LOCK(oldlist);
00359    frame = AST_LIST_FIRST(oldlist);
00360    AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
00361       if (!strcmp(data, ast_var_name(variables))) {
00362          const char *tmp = pbx_builtin_getvar_helper(chan, data);
00363          ast_copy_string(buf, S_OR(tmp, ""), len);
00364          break;
00365       }
00366    }
00367    AST_LIST_UNLOCK(oldlist);
00368    return 0;
00369 }

static int local_write ( struct ast_channel chan,
const char *  cmd,
char *  var,
const char *  value 
) [static]

Definition at line 371 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.

00372 {
00373    struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00374    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00375    struct gosub_stack_frame *frame;
00376 
00377    if (!stack_store) {
00378       ast_log(LOG_ERROR, "Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var);
00379       return -1;
00380    }
00381 
00382    oldlist = stack_store->data;
00383    AST_LIST_LOCK(oldlist);
00384    frame = AST_LIST_FIRST(oldlist);
00385 
00386    if (frame)
00387       frame_set_var(chan, frame, var, value);
00388 
00389    AST_LIST_UNLOCK(oldlist);
00390 
00391    return 0;
00392 }

static int pop_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 168 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().

00169 {
00170    struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00171    struct gosub_stack_frame *oldframe;
00172    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00173 
00174    if (!stack_store) {
00175       ast_log(LOG_WARNING, "%s called with no gosub stack allocated.\n", app_pop);
00176       return 0;
00177    }
00178 
00179    oldlist = stack_store->data;
00180    AST_LIST_LOCK(oldlist);
00181    oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
00182    AST_LIST_UNLOCK(oldlist);
00183 
00184    if (oldframe) {
00185       gosub_release_frame(chan, oldframe);
00186    } else {
00187       ast_debug(1, "%s called with an empty gosub stack\n", app_pop);
00188    }
00189    return 0;
00190 }

static int return_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 192 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().

00193 {
00194    struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00195    struct gosub_stack_frame *oldframe;
00196    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00197    char *retval = data;
00198 
00199    if (!stack_store) {
00200       ast_log(LOG_ERROR, "Return without Gosub: stack is unallocated\n");
00201       return -1;
00202    }
00203 
00204    oldlist = stack_store->data;
00205    AST_LIST_LOCK(oldlist);
00206    oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
00207    AST_LIST_UNLOCK(oldlist);
00208 
00209    if (!oldframe) {
00210       ast_log(LOG_ERROR, "Return without Gosub: stack is empty\n");
00211       return -1;
00212    }
00213 
00214    ast_explicit_goto(chan, oldframe->context, oldframe->extension, oldframe->priority);
00215    gosub_release_frame(chan, oldframe);
00216 
00217    /* Set a return value, if any */
00218    pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", S_OR(retval, ""));
00219    return 0;
00220 }

static int unload_module ( void   )  [static]

Definition at line 503 of file app_stack.c.

References ast_agi_unregister(), ast_custom_function_unregister(), ast_unregister_application(), gosub_agi_command, and local_function.


Variable Documentation

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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, } [static]

Definition at line 536 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.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 536 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 500 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]

Definition at line 394 of file app_stack.c.

Referenced by load_module(), and unload_module().

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 495 of file app_stack.c.


Generated on Thu Jul 9 13:40:49 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7