Tue Aug 20 16:34:44 2013

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

 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       variables = ast_var_assign(var, "");
00246       AST_LIST_INSERT_HEAD(&frame->varshead, variables, entries);
00247       pbx_builtin_pushvar_helper(chan, var, value);
00248    } else {
00249       pbx_builtin_setvar_helper(chan, var, value);
00250    }
00251 
00252    manager_event(EVENT_FLAG_DIALPLAN, "VarSet",
00253       "Channel: %s\r\n"
00254       "Variable: LOCAL(%s)\r\n"
00255       "Value: %s\r\n"
00256       "Uniqueid: %s\r\n",
00257       chan->name, var, value, chan->uniqueid);
00258    return 0;
00259 }

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

Definition at line 280 of file app_stack.c.

References ast_calloc, and AST_LIST_HEAD_INIT_NOLOCK.

Referenced by gosub_exec().

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

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

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

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

static void gosub_free ( void *  data  )  [static]

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Definition at line 626 of file app_stack.c.

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

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


Generated on 20 Aug 2013 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1