Thu Apr 3 08:20:50 2014

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

 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT|AST_MODFLAG_LOAD_ORDER,"Dialplan subroutines (Gosub, Return, etc)",.load=load_module,.unload=unload_module,.load_pri=AST_MODPRI_APP_DEPEND,.nonoptreq="res_agi",)
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 stackpeek_read (struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
static int unload_module (void)

Variables

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 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 struct ast_custom_function stackpeek_function

Detailed Description

Stack applications Gosub, Return, etc.

Author:
Tilghman Lesher <app_stack_v003@the-tilghman.com>

Definition in file app_stack.c.


Function Documentation

AST_MODULE_INFO ( ASTERISK_GPL_KEY  ,
AST_MODFLAG_DEFAULT|  AST_MODFLAG_LOAD_ORDER,
"Dialplan subroutines (Gosub, Return, etc)"  ,
load = load_module,
unload = unload_module,
load_pri = AST_MODPRI_APP_DEPEND,
nonoptreq = "res_agi" 
)
static int frame_set_var ( struct ast_channel chan,
struct gosub_stack_frame frame,
const char *  var,
const char *  value 
) [static]

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

00232 {
00233    struct ast_var_t *variables;
00234    int found = 0;
00235 
00236    /* Does this variable already exist? */
00237    AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
00238       if (!strcmp(var, ast_var_name(variables))) {
00239          found = 1;
00240          break;
00241       }
00242    }
00243 
00244    if (!found) {
00245       if ((variables = ast_var_assign(var, ""))) {
00246          AST_LIST_INSERT_HEAD(&frame->varshead, variables, entries);
00247       }
00248       pbx_builtin_pushvar_helper(chan, var, value);
00249    } else {
00250       pbx_builtin_setvar_helper(chan, var, value);
00251    }
00252 
00253    manager_event(EVENT_FLAG_DIALPLAN, "VarSet",
00254       "Channel: %s\r\n"
00255       "Variable: LOCAL(%s)\r\n"
00256       "Value: %s\r\n"
00257       "Uniqueid: %s\r\n",
00258       chan->name, var, value, chan->uniqueid);
00259    return 0;
00260 }

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

Definition at line 281 of file app_stack.c.

References ast_calloc, and AST_LIST_HEAD_INIT_NOLOCK.

Referenced by gosub_exec().

00282 {
00283    struct gosub_stack_frame *new = NULL;
00284    int len_extension = strlen(extension), len_context = strlen(context);
00285 
00286    if ((new = ast_calloc(1, sizeof(*new) + 2 + len_extension + len_context))) {
00287       AST_LIST_HEAD_INIT_NOLOCK(&new->varshead);
00288       strcpy(new->extension, extension);
00289       new->context = new->extension + len_extension + 1;
00290       strcpy(new->context, context);
00291       new->priority = priority;
00292       new->arguments = arguments;
00293    }
00294    return new;
00295 }

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

Definition at line 375 of file app_stack.c.

References AST_APP_ARG, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_datastore_alloc, ast_datastore_free(), ast_debug, AST_DECLARE_APP_ARGS, ast_exists_extension(), AST_FLAG_IN_AUTOLOOP, 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, ast_channel::context, ast_datastore::data, ast_channel::exten, frame_set_var(), gosub_allocate_frame(), ast_party_caller::id, LOG_ERROR, LOG_WARNING, ast_party_id::number, orig_exten(), parse(), ast_channel::priority, S_COR, ast_party_number::str, and ast_party_number::valid.

Referenced by gosubif_exec(), and load_module().

00376 {
00377    struct ast_datastore *stack_store;
00378    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00379    struct gosub_stack_frame *newframe;
00380    struct gosub_stack_frame *lastframe;
00381    char argname[15];
00382    char *parse;
00383    char *label;
00384    char *caller_id;
00385    char *orig_context;
00386    char *orig_exten;
00387    char *dest_context;
00388    char *dest_exten;
00389    int orig_priority;
00390    int dest_priority;
00391    int i;
00392    int max_argc = 0;
00393    AST_DECLARE_APP_ARGS(args2,
00394       AST_APP_ARG(argval)[100];
00395    );
00396 
00397    if (ast_strlen_zero(data)) {
00398       ast_log(LOG_ERROR, "%s requires an argument: %s([[context,]exten,]priority[(arg1[,...][,argN])])\n", app_gosub, app_gosub);
00399       return -1;
00400    }
00401 
00402    /*
00403     * Separate the arguments from the label
00404     *
00405     * NOTE:  You cannot use ast_app_separate_args for this, because
00406     * '(' cannot be used as a delimiter.
00407     */
00408    parse = ast_strdupa(data);
00409    label = strsep(&parse, "(");
00410    if (parse) {
00411       char *endparen;
00412 
00413       endparen = strrchr(parse, ')');
00414       if (endparen) {
00415          *endparen = '\0';
00416       } else {
00417          ast_log(LOG_WARNING, "Ouch.  No closing paren: '%s'?\n", data);
00418       }
00419       AST_STANDARD_RAW_ARGS(args2, parse);
00420    } else {
00421       args2.argc = 0;
00422    }
00423 
00424    ast_channel_lock(chan);
00425    orig_context = ast_strdupa(chan->context);
00426    orig_exten = ast_strdupa(chan->exten);
00427    orig_priority = chan->priority;
00428    ast_channel_unlock(chan);
00429 
00430    if (ast_parseable_goto(chan, label)) {
00431       ast_log(LOG_ERROR, "%s address is invalid: '%s'\n", app_gosub, data);
00432       goto error_exit;
00433    }
00434 
00435    ast_channel_lock(chan);
00436    dest_context = ast_strdupa(chan->context);
00437    dest_exten = ast_strdupa(chan->exten);
00438    dest_priority = chan->priority;
00439    if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP)) {
00440       ++dest_priority;
00441    }
00442    caller_id = S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL);
00443    if (caller_id) {
00444       caller_id = ast_strdupa(caller_id);
00445    }
00446    ast_channel_unlock(chan);
00447 
00448    if (!ast_exists_extension(chan, dest_context, dest_exten, dest_priority, caller_id)) {
00449       ast_log(LOG_ERROR, "Attempt to reach a non-existent destination for %s: (Context:%s, Extension:%s, Priority:%d)\n",
00450          app_gosub, dest_context, dest_exten, dest_priority);
00451       goto error_exit;
00452    }
00453 
00454    /* Now we know that we're going to a new location */
00455 
00456    ast_channel_lock(chan);
00457 
00458    /* Find stack datastore return list. */
00459    if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00460       ast_debug(1, "Channel %s has no datastore, so we're allocating one.\n",
00461          chan->name);
00462       stack_store = ast_datastore_alloc(&stack_info, NULL);
00463       if (!stack_store) {
00464          ast_log(LOG_ERROR, "Unable to allocate new datastore.  %s failed.\n",
00465             app_gosub);
00466          goto error_exit_locked;
00467       }
00468 
00469       oldlist = ast_calloc(1, sizeof(*oldlist));
00470       if (!oldlist) {
00471          ast_log(LOG_ERROR, "Unable to allocate datastore list head.  %s failed.\n",
00472             app_gosub);
00473          ast_datastore_free(stack_store);
00474          goto error_exit_locked;
00475       }
00476       AST_LIST_HEAD_INIT(oldlist);
00477 
00478       stack_store->data = oldlist;
00479       ast_channel_datastore_add(chan, stack_store);
00480    } else {
00481       oldlist = stack_store->data;
00482    }
00483 
00484    if ((lastframe = AST_LIST_FIRST(oldlist))) {
00485       max_argc = lastframe->arguments;
00486    }
00487 
00488    /* Mask out previous Gosub arguments in this invocation */
00489    if (args2.argc > max_argc) {
00490       max_argc = args2.argc;
00491    }
00492 
00493    /* Create the return address */
00494    newframe = gosub_allocate_frame(orig_context, orig_exten, orig_priority + 1, max_argc);
00495    if (!newframe) {
00496       goto error_exit_locked;
00497    }
00498 
00499    /* Set our arguments */
00500    for (i = 0; i < max_argc; i++) {
00501       snprintf(argname, sizeof(argname), "ARG%d", i + 1);
00502       frame_set_var(chan, newframe, argname, i < args2.argc ? args2.argval[i] : "");
00503       ast_debug(1, "Setting '%s' to '%s'\n", argname, i < args2.argc ? args2.argval[i] : "");
00504    }
00505    snprintf(argname, sizeof(argname), "%d", args2.argc);
00506    frame_set_var(chan, newframe, "ARGC", argname);
00507 
00508    /* And finally, save our return address */
00509    AST_LIST_LOCK(oldlist);
00510    AST_LIST_INSERT_HEAD(oldlist, newframe, entries);
00511    AST_LIST_UNLOCK(oldlist);
00512    ast_channel_unlock(chan);
00513 
00514    return 0;
00515 
00516 error_exit:
00517    ast_channel_lock(chan);
00518 
00519 error_exit_locked:
00520    /* Restore the original dialplan location. */
00521    ast_copy_string(chan->context, orig_context, sizeof(chan->context));
00522    ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
00523    chan->priority = orig_priority;
00524    ast_channel_unlock(chan);
00525    return -1;
00526 }

static void gosub_free ( void *  data  )  [static]

Definition at line 297 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, and gosub_release_frame().

00298 {
00299    AST_LIST_HEAD(, gosub_stack_frame) *oldlist = data;
00300    struct gosub_stack_frame *oldframe;
00301    AST_LIST_LOCK(oldlist);
00302    while ((oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries))) {
00303       gosub_release_frame(NULL, oldframe);
00304    }
00305    AST_LIST_UNLOCK(oldlist);
00306    AST_LIST_HEAD_DESTROY(oldlist);
00307    ast_free(oldlist);
00308 }

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

Definition at line 262 of file app_stack.c.

References ast_free, AST_LIST_REMOVE_HEAD, ast_var_delete(), ast_var_name(), and pbx_builtin_setvar_helper().

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

00263 {
00264    struct ast_var_t *vardata;
00265 
00266    /* If chan is not defined, then we're calling it as part of gosub_free,
00267     * and the channel variables will be deallocated anyway.  Otherwise, we're
00268     * just releasing a single frame, so we need to clean up the arguments for
00269     * that frame, so that we re-expose the variables from the previous frame
00270     * that were hidden by this one.
00271     */
00272    while ((vardata = AST_LIST_REMOVE_HEAD(&frame->varshead, entries))) {
00273       if (chan)
00274          pbx_builtin_setvar_helper(chan, ast_var_name(vardata), NULL);  
00275       ast_var_delete(vardata);
00276    }
00277 
00278    ast_free(frame);
00279 }

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

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

00529 {
00530    char *args;
00531    int res=0;
00532    AST_DECLARE_APP_ARGS(cond,
00533       AST_APP_ARG(ition);
00534       AST_APP_ARG(labels);
00535    );
00536    AST_DECLARE_APP_ARGS(label,
00537       AST_APP_ARG(iftrue);
00538       AST_APP_ARG(iffalse);
00539    );
00540 
00541    if (ast_strlen_zero(data)) {
00542       ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
00543       return 0;
00544    }
00545 
00546    args = ast_strdupa(data);
00547    AST_NONSTANDARD_RAW_ARGS(cond, args, '?');
00548    if (cond.argc != 2) {
00549       ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
00550       return 0;
00551    }
00552 
00553    AST_NONSTANDARD_RAW_ARGS(label, cond.labels, ':');
00554 
00555    if (pbx_checkcondition(cond.ition)) {
00556       if (!ast_strlen_zero(label.iftrue))
00557          res = gosub_exec(chan, label.iftrue);
00558    } else if (!ast_strlen_zero(label.iffalse)) {
00559       res = gosub_exec(chan, label.iffalse);
00560    }
00561 
00562    return res;
00563 }

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

Definition at line 750 of file app_stack.c.

References ast_agi_send(), ast_asprintf, 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, ast_channel::exten, agi_state::fd, ast_party_caller::id, LOG_ERROR, LOG_WARNING, ast_pbx_args::no_hangup_chan, ast_party_id::number, ast_channel::pbx, pbx_exec(), pbx_findapp(), ast_channel::priority, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, S_COR, ast_party_number::str, and ast_party_number::valid.

00751 {
00752    int old_priority, priority;
00753    char old_context[AST_MAX_CONTEXT], old_extension[AST_MAX_EXTENSION];
00754    struct ast_app *theapp;
00755    char *gosub_args;
00756 
00757    if (argc < 4 || argc > 5) {
00758       return RESULT_SHOWUSAGE;
00759    }
00760 
00761    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] : "");
00762 
00763    if (sscanf(argv[3], "%30d", &priority) != 1 || priority < 1) {
00764       /* Lookup the priority label */
00765       priority = ast_findlabel_extension(chan, argv[1], argv[2], argv[3],
00766          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL));
00767       if (priority < 0) {
00768          ast_log(LOG_ERROR, "Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]);
00769          ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
00770          return RESULT_FAILURE;
00771       }
00772    } else if (!ast_exists_extension(chan, argv[1], argv[2], priority,
00773       S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
00774       ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
00775       return RESULT_FAILURE;
00776    }
00777 
00778    /* Save previous location, since we're going to change it */
00779    ast_copy_string(old_context, chan->context, sizeof(old_context));
00780    ast_copy_string(old_extension, chan->exten, sizeof(old_extension));
00781    old_priority = chan->priority;
00782 
00783    if (!(theapp = pbx_findapp("Gosub"))) {
00784       ast_log(LOG_ERROR, "Gosub() cannot be found in the list of loaded applications\n");
00785       ast_agi_send(agi->fd, chan, "503 result=-2 Gosub is not loaded\n");
00786       return RESULT_FAILURE;
00787    }
00788 
00789    /* Apparently, if you run ast_pbx_run on a channel that already has a pbx
00790     * structure, you need to add 1 to the priority to get it to go to the
00791     * right place.  But if it doesn't have a pbx structure, then leaving off
00792     * the 1 is the right thing to do.  See how this code differs when we
00793     * call a Gosub for the CALLEE channel in Dial or Queue.
00794     */
00795    if (argc == 5) {
00796       if (ast_asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority + (chan->pbx ? 1 : 0), argv[4]) < 0) {
00797          gosub_args = NULL;
00798       }
00799    } else {
00800       if (ast_asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority + (chan->pbx ? 1 : 0)) < 0) {
00801          gosub_args = NULL;
00802       }
00803    }
00804 
00805    if (gosub_args) {
00806       int res;
00807 
00808       ast_debug(1, "Trying gosub with arguments '%s'\n", gosub_args);
00809 
00810       if ((res = pbx_exec(chan, theapp, gosub_args)) == 0) {
00811          struct ast_pbx *pbx = chan->pbx;
00812          struct ast_pbx_args args;
00813          struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00814          AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00815          struct gosub_stack_frame *cur;
00816          if (!stack_store) {
00817             ast_log(LOG_WARNING, "No GoSub stack remaining after AGI GoSub execution.\n");
00818             ast_free(gosub_args);
00819             return RESULT_FAILURE;
00820          }
00821          oldlist = stack_store->data;
00822          cur = AST_LIST_FIRST(oldlist);
00823          cur->is_agi = 1;
00824 
00825          memset(&args, 0, sizeof(args));
00826          args.no_hangup_chan = 1;
00827          /* Suppress warning about PBX already existing */
00828          chan->pbx = NULL;
00829          ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n");
00830          ast_pbx_run_args(chan, &args);
00831          ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete\n");
00832          if (chan->pbx) {
00833             ast_free(chan->pbx);
00834          }
00835          chan->pbx = pbx;
00836       } else {
00837          ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res);
00838       }
00839       ast_free(gosub_args);
00840    } else {
00841       ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n");
00842       return RESULT_FAILURE;
00843    }
00844 
00845    /* Restore previous location */
00846    ast_copy_string(chan->context, old_context, sizeof(chan->context));
00847    ast_copy_string(chan->exten, old_extension, sizeof(chan->exten));
00848    chan->priority = old_priority;
00849 
00850    return RESULT_SUCCESS;
00851 }

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 565 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, pbx_builtin_getvar_helper(), and S_OR.

00566 {
00567    struct ast_datastore *stack_store;
00568    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00569    struct gosub_stack_frame *frame;
00570    struct ast_var_t *variables;
00571 
00572    ast_channel_lock(chan);
00573    if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00574       ast_channel_unlock(chan);
00575       return -1;
00576    }
00577 
00578    oldlist = stack_store->data;
00579    AST_LIST_LOCK(oldlist);
00580    if (!(frame = AST_LIST_FIRST(oldlist))) {
00581       /* Not within a Gosub routine */
00582       AST_LIST_UNLOCK(oldlist);
00583       ast_channel_unlock(chan);
00584       return -1;
00585    }
00586 
00587    AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
00588       if (!strcmp(data, ast_var_name(variables))) {
00589          const char *tmp;
00590          tmp = pbx_builtin_getvar_helper(chan, data);
00591          ast_copy_string(buf, S_OR(tmp, ""), len);
00592          break;
00593       }
00594    }
00595    AST_LIST_UNLOCK(oldlist);
00596    ast_channel_unlock(chan);
00597    return 0;
00598 }

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

Definition at line 600 of file app_stack.c.

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

00601 {
00602    struct ast_datastore *stack_store;
00603    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00604    struct gosub_stack_frame *frame;
00605 
00606    ast_channel_lock(chan);
00607    if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00608       ast_log(LOG_ERROR, "Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var);
00609       ast_channel_unlock(chan);
00610       return -1;
00611    }
00612 
00613    oldlist = stack_store->data;
00614    AST_LIST_LOCK(oldlist);
00615    frame = AST_LIST_FIRST(oldlist);
00616 
00617    if (frame) {
00618       frame_set_var(chan, frame, var, value);
00619    }
00620 
00621    AST_LIST_UNLOCK(oldlist);
00622    ast_channel_unlock(chan);
00623 
00624    return 0;
00625 }

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

Definition at line 633 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(), LOG_ERROR, name, and ast_channel::varshead.

00634 {
00635    int found = 0, n;
00636    struct ast_var_t *variables;
00637    AST_DECLARE_APP_ARGS(args,
00638       AST_APP_ARG(n);
00639       AST_APP_ARG(name);
00640    );
00641 
00642    if (!chan) {
00643       ast_log(LOG_ERROR, "LOCAL_PEEK must be called on an active channel\n");
00644       return -1;
00645    }
00646 
00647    AST_STANDARD_RAW_ARGS(args, data);
00648    n = atoi(args.n);
00649    *buf = '\0';
00650 
00651    ast_channel_lock(chan);
00652    AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
00653       if (!strcmp(args.name, ast_var_name(variables)) && ++found > n) {
00654          ast_copy_string(buf, ast_var_value(variables), len);
00655          break;
00656       }
00657    }
00658    ast_channel_unlock(chan);
00659    return 0;
00660 }

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

Definition at line 310 of file app_stack.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_debug, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log(), ast_datastore::data, gosub_release_frame(), and LOG_WARNING.

Referenced by load_module().

00311 {
00312    struct ast_datastore *stack_store;
00313    struct gosub_stack_frame *oldframe;
00314    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00315 
00316    ast_channel_lock(chan);
00317    if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00318       ast_log(LOG_WARNING, "%s called with no gosub stack allocated.\n", app_pop);
00319       ast_channel_unlock(chan);
00320       return 0;
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       gosub_release_frame(chan, oldframe);
00330    } else {
00331       ast_debug(1, "%s called with an empty gosub stack\n", app_pop);
00332    }
00333    ast_channel_unlock(chan);
00334    return 0;
00335 }

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

Definition at line 337 of file app_stack.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_explicit_goto(), AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log(), ast_datastore::data, gosub_release_frame(), LOG_ERROR, pbx_builtin_setvar_helper(), and S_OR.

Referenced by load_module().

00338 {
00339    struct ast_datastore *stack_store;
00340    struct gosub_stack_frame *oldframe;
00341    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00342    const char *retval = data;
00343    int res = 0;
00344 
00345    ast_channel_lock(chan);
00346    if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00347       ast_log(LOG_ERROR, "Return without Gosub: stack is unallocated\n");
00348       ast_channel_unlock(chan);
00349       return -1;
00350    }
00351 
00352    oldlist = stack_store->data;
00353    AST_LIST_LOCK(oldlist);
00354    oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
00355    AST_LIST_UNLOCK(oldlist);
00356 
00357    if (!oldframe) {
00358       ast_log(LOG_ERROR, "Return without Gosub: stack is empty\n");
00359       ast_channel_unlock(chan);
00360       return -1;
00361    } else if (oldframe->is_agi) {
00362       /* Exit from AGI */
00363       res = -1;
00364    }
00365 
00366    ast_explicit_goto(chan, oldframe->context, oldframe->extension, oldframe->priority);
00367    gosub_release_frame(chan, oldframe);
00368 
00369    /* Set a return value, if any */
00370    pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", S_OR(retval, ""));
00371    ast_channel_unlock(chan);
00372    return res;
00373 }

static int stackpeek_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
struct ast_str **  str,
ssize_t  len 
) [static]

Definition at line 667 of file app_stack.c.

References args, AST_APP_ARG, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, AST_DECLARE_APP_ARGS, AST_LIST_HEAD, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_skip_blanks(), AST_STANDARD_APP_ARGS, ast_str_set(), ast_strdupa, ast_true(), ast_datastore::data, and LOG_ERROR.

00668 {
00669    struct ast_datastore *stack_store;
00670    AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00671    struct gosub_stack_frame *frame;
00672    int n;
00673    AST_DECLARE_APP_ARGS(args,
00674       AST_APP_ARG(n);
00675       AST_APP_ARG(which);
00676       AST_APP_ARG(suppress);
00677    );
00678 
00679    if (!chan) {
00680       ast_log(LOG_ERROR, "STACK_PEEK must be called on an active channel\n");
00681       return -1;
00682    }
00683 
00684    data = ast_strdupa(data);
00685    AST_STANDARD_APP_ARGS(args, data);
00686 
00687    n = atoi(args.n);
00688    if (n <= 0) {
00689       ast_log(LOG_ERROR, "STACK_PEEK must be called with a positive peek value\n");
00690       return -1;
00691    }
00692 
00693    ast_channel_lock(chan);
00694    if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00695       if (!ast_true(args.suppress)) {
00696          ast_log(LOG_ERROR, "STACK_PEEK called on a channel without a gosub stack\n");
00697       }
00698       ast_channel_unlock(chan);
00699       return -1;
00700    }
00701 
00702    oldlist = stack_store->data;
00703 
00704    AST_LIST_LOCK(oldlist);
00705    AST_LIST_TRAVERSE(oldlist, frame, entries) {
00706       if (--n == 0) {
00707          break;
00708       }
00709    }
00710 
00711    if (!frame) {
00712       /* Too deep */
00713       if (!ast_true(args.suppress)) {
00714          ast_log(LOG_ERROR, "Stack peek of '%s' is more stack frames than I have\n", args.n);
00715       }
00716       ast_channel_unlock(chan);
00717       return -1;
00718    }
00719 
00720    args.which = ast_skip_blanks(args.which);
00721 
00722    switch (args.which[0]) {
00723    case 'l': /* label */
00724       ast_str_set(str, len, "%s,%s,%d", frame->context, frame->extension, frame->priority - 1);
00725       break;
00726    case 'c': /* context */
00727       ast_str_set(str, len, "%s", frame->context);
00728       break;
00729    case 'e': /* extension */
00730       ast_str_set(str, len, "%s", frame->extension);
00731       break;
00732    case 'p': /* priority */
00733       ast_str_set(str, len, "%d", frame->priority - 1);
00734       break;
00735    default:
00736       ast_log(LOG_ERROR, "Unknown argument '%s' to STACK_PEEK\n", args.which);
00737    }
00738 
00739    AST_LIST_UNLOCK(oldlist);
00740    ast_channel_unlock(chan);
00741 
00742    return 0;
00743 }

static int unload_module ( void   )  [static]

Variable Documentation

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

Definition at line 208 of file app_stack.c.

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

Definition at line 209 of file app_stack.c.

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

Definition at line 211 of file app_stack.c.

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

Definition at line 210 of file app_stack.c.

struct agi_command gosub_agi_command [static]
Initial value:
   { { "gosub", NULL }, handle_gosub, NULL, NULL, 0 }

Definition at line 853 of file app_stack.c.

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

Definition at line 627 of file app_stack.c.

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

Definition at line 662 of file app_stack.c.

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

Definition at line 215 of file app_stack.c.

Initial value:
 {
   .name = "STACK_PEEK",
   .read2 = stackpeek_read,
}

Definition at line 745 of file app_stack.c.


Generated on 3 Apr 2014 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1