Mon Oct 8 12:39:08 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 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 struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_LOAD_ORDER , .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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .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
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

static void __reg_module ( void   )  [static]

Definition at line 892 of file app_stack.c.

static void __unreg_module ( void   )  [static]

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

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]

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 gosub_stack_frame::arguments, 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, gosub_stack_frame::entries, ast_channel::exten, frame_set_var(), gosub_allocate_frame(), ast_party_caller::id, LOG_ERROR, LOG_WARNING, ast_channel::name, ast_party_id::number, orig_exten(), parse(), ast_channel::priority, S_COR, stack_info, ast_party_number::str, strsep(), 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, gosub_stack_frame::entries, 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(), gosub_stack_frame::entries, pbx_builtin_setvar_helper(), and gosub_stack_frame::varshead.

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

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 (asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority + (chan->pbx ? 1 : 0), argv[4]) < 0) {
00796          ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00797          gosub_args = NULL;
00798       }
00799    } else {
00800       if (asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority + (chan->pbx ? 1 : 0)) < 0) {
00801          ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00802          gosub_args = NULL;
00803       }
00804    }
00805 
00806    if (gosub_args) {
00807       int res;
00808 
00809       ast_debug(1, "Trying gosub with arguments '%s'\n", gosub_args);
00810 
00811       if ((res = pbx_exec(chan, theapp, gosub_args)) == 0) {
00812          struct ast_pbx *pbx = chan->pbx;
00813          struct ast_pbx_args args;
00814          struct ast_datastore *stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00815          AST_LIST_HEAD(, gosub_stack_frame) *oldlist;
00816          struct gosub_stack_frame *cur;
00817          if (!stack_store) {
00818             ast_log(LOG_WARNING, "No GoSub stack remaining after AGI GoSub execution.\n");
00819             ast_free(gosub_args);
00820             return RESULT_FAILURE;
00821          }
00822          oldlist = stack_store->data;
00823          cur = AST_LIST_FIRST(oldlist);
00824          cur->is_agi = 1;
00825 
00826          memset(&args, 0, sizeof(args));
00827          args.no_hangup_chan = 1;
00828          /* Suppress warning about PBX already existing */
00829          chan->pbx = NULL;
00830          ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n");
00831          ast_pbx_run_args(chan, &args);
00832          ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete\n");
00833          if (chan->pbx) {
00834             ast_free(chan->pbx);
00835          }
00836          chan->pbx = pbx;
00837       } else {
00838          ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res);
00839       }
00840       ast_free(gosub_args);
00841    } else {
00842       ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n");
00843       return RESULT_FAILURE;
00844    }
00845 
00846    /* Restore previous location */
00847    ast_copy_string(chan->context, old_context, sizeof(chan->context));
00848    ast_copy_string(chan->exten, old_extension, sizeof(chan->exten));
00849    chan->priority = old_priority;
00850 
00851    return RESULT_SUCCESS;
00852 }

static int load_module ( void   )  [static]

Definition at line 872 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(), return_exec(), and stackpeek_function.

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, gosub_stack_frame::entries, pbx_builtin_getvar_helper(), S_OR, stack_info, and gosub_stack_frame::varshead.

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(), LOG_ERROR, and stack_info.

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(), gosub_stack_frame::entries, 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_stack_frame::entries, gosub_release_frame(), LOG_WARNING, and stack_info.

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

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(), gosub_stack_frame::context, ast_datastore::data, gosub_stack_frame::entries, gosub_stack_frame::extension, LOG_ERROR, gosub_stack_frame::priority, stack_info, and str.

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]

Definition at line 857 of file app_stack.c.

References ast_agi_unregister(), ast_custom_function_unregister(), ast_unregister_application(), gosub_agi_command, local_function, peek_function, and stackpeek_function.


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_LOAD_ORDER , .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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .nonoptreq = "res_agi", } [static]

Definition at line 892 of file app_stack.c.

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 ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 892 of file app_stack.c.

struct agi_command gosub_agi_command [static]

Initial value:

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

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

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

struct ast_custom_function stackpeek_function [static]

Initial value:

 {
   .name = "STACK_PEEK",
   .read2 = stackpeek_read,
}

Definition at line 744 of file app_stack.c.

Referenced by load_module(), and unload_module().


Generated on Mon Oct 8 12:39:08 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7