Sat Mar 10 01:54:38 2012

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 = "88eaa8f5c1bd988bedd71113385e0886" , .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 712 of file app_stack.c.

static void __unreg_module ( void   )  [static]

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

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

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

Definition at line 257 of file app_stack.c.

References ast_calloc, and AST_LIST_HEAD_INIT_NOLOCK.

Referenced by gosub_exec().

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

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

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

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

static void gosub_free ( void *  data  )  [static]

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

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

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

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

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

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

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

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

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

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

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

static int load_module ( void   )  [static]

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

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

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

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

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

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

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

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

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

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

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

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

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

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

static int unload_module ( void   )  [static]

Definition at line 680 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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .nonoptreq = "res_agi", } [static]

Definition at line 712 of file app_stack.c.

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

Definition at line 185 of file app_stack.c.

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

Definition at line 186 of file app_stack.c.

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

Definition at line 188 of file app_stack.c.

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

Definition at line 187 of file app_stack.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 712 of file app_stack.c.

struct agi_command gosub_agi_command [static]

Initial value:

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

Definition at line 677 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 539 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 574 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 192 of file app_stack.c.

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


Generated on Sat Mar 10 01:54:38 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7