Fri Jun 19 12:10:03 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 = "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 537 of file app_stack.c.

static void __unreg_module ( void   )  [static]

Definition at line 537 of file app_stack.c.

static int frame_set_var ( struct ast_channel chan,
struct gosub_stack_frame frame,
const char *  var,
const char *  value 
) [static]

Definition at line 90 of file app_stack.c.

References AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_strlen_zero(), ast_var_assign(), ast_var_name(), gosub_stack_frame::entries, EVENT_FLAG_DIALPLAN, manager_event, pbx_builtin_pushvar_helper(), and pbx_builtin_setvar_helper().

Referenced by gosub_exec(), and local_write().

00091 {
00092    struct ast_var_t *variables;
00093    int found = 0;
00094 
00095    /* Does this variable already exist? */
00096    AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
00097       if (!strcmp(var, ast_var_name(variables))) {
00098          found = 1;
00099          break;
00100       }
00101    }
00102 
00103    if (!ast_strlen_zero(value)) {
00104       if (!found) {
00105          variables = ast_var_assign(var, "");
00106          AST_LIST_INSERT_HEAD(&frame->varshead, variables, entries);
00107          pbx_builtin_pushvar_helper(chan, var, value);
00108       } else
00109          pbx_builtin_setvar_helper(chan, var, value);
00110 
00111       manager_event(EVENT_FLAG_DIALPLAN, "VarSet", 
00112          "Channel: %s\r\n"
00113          "Variable: LOCAL(%s)\r\n"
00114          "Value: %s\r\n"
00115          "Uniqueid: %s\r\n", 
00116          chan->name, var, value, chan->uniqueid);
00117    }
00118    return 0;
00119 }

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

Definition at line 140 of file app_stack.c.

References ast_calloc, and AST_LIST_HEAD_INIT_NOLOCK.

Referenced by gosub_exec().

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

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

Definition at line 223 of file app_stack.c.

References AST_APP_ARG, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_copy_string(), ast_datastore_alloc(), ast_datastore_free(), ast_debug, AST_DECLARE_APP_ARGS, ast_exists_extension(), AST_FLAG_IN_AUTOLOOP, ast_free, AST_LIST_HEAD, AST_LIST_HEAD_INIT, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_parseable_goto(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, chan, ast_channel::cid, ast_callerid::cid_num, gosub_stack_frame::context, ast_channel::context, ast_datastore::data, gosub_stack_frame::entries, ast_channel::exten, gosub_stack_frame::extension, frame_set_var(), gosub_allocate_frame(), LOG_ERROR, LOG_WARNING, ast_channel::name, gosub_stack_frame::priority, ast_channel::priority, stack_info, and strsep().

Referenced by gosubif_exec(), and load_module().

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

static void gosub_free ( void *  data  )  [static]

Definition at line 156 of file app_stack.c.

References ast_free, AST_LIST_HEAD, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, gosub_stack_frame::entries, and gosub_release_frame().

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

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

Definition at line 121 of file app_stack.c.

References ast_free, AST_LIST_REMOVE_HEAD, ast_var_delete(), ast_var_name(), chan, gosub_stack_frame::entries, pbx_builtin_setvar_helper(), and gosub_stack_frame::varshead.

Referenced by gosub_free(), pop_exec(), and return_exec().

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

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

Definition at line 311 of file app_stack.c.

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

Referenced by load_module().

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

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

Definition at line 406 of file app_stack.c.

References asprintf, ast_agi_send(), ast_copy_string(), ast_debug, ast_exists_extension(), ast_findlabel_extension(), ast_free, ast_log(), AST_MAX_CONTEXT, AST_MAX_EXTENSION, ast_pbx_run_args(), chan, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, errno, ast_channel::exten, agi_state::fd, LOG_ERROR, LOG_WARNING, ast_channel::pbx, pbx_exec(), pbx_findapp(), ast_channel::priority, gosub_stack_frame::priority, RESULT_FAILURE, RESULT_SHOWUSAGE, and RESULT_SUCCESS.

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

static int load_module ( void   )  [static]

Definition at line 519 of file app_stack.c.

References ast_agi_register(), ast_custom_function_register, ast_register_application, gosub_agi_command, gosub_exec(), gosubif_exec(), local_function, pop_exec(), and return_exec().

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

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

Definition at line 348 of file app_stack.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_LIST_FIRST, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_var_name(), chan, ast_datastore::data, gosub_stack_frame::entries, pbx_builtin_getvar_helper(), S_OR, stack_info, and gosub_stack_frame::varshead.

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

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

Definition at line 375 of file app_stack.c.

References ast_channel_datastore_find(), AST_LIST_FIRST, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), chan, ast_datastore::data, frame_set_var(), LOG_ERROR, and stack_info.

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

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

Definition at line 169 of file app_stack.c.

References ast_channel_datastore_find(), ast_debug, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log(), chan, ast_datastore::data, gosub_stack_frame::entries, gosub_release_frame(), LOG_WARNING, and stack_info.

Referenced by load_module().

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

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

Definition at line 193 of file app_stack.c.

References ast_channel_datastore_find(), ast_explicit_goto(), AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log(), chan, gosub_stack_frame::context, ast_datastore::data, gosub_stack_frame::entries, gosub_stack_frame::extension, gosub_release_frame(), LOG_ERROR, pbx_builtin_setvar_helper(), gosub_stack_frame::priority, S_OR, and stack_info.

Referenced by load_module().

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

static int unload_module ( void   )  [static]

Definition at line 504 of file app_stack.c.

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


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

const char* app_gosub = "Gosub" [static]

Definition at line 47 of file app_stack.c.

const char* app_gosubif = "GosubIf" [static]

Definition at line 48 of file app_stack.c.

const char* app_pop = "StackPop" [static]

Definition at line 50 of file app_stack.c.

const char* app_return = "Return" [static]

Definition at line 49 of file app_stack.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 537 of file app_stack.c.

struct agi_command gosub_agi_command

Initial value:

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

Definition at line 501 of file app_stack.c.

Referenced by load_module(), and unload_module().

const char* gosub_descrip [static]

Initial value:

"  Gosub([[context,]exten,]priority[(arg1[,...][,argN])]):\n"
"Jumps to the label specified, saving the return address.\n"

Definition at line 57 of file app_stack.c.

const char* gosub_synopsis = "Jump to label, saving return address" [static]

Definition at line 52 of file app_stack.c.

const char* gosubif_descrip [static]

Initial value:

"  GosubIf(condition?labeliftrue[(arg1[,...])][:labeliffalse[(arg1[,...])]]):\n"
"If the condition is true, then jump to labeliftrue.  If false, jumps to\n"
"labeliffalse, if specified.  In either case, a jump saves the return point\n"
"in the dialplan, to be returned to with a Return.\n"

Definition at line 60 of file app_stack.c.

const char* gosubif_synopsis = "Conditionally jump to label, saving return address" [static]

Definition at line 53 of file app_stack.c.

struct ast_custom_function local_function [static]

Definition at line 398 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 496 of file app_stack.c.


Generated on Fri Jun 19 12:10:03 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7