Wed Apr 6 11:29:51 2011

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

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, const char *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, const char *data)
static int handle_gosub (struct ast_channel *chan, AGI *agi, int argc, const char *const *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, const char *data)
static int return_exec (struct ast_channel *chan, const char *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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .nonoptreq = "res_agi", }
static const char *const app_gosub = "Gosub"
static const char *const app_gosubif = "GosubIf"
static const char *const app_pop = "StackPop"
static const char *const app_return = "Return"
static struct ast_module_infoast_module_info = &__mod_info
static 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


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

static void __unreg_module ( void   )  [static]

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

00208 {
00209    struct ast_var_t *variables;
00210    int found = 0;
00211 
00212    /* Does this variable already exist? */
00213    AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
00214       if (!strcmp(var, ast_var_name(variables))) {
00215          found = 1;
00216          break;
00217       }
00218    }
00219 
00220    if (!found) {
00221       variables = ast_var_assign(var, "");
00222       AST_LIST_INSERT_HEAD(&frame->varshead, variables, entries);
00223       pbx_builtin_pushvar_helper(chan, var, value);
00224    } else {
00225       pbx_builtin_setvar_helper(chan, var, value);
00226    }
00227 
00228    manager_event(EVENT_FLAG_DIALPLAN, "VarSet",
00229       "Channel: %s\r\n"
00230       "Variable: LOCAL(%s)\r\n"
00231       "Value: %s\r\n"
00232       "Uniqueid: %s\r\n",
00233       chan->name, var, value, chan->uniqueid);
00234    return 0;
00235 }

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

Definition at line 256 of file app_stack.c.

References ast_calloc, and AST_LIST_HEAD_INIT_NOLOCK.

Referenced by gosub_exec().

00257 {
00258    struct gosub_stack_frame *new = NULL;
00259    int len_extension = strlen(extension), len_context = strlen(context);
00260 
00261    if ((new = ast_calloc(1, sizeof(*new) + 2 + len_extension + len_context))) {
00262       AST_LIST_HEAD_INIT_NOLOCK(&new->varshead);
00263       strcpy(new->extension, extension);
00264       new->context = new->extension + len_extension + 1;
00265       strcpy(new->context, context);
00266       new->priority = priority;
00267       new->arguments = arguments;
00268    }
00269    return new;
00270 }

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

Definition at line 343 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, ast_channel::caller, 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(), ast_party_caller::id, LOG_ERROR, LOG_WARNING, ast_channel::name, ast_party_id::number, gosub_stack_frame::priority, ast_channel::priority, S_COR, stack_info, ast_party_number::str, strsep(), and ast_party_number::valid.

Referenced by gosubif_exec(), and load_module().

00344 {
00345    struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00346    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00347    struct gosub_stack_frame *newframe, *lastframe;
00348    char argname[15], *tmp = ast_strdupa(data), *label, *endparen;
00349    int i, max_argc = 0;
00350    AST_DECLARE_APP_ARGS(args2,
00351       AST_APP_ARG(argval)[100];
00352    );
00353 
00354    if (ast_strlen_zero(data)) {
00355       ast_log(LOG_ERROR, "%s requires an argument: %s([[context,]exten,]priority[(arg1[,...][,argN])])\n", app_gosub, app_gosub);
00356       return -1;
00357    }
00358 
00359    if (!stack_store) {
00360       ast_debug(1, "Channel %s has no datastore, so we're allocating one.\n", chan->name);
00361       stack_store = ast_datastore_alloc(&stack_info, NULL);
00362       if (!stack_store) {
00363          ast_log(LOG_ERROR, "Unable to allocate new datastore.  Gosub will fail.\n");
00364          return -1;
00365       }
00366 
00367       oldlist = ast_calloc(1, sizeof(*oldlist));
00368       if (!oldlist) {
00369          ast_log(LOG_ERROR, "Unable to allocate datastore list head.  Gosub will fail.\n");
00370          ast_datastore_free(stack_store);
00371          return -1;
00372       }
00373 
00374       stack_store->data = oldlist;
00375       AST_LIST_HEAD_INIT(oldlist);
00376       ast_channel_datastore_add(chan, stack_store);
00377    } else {
00378       oldlist = stack_store->data;
00379    }
00380 
00381    if ((lastframe = AST_LIST_FIRST(oldlist))) {
00382       max_argc = lastframe->arguments;
00383    }
00384 
00385    /* Separate the arguments from the label */
00386    /* NOTE:  you cannot use ast_app_separate_args for this, because '(' cannot be used as a delimiter. */
00387    label = strsep(&tmp, "(");
00388    if (tmp) {
00389       endparen = strrchr(tmp, ')');
00390       if (endparen)
00391          *endparen = '\0';
00392       else
00393          ast_log(LOG_WARNING, "Ouch.  No closing paren: '%s'?\n", (char *)data);
00394       AST_STANDARD_RAW_ARGS(args2, tmp);
00395    } else
00396       args2.argc = 0;
00397 
00398    /* Mask out previous arguments in this invocation */
00399    if (args2.argc > max_argc) {
00400       max_argc = args2.argc;
00401    }
00402 
00403    /* Create the return address, but don't save it until we know that the Gosub destination exists */
00404    newframe = gosub_allocate_frame(chan->context, chan->exten, chan->priority + 1, max_argc);
00405 
00406    if (!newframe) {
00407       return -1;
00408    }
00409 
00410    if (ast_parseable_goto(chan, label)) {
00411       ast_log(LOG_ERROR, "Gosub address is invalid: '%s'\n", (char *)data);
00412       ast_free(newframe);
00413       return -1;
00414    }
00415 
00416    if (!ast_exists_extension(chan, chan->context, chan->exten,
00417       ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP) ? chan->priority + 1 : chan->priority,
00418       S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
00419       ast_log(LOG_ERROR, "Attempt to reach a non-existent destination for gosub: (Context:%s, Extension:%s, Priority:%d)\n",
00420             chan->context, chan->exten, ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP) ? chan->priority + 1 : chan->priority);
00421       ast_copy_string(chan->context, newframe->context, sizeof(chan->context));
00422       ast_copy_string(chan->exten, newframe->extension, sizeof(chan->exten));
00423       chan->priority = newframe->priority;
00424       ast_free(newframe);
00425       return -1;
00426    }
00427 
00428    /* Now that we know for certain that we're going to a new location, set our arguments */
00429    for (i = 0; i < max_argc; i++) {
00430       snprintf(argname, sizeof(argname), "ARG%d", i + 1);
00431       frame_set_var(chan, newframe, argname, i < args2.argc ? args2.argval[i] : "");
00432       ast_debug(1, "Setting '%s' to '%s'\n", argname, i < args2.argc ? args2.argval[i] : "");
00433    }
00434    snprintf(argname, sizeof(argname), "%d", args2.argc);
00435    frame_set_var(chan, newframe, "ARGC", argname);
00436 
00437    /* And finally, save our return address */
00438    oldlist = stack_store->data;
00439    AST_LIST_LOCK(oldlist);
00440    AST_LIST_INSERT_HEAD(oldlist, newframe, entries);
00441    AST_LIST_UNLOCK(oldlist);
00442 
00443    return 0;
00444 }

static void gosub_free ( void *  data  )  [static]

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

00273 {
00274    AST_LIST_HEAD(, gosub_stack_frame) *oldlist = data;
00275    struct gosub_stack_frame *oldframe;
00276    AST_LIST_LOCK(oldlist);
00277    while ((oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries))) {
00278       gosub_release_frame(NULL, oldframe);
00279    }
00280    AST_LIST_UNLOCK(oldlist);
00281    AST_LIST_HEAD_DESTROY(oldlist);
00282    ast_free(oldlist);
00283 }

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

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

00238 {
00239    struct ast_var_t *vardata;
00240 
00241    /* If chan is not defined, then we're calling it as part of gosub_free,
00242     * and the channel variables will be deallocated anyway.  Otherwise, we're
00243     * just releasing a single frame, so we need to clean up the arguments for
00244     * that frame, so that we re-expose the variables from the previous frame
00245     * that were hidden by this one.
00246     */
00247    while ((vardata = AST_LIST_REMOVE_HEAD(&frame->varshead, entries))) {
00248       if (chan)
00249          pbx_builtin_setvar_helper(chan, ast_var_name(vardata), NULL);  
00250       ast_var_delete(vardata);
00251    }
00252 
00253    ast_free(frame);
00254 }

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

Definition at line 446 of file app_stack.c.

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

00447 {
00448    char *args;
00449    int res=0;
00450    AST_DECLARE_APP_ARGS(cond,
00451       AST_APP_ARG(ition);
00452       AST_APP_ARG(labels);
00453    );
00454    AST_DECLARE_APP_ARGS(label,
00455       AST_APP_ARG(iftrue);
00456       AST_APP_ARG(iffalse);
00457    );
00458 
00459    if (ast_strlen_zero(data)) {
00460       ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
00461       return 0;
00462    }
00463 
00464    args = ast_strdupa(data);
00465    AST_NONSTANDARD_RAW_ARGS(cond, args, '?');
00466    if (cond.argc != 2) {
00467       ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
00468       return 0;
00469    }
00470 
00471    AST_NONSTANDARD_RAW_ARGS(label, cond.labels, ':');
00472 
00473    if (pbx_checkcondition(cond.ition)) {
00474       if (!ast_strlen_zero(label.iftrue))
00475          res = gosub_exec(chan, label.iftrue);
00476    } else if (!ast_strlen_zero(label.iffalse)) {
00477       res = gosub_exec(chan, label.iffalse);
00478    }
00479 
00480    return res;
00481 }

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

Definition at line 578 of file app_stack.c.

References args, 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::caller, ast_channel::context, ast_datastore::data, errno, ast_channel::exten, agi_state::fd, ast_party_caller::id, gosub_stack_frame::is_agi, LOG_ERROR, LOG_WARNING, ast_party_id::number, ast_channel::pbx, pbx_exec(), pbx_findapp(), ast_channel::priority, gosub_stack_frame::priority, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, S_COR, stack_info, ast_party_number::str, and ast_party_number::valid.

00579 {
00580    int old_priority, priority;
00581    char old_context[AST_MAX_CONTEXT], old_extension[AST_MAX_EXTENSION];
00582    struct ast_app *theapp;
00583    char *gosub_args;
00584 
00585    if (argc < 4 || argc > 5) {
00586       return RESULT_SHOWUSAGE;
00587    }
00588 
00589    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] : "");
00590 
00591    if (sscanf(argv[3], "%30d", &priority) != 1 || priority < 1) {
00592       /* Lookup the priority label */
00593       priority = ast_findlabel_extension(chan, argv[1], argv[2], argv[3],
00594          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL));
00595       if (priority < 0) {
00596          ast_log(LOG_ERROR, "Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]);
00597          ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
00598          return RESULT_FAILURE;
00599       }
00600    } else if (!ast_exists_extension(chan, argv[1], argv[2], priority,
00601       S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
00602       ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
00603       return RESULT_FAILURE;
00604    }
00605 
00606    /* Save previous location, since we're going to change it */
00607    ast_copy_string(old_context, chan->context, sizeof(old_context));
00608    ast_copy_string(old_extension, chan->exten, sizeof(old_extension));
00609    old_priority = chan->priority;
00610 
00611    if (!(theapp = pbx_findapp("Gosub"))) {
00612       ast_log(LOG_ERROR, "Gosub() cannot be found in the list of loaded applications\n");
00613       ast_agi_send(agi->fd, chan, "503 result=-2 Gosub is not loaded\n");
00614       return RESULT_FAILURE;
00615    }
00616 
00617    /* Apparently, if you run ast_pbx_run on a channel that already has a pbx
00618     * structure, you need to add 1 to the priority to get it to go to the
00619     * right place.  But if it doesn't have a pbx structure, then leaving off
00620     * the 1 is the right thing to do.  See how this code differs when we
00621     * call a Gosub for the CALLEE channel in Dial or Queue.
00622     */
00623    if (argc == 5) {
00624       if (asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority + (chan->pbx ? 1 : 0), argv[4]) < 0) {
00625          ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00626          gosub_args = NULL;
00627       }
00628    } else {
00629       if (asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority + (chan->pbx ? 1 : 0)) < 0) {
00630          ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00631          gosub_args = NULL;
00632       }
00633    }
00634 
00635    if (gosub_args) {
00636       int res;
00637 
00638       ast_debug(1, "Trying gosub with arguments '%s'\n", gosub_args);
00639 
00640       if ((res = pbx_exec(chan, theapp, gosub_args)) == 0) {
00641          struct ast_pbx *pbx = chan->pbx;
00642          struct ast_pbx_args args;
00643          struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00644          AST_LIST_HEAD(, gosub_stack_frame) *oldlist = stack_store->data;
00645          struct gosub_stack_frame *cur = AST_LIST_FIRST(oldlist);
00646          cur->is_agi = 1;
00647 
00648          memset(&args, 0, sizeof(args));
00649          args.no_hangup_chan = 1;
00650          /* Suppress warning about PBX already existing */
00651          chan->pbx = NULL;
00652          ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n");
00653          ast_pbx_run_args(chan, &args);
00654          ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete\n");
00655          if (chan->pbx) {
00656             ast_free(chan->pbx);
00657          }
00658          chan->pbx = pbx;
00659       } else {
00660          ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res);
00661       }
00662       ast_free(gosub_args);
00663    } else {
00664       ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n");
00665       return RESULT_FAILURE;
00666    }
00667 
00668    /* Restore previous location */
00669    ast_copy_string(chan->context, old_context, sizeof(chan->context));
00670    ast_copy_string(chan->exten, old_extension, sizeof(chan->exten));
00671    chan->priority = old_priority;
00672 
00673    return RESULT_SUCCESS;
00674 }

static int load_module ( void   )  [static]

Definition at line 693 of file app_stack.c.

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

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

Definition at line 483 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, stack_info, and gosub_stack_frame::varshead.

00484 {
00485    struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00486    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00487    struct gosub_stack_frame *frame;
00488    struct ast_var_t *variables;
00489 
00490    if (!stack_store)
00491       return -1;
00492 
00493    oldlist = stack_store->data;
00494    AST_LIST_LOCK(oldlist);
00495    if (!(frame = AST_LIST_FIRST(oldlist))) {
00496       /* Not within a Gosub routine */
00497       AST_LIST_UNLOCK(oldlist);
00498       return -1;
00499    }
00500 
00501    AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
00502       if (!strcmp(data, ast_var_name(variables))) {
00503          const char *tmp;
00504          ast_channel_lock(chan);
00505          tmp = pbx_builtin_getvar_helper(chan, data);
00506          ast_copy_string(buf, S_OR(tmp, ""), len);
00507          ast_channel_unlock(chan);
00508          break;
00509       }
00510    }
00511    AST_LIST_UNLOCK(oldlist);
00512    return 0;
00513 }

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

Definition at line 515 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(), LOG_ERROR, and stack_info.

00516 {
00517    struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00518    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00519    struct gosub_stack_frame *frame;
00520 
00521    if (!stack_store) {
00522       ast_log(LOG_ERROR, "Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var);
00523       return -1;
00524    }
00525 
00526    oldlist = stack_store->data;
00527    AST_LIST_LOCK(oldlist);
00528    frame = AST_LIST_FIRST(oldlist);
00529 
00530    if (frame)
00531       frame_set_var(chan, frame, var, value);
00532 
00533    AST_LIST_UNLOCK(oldlist);
00534 
00535    return 0;
00536 }

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

Definition at line 544 of file app_stack.c.

References args, 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.

00545 {
00546    int found = 0, n;
00547    struct ast_var_t *variables;
00548    AST_DECLARE_APP_ARGS(args,
00549       AST_APP_ARG(n);
00550       AST_APP_ARG(name);
00551    );
00552 
00553    if (!chan) {
00554       ast_log(LOG_ERROR, "LOCAL_PEEK must be called on an active channel\n");
00555       return -1;
00556    }
00557 
00558    AST_STANDARD_RAW_ARGS(args, data);
00559    n = atoi(args.n);
00560    *buf = '\0';
00561 
00562    ast_channel_lock(chan);
00563    AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
00564       if (!strcmp(args.name, ast_var_name(variables)) && ++found > n) {
00565          ast_copy_string(buf, ast_var_value(variables), len);
00566          break;
00567       }
00568    }
00569    ast_channel_unlock(chan);
00570    return 0;
00571 }

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

Definition at line 285 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(), LOG_WARNING, and stack_info.

Referenced by load_module().

00286 {
00287    struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00288    struct gosub_stack_frame *oldframe;
00289    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00290 
00291    if (!stack_store) {
00292       ast_log(LOG_WARNING, "%s called with no gosub stack allocated.\n", app_pop);
00293       return 0;
00294    }
00295 
00296    oldlist = stack_store->data;
00297    AST_LIST_LOCK(oldlist);
00298    oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
00299    AST_LIST_UNLOCK(oldlist);
00300 
00301    if (oldframe) {
00302       gosub_release_frame(chan, oldframe);
00303    } else {
00304       ast_debug(1, "%s called with an empty gosub stack\n", app_pop);
00305    }
00306    return 0;
00307 }

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

Definition at line 309 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, S_OR, and stack_info.

Referenced by load_module().

00310 {
00311    struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00312    struct gosub_stack_frame *oldframe;
00313    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00314    const char *retval = data;
00315    int res = 0;
00316 
00317    if (!stack_store) {
00318       ast_log(LOG_ERROR, "Return without Gosub: stack is unallocated\n");
00319       return -1;
00320    }
00321 
00322    oldlist = stack_store->data;
00323    AST_LIST_LOCK(oldlist);
00324    oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
00325    AST_LIST_UNLOCK(oldlist);
00326 
00327    if (!oldframe) {
00328       ast_log(LOG_ERROR, "Return without Gosub: stack is empty\n");
00329       return -1;
00330    } else if (oldframe->is_agi) {
00331       /* Exit from AGI */
00332       res = -1;
00333    }
00334 
00335    ast_explicit_goto(chan, oldframe->context, oldframe->extension, oldframe->priority);
00336    gosub_release_frame(chan, oldframe);
00337 
00338    /* Set a return value, if any */
00339    pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", S_OR(retval, ""));
00340    return res;
00341 }

static int unload_module ( void   )  [static]

Definition at line 679 of file app_stack.c.

References ast_agi_unregister(), ast_custom_function_unregister(), ast_unregister_application(), gosub_agi_command, local_function, and peek_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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .nonoptreq = "res_agi", } [static]

Definition at line 711 of file app_stack.c.

const char* const app_gosub = "Gosub" [static]

Definition at line 184 of file app_stack.c.

const char* const app_gosubif = "GosubIf" [static]

Definition at line 185 of file app_stack.c.

const char* const app_pop = "StackPop" [static]

Definition at line 187 of file app_stack.c.

const char* const app_return = "Return" [static]

Definition at line 186 of file app_stack.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 711 of file app_stack.c.

struct agi_command gosub_agi_command [static]

Initial value:

   { { "gosub", NULL }, handle_gosub, NULL, NULL, 0 }

Definition at line 676 of file app_stack.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function local_function [static]

Initial value:

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

Definition at line 538 of file app_stack.c.

Referenced by load_module(), and unload_module().

struct ast_custom_function peek_function [static]

Initial value:

 {
   .name = "LOCAL_PEEK",
   .read = peek_read,
}

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

Referenced by gosub_exec(), handle_gosub(), local_read(), local_write(), pop_exec(), and return_exec().


Generated on Wed Apr 6 11:29:51 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7