Wed Aug 18 22:34:02 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"

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

static void __unreg_module ( void   )  [static]

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

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]

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 gosub_stack_frame::arguments, 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_FIRST, 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, 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().

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, *lastframe;
00232    char argname[15], *tmp = ast_strdupa(data), *label, *endparen;
00233    int i, max_argc = 0;
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    } else {
00262       oldlist = stack_store->data;
00263    }
00264 
00265    if ((lastframe = AST_LIST_FIRST(oldlist))) {
00266       max_argc = lastframe->arguments;
00267    }
00268 
00269    /* Separate the arguments from the label */
00270    /* NOTE:  you cannot use ast_app_separate_args for this, because '(' cannot be used as a delimiter. */
00271    label = strsep(&tmp, "(");
00272    if (tmp) {
00273       endparen = strrchr(tmp, ')');
00274       if (endparen)
00275          *endparen = '\0';
00276       else
00277          ast_log(LOG_WARNING, "Ouch.  No closing paren: '%s'?\n", (char *)data);
00278       AST_STANDARD_RAW_ARGS(args2, tmp);
00279    } else
00280       args2.argc = 0;
00281 
00282    /* Mask out previous arguments in this invocation */
00283    if (args2.argc > max_argc) {
00284       max_argc = args2.argc;
00285    }
00286 
00287    /* Create the return address, but don't save it until we know that the Gosub destination exists */
00288    newframe = gosub_allocate_frame(chan->context, chan->exten, chan->priority + 1, max_argc);
00289 
00290    if (!newframe) {
00291       return -1;
00292    }
00293 
00294    if (ast_parseable_goto(chan, label)) {
00295       ast_log(LOG_ERROR, "Gosub address is invalid: '%s'\n", (char *)data);
00296       ast_free(newframe);
00297       return -1;
00298    }
00299 
00300    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)) {
00301       ast_log(LOG_ERROR, "Attempt to reach a non-existent destination for gosub: (Context:%s, Extension:%s, Priority:%d)\n",
00302             chan->context, chan->exten, chan->priority);
00303       ast_copy_string(chan->context, newframe->context, sizeof(chan->context));
00304       ast_copy_string(chan->exten, newframe->extension, sizeof(chan->exten));
00305       chan->priority = newframe->priority;
00306       ast_free(newframe);
00307       return -1;
00308    }
00309 
00310    /* Now that we know for certain that we're going to a new location, set our arguments */
00311    for (i = 0; i < max_argc; i++) {
00312       snprintf(argname, sizeof(argname), "ARG%d", i + 1);
00313       frame_set_var(chan, newframe, argname, i < args2.argc ? args2.argval[i] : "");
00314       ast_debug(1, "Setting '%s' to '%s'\n", argname, i < args2.argc ? args2.argval[i] : "");
00315    }
00316 
00317    /* And finally, save our return address */
00318    oldlist = stack_store->data;
00319    AST_LIST_LOCK(oldlist);
00320    AST_LIST_INSERT_HEAD(oldlist, newframe, entries);
00321    AST_LIST_UNLOCK(oldlist);
00322 
00323    return 0;
00324 }

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

References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), AST_NONSTANDARD_RAW_ARGS, ast_strdupa, ast_strlen_zero(), chan, cond, gosub_exec(), LOG_WARNING, and pbx_checkcondition().

Referenced by load_module().

00327 {
00328    char *args;
00329    int res=0;
00330    AST_DECLARE_APP_ARGS(cond,
00331       AST_APP_ARG(ition);
00332       AST_APP_ARG(labels);
00333    );
00334    AST_DECLARE_APP_ARGS(label,
00335       AST_APP_ARG(iftrue);
00336       AST_APP_ARG(iffalse);
00337    );
00338 
00339    if (ast_strlen_zero(data)) {
00340       ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
00341       return 0;
00342    }
00343 
00344    args = ast_strdupa(data);
00345    AST_NONSTANDARD_RAW_ARGS(cond, args, '?');
00346    if (cond.argc != 2) {
00347       ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
00348       return 0;
00349    }
00350 
00351    AST_NONSTANDARD_RAW_ARGS(label, cond.labels, ':');
00352 
00353    if (pbx_checkcondition(cond.ition)) {
00354       if (!ast_strlen_zero(label.iftrue))
00355          res = gosub_exec(chan, label.iftrue);
00356    } else if (!ast_strlen_zero(label.iffalse)) {
00357       res = gosub_exec(chan, label.iffalse);
00358    }
00359 
00360    return res;
00361 }

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

Definition at line 426 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(), chan, 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_channel::pbx, pbx_exec(), pbx_findapp(), ast_channel::priority, gosub_stack_frame::priority, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, and stack_info.

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

static int load_module ( void   )  [static]

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

00545 {
00546    /* usage of AGI is optional, so check to see if the ast_agi_register()
00547       function is available; if so, use it.
00548    */
00549    if (ast_agi_register) {
00550       ast_agi_register(ast_module_info->self, &gosub_agi_command);
00551    }
00552 
00553    ast_register_application(app_pop, pop_exec, pop_synopsis, pop_descrip);
00554    ast_register_application(app_return, return_exec, return_synopsis, return_descrip);
00555    ast_register_application(app_gosubif, gosubif_exec, gosubif_synopsis, gosubif_descrip);
00556    ast_register_application(app_gosub, gosub_exec, gosub_synopsis, gosub_descrip);
00557    ast_custom_function_register(&local_function);
00558 
00559    return 0;
00560 }

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

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

00364 {
00365    struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00366    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00367    struct gosub_stack_frame *frame;
00368    struct ast_var_t *variables;
00369 
00370    if (!stack_store)
00371       return -1;
00372 
00373    oldlist = stack_store->data;
00374    AST_LIST_LOCK(oldlist);
00375    if (!(frame = AST_LIST_FIRST(oldlist))) {
00376       /* Not within a Gosub routine */
00377       AST_LIST_UNLOCK(oldlist);
00378       return -1;
00379    }
00380 
00381    AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
00382       if (!strcmp(data, ast_var_name(variables))) {
00383          const char *tmp;
00384          ast_channel_lock(chan);
00385          tmp = pbx_builtin_getvar_helper(chan, data);
00386          ast_copy_string(buf, S_OR(tmp, ""), len);
00387          ast_channel_unlock(chan);
00388          break;
00389       }
00390    }
00391    AST_LIST_UNLOCK(oldlist);
00392    return 0;
00393 }

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

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

00396 {
00397    struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00398    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00399    struct gosub_stack_frame *frame;
00400 
00401    if (!stack_store) {
00402       ast_log(LOG_ERROR, "Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var);
00403       return -1;
00404    }
00405 
00406    oldlist = stack_store->data;
00407    AST_LIST_LOCK(oldlist);
00408    frame = AST_LIST_FIRST(oldlist);
00409 
00410    if (frame)
00411       frame_set_var(chan, frame, var, value);
00412 
00413    AST_LIST_UNLOCK(oldlist);
00414 
00415    return 0;
00416 }

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(), gosub_stack_frame::is_agi, 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    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]

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

Definition at line 562 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 562 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 526 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 418 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(), handle_gosub(), 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 521 of file app_stack.c.


Generated on Wed Aug 18 22:34:02 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7