Fri Nov 12 11:52:07 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

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 peek_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
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 = "0901e4e500243c855563a2d78b0c03e4" , .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 struct ast_custom_function local_function
static struct ast_custom_function peek_function
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.


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 685 of file app_stack.c.

static void __unreg_module ( void   )  [static]

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

00193 {
00194    struct ast_var_t *variables;
00195    int found = 0;
00196 
00197    /* Does this variable already exist? */
00198    AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
00199       if (!strcmp(var, ast_var_name(variables))) {
00200          found = 1;
00201          break;
00202       }
00203    }
00204 
00205    if (!found) {
00206       variables = ast_var_assign(var, "");
00207       AST_LIST_INSERT_HEAD(&frame->varshead, variables, entries);
00208       pbx_builtin_pushvar_helper(chan, var, value);
00209    } else {
00210       pbx_builtin_setvar_helper(chan, var, value);
00211    }
00212 
00213    manager_event(EVENT_FLAG_DIALPLAN, "VarSet",
00214       "Channel: %s\r\n"
00215       "Variable: LOCAL(%s)\r\n"
00216       "Value: %s\r\n"
00217       "Uniqueid: %s\r\n",
00218       chan->name, var, value, chan->uniqueid);
00219    return 0;
00220 }

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

Definition at line 241 of file app_stack.c.

References ast_calloc, and AST_LIST_HEAD_INIT_NOLOCK.

Referenced by gosub_exec().

00242 {
00243    struct gosub_stack_frame *new = NULL;
00244    int len_extension = strlen(extension), len_context = strlen(context);
00245 
00246    if ((new = ast_calloc(1, sizeof(*new) + 2 + len_extension + len_context))) {
00247       AST_LIST_HEAD_INIT_NOLOCK(&new->varshead);
00248       strcpy(new->extension, extension);
00249       new->context = new->extension + len_extension + 1;
00250       strcpy(new->context, context);
00251       new->priority = priority;
00252       new->arguments = arguments;
00253    }
00254    return new;
00255 }

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

Definition at line 328 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_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, ast_channel::name, gosub_stack_frame::priority, and ast_channel::priority.

Referenced by gosubif_exec(), and load_module().

00329 {
00330    struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00331    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00332    struct gosub_stack_frame *newframe;
00333    char argname[15], *tmp = ast_strdupa(data), *label, *endparen;
00334    int i;
00335    AST_DECLARE_APP_ARGS(args2,
00336       AST_APP_ARG(argval)[100];
00337    );
00338 
00339    if (ast_strlen_zero(data)) {
00340       ast_log(LOG_ERROR, "%s requires an argument: %s([[context,]exten,]priority[(arg1[,...][,argN])])\n", app_gosub, app_gosub);
00341       return -1;
00342    }
00343 
00344    if (!stack_store) {
00345       ast_debug(1, "Channel %s has no datastore, so we're allocating one.\n", chan->name);
00346       stack_store = ast_datastore_alloc(&stack_info, NULL);
00347       if (!stack_store) {
00348          ast_log(LOG_ERROR, "Unable to allocate new datastore.  Gosub will fail.\n");
00349          return -1;
00350       }
00351 
00352       oldlist = ast_calloc(1, sizeof(*oldlist));
00353       if (!oldlist) {
00354          ast_log(LOG_ERROR, "Unable to allocate datastore list head.  Gosub will fail.\n");
00355          ast_datastore_free(stack_store);
00356          return -1;
00357       }
00358 
00359       stack_store->data = oldlist;
00360       AST_LIST_HEAD_INIT(oldlist);
00361       ast_channel_datastore_add(chan, stack_store);
00362    }
00363 
00364    /* Separate the arguments from the label */
00365    /* NOTE:  you cannot use ast_app_separate_args for this, because '(' cannot be used as a delimiter. */
00366    label = strsep(&tmp, "(");
00367    if (tmp) {
00368       endparen = strrchr(tmp, ')');
00369       if (endparen)
00370          *endparen = '\0';
00371       else
00372          ast_log(LOG_WARNING, "Ouch.  No closing paren: '%s'?\n", (char *)data);
00373       AST_STANDARD_RAW_ARGS(args2, tmp);
00374    } else
00375       args2.argc = 0;
00376 
00377    /* Create the return address, but don't save it until we know that the Gosub destination exists */
00378    newframe = gosub_allocate_frame(chan->context, chan->exten, chan->priority + 1, args2.argc);
00379 
00380    if (!newframe) {
00381       return -1;
00382    }
00383 
00384    if (ast_parseable_goto(chan, label)) {
00385       ast_log(LOG_ERROR, "Gosub address is invalid: '%s'\n", (char *)data);
00386       ast_free(newframe);
00387       return -1;
00388    }
00389 
00390    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)) {
00391       ast_log(LOG_ERROR, "Attempt to reach a non-existent destination for gosub: (Context:%s, Extension:%s, Priority:%d)\n",
00392             chan->context, chan->exten, chan->priority);
00393       ast_copy_string(chan->context, newframe->context, sizeof(chan->context));
00394       ast_copy_string(chan->exten, newframe->extension, sizeof(chan->exten));
00395       chan->priority = newframe->priority;
00396       ast_free(newframe);
00397       return -1;
00398    }
00399 
00400    /* Now that we know for certain that we're going to a new location, set our arguments */
00401    for (i = 0; i < args2.argc; i++) {
00402       snprintf(argname, sizeof(argname), "ARG%d", i + 1);
00403       frame_set_var(chan, newframe, argname, args2.argval[i]);
00404       ast_debug(1, "Setting '%s' to '%s'\n", argname, args2.argval[i]);
00405    }
00406    snprintf(argname, sizeof(argname), "%d", args2.argc);
00407    frame_set_var(chan, newframe, "ARGC", argname);
00408 
00409    /* And finally, save our return address */
00410    oldlist = stack_store->data;
00411    AST_LIST_LOCK(oldlist);
00412    AST_LIST_INSERT_HEAD(oldlist, newframe, entries);
00413    AST_LIST_UNLOCK(oldlist);
00414 
00415    return 0;
00416 }

static void gosub_free ( void *  data  )  [static]

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

00258 {
00259    AST_LIST_HEAD(, gosub_stack_frame) *oldlist = data;
00260    struct gosub_stack_frame *oldframe;
00261    AST_LIST_LOCK(oldlist);
00262    while ((oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries))) {
00263       gosub_release_frame(NULL, oldframe);
00264    }
00265    AST_LIST_UNLOCK(oldlist);
00266    AST_LIST_HEAD_DESTROY(oldlist);
00267    ast_free(oldlist);
00268 }

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

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

00223 {
00224    struct ast_var_t *vardata;
00225 
00226    /* If chan is not defined, then we're calling it as part of gosub_free,
00227     * and the channel variables will be deallocated anyway.  Otherwise, we're
00228     * just releasing a single frame, so we need to clean up the arguments for
00229     * that frame, so that we re-expose the variables from the previous frame
00230     * that were hidden by this one.
00231     */
00232    while ((vardata = AST_LIST_REMOVE_HEAD(&frame->varshead, entries))) {
00233       if (chan)
00234          pbx_builtin_setvar_helper(chan, ast_var_name(vardata), NULL);  
00235       ast_var_delete(vardata);
00236    }
00237 
00238    ast_free(frame);
00239 }

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

Definition at line 418 of file app_stack.c.

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

Referenced by load_module().

00419 {
00420    char *args;
00421    int res=0;
00422    AST_DECLARE_APP_ARGS(cond,
00423       AST_APP_ARG(ition);
00424       AST_APP_ARG(labels);
00425    );
00426    AST_DECLARE_APP_ARGS(label,
00427       AST_APP_ARG(iftrue);
00428       AST_APP_ARG(iffalse);
00429    );
00430 
00431    if (ast_strlen_zero(data)) {
00432       ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
00433       return 0;
00434    }
00435 
00436    args = ast_strdupa(data);
00437    AST_NONSTANDARD_RAW_ARGS(cond, args, '?');
00438    if (cond.argc != 2) {
00439       ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
00440       return 0;
00441    }
00442 
00443    AST_NONSTANDARD_RAW_ARGS(label, cond.labels, ':');
00444 
00445    if (pbx_checkcondition(cond.ition)) {
00446       if (!ast_strlen_zero(label.iftrue))
00447          res = gosub_exec(chan, label.iftrue);
00448    } else if (!ast_strlen_zero(label.iffalse)) {
00449       res = gosub_exec(chan, label.iffalse);
00450    }
00451 
00452    return res;
00453 }

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

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

00551 {
00552    int old_priority, priority;
00553    char old_context[AST_MAX_CONTEXT], old_extension[AST_MAX_EXTENSION];
00554    struct ast_app *theapp;
00555    char *gosub_args;
00556 
00557    if (argc < 4 || argc > 5) {
00558       return RESULT_SHOWUSAGE;
00559    }
00560 
00561    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] : "");
00562 
00563    if (sscanf(argv[3], "%30d", &priority) != 1 || priority < 1) {
00564       /* Lookup the priority label */
00565       if ((priority = ast_findlabel_extension(chan, argv[1], argv[2], argv[3], chan->cid.cid_num)) < 0) {
00566          ast_log(LOG_ERROR, "Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]);
00567          ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
00568          return RESULT_FAILURE;
00569       }
00570    } else if (!ast_exists_extension(chan, argv[1], argv[2], priority, chan->cid.cid_num)) {
00571       ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
00572       return RESULT_FAILURE;
00573    }
00574 
00575    /* Save previous location, since we're going to change it */
00576    ast_copy_string(old_context, chan->context, sizeof(old_context));
00577    ast_copy_string(old_extension, chan->exten, sizeof(old_extension));
00578    old_priority = chan->priority;
00579 
00580    if (!(theapp = pbx_findapp("Gosub"))) {
00581       ast_log(LOG_ERROR, "Gosub() cannot be found in the list of loaded applications\n");
00582       ast_agi_send(agi->fd, chan, "503 result=-2 Gosub is not loaded\n");
00583       return RESULT_FAILURE;
00584    }
00585 
00586    /* Apparently, if you run ast_pbx_run on a channel that already has a pbx
00587     * structure, you need to add 1 to the priority to get it to go to the
00588     * right place.  But if it doesn't have a pbx structure, then leaving off
00589     * the 1 is the right thing to do.  See how this code differs when we
00590     * call a Gosub for the CALLEE channel in Dial or Queue.
00591     */
00592    if (argc == 5) {
00593       if (asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority + (chan->pbx ? 1 : 0), argv[4]) < 0) {
00594          ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00595          gosub_args = NULL;
00596       }
00597    } else {
00598       if (asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority + (chan->pbx ? 1 : 0)) < 0) {
00599          ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00600          gosub_args = NULL;
00601       }
00602    }
00603 
00604    if (gosub_args) {
00605       int res;
00606 
00607       ast_debug(1, "Trying gosub with arguments '%s'\n", gosub_args);
00608 
00609       if ((res = pbx_exec(chan, theapp, gosub_args)) == 0) {
00610          struct ast_pbx *pbx = chan->pbx;
00611          struct ast_pbx_args args;
00612          struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00613          AST_LIST_HEAD(, gosub_stack_frame) *oldlist = stack_store->data;
00614          struct gosub_stack_frame *cur = AST_LIST_FIRST(oldlist);
00615          cur->is_agi = 1;
00616 
00617          memset(&args, 0, sizeof(args));
00618          args.no_hangup_chan = 1;
00619          /* Suppress warning about PBX already existing */
00620          chan->pbx = NULL;
00621          ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n");
00622          ast_pbx_run_args(chan, &args);
00623          ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete\n");
00624          if (chan->pbx) {
00625             ast_free(chan->pbx);
00626          }
00627          chan->pbx = pbx;
00628       } else {
00629          ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res);
00630       }
00631       ast_free(gosub_args);
00632    } else {
00633       ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n");
00634       return RESULT_FAILURE;
00635    }
00636 
00637    /* Restore previous location */
00638    ast_copy_string(chan->context, old_context, sizeof(chan->context));
00639    ast_copy_string(chan->exten, old_extension, sizeof(chan->exten));
00640    chan->priority = old_priority;
00641 
00642    return RESULT_SUCCESS;
00643 }

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

00456 {
00457    struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00458    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00459    struct gosub_stack_frame *frame;
00460    struct ast_var_t *variables;
00461 
00462    if (!stack_store)
00463       return -1;
00464 
00465    oldlist = stack_store->data;
00466    AST_LIST_LOCK(oldlist);
00467    if (!(frame = AST_LIST_FIRST(oldlist))) {
00468       /* Not within a Gosub routine */
00469       AST_LIST_UNLOCK(oldlist);
00470       return -1;
00471    }
00472 
00473    AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
00474       if (!strcmp(data, ast_var_name(variables))) {
00475          const char *tmp;
00476          ast_channel_lock(chan);
00477          tmp = pbx_builtin_getvar_helper(chan, data);
00478          ast_copy_string(buf, S_OR(tmp, ""), len);
00479          ast_channel_unlock(chan);
00480          break;
00481       }
00482    }
00483    AST_LIST_UNLOCK(oldlist);
00484    return 0;
00485 }

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

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

00488 {
00489    struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00490    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00491    struct gosub_stack_frame *frame;
00492 
00493    if (!stack_store) {
00494       ast_log(LOG_ERROR, "Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var);
00495       return -1;
00496    }
00497 
00498    oldlist = stack_store->data;
00499    AST_LIST_LOCK(oldlist);
00500    frame = AST_LIST_FIRST(oldlist);
00501 
00502    if (frame)
00503       frame_set_var(chan, frame, var, value);
00504 
00505    AST_LIST_UNLOCK(oldlist);
00506 
00507    return 0;
00508 }

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

Definition at line 516 of file app_stack.c.

References AST_APP_ARG, ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_DECLARE_APP_ARGS, AST_LIST_TRAVERSE, ast_log(), AST_STANDARD_RAW_ARGS, ast_var_name(), ast_var_value(), gosub_stack_frame::entries, LOG_ERROR, name, and ast_channel::varshead.

00517 {
00518    int found = 0, n;
00519    struct ast_var_t *variables;
00520    AST_DECLARE_APP_ARGS(args,
00521       AST_APP_ARG(n);
00522       AST_APP_ARG(name);
00523    );
00524 
00525    if (!chan) {
00526       ast_log(LOG_ERROR, "LOCAL_PEEK must be called on an active channel\n");
00527       return -1;
00528    }
00529 
00530    AST_STANDARD_RAW_ARGS(args, data);
00531    n = atoi(args.n);
00532    *buf = '\0';
00533 
00534    ast_channel_lock(chan);
00535    AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
00536       if (!strcmp(args.name, ast_var_name(variables)) && ++found > n) {
00537          ast_copy_string(buf, ast_var_value(variables), len);
00538          break;
00539       }
00540    }
00541    ast_channel_unlock(chan);
00542    return 0;
00543 }

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

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

00271 {
00272    struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00273    struct gosub_stack_frame *oldframe;
00274    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00275 
00276    if (!stack_store) {
00277       ast_log(LOG_WARNING, "%s called with no gosub stack allocated.\n", app_pop);
00278       return 0;
00279    }
00280 
00281    oldlist = stack_store->data;
00282    AST_LIST_LOCK(oldlist);
00283    oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
00284    AST_LIST_UNLOCK(oldlist);
00285 
00286    if (oldframe) {
00287       gosub_release_frame(chan, oldframe);
00288    } else {
00289       ast_debug(1, "%s called with an empty gosub stack\n", app_pop);
00290    }
00291    return 0;
00292 }

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

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

00295 {
00296    struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00297    struct gosub_stack_frame *oldframe;
00298    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00299    char *retval = data;
00300    int res = 0;
00301 
00302    if (!stack_store) {
00303       ast_log(LOG_ERROR, "Return without Gosub: stack is unallocated\n");
00304       return -1;
00305    }
00306 
00307    oldlist = stack_store->data;
00308    AST_LIST_LOCK(oldlist);
00309    oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
00310    AST_LIST_UNLOCK(oldlist);
00311 
00312    if (!oldframe) {
00313       ast_log(LOG_ERROR, "Return without Gosub: stack is empty\n");
00314       return -1;
00315    } else if (oldframe->is_agi) {
00316       /* Exit from AGI */
00317       res = -1;
00318    }
00319 
00320    ast_explicit_goto(chan, oldframe->context, oldframe->extension, oldframe->priority);
00321    gosub_release_frame(chan, oldframe);
00322 
00323    /* Set a return value, if any */
00324    pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", S_OR(retval, ""));
00325    return res;
00326 }

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

Definition at line 685 of file app_stack.c.

const char* app_gosub = "Gosub" [static]

Definition at line 169 of file app_stack.c.

const char* app_gosubif = "GosubIf" [static]

Definition at line 170 of file app_stack.c.

const char* app_pop = "StackPop" [static]

Definition at line 172 of file app_stack.c.

const char* app_return = "Return" [static]

Definition at line 171 of file app_stack.c.

Definition at line 685 of file app_stack.c.

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

Definition at line 650 of file app_stack.c.

Referenced by load_module(), and unload_module().

Initial value:
 {
   .name = "LOCAL",
   .write = local_write,
   .read = local_read,
}

Definition at line 510 of file app_stack.c.

Referenced by load_module(), and unload_module().

Initial value:
 {
   .name = "LOCAL_PEEK",
   .read = peek_read,
}

Definition at line 545 of file app_stack.c.

Referenced by load_module(), and unload_module().

struct ast_datastore_info stack_info [static]
Initial value:
 {
   .type = "GOSUB",
   .destroy = gosub_free,
}

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


Generated by  doxygen 1.6.2