37 #include "asterisk/pbx.h"
258 "Variable: LOCAL(%s)\r\n"
261 chan->name, var, value, chan->uniqueid);
287 int len_extension = strlen(extension), len_context = strlen(context);
289 if ((
new =
ast_calloc(1,
sizeof(*
new) + 2 + len_extension + len_context))) {
291 strcpy(new->extension, extension);
292 new->context =
new->extension + len_extension + 1;
293 strcpy(new->context, context);
328 oldlist = stack_store->
data;
333 ast_debug(1,
"%s attempted to pop special return location.\n", app_pop);
342 ast_debug(1,
"%s called with an empty gosub stack\n", app_pop);
354 const char *retval = data;
364 oldlist = stack_store->
data;
431 label =
strsep(&parse,
"(");
435 endparen = strrchr(parse,
')');
444 context =
strsep(&label,
",");
445 exten =
strsep(&label,
",");
446 pri =
strsep(&label,
",");
466 len = strlen(context) + strlen(exten) + strlen(pri) + 3;
468 len += 2 + strlen(parse);
473 snprintf(new_args, len,
"%s,%s,%s", context, exten, pri);
475 snprintf(new_args, len,
"%s,%s,%s(%s)", context, exten, pri, parse);
480 ast_debug(4,
"Gosub args:%s new_args:%s\n", args, new_args ? new_args :
"");
508 ast_log(
LOG_ERROR,
"%s requires an argument: %s([[context,]exten,]priority[(arg1[,...][,argN])])\n", app_gosub, app_gosub);
519 label =
strsep(&parse,
"(");
523 endparen = strrchr(parse,
')');
559 ast_log(
LOG_ERROR,
"Attempt to reach a non-existent destination for %s: (Context:%s, Extension:%s, Priority:%d)\n",
560 app_gosub, dest_context, dest_exten, dest_priority);
570 ast_debug(1,
"Channel %s has no datastore, so we're allocating one.\n",
576 goto error_exit_locked;
584 goto error_exit_locked;
588 stack_store->
data = oldlist;
591 oldlist = stack_store->
data;
599 if (args2.argc > max_argc) {
600 max_argc = args2.argc;
606 goto error_exit_locked;
610 for (i = 0; i < max_argc; i++) {
611 snprintf(argname,
sizeof(argname),
"ARG%d", i + 1);
612 frame_set_var(chan, newframe, argname, i < args2.argc ? args2.argval[i] :
"");
613 ast_debug(1,
"Setting '%s' to '%s'\n", argname, i < args2.argc ? args2.argval[i] :
"");
615 snprintf(argname,
sizeof(argname),
"%u", args2.argc);
652 ast_log(
LOG_WARNING,
"GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
658 if (
cond.argc != 2) {
659 ast_log(
LOG_WARNING,
"GosubIf requires an argument: GosubIf(cond?label1(args):label2(args)\n");
693 oldlist = stack_store->
data;
728 ast_log(
LOG_ERROR,
"Tried to set LOCAL(%s), but we aren't within a Gosub routine\n", var);
733 oldlist = stack_store->
data;
789 .
name =
"LOCAL_PEEK",
820 ast_log(
LOG_ERROR,
"STACK_PEEK must be called with a positive peek value\n");
827 ast_log(
LOG_ERROR,
"STACK_PEEK called on a channel without a gosub stack\n");
833 oldlist = stack_store->
data;
854 switch (
args.which[0]) {
879 .
name =
"STACK_PEEK",
908 oldlist = stack_store->
data;
938 const char *saved_context;
939 const char *saved_exten;
941 int saved_hangup_flags;
942 int saved_autoloopflag;
947 ast_verb(3,
"%s Internal %s(%s) start\n", chan->
name, app_gosub, sub_args);
952 if (saved_hangup_flags) {
966 saved_context, saved_exten, saved_priority);
970 ast_debug(4,
"%s exited with status %d\n", app_gosub, res);
985 oldlist = stack_store->
data;
1008 ast_log(
LOG_ERROR,
"%s An async goto just messed up our execution location.\n",
1012 if (!ignore_hangup) {
1028 ast_debug(1,
"Spawn extension (%s,%s,%d) exited with %d on '%s'\n",
1030 ast_verb(2,
"Spawn extension (%s, %s, %d) exited non-zero on '%s'\n",
1035 if (chan->
priority == saved_priority
1036 && !strcmp(chan->
context, saved_context)
1037 && !strcmp(chan->
exten, saved_exten)) {
1038 ast_verb(3,
"%s Internal %s(%s) complete GOSUB_RETVAL=%s\n",
1039 chan->
name, app_gosub, sub_args,
1042 ast_log(
LOG_NOTICE,
"%s Abnormal '%s(%s)' exit. Popping routine return locations.\n",
1043 chan->
name, app_gosub, sub_args);
1066 if (saved_hangup_flags) {
1079 int old_autoloopflag;
1081 const char *old_context;
1082 const char *old_extension;
1085 if (argc < 4 || argc > 5) {
1089 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] :
"");
1091 if (sscanf(argv[3],
"%30d", &priority) != 1 || priority < 1) {
1096 ast_log(
LOG_ERROR,
"Priority '%s' not found in '%s@%s'\n", argv[3], argv[2], argv[1]);
1097 ast_agi_send(agi->
fd, chan,
"200 result=-1 Gosub label not found\n");
1102 ast_agi_send(agi->
fd, chan,
"200 result=-1 Gosub label not found\n");
1107 if (
ast_asprintf(&gosub_args,
"%s,%s,%d(%s)", argv[1], argv[2], priority, argv[4]) < 0) {
1111 if (
ast_asprintf(&gosub_args,
"%s,%s,%d", argv[1], argv[2], priority) < 0) {
1116 ast_agi_send(agi->
fd, chan,
"503 result=-2 Memory allocation failure\n");
1122 ast_verb(3,
"%s AGI %s(%s) start\n", chan->
name, app_gosub, gosub_args);
1133 ast_debug(4,
"%s Original location: %s,%s,%d\n", chan->
name,
1134 old_context, old_extension, old_priority);
1152 oldlist = stack_store->
data;
1163 memset(&args, 0,
sizeof(args));
1185 && !strcmp(chan->
context, old_context)
1186 && !strcmp(chan->
exten, old_extension)) {
1187 ast_verb(3,
"%s AGI %s(%s) complete GOSUB_RETVAL=%s\n",
1188 chan->
name, app_gosub, gosub_args,
1192 ast_log(
LOG_NOTICE,
"%s Abnormal AGI %s(%s) exit. Popping routine return locations.\n",
1193 chan->
name, app_gosub, gosub_args);
1201 abnormal_exit ?
" (abnormal exit)" :
"");
1203 ast_agi_send(agi->
fd, chan,
"200 result=%d Gosub failed\n", res);
1273 .nonoptreq =
"res_agi",
static void balance_stack(struct ast_channel *chan)
struct gosub_stack_frame::@64 entries
Options for ast_pbx_run()
#define ast_channel_lock(chan)
static char exten[AST_MAX_EXTENSION]
Main Channel structure associated with a channel.
char * str
Subscriber phone number (Malloced)
#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.
struct ast_party_caller caller
Channel Caller ID information.
char * strsep(char **str, const char *delims)
#define ast_set2_flag(p, value, flag)
#define ast_test_flag(p, flag)
const char * ast_var_value(const struct ast_var_t *var)
int ast_agi_register(struct ast_module *mod, agi_command *cmd)
Registers an AGI command.
struct ast_var_t * ast_var_assign(const char *name, const char *value)
char context[AST_MAX_CONTEXT]
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_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)
static int pop_exec(struct ast_channel *chan, const char *data)
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
int pbx_checkcondition(const char *condition)
Evaluate a condition.
Structure for a data store type.
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
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.
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...
#define EVENT_FLAG_DIALPLAN
int ast_unregister_application(const char *app)
Unregister an application.
void ast_var_delete(struct ast_var_t *var)
#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_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.
struct ast_party_id id
Caller party ID.
static const char * expand_gosub_args(struct ast_channel *chan, const char *args)
#define ast_asprintf(a, b, c...)
#define ast_debug(level,...)
Log a DEBUG message.
static const char app_return[]
General Asterisk PBX channel definitions.
int(* run_sub)(struct ast_channel *chan, const char *args, int ignore_hangup)
Callback for the routine to run a subroutine on a channel.
static struct gosub_stack_frame * gosub_allocate_frame(const char *context, const char *extension, int priority, unsigned char arguments)
static force_inline int attribute_pure ast_strlen_zero(const char *s)
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)
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
static char * orig_exten(int fd, const char *chan, const char *data)
orginate from extension
#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.
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define ast_strdupa(s)
duplicate a string in memory from the stack
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)
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.
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
const ast_string_field name
char * ast_skip_blanks(const char *str)
Gets a pointer to the first non-whitespace character in a string.
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
struct ast_datastore * ast_datastore_alloc(const struct ast_datastore_info *info, const char *uid)
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.
static struct ast_datastore_info stack_info
static struct agi_command gosub_agi_command
void ast_install_stack_functions(const struct ast_app_stack_funcs *funcs)
Set stack application function callbacks.
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 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)
static const char app_pop[]
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
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...
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
static void gosub_free(void *data)
#define AST_STANDARD_RAW_ARGS(args, parse)
#define AST_APP_ARG(name)
Define an application argument.
static const char app_gosubif[]
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define ASTERISK_GPL_KEY
The text the key() function should return.
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
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.
unsigned char valid
TRUE if the number information is valid/present.
#define ast_custom_function_register(acf)
Register a custom function.
int ast_agi_unregister(struct ast_module *mod, agi_command *cmd)
Unregisters an AGI command.
int ast_agi_send(int fd, struct ast_channel *chan, char *fmt,...)
Sends a string of text to an application connected via AGI.
char exten[AST_MAX_EXTENSION]
#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)
#define AST_NONSTANDARD_RAW_ARGS(args, parse, sep)
static struct ast_custom_function local_function
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
static int local_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
struct ast_party_number number
Subscriber phone number.
static void gosub_release_frame(struct ast_channel *chan, struct gosub_stack_frame *frame)
static int unload_module(void)