diff options
-rwxr-xr-x | ChangeLog | 6 | ||||
-rwxr-xr-x | apps/Makefile | 2 | ||||
-rwxr-xr-x | apps/app_stack.c | 197 | ||||
-rwxr-xr-x | include/asterisk/pbx.h | 1 | ||||
-rwxr-xr-x | pbx.c | 20 |
5 files changed, 224 insertions, 2 deletions
@@ -1,5 +1,9 @@ 2005-11-08 Kevin P. Fleming <kpfleming@digium.com> - + + * pbx.c (pbx_builtin_pushvar_helper): add new API function for setting variables that can exist multiple times (issue #2720) + * apps/Makefile (APPS): add app_stack (issue #2720) + * apps/app_stack.c: new applications (issue #2720) + * apps/app_meetme.c: fix two audio delay problems related to using non-Zap channels in conferences (issues #3599 and #4252) * configs/meetme.conf.sample: add documentation of new 'audiobuffers' setting to control buffering on incoming audio from non-Zap channels diff --git a/apps/Makefile b/apps/Makefile index 6bf2171ea..58118590d 100755 --- a/apps/Makefile +++ b/apps/Makefile @@ -29,7 +29,7 @@ APPS=app_dial.so app_playback.so app_voicemail.so app_directory.so app_mp3.so\ app_dumpchan.so app_waitforsilence.so app_while.so app_setrdnis.so \ app_md5.so app_readfile.so app_chanspy.so app_settransfercapability.so \ app_dictate.so app_externalivr.so app_directed_pickup.so \ - app_mixmonitor.so + app_mixmonitor.so app_stack.so # # Obsolete things... diff --git a/apps/app_stack.c b/apps/app_stack.c new file mode 100755 index 000000000..d24f2267f --- /dev/null +++ b/apps/app_stack.c @@ -0,0 +1,197 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (c) 2004-2005 Tilghman Lesher <app_stack_v002@the-tilghman.com>. + * + * This code is released by the author with no restrictions on usage. + * + * See http://www.asterisk.org for more information about + * the Asterisk project. Please do not directly contact + * any of the maintainers of this project for assistance; + * the project provides a web site, mailing lists and IRC + * channels for your use. + * + * This program is free software, distributed under the terms of + * the GNU General Public License Version 2. See the LICENSE file + * at the top of the source tree. + */ + +/*! \file + * + * \brief Stack applications Gosub, Return, etc. + * + * \ingroup applications + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include "asterisk/options.h" +#include "asterisk/logger.h" +#include "asterisk/channel.h" +#include "asterisk/chanvars.h" +#include "asterisk/pbx.h" +#include "asterisk/module.h" +#include "asterisk/config.h" + +#define STACKVAR "~GOSUB~STACK~" + +static const char *tdesc = "Stack Routines"; + +static const char *app_gosub = "Gosub"; +static const char *app_gosubif = "GosubIf"; +static const char *app_return = "Return"; +static const char *app_pop = "StackPop"; + +static const char *gosub_synopsis = "Jump to label, saving return address"; +static const char *gosubif_synopsis = "Jump to label, saving return address"; +static const char *return_synopsis = "Return from gosub routine"; +static const char *pop_synopsis = "Remove one address from gosub stack"; + +static const char *gosub_descrip = +"Gosub([[context|]exten|]priority)\n" +" Jumps to the label specified, saving the return address.\n" +" Returns 0 if the label exists or -1 otherwise.\n"; +static const char *gosubif_descrip = +"Gosub(condition?labeliftrue[:labeliffalse])\n" +" If the condition is true, then jump to labeliftrue. If false, jumps to\n" +"labeliffalse, if specified. In either case, a jump saves the return point\n" +"in the dialplan, to be returned to with a Return.\n" +" Returns 0 if the label exists or -1 otherwise.\n"; +static const char *return_descrip = +"Return()\n" +" Jumps to the last label in the stack, removing it.\n" +" Returns 0 if there's a label in the stack or -1 otherwise.\n"; +static const char *pop_descrip = +"StackPop()\n" +" Removes last label in the stack, discarding it.\n" +" Always returns 0, even if the stack is empty.\n"; + +STANDARD_LOCAL_USER; + +LOCAL_USER_DECL; + +static int pop_exec(struct ast_channel *chan, void *data) +{ + pbx_builtin_setvar_helper(chan, STACKVAR, NULL); + + return 0; +} + +static int return_exec(struct ast_channel *chan, void *data) +{ + char *label = pbx_builtin_getvar_helper(chan, STACKVAR); + + if (ast_strlen_zero(label)) { + ast_log(LOG_ERROR, "Return without Gosub: stack is empty\n"); + return -1; + } else if (ast_parseable_goto(chan, label)) { + ast_log(LOG_WARNING, "No next statement after Gosub?\n"); + return -1; + } + + pbx_builtin_setvar_helper(chan, STACKVAR, NULL); + return 0; +} + +static int gosub_exec(struct ast_channel *chan, void *data) +{ + char newlabel[AST_MAX_EXTENSION * 2 + 3 + 11]; + struct localuser *u; + + if (ast_strlen_zero(data)) { + ast_log(LOG_ERROR, "%s requires an argument: %s([[context|]exten|]priority)\n", app_gosub, app_gosub); + return -1; + } + + LOCAL_USER_ADD(u); + snprintf(newlabel, sizeof(newlabel), "%s|%s|%d", chan->context, chan->exten, chan->priority + 1); + + if (ast_parseable_goto(chan, data)) { + LOCAL_USER_REMOVE(u); + return -1; + } + + pbx_builtin_pushvar_helper(chan, STACKVAR, newlabel); + LOCAL_USER_REMOVE(u); + + return 0; +} + +static int gosubif_exec(struct ast_channel *chan, void *data) +{ + struct localuser *u; + char *condition="", *label1, *label2, *args; + int res=0; + + if (ast_strlen_zero(data)) { + ast_log(LOG_WARNING, "GosubIf requires an argument\n"); + return 0; + } + + args = ast_strdupa((char *)data); + if (!args) { + ast_log(LOG_ERROR, "Out of memory\n"); + return -1; + } + + LOCAL_USER_ADD(u); + + condition = strsep(&args, "?"); + label1 = strsep(&args, ":"); + label2 = args; + + if (ast_true(condition)) { + if (label1) { + res = gosub_exec(chan, label1); + } + } else if (label2) { + res = gosub_exec(chan, label2); + } + + LOCAL_USER_REMOVE(u); + return res; +} + +int unload_module(void) +{ + ast_unregister_application(app_return); + ast_unregister_application(app_pop); + ast_unregister_application(app_gosubif); + ast_unregister_application(app_gosub); + + STANDARD_HANGUP_LOCALUSERS; + + return 0; +} + +int load_module(void) +{ + ast_register_application(app_pop, pop_exec, pop_synopsis, pop_descrip); + ast_register_application(app_return, return_exec, return_synopsis, return_descrip); + ast_register_application(app_gosubif, gosubif_exec, gosubif_synopsis, gosubif_descrip); + ast_register_application(app_gosub, gosub_exec, gosub_synopsis, gosub_descrip); + + return 0; +} + +char *description(void) +{ + return (char *) tdesc; +} + +int usecount(void) +{ + int res; + + STANDARD_USECOUNT(res); + + return res; +} + +char *key() +{ + return ASTERISK_GPL_KEY; +} diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index 4a5beb78e..a10546174 100755 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -606,6 +606,7 @@ struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw int pbx_builtin_serialize_variables(struct ast_channel *chan, char *buf, size_t size); extern char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name); +extern void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value); extern void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value); extern void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp); extern void pbx_builtin_clear_globals(void); @@ -5897,6 +5897,26 @@ char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name) return NULL; } +void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value) +{ + struct ast_var_t *newvariable; + struct varshead *headp; + + if (name[strlen(name)-1] == ')') { + ast_log(LOG_WARNING, "Cannot push a value onto a function\n"); + return ast_func_write(chan, name, value); + } + + headp = (chan) ? &chan->varshead : &globals; + + if (value) { + if ((option_verbose > 1) && (headp == &globals)) + ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value); + newvariable = ast_var_assign(name, value); + AST_LIST_INSERT_HEAD(headp, newvariable, entries); + } +} + void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value) { struct ast_var_t *newvariable; |