Wed Mar 3 22:43:30 2010

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"
Include dependency graph for app_stack.c:

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 = "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_infoast_module_info = &__mod_info
struct 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 541 of file app_stack.c.

static void __unreg_module ( void   )  [static]

Definition at line 541 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(), 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, read]

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_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_strdupa, 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, gosub_stack_frame::priority, ast_channel::priority, 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_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_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_RAW_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(), 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_RAW_ARGS, ast_strdupa, ast_strlen_zero(), 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_RAW_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_RAW_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 410 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(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, errno, ast_channel::exten, agi_state::fd, 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.

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

static int load_module ( void   )  [static]
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_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.

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    if (!(frame = AST_LIST_FIRST(oldlist))) {
00360       /* Not within a Gosub routine */
00361       AST_LIST_UNLOCK(oldlist);
00362       return -1;
00363    }
00364 
00365    AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
00366       if (!strcmp(data, ast_var_name(variables))) {
00367          const char *tmp;
00368          ast_channel_lock(chan);
00369          tmp = pbx_builtin_getvar_helper(chan, data);
00370          ast_copy_string(buf, S_OR(tmp, ""), len);
00371          ast_channel_unlock(chan);
00372          break;
00373       }
00374    }
00375    AST_LIST_UNLOCK(oldlist);
00376    return 0;
00377 }

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

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

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

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(), ast_datastore::data, gosub_stack_frame::entries, gosub_release_frame(), and LOG_WARNING.

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(), 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, and S_OR.

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]

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

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

Definition at line 541 of file app_stack.c.

Initial value:
   { { "gosub", NULL }, handle_gosub, "Execute a dialplan subroutine", usage_gosub , 0 }

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

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

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


Generated on 3 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1