284 len = 8 + strlen(var);
289 sprintf(local_buffer,
"LOCAL(%s)", var);
316 int len_extension = strlen(extension) + 1;
317 int len_context = strlen(context) + 1;
319 if ((
new =
ast_calloc(1,
sizeof(*
new) + len_extension + len_context))) {
322 new->context =
new->extension + len_extension;
325 new->in_subroutine = in_subroutine ? 1 : 0;
359 oldlist = stack_store->
data;
385 const char *
retval = data;
395 oldlist = stack_store->
data;
462 label =
strsep(&parse,
"(");
466 endparen = strrchr(parse,
')');
475 context =
strsep(&label,
",");
476 exten =
strsep(&label,
",");
477 pri =
strsep(&label,
",");
497 len = strlen(context) + strlen(exten) + strlen(pri) + 3;
499 len += 2 + strlen(parse);
504 snprintf(new_args, len,
"%s,%s,%s", context, exten, pri);
506 snprintf(new_args, len,
"%s,%s,%s(%s)", context, exten, pri, parse);
511 ast_debug(4,
"Gosub args:%s new_args:%s\n", args, new_args ? new_args :
"");
530 int orig_in_subroutine;
551 label =
strsep(&parse,
"(");
555 endparen = strrchr(parse,
')');
593 ast_log(
LOG_ERROR,
"Attempt to reach a non-existent destination for %s: (Context:%s, Extension:%s, Priority:%d)\n",
594 app_gosub, dest_context, dest_exten, dest_priority);
604 ast_debug(1,
"Channel %s has no datastore, so we're allocating one.\n",
610 goto error_exit_locked;
618 goto error_exit_locked;
622 stack_store->
data = oldlist;
625 oldlist = stack_store->
data;
633 if (args2.argc > max_argc) {
634 max_argc = args2.argc;
638 newframe =
gosub_allocate_frame(orig_context, orig_exten, orig_priority + 1, orig_in_subroutine, max_argc);
640 goto error_exit_locked;
644 for (i = 0; i < max_argc; i++) {
645 snprintf(argname,
sizeof(argname),
"ARG%d", i + 1);
646 frame_set_var(chan, newframe, argname, i < args2.argc ? args2.argval[i] :
"");
647 ast_debug(1,
"Setting '%s' to '%s'\n", argname, i < args2.argc ? args2.argval[i] :
"");
649 snprintf(argname,
sizeof(argname),
"%u", args2.argc);
688 ast_log(
LOG_WARNING,
"GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
694 if (
cond.argc != 2) {
695 ast_log(
LOG_WARNING,
"GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
729 oldlist = stack_store->
data;
764 ast_log(
LOG_ERROR,
"Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var);
769 oldlist = stack_store->
data;
825 .
name =
"LOCAL_PEEK",
856 ast_log(
LOG_ERROR,
"STACK_PEEK must be called with a positive peek value\n");
863 ast_log(
LOG_ERROR,
"STACK_PEEK called on a channel without a gosub stack\n");
869 oldlist = stack_store->
data;
890 switch (
args.which[0]) {
915 .
name =
"STACK_PEEK",
943 oldlist = stack_store->
data;
972 const char *saved_context;
973 const char *saved_exten;
975 int saved_hangup_flags;
976 int saved_autoloopflag;
977 int saved_in_subroutine;
982 ast_verb(3,
"%s Internal %s(%s) start\n",
988 if (saved_hangup_flags) {
1005 saved_context, saved_exten, saved_priority);
1024 oldlist = stack_store->
data;
1043 ast_log(
LOG_ERROR,
"%s An async goto just messed up our execution location.\n",
1047 if (!ignore_hangup) {
1065 ast_debug(1,
"Spawn extension (%s,%s,%d) exited with %d on '%s'\n",
1068 ast_verb(2,
"Spawn extension (%s, %s, %d) exited non-zero on '%s'\n",
1077 ast_verb(3,
"%s Internal %s(%s) complete GOSUB_RETVAL=%s\n",
1081 ast_log(
LOG_NOTICE,
"%s Abnormal '%s(%s)' exit. Popping routine return locations.\n",
1109 if (saved_hangup_flags) {
1122 int old_autoloopflag;
1123 int old_in_subroutine;
1125 const char *old_context;
1126 const char *old_extension;
1129 if (argc < 4 || argc > 5) {
1133 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] :
"");
1135 if (sscanf(argv[3],
"%30d", &priority) != 1 || priority < 1) {
1140 ast_log(
LOG_ERROR,
"Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]);
1141 ast_agi_send(agi->
fd, chan,
"200 result=-1 Gosub label not found\n");
1146 ast_agi_send(agi->
fd, chan,
"200 result=-1 Gosub label not found\n");
1151 if (
ast_asprintf(&gosub_args,
"%s,%s,%d(%s)", argv[1], argv[2], priority, argv[4]) < 0) {
1155 if (
ast_asprintf(&gosub_args,
"%s,%s,%d", argv[1], argv[2], priority) < 0) {
1160 ast_agi_send(agi->
fd, chan,
"503 result=-2 Memory allocation failure\n");
1181 old_context, old_extension, old_priority);
1199 oldlist = stack_store->
data;
1210 memset(&args, 0,
sizeof(args));
1234 ast_verb(3,
"%s AGI %s(%s) complete GOSUB_RETVAL=%s\n",
1239 ast_log(
LOG_NOTICE,
"%s Abnormal AGI %s(%s) exit. Popping routine return locations.\n",
1248 abnormal_exit ?
" (abnormal exit)" :
"");
1250 ast_agi_send(agi->
fd, chan,
"200 result=%d Gosub failed\n", res);
1324 .optional_modules =
"res_agi",
void ast_install_stack_functions(const struct ast_app_stack_funcs *funcs)
Set stack application function callbacks.
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
static void balance_stack(struct ast_channel *chan)
Options for ast_pbx_run()
#define ast_channel_lock(chan)
static char exten[AST_MAX_EXTENSION]
Main Channel structure associated with a channel.
#define AST_LIST_LOCK(head)
Locks a list.
Asterisk main include file. File version handling, generic pbx functions.
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
static const char app_gosub[]
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
unsigned int in_subroutine
static const struct ast_datastore_info stack_info
#define ast_set2_flag(p, value, flag)
#define ast_test_flag(p, flag)
const char * ast_var_value(const struct ast_var_t *var)
static struct gosub_stack_frame * gosub_allocate_frame(const char *context, const char *extension, int priority, int in_subroutine, unsigned char arguments)
const char * ast_var_name(const struct ast_var_t *var)
AGI Extension interfaces - Asterisk Gateway Interface.
#define ast_set_flag(p, flag)
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
static int stackpeek_read(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len)
int AST_OPTIONAL_API_NAME() ast_agi_unregister(agi_command *cmd)
static int pop_exec(struct ast_channel *chan, const char *data)
int pbx_checkcondition(const char *condition)
Evaluate a condition.
Structure for a data store type.
#define AST_STANDARD_RAW_ARGS(args, parse)
Structure for a data store object.
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
struct varshead * ast_channel_varshead(struct ast_channel *chan)
static int frame_set_var(struct ast_channel *chan, struct gosub_stack_frame *frame, const char *var, const char *value)
void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, without removing any previously set value...
int ast_unregister_application(const char *app)
Unregister an application.
int ast_channel_priority(const struct ast_channel *chan)
#define ast_verb(level,...)
static int gosub_exec(struct ast_channel *chan, const char *data)
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
static int return_exec(struct ast_channel *chan, const char *data)
static struct ast_custom_function stackpeek_function
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
#define ast_strlen_zero(foo)
#define AST_LIST_HEAD_DESTROY(head)
Destroys a list head structure.
static int gosubif_exec(struct ast_channel *chan, const char *data)
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
static const char * expand_gosub_args(struct ast_channel *chan, const char *args)
#define ast_debug(level,...)
Log a DEBUG message.
static const char app_return[]
General Asterisk PBX channel definitions.
void ast_channel_clear_softhangup(struct ast_channel *chan, int flag)
Clear a set of softhangup flags from a channel.
int AST_OPTIONAL_API_NAME() ast_agi_register(struct ast_module *mod, agi_command *cmd)
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
struct ast_pbx * ast_channel_pbx(const struct ast_channel *chan)
Data structure associated with a custom dialplan function.
enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args)
Execute the PBX in the current thread.
int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
structure to hold extensions
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
#define ast_strdupa(s)
duplicate a string in memory from the stack
static char * orig_exten(int fd, const char *chan, const char *data)
orginate from extension
#define ast_malloc(len)
A wrapper for malloc()
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
const char * ast_channel_exten(const struct ast_channel *chan)
Core PBX routines and definitions.
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
#define AST_NONSTANDARD_RAW_ARGS(args, parse, sep)
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
static struct ast_custom_function peek_function
static int peek_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
void ast_channel_publish_varset(struct ast_channel *chan, const char *variable, const char *value)
Publish a ast_channel_varset for a channel.
Stack applications callback functions.
int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
Find the priority of an extension that has the specified label.
void ast_var_delete(struct ast_var_t *var)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
int ast_softhangup_nolock(struct ast_channel *chan, int reason)
Softly hangup up a channel (no channel lock)
static int gosub_run(struct ast_channel *chan, const char *sub_args, int ignore_hangup)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
#define ast_channel_unlock(chan)
static void parse(struct mgcp_request *req)
#define AST_LIST_HEAD_INIT(head)
Initializes a list head structure.
#define ast_calloc(num, len)
A wrapper for calloc()
#define ast_var_assign(name, value)
static struct agi_command gosub_agi_command
void ast_channel_pbx_set(struct ast_channel *chan, struct ast_pbx *value)
static int local_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid, int *found, int combined_find_spawn)
Launch a new extension (i.e. new stack)
int(* run_sub)(struct ast_channel *chan, const char *args, int ignore_hangup)
Callback for the routine to run a subroutine on a channel.
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
static int load_module(void)
int ast_channel_softhangup_internal_flag(struct ast_channel *chan)
static const char app_pop[]
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
char * strsep(char **str, const char *delims)
void ast_channel_context_set(struct ast_channel *chan, const char *value)
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
const char * ast_channel_name(const struct ast_channel *chan)
static void gosub_free(void *data)
struct gosub_stack_frame::@78 entries
const char * ast_channel_context(const struct ast_channel *chan)
#define ast_datastore_alloc(info, uid)
static const char app_gosubif[]
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
int AST_OPTIONAL_API_NAME() ast_agi_send(int fd, struct ast_channel *chan, char *fmt,...)
#define ASTERISK_GPL_KEY
The text the key() function should return.
void ast_channel_priority_set(struct ast_channel *chan, int value)
Asterisk module definitions.
unsigned int no_hangup_chan
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define ast_custom_function_register(acf)
Register a custom function.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
static int handle_gosub(struct ast_channel *chan, AGI *agi, int argc, const char *const *argv)
static struct ast_custom_function local_function
#define AST_APP_ARG(name)
Define an application argument.
static int local_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static void gosub_release_frame(struct ast_channel *chan, struct gosub_stack_frame *frame)
static int unload_module(void)