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 "asterisk/stasis_channels.h"

Include dependency graph for app_stack.c:

Go to the source code of this file.

Data Structures

struct  gosub_stack_frame
struct  gosub_stack_list

Functions

static void __reg_module (void)
static void __unreg_module (void)
static void balance_stack (struct ast_channel *chan)
static const char * expand_gosub_args (struct ast_channel *chan, const char *args)
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, int in_subroutine, 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 gosub_run (struct ast_channel *chan, const char *sub_args, int ignore_hangup)
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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .nonoptreq = "res_agi", }
static const char app_gosub [] = "Gosub"
static const char app_gosubif [] = "GosubIf"
static const char app_pop [] = "StackPop"
static const char 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 1326 of file app_stack.c.

static void __unreg_module ( void   )  [static]

Definition at line 1326 of file app_stack.c.

static void balance_stack ( struct ast_channel chan  )  [static]

Definition at line 931 of file app_stack.c.

References ast_channel_datastore_find(), AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log, ast_datastore::data, gosub_stack_frame::entries, gosub_release_frame(), gosub_stack_frame::is_special, LOG_WARNING, and NULL.

Referenced by gosub_run(), and handle_gosub().

00932 {
00933    struct ast_datastore *stack_store;
00934    struct gosub_stack_list *oldlist;
00935    struct gosub_stack_frame *oldframe;
00936    int found;
00937 
00938    stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
00939    if (!stack_store) {
00940       ast_log(LOG_WARNING, "No %s stack allocated.\n", app_gosub);
00941       return;
00942    }
00943 
00944    oldlist = stack_store->data;
00945    AST_LIST_LOCK(oldlist);
00946    do {
00947       oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
00948       if (!oldframe) {
00949          break;
00950       }
00951       found = oldframe->is_special;
00952       gosub_release_frame(chan, oldframe);
00953    } while (!found);
00954    AST_LIST_UNLOCK(oldlist);
00955 }

static const char* expand_gosub_args ( struct ast_channel chan,
const char *  args 
) [static]

Definition at line 451 of file app_stack.c.

References ast_channel_context(), ast_channel_exten(), ast_channel_lock, ast_channel_unlock, ast_debug, ast_log, ast_malloc, ast_strdupa, ast_strlen_zero, gosub_stack_frame::context, exten, len(), LOG_WARNING, NULL, parse(), and strsep().

Referenced by load_module().

00452 {
00453    int len;
00454    char *parse;
00455    char *label;
00456    char *new_args;
00457    const char *context;
00458    const char *exten;
00459    const char *pri;
00460 
00461    /* Separate the context,exten,pri from the optional routine arguments. */
00462    parse = ast_strdupa(args);
00463    label = strsep(&parse, "(");
00464    if (parse) {
00465       char *endparen;
00466 
00467       endparen = strrchr(parse, ')');
00468       if (endparen) {
00469          *endparen = '\0';
00470       } else {
00471          ast_log(LOG_WARNING, "Ouch.  No closing paren: '%s'?\n", args);
00472       }
00473    }
00474 
00475    /* Split context,exten,pri */
00476    context = strsep(&label, ",");
00477    exten = strsep(&label, ",");
00478    pri = strsep(&label, ",");
00479    if (!exten) {
00480       /* Only a priority in this one */
00481       pri = context;
00482       exten = NULL;
00483       context = NULL;
00484    } else if (!pri) {
00485       /* Only an extension and priority in this one */
00486       pri = exten;
00487       exten = context;
00488       context = NULL;
00489    }
00490 
00491    ast_channel_lock(chan);
00492    if (ast_strlen_zero(exten)) {
00493       exten = ast_channel_exten(chan);
00494    }
00495    if (ast_strlen_zero(context)) {
00496       context = ast_channel_context(chan);
00497    }
00498    len = strlen(context) + strlen(exten) + strlen(pri) + 3;
00499    if (!ast_strlen_zero(parse)) {
00500       len += 2 + strlen(parse);
00501    }
00502    new_args = ast_malloc(len);
00503    if (new_args) {
00504       if (ast_strlen_zero(parse)) {
00505          snprintf(new_args, len, "%s,%s,%s", context, exten, pri);
00506       } else {
00507          snprintf(new_args, len, "%s,%s,%s(%s)", context, exten, pri, parse);
00508       }
00509    }
00510    ast_channel_unlock(chan);
00511 
00512    ast_debug(4, "Gosub args:%s new_args:%s\n", args, new_args ? new_args : "");
00513 
00514    return new_args;
00515 }

static int frame_set_var ( struct ast_channel chan,
struct gosub_stack_frame frame,
const char *  var,
const char *  value 
) [static]

Definition at line 262 of file app_stack.c.

References ast_channel_publish_varset(), ast_free, AST_LIST_INSERT_HEAD, AST_LIST_TRAVERSE, ast_malloc, ast_var_assign(), ast_var_name(), len(), NULL, pbx_builtin_pushvar_helper(), pbx_builtin_setvar_helper(), and RAII_VAR.

Referenced by gosub_exec(), and local_write().

00263 {
00264    struct ast_var_t *variables;
00265    int found = 0;
00266    int len;
00267    RAII_VAR(char *, local_buffer, NULL, ast_free);
00268 
00269    /* Does this variable already exist? */
00270    AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
00271       if (!strcmp(var, ast_var_name(variables))) {
00272          found = 1;
00273          break;
00274       }
00275    }
00276 
00277    if (!found) {
00278       if ((variables = ast_var_assign(var, ""))) {
00279          AST_LIST_INSERT_HEAD(&frame->varshead, variables, entries);
00280       }
00281       pbx_builtin_pushvar_helper(chan, var, value);
00282    } else {
00283       pbx_builtin_setvar_helper(chan, var, value);
00284    }
00285 
00286    len = 8 + strlen(var); /* LOCAL() + var */
00287    local_buffer = ast_malloc(len);
00288    if (!local_buffer) {
00289       return 0;
00290    }
00291    sprintf(local_buffer, "LOCAL(%s)", var);
00292    ast_channel_publish_varset(chan, local_buffer, value);
00293    return 0;
00294 }

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

Definition at line 315 of file app_stack.c.

References ast_calloc, AST_LIST_HEAD_INIT_NOLOCK, and NULL.

Referenced by gosub_exec().

00316 {
00317    struct gosub_stack_frame *new = NULL;
00318    int len_extension = strlen(extension), len_context = strlen(context);
00319 
00320    if ((new = ast_calloc(1, sizeof(*new) + 2 + len_extension + len_context))) {
00321       AST_LIST_HEAD_INIT_NOLOCK(&new->varshead);
00322       strcpy(new->extension, extension);
00323       new->context = new->extension + len_extension + 1;
00324       strcpy(new->context, context);
00325       new->priority = priority;
00326       new->in_subroutine = in_subroutine ? 1 : 0;
00327       new->arguments = arguments;
00328    }
00329    return new;
00330 }

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

Definition at line 517 of file app_stack.c.

References gosub_stack_frame::arguments, AST_APP_ARG, ast_calloc, ast_channel_caller(), ast_channel_context(), ast_channel_context_set(), ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_exten(), ast_channel_exten_set(), ast_channel_flags(), ast_channel_lock, ast_channel_name(), ast_channel_priority(), ast_channel_priority_set(), ast_channel_unlock, ast_datastore_alloc, ast_datastore_free(), ast_debug, AST_DECLARE_APP_ARGS, ast_exists_extension(), AST_FLAG_IN_AUTOLOOP, AST_FLAG_SUBROUTINE_EXEC, AST_LIST_FIRST, AST_LIST_HEAD_INIT, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log, ast_parseable_goto(), ast_set_flag, AST_STANDARD_RAW_ARGS, ast_strdupa, ast_strlen_zero, ast_test_flag, ast_datastore::data, gosub_stack_frame::entries, frame_set_var(), gosub_allocate_frame(), LOG_ERROR, LOG_WARNING, NULL, orig_exten(), parse(), S_COR, and strsep().

Referenced by gosub_run(), gosubif_exec(), handle_gosub(), and load_module().

00518 {
00519    struct ast_datastore *stack_store;
00520    struct gosub_stack_list *oldlist;
00521    struct gosub_stack_frame *newframe;
00522    struct gosub_stack_frame *lastframe;
00523    char argname[15];
00524    char *parse;
00525    char *label;
00526    char *caller_id;
00527    char *orig_context;
00528    char *orig_exten;
00529    char *dest_context;
00530    char *dest_exten;
00531    int orig_in_subroutine;
00532    int orig_priority;
00533    int dest_priority;
00534    int i;
00535    int max_argc = 0;
00536    AST_DECLARE_APP_ARGS(args2,
00537       AST_APP_ARG(argval)[100];
00538    );
00539 
00540    if (ast_strlen_zero(data)) {
00541       ast_log(LOG_ERROR, "%s requires an argument: %s([[context,]exten,]priority[(arg1[,...][,argN])])\n", app_gosub, app_gosub);
00542       return -1;
00543    }
00544 
00545    /*
00546     * Separate the arguments from the label
00547     *
00548     * NOTE:  You cannot use ast_app_separate_args for this, because
00549     * '(' cannot be used as a delimiter.
00550     */
00551    parse = ast_strdupa(data);
00552    label = strsep(&parse, "(");
00553    if (parse) {
00554       char *endparen;
00555 
00556       endparen = strrchr(parse, ')');
00557       if (endparen) {
00558          *endparen = '\0';
00559       } else {
00560          ast_log(LOG_WARNING, "Ouch.  No closing paren: '%s'?\n", data);
00561       }
00562       AST_STANDARD_RAW_ARGS(args2, parse);
00563    } else {
00564       args2.argc = 0;
00565    }
00566 
00567    ast_channel_lock(chan);
00568    orig_context = ast_strdupa(ast_channel_context(chan));
00569    orig_exten = ast_strdupa(ast_channel_exten(chan));
00570    orig_priority = ast_channel_priority(chan);
00571    orig_in_subroutine = ast_test_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
00572    ast_channel_unlock(chan);
00573 
00574    if (ast_parseable_goto(chan, label)) {
00575       ast_log(LOG_ERROR, "%s address is invalid: '%s'\n", app_gosub, data);
00576       goto error_exit;
00577    }
00578 
00579    ast_channel_lock(chan);
00580    dest_context = ast_strdupa(ast_channel_context(chan));
00581    dest_exten = ast_strdupa(ast_channel_exten(chan));
00582    dest_priority = ast_channel_priority(chan);
00583    if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP)) {
00584       ++dest_priority;
00585    }
00586    caller_id = S_COR(ast_channel_caller(chan)->id.number.valid,
00587       ast_channel_caller(chan)->id.number.str, NULL);
00588    if (caller_id) {
00589       caller_id = ast_strdupa(caller_id);
00590    }
00591    ast_channel_unlock(chan);
00592 
00593    if (!ast_exists_extension(chan, dest_context, dest_exten, dest_priority, caller_id)) {
00594       ast_log(LOG_ERROR, "Attempt to reach a non-existent destination for %s: (Context:%s, Extension:%s, Priority:%d)\n",
00595          app_gosub, dest_context, dest_exten, dest_priority);
00596       goto error_exit;
00597    }
00598 
00599    /* Now we know that we're going to a new location */
00600 
00601    ast_channel_lock(chan);
00602 
00603    /* Find stack datastore return list. */
00604    if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00605       ast_debug(1, "Channel %s has no datastore, so we're allocating one.\n",
00606          ast_channel_name(chan));
00607       stack_store = ast_datastore_alloc(&stack_info, NULL);
00608       if (!stack_store) {
00609          ast_log(LOG_ERROR, "Unable to allocate new datastore.  %s failed.\n",
00610             app_gosub);
00611          goto error_exit_locked;
00612       }
00613 
00614       oldlist = ast_calloc(1, sizeof(*oldlist));
00615       if (!oldlist) {
00616          ast_log(LOG_ERROR, "Unable to allocate datastore list head.  %s failed.\n",
00617             app_gosub);
00618          ast_datastore_free(stack_store);
00619          goto error_exit_locked;
00620       }
00621       AST_LIST_HEAD_INIT(oldlist);
00622 
00623       stack_store->data = oldlist;
00624       ast_channel_datastore_add(chan, stack_store);
00625    } else {
00626       oldlist = stack_store->data;
00627    }
00628 
00629    if ((lastframe = AST_LIST_FIRST(oldlist))) {
00630       max_argc = lastframe->arguments;
00631    }
00632 
00633    /* Mask out previous Gosub arguments in this invocation */
00634    if (args2.argc > max_argc) {
00635       max_argc = args2.argc;
00636    }
00637 
00638    /* Create the return address */
00639    newframe = gosub_allocate_frame(orig_context, orig_exten, orig_priority + 1, orig_in_subroutine, max_argc);
00640    if (!newframe) {
00641       goto error_exit_locked;
00642    }
00643 
00644    /* Set our arguments */
00645    for (i = 0; i < max_argc; i++) {
00646       snprintf(argname, sizeof(argname), "ARG%d", i + 1);
00647       frame_set_var(chan, newframe, argname, i < args2.argc ? args2.argval[i] : "");
00648       ast_debug(1, "Setting '%s' to '%s'\n", argname, i < args2.argc ? args2.argval[i] : "");
00649    }
00650    snprintf(argname, sizeof(argname), "%u", args2.argc);
00651    frame_set_var(chan, newframe, "ARGC", argname);
00652 
00653    ast_set_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
00654 
00655    /* And finally, save our return address */
00656    AST_LIST_LOCK(oldlist);
00657    AST_LIST_INSERT_HEAD(oldlist, newframe, entries);
00658    AST_LIST_UNLOCK(oldlist);
00659    ast_channel_unlock(chan);
00660 
00661    return 0;
00662 
00663 error_exit:
00664    ast_channel_lock(chan);
00665 
00666 error_exit_locked:
00667    /* Restore the original dialplan location. */
00668    ast_channel_context_set(chan, orig_context);
00669    ast_channel_exten_set(chan, orig_exten);
00670    ast_channel_priority_set(chan, orig_priority);
00671    ast_channel_unlock(chan);
00672    return -1;
00673 }

static void gosub_free ( void *  data  )  [static]

Definition at line 332 of file app_stack.c.

References ast_free, AST_LIST_HEAD_DESTROY, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, gosub_stack_frame::entries, gosub_release_frame(), and NULL.

00333 {
00334    struct gosub_stack_list *oldlist = data;
00335    struct gosub_stack_frame *oldframe;
00336 
00337    AST_LIST_LOCK(oldlist);
00338    while ((oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries))) {
00339       gosub_release_frame(NULL, oldframe);
00340    }
00341    AST_LIST_UNLOCK(oldlist);
00342    AST_LIST_HEAD_DESTROY(oldlist);
00343    ast_free(oldlist);
00344 }

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

Definition at line 296 of file app_stack.c.

References ast_free, AST_LIST_REMOVE_HEAD, ast_var_delete(), ast_var_name(), gosub_stack_frame::entries, NULL, pbx_builtin_setvar_helper(), and gosub_stack_frame::varshead.

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

00297 {
00298    struct ast_var_t *vardata;
00299 
00300    /* If chan is not defined, then we're calling it as part of gosub_free,
00301     * and the channel variables will be deallocated anyway.  Otherwise, we're
00302     * just releasing a single frame, so we need to clean up the arguments for
00303     * that frame, so that we re-expose the variables from the previous frame
00304     * that were hidden by this one.
00305     */
00306    while ((vardata = AST_LIST_REMOVE_HEAD(&frame->varshead, entries))) {
00307       if (chan)
00308          pbx_builtin_setvar_helper(chan, ast_var_name(vardata), NULL);  
00309       ast_var_delete(vardata);
00310    }
00311 
00312    ast_free(frame);
00313 }

static int gosub_run ( struct ast_channel chan,
const char *  sub_args,
int  ignore_hangup 
) [static]

Definition at line 971 of file app_stack.c.

References ast_channel_caller(), ast_channel_clear_softhangup(), ast_channel_context(), ast_channel_context_set(), ast_channel_datastore_find(), ast_channel_exten(), ast_channel_exten_set(), ast_channel_flags(), ast_channel_lock, ast_channel_name(), ast_channel_priority(), ast_channel_priority_set(), ast_channel_softhangup_internal_flag(), ast_channel_unlock, ast_check_hangup(), ast_debug, AST_FLAG_IN_AUTOLOOP, AST_FLAG_SUBROUTINE_EXEC, AST_LIST_FIRST, ast_log, ast_set2_flag, ast_set_flag, AST_SOFTHANGUP_ASYNCGOTO, ast_softhangup_nolock(), ast_spawn_extension(), ast_strdupa, ast_test_flag, ast_verb, balance_stack(), ast_datastore::data, gosub_exec(), gosub_stack_frame::is_special, LOG_ERROR, LOG_NOTICE, NULL, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), S_COR, and S_OR.

Referenced by load_module().

00972 {
00973    const char *saved_context;
00974    const char *saved_exten;
00975    int saved_priority;
00976    int saved_hangup_flags;
00977    int saved_autoloopflag;
00978    int saved_in_subroutine;
00979    int res;
00980 
00981    ast_channel_lock(chan);
00982 
00983    ast_verb(3, "%s Internal %s(%s) start\n",
00984       ast_channel_name(chan), app_gosub, sub_args);
00985 
00986    /* Save non-hangup softhangup flags. */
00987    saved_hangup_flags = ast_channel_softhangup_internal_flag(chan)
00988       & AST_SOFTHANGUP_ASYNCGOTO;
00989    if (saved_hangup_flags) {
00990       ast_channel_clear_softhangup(chan, AST_SOFTHANGUP_ASYNCGOTO);
00991    }
00992 
00993    /* Save autoloop flag */
00994    saved_autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
00995    ast_set_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
00996 
00997    /* Save current dialplan location */
00998    saved_context = ast_strdupa(ast_channel_context(chan));
00999    saved_exten = ast_strdupa(ast_channel_exten(chan));
01000    saved_priority = ast_channel_priority(chan);
01001 
01002    /* Save whether or not we are in a subroutine */
01003    saved_in_subroutine = ast_test_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
01004 
01005    ast_debug(4, "%s Original location: %s,%s,%d\n", ast_channel_name(chan),
01006       saved_context, saved_exten, saved_priority);
01007 
01008    ast_channel_unlock(chan);
01009    res = gosub_exec(chan, sub_args);
01010    ast_debug(4, "%s exited with status %d\n", app_gosub, res);
01011    ast_channel_lock(chan);
01012    if (!res) {
01013       struct ast_datastore *stack_store;
01014 
01015       /* Mark the return location as special. */
01016       stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
01017       if (!stack_store) {
01018          /* Should never happen! */
01019          ast_log(LOG_ERROR, "No %s stack!\n", app_gosub);
01020          res = -1;
01021       } else {
01022          struct gosub_stack_list *oldlist;
01023          struct gosub_stack_frame *cur;
01024 
01025          oldlist = stack_store->data;
01026          cur = AST_LIST_FIRST(oldlist);
01027          cur->is_special = 1;
01028       }
01029    }
01030    if (!res) {
01031       int found = 0; /* set if we find at least one match */
01032 
01033       /*
01034        * Run gosub body autoloop.
01035        *
01036        * Note that this loop is inverted from the normal execution
01037        * loop because we just executed the Gosub application as the
01038        * first extension of the autoloop.
01039        */
01040       do {
01041          /* Check for hangup. */
01042          if (ast_check_hangup(chan)) {
01043             if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) {
01044                ast_log(LOG_ERROR, "%s An async goto just messed up our execution location.\n",
01045                   ast_channel_name(chan));
01046                break;
01047             }
01048             if (!ignore_hangup) {
01049                break;
01050             }
01051          }
01052 
01053          /* Next dialplan priority. */
01054          ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
01055 
01056          ast_channel_unlock(chan);
01057          res = ast_spawn_extension(chan, ast_channel_context(chan),
01058             ast_channel_exten(chan), ast_channel_priority(chan),
01059             S_COR(ast_channel_caller(chan)->id.number.valid,
01060                ast_channel_caller(chan)->id.number.str, NULL),
01061             &found, 1);
01062          ast_channel_lock(chan);
01063       } while (!res);
01064       if (found && res) {
01065          /* Something bad happened, or a hangup has been requested. */
01066          ast_debug(1, "Spawn extension (%s,%s,%d) exited with %d on '%s'\n",
01067             ast_channel_context(chan), ast_channel_exten(chan),
01068             ast_channel_priority(chan), res, ast_channel_name(chan));
01069          ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n",
01070             ast_channel_context(chan), ast_channel_exten(chan),
01071             ast_channel_priority(chan), ast_channel_name(chan));
01072       }
01073 
01074       /* Did the routine return? */
01075       if (ast_channel_priority(chan) == saved_priority
01076          && !strcmp(ast_channel_context(chan), saved_context)
01077          && !strcmp(ast_channel_exten(chan), saved_exten)) {
01078          ast_verb(3, "%s Internal %s(%s) complete GOSUB_RETVAL=%s\n",
01079             ast_channel_name(chan), app_gosub, sub_args,
01080             S_OR(pbx_builtin_getvar_helper(chan, "GOSUB_RETVAL"), ""));
01081       } else {
01082          ast_log(LOG_NOTICE, "%s Abnormal '%s(%s)' exit.  Popping routine return locations.\n",
01083             ast_channel_name(chan), app_gosub, sub_args);
01084          balance_stack(chan);
01085          pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", "");
01086       }
01087 
01088       /* We executed the requested subroutine to the best of our ability. */
01089       res = 0;
01090    }
01091 
01092    ast_debug(4, "%s Ending location: %s,%s,%d\n", ast_channel_name(chan),
01093       ast_channel_context(chan), ast_channel_exten(chan),
01094       ast_channel_priority(chan));
01095 
01096    /* Restore dialplan location */
01097    if (!(ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO)) {
01098       ast_channel_context_set(chan, saved_context);
01099       ast_channel_exten_set(chan, saved_exten);
01100       ast_channel_priority_set(chan, saved_priority);
01101    }
01102 
01103    /* Restore autoloop flag */
01104    ast_set2_flag(ast_channel_flags(chan), saved_autoloopflag, AST_FLAG_IN_AUTOLOOP);
01105 
01106    /* Restore subroutine flag */
01107    ast_set2_flag(ast_channel_flags(chan), saved_in_subroutine, AST_FLAG_SUBROUTINE_EXEC);
01108 
01109    /* Restore non-hangup softhangup flags. */
01110    if (saved_hangup_flags) {
01111       ast_softhangup_nolock(chan, saved_hangup_flags);
01112    }
01113 
01114    ast_channel_unlock(chan);
01115 
01116    return res;
01117 }

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

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

00676 {
00677    char *args;
00678    int res=0;
00679    AST_DECLARE_APP_ARGS(cond,
00680       AST_APP_ARG(ition);
00681       AST_APP_ARG(labels);
00682    );
00683    AST_DECLARE_APP_ARGS(label,
00684       AST_APP_ARG(iftrue);
00685       AST_APP_ARG(iffalse);
00686    );
00687 
00688    if (ast_strlen_zero(data)) {
00689       ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
00690       return 0;
00691    }
00692 
00693    args = ast_strdupa(data);
00694    AST_NONSTANDARD_RAW_ARGS(cond, args, '?');
00695    if (cond.argc != 2) {
00696       ast_log(LOG_WARNING, "GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
00697       return 0;
00698    }
00699 
00700    AST_NONSTANDARD_RAW_ARGS(label, cond.labels, ':');
00701 
00702    if (pbx_checkcondition(cond.ition)) {
00703       if (!ast_strlen_zero(label.iftrue))
00704          res = gosub_exec(chan, label.iftrue);
00705    } else if (!ast_strlen_zero(label.iffalse)) {
00706       res = gosub_exec(chan, label.iffalse);
00707    }
00708 
00709    return res;
00710 }

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

Definition at line 1119 of file app_stack.c.

References ast_agi_send(), ast_asprintf, ast_channel_caller(), ast_channel_context(), ast_channel_context_set(), ast_channel_datastore_find(), ast_channel_exten(), ast_channel_exten_set(), ast_channel_flags(), ast_channel_lock, ast_channel_name(), ast_channel_pbx(), ast_channel_pbx_set(), ast_channel_priority(), ast_channel_priority_set(), ast_channel_unlock, ast_debug, ast_exists_extension(), ast_findlabel_extension(), AST_FLAG_IN_AUTOLOOP, AST_FLAG_SUBROUTINE_EXEC, ast_free, AST_LIST_FIRST, ast_log, ast_pbx_run_args(), ast_set2_flag, ast_set_flag, ast_strdupa, ast_test_flag, ast_verb, balance_stack(), ast_datastore::data, agi_state::fd, gosub_exec(), gosub_stack_frame::is_special, LOG_ERROR, LOG_NOTICE, ast_pbx_args::no_hangup_chan, NULL, pbx_builtin_getvar_helper(), pbx_builtin_setvar_helper(), gosub_stack_frame::priority, RESULT_FAILURE, RESULT_SHOWUSAGE, RESULT_SUCCESS, S_COR, and S_OR.

01120 {
01121    int res;
01122    int priority;
01123    int old_autoloopflag;
01124    int old_in_subroutine;
01125    int old_priority;
01126    const char *old_context;
01127    const char *old_extension;
01128    char *gosub_args;
01129 
01130    if (argc < 4 || argc > 5) {
01131       return RESULT_SHOWUSAGE;
01132    }
01133 
01134    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] : "");
01135 
01136    if (sscanf(argv[3], "%30d", &priority) != 1 || priority < 1) {
01137       /* Lookup the priority label */
01138       priority = ast_findlabel_extension(chan, argv[1], argv[2], argv[3],
01139          S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
01140       if (priority < 0) {
01141          ast_log(LOG_ERROR, "Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]);
01142          ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
01143          return RESULT_FAILURE;
01144       }
01145    } else if (!ast_exists_extension(chan, argv[1], argv[2], priority,
01146       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
01147       ast_agi_send(agi->fd, chan, "200 result=-1 Gosub label not found\n");
01148       return RESULT_FAILURE;
01149    }
01150 
01151    if (argc == 5) {
01152       if (ast_asprintf(&gosub_args, "%s,%s,%d(%s)", argv[1], argv[2], priority, argv[4]) < 0) {
01153          gosub_args = NULL;
01154       }
01155    } else {
01156       if (ast_asprintf(&gosub_args, "%s,%s,%d", argv[1], argv[2], priority) < 0) {
01157          gosub_args = NULL;
01158       }
01159    }
01160    if (!gosub_args) {
01161       ast_agi_send(agi->fd, chan, "503 result=-2 Memory allocation failure\n");
01162       return RESULT_FAILURE;
01163    }
01164 
01165    ast_channel_lock(chan);
01166 
01167    ast_verb(3, "%s AGI %s(%s) start\n", ast_channel_name(chan), app_gosub, gosub_args);
01168 
01169    /* Save autoloop flag */
01170    old_autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
01171    ast_set_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
01172 
01173    /* Save subroutine flag */
01174    old_in_subroutine = ast_test_flag(ast_channel_flags(chan), AST_FLAG_SUBROUTINE_EXEC);
01175 
01176    /* Save previous location, since we're going to change it */
01177    old_context = ast_strdupa(ast_channel_context(chan));
01178    old_extension = ast_strdupa(ast_channel_exten(chan));
01179    old_priority = ast_channel_priority(chan);
01180 
01181    ast_debug(4, "%s Original location: %s,%s,%d\n", ast_channel_name(chan),
01182       old_context, old_extension, old_priority);
01183    ast_channel_unlock(chan);
01184 
01185    res = gosub_exec(chan, gosub_args);
01186    if (!res) {
01187       struct ast_datastore *stack_store;
01188 
01189       /* Mark the return location as special. */
01190       ast_channel_lock(chan);
01191       stack_store = ast_channel_datastore_find(chan, &stack_info, NULL);
01192       if (!stack_store) {
01193          /* Should never happen! */
01194          ast_log(LOG_ERROR, "No %s stack!\n", app_gosub);
01195          res = -1;
01196       } else {
01197          struct gosub_stack_list *oldlist;
01198          struct gosub_stack_frame *cur;
01199 
01200          oldlist = stack_store->data;
01201          cur = AST_LIST_FIRST(oldlist);
01202          cur->is_special = 1;
01203       }
01204       ast_channel_unlock(chan);
01205    }
01206    if (!res) {
01207       struct ast_pbx *pbx;
01208       struct ast_pbx_args args;
01209       int abnormal_exit;
01210 
01211       memset(&args, 0, sizeof(args));
01212       args.no_hangup_chan = 1;
01213 
01214       ast_channel_lock(chan);
01215 
01216       /* Next dialplan priority. */
01217       ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
01218 
01219       /* Suppress warning about PBX already existing */
01220       pbx = ast_channel_pbx(chan);
01221       ast_channel_pbx_set(chan, NULL);
01222       ast_channel_unlock(chan);
01223 
01224       ast_agi_send(agi->fd, chan, "100 result=0 Trying...\n");
01225       ast_pbx_run_args(chan, &args);
01226 
01227       ast_channel_lock(chan);
01228       ast_free(ast_channel_pbx(chan));
01229       ast_channel_pbx_set(chan, pbx);
01230 
01231       /* Did the routine return? */
01232       if (ast_channel_priority(chan) == old_priority
01233          && !strcmp(ast_channel_context(chan), old_context)
01234          && !strcmp(ast_channel_exten(chan), old_extension)) {
01235          ast_verb(3, "%s AGI %s(%s) complete GOSUB_RETVAL=%s\n",
01236             ast_channel_name(chan), app_gosub, gosub_args,
01237             S_OR(pbx_builtin_getvar_helper(chan, "GOSUB_RETVAL"), ""));
01238          abnormal_exit = 0;
01239       } else {
01240          ast_log(LOG_NOTICE, "%s Abnormal AGI %s(%s) exit.  Popping routine return locations.\n",
01241             ast_channel_name(chan), app_gosub, gosub_args);
01242          balance_stack(chan);
01243          pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", "");
01244          abnormal_exit = 1;
01245       }
01246       ast_channel_unlock(chan);
01247 
01248       ast_agi_send(agi->fd, chan, "200 result=0 Gosub complete%s\n",
01249          abnormal_exit ? " (abnormal exit)" : "");
01250    } else {
01251       ast_agi_send(agi->fd, chan, "200 result=%d Gosub failed\n", res);
01252    }
01253 
01254    ast_free(gosub_args);
01255 
01256    ast_channel_lock(chan);
01257    ast_debug(4, "%s Ending location: %s,%s,%d\n", ast_channel_name(chan),
01258       ast_channel_context(chan), ast_channel_exten(chan),
01259       ast_channel_priority(chan));
01260 
01261    /* Restore previous location */
01262    ast_channel_context_set(chan, old_context);
01263    ast_channel_exten_set(chan, old_extension);
01264    ast_channel_priority_set(chan, old_priority);
01265 
01266    /* Restore autoloop flag */
01267    ast_set2_flag(ast_channel_flags(chan), old_autoloopflag, AST_FLAG_IN_AUTOLOOP);
01268 
01269    /* Restore subroutine flag */
01270    ast_set2_flag(ast_channel_flags(chan), old_in_subroutine, AST_FLAG_SUBROUTINE_EXEC);
01271    ast_channel_unlock(chan);
01272 
01273    return RESULT_SUCCESS;
01274 }

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

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_LIST_FIRST, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_var_name(), ast_datastore::data, gosub_stack_frame::entries, LOG_WARNING, NULL, pbx_builtin_getvar_helper(), S_OR, tmp(), and gosub_stack_frame::varshead.

00713 {
00714    struct ast_datastore *stack_store;
00715    struct gosub_stack_list *oldlist;
00716    struct gosub_stack_frame *frame;
00717    struct ast_var_t *variables;
00718 
00719    if (!chan) {
00720       ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00721       return -1;
00722    }
00723 
00724    ast_channel_lock(chan);
00725    if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00726       ast_channel_unlock(chan);
00727       return -1;
00728    }
00729 
00730    oldlist = stack_store->data;
00731    AST_LIST_LOCK(oldlist);
00732    if (!(frame = AST_LIST_FIRST(oldlist))) {
00733       /* Not within a Gosub routine */
00734       AST_LIST_UNLOCK(oldlist);
00735       ast_channel_unlock(chan);
00736       return -1;
00737    }
00738 
00739    AST_LIST_TRAVERSE(&frame->varshead, variables, entries) {
00740       if (!strcmp(data, ast_var_name(variables))) {
00741          const char *tmp;
00742          tmp = pbx_builtin_getvar_helper(chan, data);
00743          ast_copy_string(buf, S_OR(tmp, ""), len);
00744          break;
00745       }
00746    }
00747    AST_LIST_UNLOCK(oldlist);
00748    ast_channel_unlock(chan);
00749    return 0;
00750 }

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

Definition at line 752 of file app_stack.c.

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

00753 {
00754    struct ast_datastore *stack_store;
00755    struct gosub_stack_list *oldlist;
00756    struct gosub_stack_frame *frame;
00757 
00758    if (!chan) {
00759       ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00760       return -1;
00761    }
00762 
00763    ast_channel_lock(chan);
00764    if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00765       ast_log(LOG_ERROR, "Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var);
00766       ast_channel_unlock(chan);
00767       return -1;
00768    }
00769 
00770    oldlist = stack_store->data;
00771    AST_LIST_LOCK(oldlist);
00772    frame = AST_LIST_FIRST(oldlist);
00773 
00774    if (frame) {
00775       frame_set_var(chan, frame, var, value);
00776    }
00777 
00778    AST_LIST_UNLOCK(oldlist);
00779    ast_channel_unlock(chan);
00780 
00781    return 0;
00782 }

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

Definition at line 790 of file app_stack.c.

References args, AST_APP_ARG, ast_channel_lock, ast_channel_unlock, ast_channel_varshead(), ast_copy_string(), AST_DECLARE_APP_ARGS, AST_LIST_TRAVERSE, ast_log, AST_STANDARD_RAW_ARGS, ast_strlen_zero, ast_var_name(), ast_var_value(), gosub_stack_frame::entries, LOG_ERROR, and name.

00791 {
00792    int found = 0, n;
00793    struct ast_var_t *variables;
00794    AST_DECLARE_APP_ARGS(args,
00795       AST_APP_ARG(n);
00796       AST_APP_ARG(name);
00797    );
00798 
00799    if (!chan) {
00800       ast_log(LOG_ERROR, "LOCAL_PEEK must be called on an active channel\n");
00801       return -1;
00802    }
00803 
00804    AST_STANDARD_RAW_ARGS(args, data);
00805 
00806    if (ast_strlen_zero(args.n) || ast_strlen_zero(args.name)) {
00807       ast_log(LOG_ERROR, "LOCAL_PEEK requires parameters n and varname\n");
00808       return -1;
00809    }
00810 
00811    n = atoi(args.n);
00812    *buf = '\0';
00813 
00814    ast_channel_lock(chan);
00815    AST_LIST_TRAVERSE(ast_channel_varshead(chan), variables, entries) {
00816       if (!strcmp(args.name, ast_var_name(variables)) && ++found > n) {
00817          ast_copy_string(buf, ast_var_value(variables), len);
00818          break;
00819       }
00820    }
00821    ast_channel_unlock(chan);
00822    return 0;
00823 }

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

Definition at line 346 of file app_stack.c.

References ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_debug, AST_LIST_FIRST, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log, ast_datastore::data, gosub_stack_frame::entries, gosub_release_frame(), gosub_stack_frame::is_special, LOG_WARNING, and NULL.

Referenced by load_module().

00347 {
00348    struct ast_datastore *stack_store;
00349    struct gosub_stack_frame *oldframe;
00350    struct gosub_stack_list *oldlist;
00351    int res = 0;
00352 
00353    ast_channel_lock(chan);
00354    if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00355       ast_log(LOG_WARNING, "%s called with no gosub stack allocated.\n", app_pop);
00356       ast_channel_unlock(chan);
00357       return 0;
00358    }
00359 
00360    oldlist = stack_store->data;
00361    AST_LIST_LOCK(oldlist);
00362    oldframe = AST_LIST_FIRST(oldlist);
00363    if (oldframe) {
00364       if (oldframe->is_special) {
00365          ast_debug(1, "%s attempted to pop special return location.\n", app_pop);
00366 
00367          /* Abort the special routine dialplan execution.  Dialplan programming error. */
00368          res = -1;
00369       } else {
00370          AST_LIST_REMOVE_HEAD(oldlist, entries);
00371          gosub_release_frame(chan, oldframe);
00372       }
00373    } else {
00374       ast_debug(1, "%s called with an empty gosub stack\n", app_pop);
00375    }
00376    AST_LIST_UNLOCK(oldlist);
00377    ast_channel_unlock(chan);
00378    return res;
00379 }

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

Definition at line 381 of file app_stack.c.

References ast_channel_context_set(), ast_channel_datastore_find(), ast_channel_exten_set(), ast_channel_flags(), ast_channel_lock, ast_channel_priority_set(), ast_channel_unlock, AST_FLAG_IN_AUTOLOOP, AST_FLAG_SUBROUTINE_EXEC, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log, ast_set2_flag, ast_test_flag, gosub_stack_frame::context, ast_datastore::data, gosub_stack_frame::entries, gosub_stack_frame::extension, gosub_release_frame(), gosub_stack_frame::in_subroutine, gosub_stack_frame::is_special, LOG_ERROR, NULL, pbx_builtin_setvar_helper(), gosub_stack_frame::priority, retval, and S_OR.

Referenced by load_module().

00382 {
00383    struct ast_datastore *stack_store;
00384    struct gosub_stack_frame *oldframe;
00385    struct gosub_stack_list *oldlist;
00386    const char *retval = data;
00387    int res = 0;
00388 
00389    ast_channel_lock(chan);
00390    if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00391       ast_log(LOG_ERROR, "Return without Gosub: stack is unallocated\n");
00392       ast_channel_unlock(chan);
00393       return -1;
00394    }
00395 
00396    oldlist = stack_store->data;
00397    AST_LIST_LOCK(oldlist);
00398    oldframe = AST_LIST_REMOVE_HEAD(oldlist, entries);
00399    AST_LIST_UNLOCK(oldlist);
00400 
00401    if (!oldframe) {
00402       ast_log(LOG_ERROR, "Return without Gosub: stack is empty\n");
00403       ast_channel_unlock(chan);
00404       return -1;
00405    }
00406    if (oldframe->is_special) {
00407       /* Exit from special routine. */
00408       res = -1;
00409    }
00410 
00411    /*
00412     * We cannot use ast_explicit_goto() because we MUST restore
00413     * what was there before.  Channels that do not have a PBX may
00414     * not have the context or exten set.
00415     */
00416    ast_channel_context_set(chan, oldframe->context);
00417    ast_channel_exten_set(chan, oldframe->extension);
00418    if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP)) {
00419       --oldframe->priority;
00420    }
00421    ast_channel_priority_set(chan, oldframe->priority);
00422    ast_set2_flag(ast_channel_flags(chan), oldframe->in_subroutine, AST_FLAG_SUBROUTINE_EXEC);
00423 
00424    gosub_release_frame(chan, oldframe);
00425 
00426    /* Set a return value, if any */
00427    pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", S_OR(retval, ""));
00428    ast_channel_unlock(chan);
00429    return res;
00430 }

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

Definition at line 830 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_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log, ast_skip_blanks(), AST_STANDARD_APP_ARGS, ast_str_set(), ast_strdupa, ast_strlen_zero, ast_true(), gosub_stack_frame::context, ast_datastore::data, gosub_stack_frame::entries, gosub_stack_frame::extension, LOG_ERROR, NULL, and gosub_stack_frame::priority.

00831 {
00832    struct ast_datastore *stack_store;
00833    struct gosub_stack_list *oldlist;
00834    struct gosub_stack_frame *frame;
00835    int n;
00836    AST_DECLARE_APP_ARGS(args,
00837       AST_APP_ARG(n);
00838       AST_APP_ARG(which);
00839       AST_APP_ARG(suppress);
00840    );
00841 
00842    if (!chan) {
00843       ast_log(LOG_ERROR, "STACK_PEEK must be called on an active channel\n");
00844       return -1;
00845    }
00846 
00847    data = ast_strdupa(data);
00848    AST_STANDARD_APP_ARGS(args, data);
00849 
00850    if (ast_strlen_zero(args.n) || ast_strlen_zero(args.which)) {
00851       ast_log(LOG_ERROR, "STACK_PEEK requires parameters n and which\n");
00852       return -1;
00853    }
00854 
00855    n = atoi(args.n);
00856    if (n <= 0) {
00857       ast_log(LOG_ERROR, "STACK_PEEK must be called with a positive peek value\n");
00858       return -1;
00859    }
00860 
00861    ast_channel_lock(chan);
00862    if (!(stack_store = ast_channel_datastore_find(chan, &stack_info, NULL))) {
00863       if (!ast_true(args.suppress)) {
00864          ast_log(LOG_ERROR, "STACK_PEEK called on a channel without a gosub stack\n");
00865       }
00866       ast_channel_unlock(chan);
00867       return -1;
00868    }
00869 
00870    oldlist = stack_store->data;
00871 
00872    AST_LIST_LOCK(oldlist);
00873    AST_LIST_TRAVERSE(oldlist, frame, entries) {
00874       if (--n == 0) {
00875          break;
00876       }
00877    }
00878 
00879    if (!frame) {
00880       /* Too deep */
00881       if (!ast_true(args.suppress)) {
00882          ast_log(LOG_ERROR, "Stack peek of '%s' is more stack frames than I have\n", args.n);
00883       }
00884       AST_LIST_UNLOCK(oldlist);
00885       ast_channel_unlock(chan);
00886       return -1;
00887    }
00888 
00889    args.which = ast_skip_blanks(args.which);
00890 
00891    switch (args.which[0]) {
00892    case 'l': /* label */
00893       ast_str_set(str, len, "%s,%s,%d", frame->context, frame->extension, frame->priority - 1);
00894       break;
00895    case 'c': /* context */
00896       ast_str_set(str, len, "%s", frame->context);
00897       break;
00898    case 'e': /* extension */
00899       ast_str_set(str, len, "%s", frame->extension);
00900       break;
00901    case 'p': /* priority */
00902       ast_str_set(str, len, "%d", frame->priority - 1);
00903       break;
00904    default:
00905       ast_log(LOG_ERROR, "Unknown argument '%s' to STACK_PEEK\n", args.which);
00906       break;
00907    }
00908 
00909    AST_LIST_UNLOCK(oldlist);
00910    ast_channel_unlock(chan);
00911 
00912    return 0;
00913 }

static int unload_module ( void   )  [static]


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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_APP_DEPEND, .nonoptreq = "res_agi", } [static]

Definition at line 1326 of file app_stack.c.

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

Definition at line 234 of file app_stack.c.

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

Definition at line 235 of file app_stack.c.

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

Definition at line 237 of file app_stack.c.

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

Definition at line 236 of file app_stack.c.

Definition at line 1326 of file app_stack.c.

struct agi_command gosub_agi_command [static]

Initial value:

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

Definition at line 1276 of file app_stack.c.

Referenced by load_module(), and unload_module().

Initial value:

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

Definition at line 784 of file app_stack.c.

Referenced by load_module(), and unload_module().

Initial value:

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

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

Initial value:

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

Definition at line 915 of file app_stack.c.

Referenced by load_module(), and unload_module().


Generated on Thu Apr 16 06:28:44 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6