Thu Apr 8 01:21:35 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 551 of file app_stack.c.

static void __unreg_module ( void   )  [static]

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

00092 {
00093    struct ast_var_t *variables;
00094    int found = 0;
00095 
00096    /* Does this variable already exist? */
00097    AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
00098       if (!strcmp(var, ast_var_name(variables))) {
00099          found = 1;
00100          break;
00101       }
00102    }
00103 
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 
00112    manager_event(EVENT_FLAG_DIALPLAN, "VarSet",
00113       "Channel: %s\r\n"
00114       "Variable: LOCAL(%s)\r\n"
00115       "Value: %s\r\n"
00116       "Uniqueid: %s\r\n",
00117       chan->name, var, value, chan->uniqueid);
00118    return 0;
00119 }

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

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 227 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().

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

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

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

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

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

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

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 352 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.

00353 {
00354    struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00355    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00356    struct gosub_stack_frame *frame;
00357    struct ast_var_t *variables;
00358 
00359    if (!stack_store)
00360       return -1;
00361 
00362    oldlist = stack_store->data;
00363    AST_LIST_LOCK(oldlist);
00364    if (!(frame = AST_LIST_FIRST(oldlist))) {
00365       /* Not within a Gosub routine */
00366       AST_LIST_UNLOCK(oldlist);
00367       return -1;
00368    }
00369 
00370    AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
00371       if (!strcmp(data, ast_var_name(variables))) {
00372          const char *tmp;
00373          ast_channel_lock(chan);
00374          tmp = pbx_builtin_getvar_helper(chan, data);
00375          ast_copy_string(buf, S_OR(tmp, ""), len);
00376          ast_channel_unlock(chan);
00377          break;
00378       }
00379    }
00380    AST_LIST_UNLOCK(oldlist);
00381    return 0;
00382 }

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

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

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

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

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

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    int res = 0;
00200 
00201    if (!stack_store) {
00202       ast_log(LOG_ERROR, "Return without Gosub: stack is unallocated\n");
00203       return -1;
00204    }
00205 
00206    oldlist = stack_store->data;
00207    AST_LIST_LOCK(oldlist);
00208    oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
00209    AST_LIST_UNLOCK(oldlist);
00210 
00211    if (!oldframe) {
00212       ast_log(LOG_ERROR, "Return without Gosub: stack is empty\n");
00213       return -1;
00214    } else if (oldframe->is_agi) {
00215       /* Exit from AGI */
00216       res = -1;
00217    }
00218 
00219    ast_explicit_goto(chan, oldframe->context, oldframe->extension, oldframe->priority);
00220    gosub_release_frame(chan, oldframe);
00221 
00222    /* Set a return value, if any */
00223    pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", S_OR(retval, ""));
00224    return res;
00225 }

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

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

Definition at line 515 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 407 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 510 of file app_stack.c.


Generated on 8 Apr 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1