diff options
Diffstat (limited to '1.4.26.1/funcs')
25 files changed, 5186 insertions, 0 deletions
diff --git a/1.4.26.1/funcs/Makefile b/1.4.26.1/funcs/Makefile new file mode 100644 index 000000000..7b55e6efb --- /dev/null +++ b/1.4.26.1/funcs/Makefile @@ -0,0 +1,32 @@ +# +# Asterisk -- A telephony toolkit for Linux. +# +# Makefile for dialplan functions +# +# Copyright (C) 2005-2006, Digium, Inc. +# +# This program is free software, distributed under the terms of +# the GNU General Public License +# + +-include ../menuselect.makeopts ../menuselect.makedeps + +MENUSELECT_CATEGORY=FUNCS +MENUSELECT_DESCRIPTION=Dialplan Functions + +ALL_C_MODS:=$(patsubst %.c,%,$(wildcard func_*.c)) +ALL_CC_MODS:=$(patsubst %.cc,%,$(wildcard func_*.cc)) + +C_MODS:=$(filter-out $(MENUSELECT_FUNCS),$(ALL_C_MODS)) +CC_MODS:=$(filter-out $(MENUSELECT_FUNCS),$(ALL_CC_MODS)) + +LOADABLE_MODS:=$(C_MODS) $(CC_MODS) + +ifneq ($(findstring funcs,$(MENUSELECT_EMBED)),) + EMBEDDED_MODS:=$(LOADABLE_MODS) + LOADABLE_MODS:= +endif + +all: _all + +include $(ASTTOPDIR)/Makefile.moddir_rules diff --git a/1.4.26.1/funcs/func_audiohookinherit.c b/1.4.26.1/funcs/func_audiohookinherit.c new file mode 100644 index 000000000..6936864e3 --- /dev/null +++ b/1.4.26.1/funcs/func_audiohookinherit.c @@ -0,0 +1,282 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2008, Digium, Inc. + * + * Mark Michelson <mmichelson@digium.com> + * + * 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. + * + * Please follow coding guidelines + * http://svn.digium.com/view/asterisk/trunk/doc/CODING-GUIDELINES + */ + +/*! \file + * + * \brief Audiohook inheritance function + * + * \author \verbatim Mark Michelson <mmichelson@digium.com> \endverbatim + * + * \ingroup functions + */ + +#include "asterisk.h" +#include "asterisk/channel.h" +#include "asterisk/audiohook.h" +#include "asterisk/pbx.h" +#include "asterisk/module.h" +#include "asterisk/options.h" + +struct inheritable_audiohook { + AST_LIST_ENTRY(inheritable_audiohook) list; + char source[1]; +}; + +struct audiohook_inheritance_datastore { + AST_LIST_HEAD (, inheritable_audiohook) allowed_list; +}; + +static void audiohook_inheritance_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan); +static void audiohook_inheritance_destroy (void *data); +static const struct ast_datastore_info audiohook_inheritance_info = { + .type = "audiohook inheritance", + .destroy = audiohook_inheritance_destroy, + .chan_fixup = audiohook_inheritance_fixup, +}; + +/*! \brief Move audiohooks as defined by previous calls to the AUDIOHOOK_INHERIT function + * + * Move allowed audiohooks from the old channel to the new channel. + * + * \param data The ast_datastore containing audiohook inheritance information that will be moved + * \param old_chan The "clone" channel from a masquerade. We are moving the audiohook in question off of this channel + * \param new_chan The "original" channel from a masquerade. We are moving the audiohook in question to this channel + * \return Void + */ +static void audiohook_inheritance_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan) +{ + struct inheritable_audiohook *audiohook = NULL; + struct audiohook_inheritance_datastore *datastore = data; + + if (option_debug > 1) { + ast_log(LOG_DEBUG, "inheritance fixup occurring for channels %s(%p) and %s(%p)", old_chan->name, old_chan, new_chan->name, new_chan); + } + + AST_LIST_TRAVERSE(&datastore->allowed_list, audiohook, list) { + ast_audiohook_move_by_source(old_chan, new_chan, audiohook->source); + if (option_debug > 2) { + ast_log(LOG_DEBUG, "Moved audiohook %s from %s(%p) to %s(%p)\n", + audiohook->source, old_chan->name, old_chan, new_chan->name, new_chan); + } + } + return; +} + +/*! \brief Destroy dynamically allocated data on an audiohook_inheritance_datastore + * + * \param data Pointer to the audiohook_inheritance_datastore in question. + * \return Void + */ +static void audiohook_inheritance_destroy(void *data) +{ + struct audiohook_inheritance_datastore *audiohook_inheritance_datastore = data; + struct inheritable_audiohook *inheritable_audiohook = NULL; + + while ((inheritable_audiohook = AST_LIST_REMOVE_HEAD(&audiohook_inheritance_datastore->allowed_list, list))) { + ast_free(inheritable_audiohook); + } +} + +/*! \brief create an audiohook_inheritance_datastore and attach it to a channel + * + * \param chan The channel to which we wish to attach the new datastore + * \return Returns the newly created audiohook_inheritance_datastore or NULL on error + */ +static struct audiohook_inheritance_datastore *setup_inheritance_datastore(struct ast_channel *chan) +{ + struct ast_datastore *datastore = NULL; + struct audiohook_inheritance_datastore *audiohook_inheritance_datastore = NULL; + + if (!(datastore = ast_channel_datastore_alloc(&audiohook_inheritance_info, NULL))) { + return NULL; + } + + if (!(audiohook_inheritance_datastore = ast_calloc(1, sizeof(*audiohook_inheritance_datastore)))) { + ast_channel_datastore_free(datastore); + return NULL; + } + + datastore->data = audiohook_inheritance_datastore; + ast_channel_lock(chan); + ast_channel_datastore_add(chan, datastore); + ast_channel_unlock(chan); + return audiohook_inheritance_datastore; +} + +/*! \brief Create a new inheritable_audiohook structure and add it to an audiohook_inheritance_datastore + * + * \param audiohook_inheritance_datastore The audiohook_inheritance_datastore we want to add the new inheritable_audiohook to + * \param source The audiohook source for the newly created inheritable_audiohook + * \retval 0 Success + * \retval non-zero Failure + */ +static int setup_inheritable_audiohook(struct audiohook_inheritance_datastore *audiohook_inheritance_datastore, const char *source) +{ + struct inheritable_audiohook *inheritable_audiohook = NULL; + + inheritable_audiohook = ast_calloc(1, sizeof(*inheritable_audiohook) + strlen(source)); + + if (!inheritable_audiohook) { + return -1; + } + + strcpy(inheritable_audiohook->source, source); + AST_LIST_INSERT_TAIL(&audiohook_inheritance_datastore->allowed_list, inheritable_audiohook, list); + if (option_debug > 2) { + ast_log(LOG_DEBUG, "Set audiohook %s to be inheritable\n", source); + } + return 0; +} + +/*! \brief Set the permissibility of inheritance for a particular audiohook source on a channel + * + * For details regarding what happens in the function, see the inline comments + * + * \param chan The channel we are operating on + * \param function The name of the dialplan function (AUDIOHOOK_INHERIT) + * \param data The audiohook source for which we are setting inheritance permissions + * \param value The value indicating the permission for audiohook inheritance + */ +static int func_inheritance_write(struct ast_channel *chan, char *function, char *data, const char *value) +{ + int allow; + struct ast_datastore *datastore = NULL; + struct audiohook_inheritance_datastore *inheritance_datastore = NULL; + struct inheritable_audiohook *inheritable_audiohook; + + /* Step 1: Get data from function call */ + if (ast_strlen_zero(data)) { + ast_log(LOG_WARNING, "No argument provided to INHERITANCE function.\n"); + return -1; + } + + if (ast_strlen_zero(value)) { + ast_log(LOG_WARNING, "No value provided to INHERITANCE function.\n"); + return -1; + } + + allow = ast_true(value); + + /* Step 2: retrieve or set up datastore */ + ast_channel_lock(chan); + if (!(datastore = ast_channel_datastore_find(chan, &audiohook_inheritance_info, NULL))) { + ast_channel_unlock(chan); + /* In the case where we cannot find the datastore, we can take a few shortcuts */ + if (!allow) { + if (option_debug) { + ast_log(LOG_DEBUG, "Audiohook %s is already set to not be inheritable on channel %s\n", data, chan->name); + } + return 0; + } else if (!(inheritance_datastore = setup_inheritance_datastore(chan))) { + ast_log(LOG_WARNING, "Unable to set up audiohook inheritance datastore on channel %s\n", chan->name); + return -1; + } else { + return setup_inheritable_audiohook(inheritance_datastore, data); + } + } else { + inheritance_datastore = datastore->data; + } + ast_channel_unlock(chan); + + /* Step 3: Traverse the list to see if we're trying something redundant */ + + AST_LIST_TRAVERSE_SAFE_BEGIN(&inheritance_datastore->allowed_list, inheritable_audiohook, list) { + if (!strcasecmp(inheritable_audiohook->source, data)) { + if (allow) { + if (option_debug > 1) { + ast_log(LOG_DEBUG, "Audiohook source %s is already set up to be inherited from channel %s\n", data, chan->name); + } + return 0; + } else { + if (option_debug > 1) { + ast_log(LOG_DEBUG, "Removing inheritability of audiohook %s from channel %s\n", data, chan->name); + } + AST_LIST_REMOVE_CURRENT(&inheritance_datastore->allowed_list, list); + ast_free(inheritable_audiohook); + return 0; + } + } + } + AST_LIST_TRAVERSE_SAFE_END; + + /* Step 4: There is no step 4 */ + + /* Step 5: This means we are addressing an audiohook source which we have not encountered yet for the channel. Create a new inheritable + * audiohook structure if we're allowing inheritance, or just return if not + */ + + if (allow) { + return setup_inheritable_audiohook(inheritance_datastore, data); + } else { + if (option_debug) { + ast_log(LOG_DEBUG, "Audiohook %s is already set to not be inheritable on channel %s\n", data, chan->name); + } + return 0; + } +} + +static struct ast_custom_function inheritance_function = { + .name = "AUDIOHOOK_INHERIT", + .synopsis = "Set whether an audiohook may be inherited to another channel", + .syntax = "AUDIOHOOK_INHERIT(source)", + .desc = + "By enabling audiohook inheritance on the channel, you are giving\n" + "permission for an audiohook to be inherited by a descendent channel.\n" + "Inheritance may be be disabled at any point as well.\n" + "\n" + " Example scenario:\n" + " exten => 2000,1,MixMonitor(blah.wav)\n" + " exten => 2000,n,Set(AUDIOHOOK_INHERIT(MixMonitor)=yes)\n" + " exten => 2000,n,Dial(SIP/2000)\n" + "\n" + " exten => 4000,1,Dial(SIP/4000)\n" + "\n" + " exten => 5000,1,MixMonitor(blah2.wav)\n" + " exten => 5000,n,Dial(SIP/5000)\n" + "\n" + " In this basic dialplan scenario, let's consider the following sample calls\n" + " Call 1: Caller dials 2000. The person who answers then executes an attended\n" + " transfer to 4000.\n" + " Result: Since extension 2000 set MixMonitor to be inheritable, after the\n" + " transfer to 400 has completed, the call will continue to be recorded\n" + " to blah.wav\n" + "\n" + " Call 2: Caller dials 5000. The person who answers then executes an attended\n" + " transfer to 4000.\n" + " Result: Since extension 5000 did not set MixMonitor to be inheritable, the\n" + " recording will stop once the call has been transferred to 4000.\n", + .write = func_inheritance_write, +}; + +static int unload_module(void) +{ + return ast_custom_function_unregister(&inheritance_function); +} + +static int load_module(void) +{ + if (ast_custom_function_register(&inheritance_function)) { + return AST_MODULE_LOAD_DECLINE; + } else { + return AST_MODULE_LOAD_SUCCESS; + } +} +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Audiohook inheritance function"); diff --git a/1.4.26.1/funcs/func_base64.c b/1.4.26.1/funcs/func_base64.c new file mode 100644 index 000000000..463e6dd87 --- /dev/null +++ b/1.4.26.1/funcs/func_base64.c @@ -0,0 +1,94 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2005 - 2006, Digium, Inc. + * Copyright (C) 2005, Claude Patry + * + * 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 Use the base64 as functions + * + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/logger.h" +#include "asterisk/utils.h" +#include "asterisk/app.h" + +static int base64_encode(struct ast_channel *chan, char *cmd, char *data, + char *buf, size_t len) +{ + if (ast_strlen_zero(data)) { + ast_log(LOG_WARNING, "Syntax: BASE64_ENCODE(<data>) - missing argument!\n"); + return -1; + } + + ast_base64encode(buf, (unsigned char *) data, strlen(data), len); + + return 0; +} + +static int base64_decode(struct ast_channel *chan, char *cmd, char *data, + char *buf, size_t len) +{ + if (ast_strlen_zero(data)) { + ast_log(LOG_WARNING, "Syntax: BASE64_DECODE(<base_64 string>) - missing argument!\n"); + return -1; + } + + ast_base64decode((unsigned char *) buf, data, len); + + return 0; +} + +static struct ast_custom_function base64_encode_function = { + .name = "BASE64_ENCODE", + .synopsis = "Encode a string in base64", + .desc = "Returns the base64 string\n", + .syntax = "BASE64_ENCODE(<string>)", + .read = base64_encode, +}; + +static struct ast_custom_function base64_decode_function = { + .name = "BASE64_DECODE", + .synopsis = "Decode a base64 string", + .desc = "Returns the plain text string\n", + .syntax = "BASE64_DECODE(<base64_string>)", + .read = base64_decode, +}; + +static int unload_module(void) +{ + return ast_custom_function_unregister(&base64_encode_function) | + ast_custom_function_unregister(&base64_decode_function); +} + +static int load_module(void) +{ + return ast_custom_function_register(&base64_encode_function) | + ast_custom_function_register(&base64_decode_function); +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "base64 encode/decode dialplan functions"); diff --git a/1.4.26.1/funcs/func_callerid.c b/1.4.26.1/funcs/func_callerid.c new file mode 100644 index 000000000..86c54883e --- /dev/null +++ b/1.4.26.1/funcs/func_callerid.c @@ -0,0 +1,187 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 1999-2006, Digium, Inc. + * + * 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 Caller ID related dialplan functions + * + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/logger.h" +#include "asterisk/utils.h" +#include "asterisk/app.h" +#include "asterisk/options.h" +#include "asterisk/callerid.h" + +static int callerid_read(struct ast_channel *chan, char *cmd, char *data, + char *buf, size_t len) +{ + int res = -1; + char *opt = data; + + if (!chan) + return -1; + + if (strchr(opt, '|')) { + char name[80], num[80]; + + data = strsep(&opt, "|"); + ast_callerid_split(opt, name, sizeof(name), num, sizeof(num)); + + if (!strncasecmp("all", data, 3)) { + snprintf(buf, len, "\"%s\" <%s>", name, num); + res = 0; + } else if (!strncasecmp("name", data, 4)) { + ast_copy_string(buf, name, len); + res = 0; + } else if (!strncasecmp("num", data, 3) || + !strncasecmp("number", data, 6)) { + + ast_copy_string(buf, num, len); + res = 0; + } else { + ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data); + } + } else { + ast_channel_lock(chan); + + if (!strncasecmp("all", data, 3)) { + snprintf(buf, len, "\"%s\" <%s>", + S_OR(chan->cid.cid_name, ""), + S_OR(chan->cid.cid_num, "")); + res = 0; + } else if (!strncasecmp("name", data, 4)) { + if (chan->cid.cid_name) { + ast_copy_string(buf, chan->cid.cid_name, len); + res = 0; + } + } else if (!strncasecmp("num", data, 3) + || !strncasecmp("number", data, 6)) { + if (chan->cid.cid_num) { + ast_copy_string(buf, chan->cid.cid_num, len); + res = 0; + } + } else if (!strncasecmp("ani", data, 3)) { + if (chan->cid.cid_ani) { + ast_copy_string(buf, chan->cid.cid_ani, len); + res = 0; + } + } else if (!strncasecmp("dnid", data, 4)) { + if (chan->cid.cid_dnid) { + ast_copy_string(buf, chan->cid.cid_dnid, len); + res = 0; + } + } else if (!strncasecmp("rdnis", data, 5)) { + if (chan->cid.cid_rdnis) { + ast_copy_string(buf, chan->cid.cid_rdnis, len); + res = 0; + } + } else { + ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data); + } + + ast_channel_unlock(chan); + } + + return res; +} + +static int callerid_write(struct ast_channel *chan, char *cmd, char *data, + const char *value) +{ + if (!value || !chan) + return -1; + + if (!strncasecmp("all", data, 3)) { + char name[256]; + char num[256]; + + if (!ast_callerid_split(value, name, sizeof(name), num, sizeof(num))) { + ast_set_callerid(chan, num, name, num); + if (chan->cdr) + ast_cdr_setcid(chan->cdr, chan); + } + } else if (!strncasecmp("name", data, 4)) { + ast_set_callerid(chan, NULL, value, NULL); + if (chan->cdr) + ast_cdr_setcid(chan->cdr, chan); + } else if (!strncasecmp("num", data, 3) || + !strncasecmp("number", data, 6)) { + ast_set_callerid(chan, value, NULL, NULL); + if (chan->cdr) + ast_cdr_setcid(chan->cdr, chan); + } else if (!strncasecmp("ani", data, 3)) { + ast_set_callerid(chan, NULL, NULL, value); + if (chan->cdr) + ast_cdr_setcid(chan->cdr, chan); + } else if (!strncasecmp("dnid", data, 4)) { + ast_channel_lock(chan); + if (chan->cid.cid_dnid) + free(chan->cid.cid_dnid); + chan->cid.cid_dnid = ast_strdup(value); + if (chan->cdr) + ast_cdr_setcid(chan->cdr, chan); + ast_channel_unlock(chan); + } else if (!strncasecmp("rdnis", data, 5)) { + ast_channel_lock(chan); + if (chan->cid.cid_rdnis) + free(chan->cid.cid_rdnis); + chan->cid.cid_rdnis = ast_strdup(value); + if (chan->cdr) + ast_cdr_setcid(chan->cdr, chan); + ast_channel_unlock(chan); + } else { + ast_log(LOG_ERROR, "Unknown callerid data type '%s'.\n", data); + } + + return 0; +} + +static struct ast_custom_function callerid_function = { + .name = "CALLERID", + .synopsis = "Gets or sets Caller*ID data on the channel.", + .syntax = "CALLERID(datatype[,<optional-CID>])", + .desc = + "Gets or sets Caller*ID data on the channel. The allowable datatypes\n" + "are \"all\", \"name\", \"num\", \"ANI\", \"DNID\", \"RDNIS\".\n" + "Uses channel callerid by default or optional callerid, if specified.\n", + .read = callerid_read, + .write = callerid_write, +}; + +static int unload_module(void) +{ + return ast_custom_function_unregister(&callerid_function); +} + +static int load_module(void) +{ + return ast_custom_function_register(&callerid_function); +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Caller ID related dialplan function"); diff --git a/1.4.26.1/funcs/func_cdr.c b/1.4.26.1/funcs/func_cdr.c new file mode 100644 index 000000000..4e90246c4 --- /dev/null +++ b/1.4.26.1/funcs/func_cdr.c @@ -0,0 +1,185 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 1999-2006, Digium, Inc. + * + * Portions Copyright (C) 2005, Anthony Minessale II + * + * 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 Call Detail Record related dialplan functions + * + * \author Anthony Minessale II + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/logger.h" +#include "asterisk/utils.h" +#include "asterisk/app.h" +#include "asterisk/cdr.h" + +enum { + OPT_RECURSIVE = (1 << 0), + OPT_UNPARSED = (1 << 1), + OPT_LAST = (1 << 2), + OPT_SKIPLOCKED = (1 << 3), +} cdr_option_flags; + +AST_APP_OPTIONS(cdr_func_options, { + AST_APP_OPTION('l', OPT_LAST), + AST_APP_OPTION('r', OPT_RECURSIVE), + AST_APP_OPTION('s', OPT_SKIPLOCKED), + AST_APP_OPTION('u', OPT_UNPARSED), +}); + +static int cdr_read(struct ast_channel *chan, char *cmd, char *parse, + char *buf, size_t len) +{ + char *ret; + struct ast_flags flags = { 0 }; + struct ast_cdr *cdr = chan ? chan->cdr : NULL; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(variable); + AST_APP_ARG(options); + ); + + if (ast_strlen_zero(parse)) + return -1; + + if (!cdr) + return -1; + + AST_STANDARD_APP_ARGS(args, parse); + + if (!ast_strlen_zero(args.options)) + ast_app_parse_options(cdr_func_options, &flags, NULL, args.options); + + if (ast_test_flag(&flags, OPT_LAST)) + while (cdr->next) + cdr = cdr->next; + + if (ast_test_flag(&flags, OPT_SKIPLOCKED)) + while (ast_test_flag(cdr, AST_CDR_FLAG_LOCKED) && cdr->next) + cdr = cdr->next; + + ast_cdr_getvar(cdr, args.variable, &ret, buf, len, + ast_test_flag(&flags, OPT_RECURSIVE), + ast_test_flag(&flags, OPT_UNPARSED)); + + return ret ? 0 : -1; +} + +static int cdr_write(struct ast_channel *chan, char *cmd, char *parse, + const char *value) +{ + struct ast_cdr *cdr = chan ? chan->cdr : NULL; + struct ast_flags flags = { 0 }; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(variable); + AST_APP_ARG(options); + ); + + if (ast_strlen_zero(parse) || !value || !chan) + return -1; + + if (!cdr) + return -1; + + AST_STANDARD_APP_ARGS(args, parse); + + if (!ast_strlen_zero(args.options)) + ast_app_parse_options(cdr_func_options, &flags, NULL, args.options); + + if (ast_test_flag(&flags, OPT_LAST)) + while (cdr->next) + cdr = cdr->next; + + if (!strcasecmp(args.variable, "accountcode")) /* the 'l' flag doesn't apply to setting the accountcode, userfield, or amaflags */ + ast_cdr_setaccount(chan, value); + else if (!strcasecmp(args.variable, "userfield")) + ast_cdr_setuserfield(chan, value); + else if (!strcasecmp(args.variable, "amaflags")) + ast_cdr_setamaflags(chan, value); + else + ast_cdr_setvar(cdr, args.variable, value, ast_test_flag(&flags, OPT_RECURSIVE)); + /* No need to worry about the u flag, as all fields for which setting + * 'u' would do anything are marked as readonly. */ + + return 0; +} + +static struct ast_custom_function cdr_function = { + .name = "CDR", + .synopsis = "Gets or sets a CDR variable", + .syntax = "CDR(<name>[|options])", + .read = cdr_read, + .write = cdr_write, + .desc = +"Options:\n" +" 'l' uses the most recent CDR on a channel with multiple records\n" +" 'r' searches the entire stack of CDRs on the channel\n" +" 's' skips any CDR's that are marked 'LOCKED' due to forkCDR() calls.\n" +" (on setting/writing CDR vars only)\n" +" 'u' retrieves the raw, unprocessed value\n" +" For example, 'start', 'answer', and 'end' will be retrieved as epoch\n" +" values, when the 'u' option is passed, but formatted as YYYY-MM-DD HH:MM:SS\n" +" otherwise. Similarly, disposition and amaflags will return their raw\n" +" integral values.\n" +" Here is a list of all the available cdr field names:\n" +" clid lastdata disposition\n" +" src start amaflags\n" +" dst answer accountcode\n" +" dcontext end uniqueid\n" +" dstchannel duration userfield\n" +" lastapp billsec channel\n" +" All of the above variables are read-only, except for accountcode,\n" +" userfield, and amaflags. You may, however, supply\n" +" a name not on the above list, and create your own\n" +" variable, whose value can be changed with this function,\n" +" and this variable will be stored on the cdr.\n" +" For setting CDR values, the 'l' flag does not apply to\n" +" setting the accountcode, userfield, or amaflags.\n" +" raw values for disposition:\n" +" 1 = NO ANSWER\n" +" 2 = BUSY\n" +" 3 = FAILED\n" +" 4 = ANSWERED\n" +" raw values for amaflags:\n" +" 1 = OMIT\n" +" 2 = BILLING\n" +" 3 = DOCUMENTATION\n", +}; + +static int unload_module(void) +{ + return ast_custom_function_unregister(&cdr_function); +} + +static int load_module(void) +{ + return ast_custom_function_register(&cdr_function); +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "CDR dialplan function"); diff --git a/1.4.26.1/funcs/func_channel.c b/1.4.26.1/funcs/func_channel.c new file mode 100644 index 000000000..99f6d1e61 --- /dev/null +++ b/1.4.26.1/funcs/func_channel.c @@ -0,0 +1,200 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2006, Digium, Inc. + * + * 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 Channel info dialplan function + * + * \author Kevin P. Fleming <kpfleming@digium.com> + * + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <regex.h> + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/utils.h" +#include "asterisk/app.h" +#include "asterisk/indications.h" +#include "asterisk/stringfields.h" + +#define locked_copy_string(chan, dest, source, len) \ + do { \ + ast_channel_lock(chan); \ + ast_copy_string(dest, source, len); \ + ast_channel_unlock(chan); \ + } while (0) +#define locked_string_field_set(chan, field, source) \ + do { \ + ast_channel_lock(chan); \ + ast_string_field_set(chan, field, source); \ + ast_channel_unlock(chan); \ + } while (0) + +char *transfercapability_table[0x20] = { + "SPEECH", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", + "DIGITAL", "RESTRICTED_DIGITAL", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", + "3K1AUDIO", "DIGITAL_W_TONES", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", + "VIDEO", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", "UNK", }; + +static int func_channel_read(struct ast_channel *chan, char *function, + char *data, char *buf, size_t len) +{ + int ret = 0; + + if (!strcasecmp(data, "audionativeformat")) + /* use the _multiple version when chan->nativeformats holds multiple formats */ + /* ast_getformatname_multiple(buf, len, chan->nativeformats & AST_FORMAT_AUDIO_MASK); */ + ast_copy_string(buf, ast_getformatname(chan->nativeformats & AST_FORMAT_AUDIO_MASK), len); + else if (!strcasecmp(data, "videonativeformat")) + /* use the _multiple version when chan->nativeformats holds multiple formats */ + /* ast_getformatname_multiple(buf, len, chan->nativeformats & AST_FORMAT_VIDEO_MASK); */ + ast_copy_string(buf, ast_getformatname(chan->nativeformats & AST_FORMAT_VIDEO_MASK), len); + else if (!strcasecmp(data, "audioreadformat")) + ast_copy_string(buf, ast_getformatname(chan->readformat), len); + else if (!strcasecmp(data, "audiowriteformat")) + ast_copy_string(buf, ast_getformatname(chan->writeformat), len); + else if (!strcasecmp(data, "tonezone") && chan->zone) + locked_copy_string(chan, buf, chan->zone->country, len); + else if (!strcasecmp(data, "language")) + locked_copy_string(chan, buf, chan->language, len); + else if (!strcasecmp(data, "musicclass")) + locked_copy_string(chan, buf, chan->musicclass, len); + else if (!strcasecmp(data, "state")) + locked_copy_string(chan, buf, ast_state2str(chan->_state), len); + else if (!strcasecmp(data, "channeltype")) + locked_copy_string(chan, buf, chan->tech->type, len); + else if (!strcasecmp(data, "transfercapability")) + locked_copy_string(chan, buf, transfercapability_table[chan->transfercapability & 0x1f], len); + else if (!strcasecmp(data, "callgroup")) { + char groupbuf[256]; + locked_copy_string(chan, buf, ast_print_group(groupbuf, sizeof(groupbuf), chan->callgroup), len); + } else if (!chan->tech->func_channel_read + || chan->tech->func_channel_read(chan, function, data, buf, len)) { + ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data); + ret = -1; + } + + return ret; +} + +static int func_channel_write(struct ast_channel *chan, char *function, + char *data, const char *value) +{ + int ret = 0; + signed char gainset; + + if (!strcasecmp(data, "language")) + locked_string_field_set(chan, language, value); + else if (!strcasecmp(data, "musicclass")) + locked_string_field_set(chan, musicclass, value); + else if (!strcasecmp(data, "tonezone")) { + struct tone_zone *new_zone; + if (!(new_zone = ast_get_indication_zone(value))) { + ast_log(LOG_ERROR, "Unknown country code '%s' for tonezone. Check indications.conf for available country codes.\n", value); + ret = -1; + } else + chan->zone = new_zone; + } else if (!strcasecmp(data, "callgroup")) + chan->callgroup = ast_get_group(value); + else if (!strcasecmp(data, "txgain")) { + sscanf(value, "%4hhd", &gainset); + ast_channel_setoption(chan, AST_OPTION_TXGAIN, &gainset, sizeof(gainset), 0); + } else if (!strcasecmp(data, "rxgain")) { + sscanf(value, "%4hhd", &gainset); + ast_channel_setoption(chan, AST_OPTION_RXGAIN, &gainset, sizeof(gainset), 0); + } else if (!strcasecmp(data, "transfercapability")) { + unsigned short i; + for (i = 0; i < 0x20; i++) { + if (!strcasecmp(transfercapability_table[i], value) && strcmp(value, "UNK")) { + chan->transfercapability = i; + break; + } + } + } else if (!chan->tech->func_channel_write + || chan->tech->func_channel_write(chan, function, data, value)) { + ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", + data); + ret = -1; + } + + return ret; +} + +static struct ast_custom_function channel_function = { + .name = "CHANNEL", + .synopsis = "Gets/sets various pieces of information about the channel.", + .syntax = "CHANNEL(item)", + .desc = "Gets/set various pieces of information about the channel.\n" + "Standard items (provided by all channel technologies) are:\n" + "R/O audioreadformat format currently being read\n" + "R/O audionativeformat format used natively for audio\n" + "R/O audiowriteformat format currently being written\n" + "R/W callgroup call groups for call pickup\n" + "R/O channeltype technology used for channel\n" + "R/W language language for sounds played\n" + "R/W musicclass class (from musiconhold.conf) for hold music\n" + "R/W rxgain set rxgain level on channel drivers that support it\n" + "R/O state state for channel\n" + "R/W tonezone zone for indications played\n" + "R/W transfercapability ISDN transfer capability (one of SPEECH, DIGITAL,\n" + " RESTRICTED_DIGITAL, 3K1AUDIO, DIGITAL_W_TONES, or VIDEO).\n" + "R/W txgain set txgain level on channel drivers that support it\n" + "R/O videonativeformat format used natively for video\n" + "\n" + "chan_sip provides the following additional options:\n" + "R/O rtpqos Get QOS information about the RTP stream\n" + " This option takes two additional arguments:\n" + " Argument 1:\n" + " audio Get data about the audio stream\n" + " video Get data about the video stream\n" + " Argument 2:\n" + " local_ssrc Local SSRC (stream ID)\n" + " local_lostpackets Local lost packets\n" + " local_jitter Local calculated jitter\n" + " local_count Number of received packets\n" + " remote_ssrc Remote SSRC (stream ID)\n" + " remote_lostpackets Remote lost packets\n" + " remote_jitter Remote reported jitter\n" + " remote_count Number of transmitted packets\n" + " rtt Round trip time\n" + " all All statistics (in a form suited to logging, but not for parsing)\n" + "\n" + "Additional items may be available from the channel driver providing\n" + "the channel; see its documentation for details.\n" + "\n" + "Any item requested that is not available on the current channel will\n" + "return an empty string.\n", + .read = func_channel_read, + .write = func_channel_write, +}; + +static int unload_module(void) +{ + return ast_custom_function_unregister(&channel_function); +} + +static int load_module(void) +{ + return ast_custom_function_register(&channel_function); +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Channel information dialplan function"); diff --git a/1.4.26.1/funcs/func_curl.c b/1.4.26.1/funcs/func_curl.c new file mode 100644 index 000000000..2c71cf7a2 --- /dev/null +++ b/1.4.26.1/funcs/func_curl.c @@ -0,0 +1,215 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2004 - 2006, Tilghman Lesher + * + * Tilghman Lesher <curl-20050919@the-tilghman.com> + * and Brian Wilkins <bwilkins@cfl.rr.com> (Added POST option) + * + * app_curl.c is distributed with no restrictions on usage or + * redistribution. + * + * 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. + * + */ + +/*! \file + * + * \brief Curl - Load a URL + * + * \author Tilghman Lesher <curl-20050919@the-tilghman.com> + * + * \note Brian Wilkins <bwilkins@cfl.rr.com> (Added POST option) + * + * \ingroup functions + */ + +/*** MODULEINFO + <depend>curl</depend> + ***/ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <curl/curl.h> + +#include "asterisk/lock.h" +#include "asterisk/file.h" +#include "asterisk/logger.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/cli.h" +#include "asterisk/options.h" +#include "asterisk/module.h" +#include "asterisk/app.h" +#include "asterisk/utils.h" +#include "asterisk/threadstorage.h" + +struct MemoryStruct { + char *memory; + size_t size; +}; + +static void *myrealloc(void *ptr, size_t size) +{ + /* There might be a realloc() out there that doesn't like reallocing + NULL pointers, so we take care of it here */ + if (ptr) + return ast_realloc(ptr, size); + else + return ast_malloc(size); +} + +static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) +{ + register int realsize = size * nmemb; + struct MemoryStruct *mem = (struct MemoryStruct *)data; + + mem->memory = (char *)myrealloc(mem->memory, mem->size + realsize + 1); + if (mem->memory) { + memcpy(&(mem->memory[mem->size]), ptr, realsize); + mem->size += realsize; + mem->memory[mem->size] = 0; + } + return realsize; +} + +static const char *global_useragent = "asterisk-libcurl-agent/1.0"; + +static void curl_instance_cleanup(void *data) +{ + CURL **curl = data; + + curl_easy_cleanup(*curl); + + free(data); +} + +AST_THREADSTORAGE_CUSTOM(curl_instance, curl_instance_init, curl_instance_cleanup); + +static int curl_internal(struct MemoryStruct *chunk, char *url, char *post) +{ + int ret; + CURL **curl; + + if (!(curl = ast_threadstorage_get(&curl_instance, sizeof(*curl)))) + return -1; + + if (!*curl) { + if (!(*curl = curl_easy_init())) + return -1; + curl_easy_setopt(*curl, CURLOPT_NOSIGNAL, 1); + curl_easy_setopt(*curl, CURLOPT_TIMEOUT, 180); + curl_easy_setopt(*curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); + curl_easy_setopt(*curl, CURLOPT_USERAGENT, global_useragent); + } + + curl_easy_setopt(*curl, CURLOPT_URL, url); + curl_easy_setopt(*curl, CURLOPT_WRITEDATA, (void *) chunk); + + if (post) { + curl_easy_setopt(*curl, CURLOPT_POST, 1); + curl_easy_setopt(*curl, CURLOPT_POSTFIELDS, post); + } + + ret = curl_easy_perform(*curl); + + if (post) + curl_easy_setopt(*curl, CURLOPT_POST, 0); + + return ret ? -1 : 0; +} + +static int acf_curl_exec(struct ast_channel *chan, char *cmd, char *info, char *buf, size_t len) +{ + int ret = -1; + struct ast_module_user *u; + struct MemoryStruct chunk = { NULL, 0 }; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(url); + AST_APP_ARG(postdata); + ); + + *buf = '\0'; + + if (ast_strlen_zero(info)) { + ast_log(LOG_WARNING, "CURL requires an argument (URL)\n"); + return -1; + } + + u = ast_module_user_add(chan); + + AST_STANDARD_APP_ARGS(args, info); + + if (chan) + ast_autoservice_start(chan); + + if (!curl_internal(&chunk, args.url, args.postdata)) { + if (chunk.memory) { + chunk.memory[chunk.size] = '\0'; + if (chunk.memory[chunk.size - 1] == 10) + chunk.memory[chunk.size - 1] = '\0'; + + ast_copy_string(buf, chunk.memory, len); + free(chunk.memory); + } + ret = 0; + } else { + ast_log(LOG_ERROR, "Cannot allocate curl structure\n"); + } + + if (chan) + ast_autoservice_stop(chan); + + ast_module_user_remove(u); + + return ret; +} + +struct ast_custom_function acf_curl = { + .name = "CURL", + .synopsis = "Retrieves the contents of a URL", + .syntax = "CURL(url[|post-data])", + .desc = + " url - URL to retrieve\n" + " post-data - Optional data to send as a POST (GET is default action)\n", + .read = acf_curl_exec, +}; + +static int unload_module(void) +{ + int res; + + res = ast_custom_function_unregister(&acf_curl); + + ast_module_user_hangup_all(); + + curl_global_cleanup(); + + return res; +} + +static int load_module(void) +{ + int res; + + if (curl_global_init(CURL_GLOBAL_ALL)) { + ast_log(LOG_ERROR, "Unable to initialize the CURL library. Cannot load func_curl\n"); + return AST_MODULE_LOAD_DECLINE; + } + + res = ast_custom_function_register(&acf_curl); + + return res; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Load external URL"); + diff --git a/1.4.26.1/funcs/func_cut.c b/1.4.26.1/funcs/func_cut.c new file mode 100644 index 000000000..df17127c8 --- /dev/null +++ b/1.4.26.1/funcs/func_cut.c @@ -0,0 +1,331 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (c) 2003-2006 Tilghman Lesher. All rights reserved. + * + * Tilghman Lesher <app_cut__v003@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. + * + */ + +/*! \file + * + * \brief CUT function + * + * \author Tilghman Lesher <app_cut__v003@the-tilghman.com> + * + * \ingroup functions + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include "asterisk/file.h" +#include "asterisk/logger.h" +#include "asterisk/options.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/module.h" +#include "asterisk/app.h" + +/* Maximum length of any variable */ +#define MAXRESULT 1024 + +struct sortable_keys { + char *key; + float value; +}; + +static int sort_subroutine(const void *arg1, const void *arg2) +{ + const struct sortable_keys *one=arg1, *two=arg2; + if (one->value < two->value) + return -1; + else if (one->value == two->value) + return 0; + else + return 1; +} + +#define ERROR_NOARG (-1) +#define ERROR_NOMEM (-2) +#define ERROR_USAGE (-3) + +static int sort_internal(struct ast_channel *chan, char *data, char *buffer, size_t buflen) +{ + char *strings, *ptrkey, *ptrvalue; + int count=1, count2, element_count=0; + struct sortable_keys *sortable_keys; + + memset(buffer, 0, buflen); + + if (!data) + return ERROR_NOARG; + + strings = ast_strdupa(data); + + for (ptrkey = strings; *ptrkey; ptrkey++) { + if (*ptrkey == '|') + count++; + } + + sortable_keys = alloca(count * sizeof(struct sortable_keys)); + + memset(sortable_keys, 0, count * sizeof(struct sortable_keys)); + + /* Parse each into a struct */ + count2 = 0; + while ((ptrkey = strsep(&strings, "|"))) { + ptrvalue = index(ptrkey, ':'); + if (!ptrvalue) { + count--; + continue; + } + *ptrvalue++ = '\0'; + sortable_keys[count2].key = ptrkey; + sscanf(ptrvalue, "%30f", &sortable_keys[count2].value); + count2++; + } + + /* Sort the structs */ + qsort(sortable_keys, count, sizeof(struct sortable_keys), sort_subroutine); + + for (count2 = 0; count2 < count; count2++) { + int blen = strlen(buffer); + if (element_count++) { + strncat(buffer + blen, ",", buflen - blen - 1); + blen++; + } + strncat(buffer + blen, sortable_keys[count2].key, buflen - blen - 1); + } + + return 0; +} + +static int cut_internal(struct ast_channel *chan, char *data, char *buffer, size_t buflen) +{ + char *parse; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(varname); + AST_APP_ARG(delimiter); + AST_APP_ARG(field); + ); + + memset(buffer, 0, buflen); + + parse = ast_strdupa(data); + + AST_STANDARD_APP_ARGS(args, parse); + + /* Check and parse arguments */ + if(args.argc < 3){ + return ERROR_NOARG; + } else { + char d, ds[2]; + char *tmp = alloca(strlen(args.varname) + 4); + char varvalue[MAXRESULT], *tmp2=varvalue; + + if (tmp) { + snprintf(tmp, strlen(args.varname) + 4, "${%s}", args.varname); + memset(varvalue, 0, sizeof(varvalue)); + } else { + return ERROR_NOMEM; + } + + if (args.delimiter[0] == '\\') { + if (args.delimiter[1] == 'n') + d = '\n'; + else if (args.delimiter[1] == 't') + d = '\t'; + else if (args.delimiter[1] == 'r') + d = '\r'; + else if (args.delimiter[1]) + d = args.delimiter[1]; + else + d = '-'; + } else if (args.delimiter[0]) + d = args.delimiter[0]; + else + d = '-'; + + /* String form of the delimiter, for use with strsep(3) */ + snprintf(ds, sizeof(ds), "%c", d); + + pbx_substitute_variables_helper(chan, tmp, tmp2, MAXRESULT - 1); + + if (tmp2) { + int curfieldnum = 1, firstfield = 1; + while (tmp2 != NULL && args.field != NULL) { + char *nextgroup = strsep(&(args.field), "&"); + int num1 = 0, num2 = MAXRESULT; + char trashchar; + + if (sscanf(nextgroup, "%30d-%30d", &num1, &num2) == 2) { + /* range with both start and end */ + } else if (sscanf(nextgroup, "-%30d", &num2) == 1) { + /* range with end */ + num1 = 0; + } else if ((sscanf(nextgroup, "%30d%1c", &num1, &trashchar) == 2) && (trashchar == '-')) { + /* range with start */ + num2 = MAXRESULT; + } else if (sscanf(nextgroup, "%30d", &num1) == 1) { + /* single number */ + num2 = num1; + } else { + return ERROR_USAGE; + } + + /* Get to start, if any */ + if (num1 > 0) { + while (tmp2 != (char *)NULL + 1 && curfieldnum < num1) { + tmp2 = index(tmp2, d) + 1; + curfieldnum++; + } + } + + /* Most frequent problem is the expectation of reordering fields */ + if ((num1 > 0) && (curfieldnum > num1)) + ast_log(LOG_WARNING, "We're already past the field you wanted?\n"); + + /* Re-null tmp2 if we added 1 to NULL */ + if (tmp2 == (char *)NULL + 1) + tmp2 = NULL; + + /* Output fields until we either run out of fields or num2 is reached */ + while (tmp2 != NULL && curfieldnum <= num2) { + char *tmp3 = strsep(&tmp2, ds); + int curlen = strlen(buffer); + + if (firstfield) { + snprintf(buffer, buflen, "%s", tmp3); + firstfield = 0; + } else { + snprintf(buffer + curlen, buflen - curlen, "%c%s", d, tmp3); + } + curfieldnum++; + } + } + } + } + return 0; +} + +static int acf_sort_exec(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) +{ + struct ast_module_user *u; + int ret = -1; + + u = ast_module_user_add(chan); + + switch (sort_internal(chan, data, buf, len)) { + case ERROR_NOARG: + ast_log(LOG_ERROR, "SORT() requires an argument\n"); + break; + case ERROR_NOMEM: + ast_log(LOG_ERROR, "Out of memory\n"); + break; + case 0: + ret = 0; + break; + default: + ast_log(LOG_ERROR, "Unknown internal error\n"); + } + + ast_module_user_remove(u); + + return ret; +} + +static int acf_cut_exec(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) +{ + int ret = -1; + struct ast_module_user *u = NULL; + + if (chan) { + u = ast_module_user_add(chan); + } + + switch (cut_internal(chan, data, buf, len)) { + case ERROR_NOARG: + ast_log(LOG_ERROR, "Syntax: CUT(<varname>,<char-delim>,<range-spec>) - missing argument!\n"); + break; + case ERROR_NOMEM: + ast_log(LOG_ERROR, "Out of memory\n"); + break; + case ERROR_USAGE: + ast_log(LOG_ERROR, "Usage: CUT(<varname>,<char-delim>,<range-spec>)\n"); + break; + case 0: + ret = 0; + break; + default: + ast_log(LOG_ERROR, "Unknown internal error\n"); + } + + if (chan) { + ast_module_user_remove(u); + } + + return ret; +} + +struct ast_custom_function acf_sort = { + .name = "SORT", + .synopsis = "Sorts a list of key/vals into a list of keys, based upon the vals", + .syntax = "SORT(key1:val1[...][,keyN:valN])", + .desc = +"Takes a comma-separated list of keys and values, each separated by a colon, and returns a\n" +"comma-separated list of the keys, sorted by their values. Values will be evaluated as\n" +"floating-point numbers.\n", + .read = acf_sort_exec, +}; + +struct ast_custom_function acf_cut = { + .name = "CUT", + .synopsis = "Slices and dices strings, based upon a named delimiter.", + .syntax = "CUT(<varname>,<char-delim>,<range-spec>)", + .desc = +" varname - variable you want cut\n" +" char-delim - defaults to '-'\n" +" range-spec - number of the field you want (1-based offset)\n" +" may also be specified as a range (with -)\n" +" or group of ranges and fields (with &)\n", + .read = acf_cut_exec, +}; + +static int unload_module(void) +{ + int res = 0; + + res |= ast_custom_function_unregister(&acf_cut); + res |= ast_custom_function_unregister(&acf_sort); + + ast_module_user_hangup_all(); + + return res; +} + +static int load_module(void) +{ + int res = 0; + + res |= ast_custom_function_register(&acf_cut); + res |= ast_custom_function_register(&acf_sort); + + return res; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Cut out information from a string"); diff --git a/1.4.26.1/funcs/func_db.c b/1.4.26.1/funcs/func_db.c new file mode 100644 index 000000000..13932d27d --- /dev/null +++ b/1.4.26.1/funcs/func_db.c @@ -0,0 +1,231 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2005-2006, Russell Bryant <russelb@clemson.edu> + * + * func_db.c adapted from the old app_db.c, copyright by the following people + * Copyright (C) 2005, Mark Spencer <markster@digium.com> + * Copyright (C) 2003, Jefferson Noxon <jeff@debian.org> + * + * 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 Functions for interaction with the Asterisk database + * + * \author Russell Bryant <russelb@clemson.edu> + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <regex.h> + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/logger.h" +#include "asterisk/options.h" +#include "asterisk/utils.h" +#include "asterisk/app.h" +#include "asterisk/astdb.h" + +static int function_db_read(struct ast_channel *chan, char *cmd, + char *parse, char *buf, size_t len) +{ + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(family); + AST_APP_ARG(key); + ); + + buf[0] = '\0'; + + if (ast_strlen_zero(parse)) { + ast_log(LOG_WARNING, "DB requires an argument, DB(<family>/<key>)\n"); + return -1; + } + + AST_NONSTANDARD_APP_ARGS(args, parse, '/'); + + if (args.argc < 2) { + ast_log(LOG_WARNING, "DB requires an argument, DB(<family>/<key>)\n"); + return -1; + } + + if (ast_db_get(args.family, args.key, buf, len - 1)) { + ast_log(LOG_DEBUG, "DB: %s/%s not found in database.\n", args.family, + args.key); + } else + pbx_builtin_setvar_helper(chan, "DB_RESULT", buf); + + return 0; +} + +static int function_db_write(struct ast_channel *chan, char *cmd, char *parse, + const char *value) +{ + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(family); + AST_APP_ARG(key); + ); + + if (ast_strlen_zero(parse)) { + ast_log(LOG_WARNING, "DB requires an argument, DB(<family>/<key>)=<value>\n"); + return -1; + } + + AST_NONSTANDARD_APP_ARGS(args, parse, '/'); + + if (args.argc < 2) { + ast_log(LOG_WARNING, "DB requires an argument, DB(<family>/<key>)=value\n"); + return -1; + } + + if (ast_db_put(args.family, args.key, (char *) value)) + ast_log(LOG_WARNING, "DB: Error writing value to database.\n"); + + return 0; +} + +static struct ast_custom_function db_function = { + .name = "DB", + .synopsis = "Read from or write to the Asterisk database", + .syntax = "DB(<family>/<key>)", + .desc = +"This function will read from or write a value to the Asterisk database. On a\n" +"read, this function returns the corresponding value from the database, or blank\n" +"if it does not exist. Reading a database value will also set the variable\n" +"DB_RESULT. If you wish to find out if an entry exists, use the DB_EXISTS\n" +"function.\n", + .read = function_db_read, + .write = function_db_write, +}; + +static int function_db_exists(struct ast_channel *chan, char *cmd, + char *parse, char *buf, size_t len) +{ + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(family); + AST_APP_ARG(key); + ); + + buf[0] = '\0'; + + if (ast_strlen_zero(parse)) { + ast_log(LOG_WARNING, "DB_EXISTS requires an argument, DB(<family>/<key>)\n"); + return -1; + } + + AST_NONSTANDARD_APP_ARGS(args, parse, '/'); + + if (args.argc < 2) { + ast_log(LOG_WARNING, "DB_EXISTS requires an argument, DB(<family>/<key>)\n"); + return -1; + } + + if (ast_db_get(args.family, args.key, buf, len - 1)) + strcpy(buf, "0"); + else { + pbx_builtin_setvar_helper(chan, "DB_RESULT", buf); + strcpy(buf, "1"); + } + + return 0; +} + +static struct ast_custom_function db_exists_function = { + .name = "DB_EXISTS", + .synopsis = "Check to see if a key exists in the Asterisk database", + .syntax = "DB_EXISTS(<family>/<key>)", + .desc = + "This function will check to see if a key exists in the Asterisk\n" + "database. If it exists, the function will return \"1\". If not,\n" + "it will return \"0\". Checking for existence of a database key will\n" + "also set the variable DB_RESULT to the key's value if it exists.\n", + .read = function_db_exists, +}; + +static int function_db_delete(struct ast_channel *chan, char* cmd, + char *parse, char *buf, size_t len) +{ + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(family); + AST_APP_ARG(key); + ); + + buf[0] = '\0'; + + if (ast_strlen_zero(parse)) { + ast_log(LOG_WARNING, "DB_DELETE requires an argument, DB_DELETE(<family>/<key>)\n"); + return -1; + } + + AST_NONSTANDARD_APP_ARGS(args, parse, '/'); + + if (args.argc < 2) { + ast_log(LOG_WARNING, "DB_DELETE requires an argument, DB_DELETE(<family>/<key>)\n"); + return -1; + } + + if (ast_db_get(args.family, args.key, buf, len - 1)) { + ast_log(LOG_DEBUG, "DB_DELETE: %s/%s not found in database.\n", args.family, args.key); + } else { + if (ast_db_del(args.family, args.key)) { + ast_log(LOG_DEBUG, "DB_DELETE: %s/%s could not be deleted from the database\n", + args.family, args.key); + } + } + pbx_builtin_setvar_helper(chan, "DB_RESULT", buf); + + return 0; +} + + +static struct ast_custom_function db_delete_function = { + .name = "DB_DELETE", + .synopsis = "Return a value from the database and delete it", + .syntax = "DB_DELETE(<family>/<key>)", + .desc = + "This function will retrieve a value from the Asterisk database\n" + " and then remove that key from the database. DB_RESULT\n" + "will be set to the key's value if it exists.\n", + .read = function_db_delete, +}; + +static int unload_module(void) +{ + int res = 0; + + res |= ast_custom_function_unregister(&db_function); + res |= ast_custom_function_unregister(&db_exists_function); + res |= ast_custom_function_unregister(&db_delete_function); + + return res; +} + +static int load_module(void) +{ + int res = 0; + + res |= ast_custom_function_register(&db_function); + res |= ast_custom_function_register(&db_exists_function); + res |= ast_custom_function_register(&db_delete_function); + + return res; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Database (astdb) related dialplan functions"); diff --git a/1.4.26.1/funcs/func_enum.c b/1.4.26.1/funcs/func_enum.c new file mode 100644 index 000000000..01d96449f --- /dev/null +++ b/1.4.26.1/funcs/func_enum.c @@ -0,0 +1,198 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 1999 - 2006 + * + * Mark Spencer <markster@digium.com> + * Oleksiy Krivoshey <oleksiyk@gmail.com> + * Russell Bryant <russelb@clemson.edu> + * + * 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 ENUM Functions + * + * \author Mark Spencer <markster@digium.com> + * \author Oleksiy Krivoshey <oleksiyk@gmail.com> + * \author Russell Bryant <russelb@clemson.edu> + * + * \arg See also AstENUM + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdlib.h> +#include <stdio.h> + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/utils.h" +#include "asterisk/lock.h" +#include "asterisk/file.h" +#include "asterisk/logger.h" +#include "asterisk/pbx.h" +#include "asterisk/options.h" +#include "asterisk/enum.h" +#include "asterisk/app.h" + + static char *synopsis = "Syntax: ENUMLOOKUP(number[|Method-type[|options[|record#[|zone-suffix]]]])\n"; + +static int function_enum(struct ast_channel *chan, char *cmd, char *data, + char *buf, size_t len) +{ + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(number); + AST_APP_ARG(tech); + AST_APP_ARG(options); + AST_APP_ARG(record); + AST_APP_ARG(zone); + ); + int res = 0; + char tech[80]; + char dest[256] = "", tmp[2] = "", num[AST_MAX_EXTENSION] = ""; + struct ast_module_user *u; + char *s, *p; + unsigned int record = 1; + + buf[0] = '\0'; + + if (ast_strlen_zero(data)) { + ast_log(LOG_WARNING, "%s", synopsis); + return -1; + } + + AST_STANDARD_APP_ARGS(args, data); + + if (args.argc < 1) { + ast_log(LOG_WARNING, "%s", synopsis); + return -1; + } + + u = ast_module_user_add(chan); + + ast_copy_string(tech, args.tech ? args.tech : "sip", sizeof(tech)); + + if (!args.zone) + args.zone = "e164.arpa"; + + if (!args.options) + args.options = ""; + + if (args.record) + record = atoi(args.record); + + /* strip any '-' signs from number */ + for (s = p = args.number; *s; s++) { + if (*s != '-') { + snprintf(tmp, sizeof(tmp), "%c", *s); + strncat(num, tmp, sizeof(num) - strlen(num) - 1); + } + + } + + res = ast_get_enum(chan, num, dest, sizeof(dest), tech, sizeof(tech), args.zone, + args.options, record); + + p = strchr(dest, ':'); + if (p && strcasecmp(tech, "ALL")) + ast_copy_string(buf, p + 1, len); + else + ast_copy_string(buf, dest, len); + + ast_module_user_remove(u); + + return 0; +} + +static struct ast_custom_function enum_function = { + .name = "ENUMLOOKUP", + .synopsis = + "ENUMLOOKUP allows for general or specific querying of NAPTR records" + " or counts of NAPTR types for ENUM or ENUM-like DNS pointers", + .syntax = + "ENUMLOOKUP(number[|Method-type[|options[|record#[|zone-suffix]]]])", + .desc = + "Option 'c' returns an integer count of the number of NAPTRs of a certain RR type.\n" + "Combination of 'c' and Method-type of 'ALL' will return a count of all NAPTRs for the record.\n" + "Defaults are: Method-type=sip, no options, record=1, zone-suffix=e164.arpa\n\n" + "For more information, see doc/enum.txt", + .read = function_enum, +}; + +static int function_txtcidname(struct ast_channel *chan, char *cmd, + char *data, char *buf, size_t len) +{ + int res; + char tech[80]; + char txt[256] = ""; + char dest[80]; + struct ast_module_user *u; + + buf[0] = '\0'; + + + if (ast_strlen_zero(data)) { + ast_log(LOG_WARNING, "TXTCIDNAME requires an argument (number)\n"); + return -1; + } + + u = ast_module_user_add(chan); + + res = ast_get_txt(chan, data, dest, sizeof(dest), tech, sizeof(tech), txt, + sizeof(txt)); + + if (!ast_strlen_zero(txt)) + ast_copy_string(buf, txt, len); + + ast_module_user_remove(u); + + return 0; +} + +static struct ast_custom_function txtcidname_function = { + .name = "TXTCIDNAME", + .synopsis = "TXTCIDNAME looks up a caller name via DNS", + .syntax = "TXTCIDNAME(<number>)", + .desc = + "This function looks up the given phone number in DNS to retrieve\n" + "the caller id name. The result will either be blank or be the value\n" + "found in the TXT record in DNS.\n", + .read = function_txtcidname, +}; + +static int unload_module(void) +{ + int res = 0; + + res |= ast_custom_function_unregister(&enum_function); + res |= ast_custom_function_unregister(&txtcidname_function); + + ast_module_user_hangup_all(); + + return res; +} + +static int load_module(void) +{ + int res = 0; + + res |= ast_custom_function_register(&enum_function); + res |= ast_custom_function_register(&txtcidname_function); + + return res; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "ENUM related dialplan functions"); diff --git a/1.4.26.1/funcs/func_env.c b/1.4.26.1/funcs/func_env.c new file mode 100644 index 000000000..01ec4958d --- /dev/null +++ b/1.4.26.1/funcs/func_env.c @@ -0,0 +1,158 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 1999 - 2006, Digium, Inc. + * + * 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 Environment related dialplan functions + * + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/logger.h" +#include "asterisk/utils.h" +#include "asterisk/app.h" + +static int env_read(struct ast_channel *chan, char *cmd, char *data, + char *buf, size_t len) +{ + char *ret = NULL; + + *buf = '\0'; + + if (data) + ret = getenv(data); + + if (ret) + ast_copy_string(buf, ret, len); + + return 0; +} + +static int env_write(struct ast_channel *chan, char *cmd, char *data, + const char *value) +{ + if (!ast_strlen_zero(data)) { + if (!ast_strlen_zero(value)) { + setenv(data, value, 1); + } else { + unsetenv(data); + } + } + + return 0; +} + +static int stat_read(struct ast_channel *chan, char *cmd, char *data, + char *buf, size_t len) +{ + char *action; + struct stat s; + + ast_copy_string(buf, "0", len); + + action = strsep(&data, "|"); + if (stat(data, &s)) { + return 0; + } else { + switch (*action) { + case 'e': + strcpy(buf, "1"); + break; + case 's': + snprintf(buf, len, "%d", (unsigned int) s.st_size); + break; + case 'f': + snprintf(buf, len, "%d", S_ISREG(s.st_mode) ? 1 : 0); + break; + case 'd': + snprintf(buf, len, "%d", S_ISDIR(s.st_mode) ? 1 : 0); + break; + case 'M': + snprintf(buf, len, "%d", (int) s.st_mtime); + break; + case 'A': + snprintf(buf, len, "%d", (int) s.st_mtime); + break; + case 'C': + snprintf(buf, len, "%d", (int) s.st_ctime); + break; + case 'm': + snprintf(buf, len, "%o", (int) s.st_mode); + break; + } + } + + return 0; +} + +static struct ast_custom_function env_function = { + .name = "ENV", + .synopsis = "Gets or sets the environment variable specified", + .syntax = "ENV(<envname>)", + .read = env_read, + .write = env_write, +}; + +static struct ast_custom_function stat_function = { + .name = "STAT", + .synopsis = "Does a check on the specified file", + .syntax = "STAT(<flag>,<filename>)", + .read = stat_read, + .desc = + "flag may be one of the following:\n" + " d - Checks if the file is a directory\n" + " e - Checks if the file exists\n" + " f - Checks if the file is a regular file\n" + " m - Returns the file mode (in octal)\n" + " s - Returns the size (in bytes) of the file\n" + " A - Returns the epoch at which the file was last accessed\n" + " C - Returns the epoch at which the inode was last changed\n" + " M - Returns the epoch at which the file was last modified\n", +}; + +static int unload_module(void) +{ + int res = 0; + + res |= ast_custom_function_unregister(&env_function); + res |= ast_custom_function_unregister(&stat_function); + + return res; +} + +static int load_module(void) +{ + int res = 0; + + res |= ast_custom_function_register(&env_function); + res |= ast_custom_function_register(&stat_function); + + return res; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Environment/filesystem dialplan functions"); diff --git a/1.4.26.1/funcs/func_global.c b/1.4.26.1/funcs/func_global.c new file mode 100644 index 000000000..50a84afde --- /dev/null +++ b/1.4.26.1/funcs/func_global.c @@ -0,0 +1,86 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2006, Tilghman Lesher + * + * Tilghman Lesher <func_global__200605@the-tilghman.com> + * + * 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 Global variable dialplan functions + * + * \author Tilghman Lesher <func_global__200605@the-tilghman.com> + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/utils.h" + +static int global_read(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) +{ + const char *var = pbx_builtin_getvar_helper(NULL, data); + + *buf = '\0'; + + if (var) + ast_copy_string(buf, var, len); + + return 0; +} + +static int global_write(struct ast_channel *chan, char *cmd, char *data, const char *value) +{ + pbx_builtin_setvar_helper(NULL, data, value); + + return 0; +} + +static struct ast_custom_function global_function = { + .name = "GLOBAL", + .synopsis = "Gets or sets the global variable specified", + .syntax = "GLOBAL(<varname>)", + .read = global_read, + .write = global_write, +}; + +static int unload_module(void) +{ + int res = 0; + + res |= ast_custom_function_unregister(&global_function); + + return res; +} + +static int load_module(void) +{ + int res = 0; + + res |= ast_custom_function_register(&global_function); + + return res; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Global variable dialplan functions"); diff --git a/1.4.26.1/funcs/func_groupcount.c b/1.4.26.1/funcs/func_groupcount.c new file mode 100644 index 000000000..7f6f8937b --- /dev/null +++ b/1.4.26.1/funcs/func_groupcount.c @@ -0,0 +1,243 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 1999 - 2006, Digium, Inc. + * + * 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 Channel group related dialplan functions + * + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/logger.h" +#include "asterisk/utils.h" +#include "asterisk/app.h" + +static int group_count_function_read(struct ast_channel *chan, char *cmd, + char *data, char *buf, size_t len) +{ + int ret = -1; + int count = -1; + char group[80] = "", category[80] = ""; + + ast_app_group_split_group(data, group, sizeof(group), category, + sizeof(category)); + + /* If no group has been provided let's find one */ + if (ast_strlen_zero(group)) { + struct ast_group_info *gi = NULL; + + ast_app_group_list_lock(); + for (gi = ast_app_group_list_head(); gi; gi = AST_LIST_NEXT(gi, list)) { + if (gi->chan != chan) + continue; + if (ast_strlen_zero(category) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category))) + break; + } + if (gi) { + ast_copy_string(group, gi->group, sizeof(group)); + if (!ast_strlen_zero(gi->category)) + ast_copy_string(category, gi->category, sizeof(category)); + } + ast_app_group_list_unlock(); + } + + if ((count = ast_app_group_get_count(group, category)) == -1) { + ast_log(LOG_NOTICE, "No group could be found for channel '%s'\n", chan->name); + } else { + snprintf(buf, len, "%d", count); + ret = 0; + } + + return ret; +} + +static struct ast_custom_function group_count_function = { + .name = "GROUP_COUNT", + .syntax = "GROUP_COUNT([groupname][@category])", + .synopsis = "Counts the number of channels in the specified group", + .desc = + "Calculates the group count for the specified group, or uses the\n" + "channel's current group if not specifed (and non-empty).\n", + .read = group_count_function_read, +}; + +static int group_match_count_function_read(struct ast_channel *chan, + char *cmd, char *data, char *buf, + size_t len) +{ + int count; + char group[80] = ""; + char category[80] = ""; + + ast_app_group_split_group(data, group, sizeof(group), category, + sizeof(category)); + + if (!ast_strlen_zero(group)) { + count = ast_app_group_match_get_count(group, category); + snprintf(buf, len, "%d", count); + return 0; + } + + return -1; +} + +static struct ast_custom_function group_match_count_function = { + .name = "GROUP_MATCH_COUNT", + .syntax = "GROUP_MATCH_COUNT(groupmatch[@category])", + .synopsis = + "Counts the number of channels in the groups matching the specified pattern", + .desc = + "Calculates the group count for all groups that match the specified pattern.\n" + "Uses standard regular expression matching (see regex(7)).\n", + .read = group_match_count_function_read, + .write = NULL, +}; + +static int group_function_read(struct ast_channel *chan, char *cmd, + char *data, char *buf, size_t len) +{ + int ret = -1; + struct ast_group_info *gi = NULL; + + ast_app_group_list_lock(); + + for (gi = ast_app_group_list_head(); gi; gi = AST_LIST_NEXT(gi, list)) { + if (gi->chan != chan) + continue; + if (ast_strlen_zero(data)) + break; + if (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, data)) + break; + } + + if (gi) { + ast_copy_string(buf, gi->group, len); + ret = 0; + } + + ast_app_group_list_unlock(); + + return ret; +} + +static int group_function_write(struct ast_channel *chan, char *cmd, + char *data, const char *value) +{ + char grpcat[256]; + + if (!ast_strlen_zero(data)) { + snprintf(grpcat, sizeof(grpcat), "%s@%s", value, data); + } else { + ast_copy_string(grpcat, value, sizeof(grpcat)); + } + + if (ast_app_group_set_channel(chan, grpcat)) + ast_log(LOG_WARNING, + "Setting a group requires an argument (group name)\n"); + + return 0; +} + +static struct ast_custom_function group_function = { + .name = "GROUP", + .syntax = "GROUP([category])", + .synopsis = "Gets or sets the channel group.", + .desc = "Gets or sets the channel group.\n", + .read = group_function_read, + .write = group_function_write, +}; + +static int group_list_function_read(struct ast_channel *chan, char *cmd, + char *data, char *buf, size_t len) +{ + struct ast_group_info *gi = NULL; + char tmp1[1024] = ""; + char tmp2[1024] = ""; + + if (!chan) + return -1; + + ast_app_group_list_lock(); + + for (gi = ast_app_group_list_head(); gi; gi = AST_LIST_NEXT(gi, list)) { + if (gi->chan != chan) + continue; + if (!ast_strlen_zero(tmp1)) { + ast_copy_string(tmp2, tmp1, sizeof(tmp2)); + if (!ast_strlen_zero(gi->category)) + snprintf(tmp1, sizeof(tmp1), "%s %s@%s", tmp2, gi->group, gi->category); + else + snprintf(tmp1, sizeof(tmp1), "%s %s", tmp2, gi->group); + } else { + if (!ast_strlen_zero(gi->category)) + snprintf(tmp1, sizeof(tmp1), "%s@%s", gi->group, gi->category); + else + snprintf(tmp1, sizeof(tmp1), "%s", gi->group); + } + } + + ast_app_group_list_unlock(); + + ast_copy_string(buf, tmp1, len); + + return 0; +} + +static struct ast_custom_function group_list_function = { + .name = "GROUP_LIST", + .syntax = "GROUP_LIST()", + .synopsis = "Gets a list of the groups set on a channel.", + .desc = "Gets a list of the groups set on a channel.\n", + .read = group_list_function_read, + .write = NULL, +}; + +static int unload_module(void) +{ + int res = 0; + + res |= ast_custom_function_unregister(&group_count_function); + res |= ast_custom_function_unregister(&group_match_count_function); + res |= ast_custom_function_unregister(&group_list_function); + res |= ast_custom_function_unregister(&group_function); + + return res; +} + +static int load_module(void) +{ + int res = 0; + + res |= ast_custom_function_register(&group_count_function); + res |= ast_custom_function_register(&group_match_count_function); + res |= ast_custom_function_register(&group_list_function); + res |= ast_custom_function_register(&group_function); + + return res; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Channel group dialplan functions"); diff --git a/1.4.26.1/funcs/func_language.c b/1.4.26.1/funcs/func_language.c new file mode 100644 index 000000000..43b368f4f --- /dev/null +++ b/1.4.26.1/funcs/func_language.c @@ -0,0 +1,90 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 1999 - 2006, Digium, Inc. + * + * 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 Language related dialplan functions + * + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/logger.h" +#include "asterisk/utils.h" +#include "asterisk/app.h" +#include "asterisk/stringfields.h" + +static int depwarning = 0; + +static int language_read(struct ast_channel *chan, char *cmd, char *data, + char *buf, size_t len) +{ + if (!depwarning) { + depwarning = 1; + ast_log(LOG_WARNING, + "LANGUAGE() is deprecated; use CHANNEL(language) instead.\n"); + } + + ast_copy_string(buf, chan ? chan->language : "", len); + + return 0; +} + +static int language_write(struct ast_channel *chan, char *cmd, char *data, + const char *value) +{ + if (!depwarning) { + depwarning = 1; + ast_log(LOG_WARNING, + "LANGUAGE() is deprecated; use CHANNEL(language) instead.\n"); + } + + if (chan && value) + ast_string_field_set(chan, language, value); + + return 0; +} + +static struct ast_custom_function language_function = { + .name = "LANGUAGE", + .synopsis = "Gets or sets the channel's language.", + .syntax = "LANGUAGE()", + .desc = "Deprecated. Use CHANNEL(language) instead.\n", + .read = language_read, + .write = language_write, +}; + +static int unload_module(void) +{ + return ast_custom_function_unregister(&language_function); +} + +static int load_module(void) +{ + return ast_custom_function_register(&language_function); +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Channel language dialplan function"); diff --git a/1.4.26.1/funcs/func_logic.c b/1.4.26.1/funcs/func_logic.c new file mode 100644 index 000000000..ef972c969 --- /dev/null +++ b/1.4.26.1/funcs/func_logic.c @@ -0,0 +1,214 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 1999 - 2006, Digium, Inc. + * Portions Copyright (C) 2005, Anthony Minessale II + * + * 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 Conditional logic dialplan functions + * + * \author Anthony Minessale II + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/logger.h" +#include "asterisk/utils.h" +#include "asterisk/app.h" + +static int isnull(struct ast_channel *chan, char *cmd, char *data, + char *buf, size_t len) +{ + strcpy(buf, data && *data ? "0" : "1"); + + return 0; +} + +static int exists(struct ast_channel *chan, char *cmd, char *data, char *buf, + size_t len) +{ + strcpy(buf, data && *data ? "1" : "0"); + + return 0; +} + +static int iftime(struct ast_channel *chan, char *cmd, char *data, char *buf, + size_t len) +{ + struct ast_timing timing; + char *expr; + char *iftrue; + char *iffalse; + + data = ast_strip_quoted(data, "\"", "\""); + expr = strsep(&data, "?"); + iftrue = strsep(&data, ":"); + iffalse = data; + + if (ast_strlen_zero(expr) || !(iftrue || iffalse)) { + ast_log(LOG_WARNING, + "Syntax IFTIME(<timespec>?[<true>][:<false>])\n"); + return -1; + } + + if (!ast_build_timing(&timing, expr)) { + ast_log(LOG_WARNING, "Invalid Time Spec.\n"); + return -1; + } + + if (iftrue) + iftrue = ast_strip_quoted(iftrue, "\"", "\""); + if (iffalse) + iffalse = ast_strip_quoted(iffalse, "\"", "\""); + + ast_copy_string(buf, ast_check_timing(&timing) ? S_OR(iftrue, "") : S_OR(iffalse, ""), len); + + return 0; +} + +static int acf_if(struct ast_channel *chan, char *cmd, char *data, char *buf, + size_t len) +{ + AST_DECLARE_APP_ARGS(args1, + AST_APP_ARG(expr); + AST_APP_ARG(remainder); + ); + AST_DECLARE_APP_ARGS(args2, + AST_APP_ARG(iftrue); + AST_APP_ARG(iffalse); + ); + args2.iftrue = args2.iffalse = NULL; /* you have to set these, because if there is nothing after the '?', + then args1.remainder will be NULL, not a pointer to a null string, and + then any garbage in args2.iffalse will not be cleared, and you'll crash. + -- and if you mod the ast_app_separate_args func instead, you'll really + mess things up badly, because the rest of everything depends on null args + for non-specified stuff. */ + + AST_NONSTANDARD_APP_ARGS(args1, data, '?'); + AST_NONSTANDARD_APP_ARGS(args2, args1.remainder, ':'); + + if (ast_strlen_zero(args1.expr) || !(args2.iftrue || args2.iffalse)) { + ast_log(LOG_WARNING, "Syntax IF(<expr>?[<true>][:<false>]) (expr must be non-null, and either <true> or <false> must be non-null)\n"); + ast_log(LOG_WARNING, " In this case, <expr>='%s', <true>='%s', and <false>='%s'\n", args1.expr, args2.iftrue, args2.iffalse); + return -1; + } + + args1.expr = ast_strip(args1.expr); + if (args2.iftrue) + args2.iftrue = ast_strip(args2.iftrue); + if (args2.iffalse) + args2.iffalse = ast_strip(args2.iffalse); + + ast_copy_string(buf, pbx_checkcondition(args1.expr) ? (S_OR(args2.iftrue, "")) : (S_OR(args2.iffalse, "")), len); + + return 0; +} + +static int set(struct ast_channel *chan, char *cmd, char *data, char *buf, + size_t len) +{ + char *varname; + char *val; + + varname = strsep(&data, "="); + val = data; + + if (ast_strlen_zero(varname) || !val) { + ast_log(LOG_WARNING, "Syntax SET(<varname>=[<value>])\n"); + return -1; + } + + varname = ast_strip(varname); + val = ast_strip(val); + pbx_builtin_setvar_helper(chan, varname, val); + ast_copy_string(buf, val, len); + + return 0; +} + +static struct ast_custom_function isnull_function = { + .name = "ISNULL", + .synopsis = "NULL Test: Returns 1 if NULL or 0 otherwise", + .syntax = "ISNULL(<data>)", + .read = isnull, +}; + +static struct ast_custom_function set_function = { + .name = "SET", + .synopsis = "SET assigns a value to a channel variable", + .syntax = "SET(<varname>=[<value>])", + .read = set, +}; + +static struct ast_custom_function exists_function = { + .name = "EXISTS", + .synopsis = "Existence Test: Returns 1 if exists, 0 otherwise", + .syntax = "EXISTS(<data>)", + .read = exists, +}; + +static struct ast_custom_function if_function = { + .name = "IF", + .synopsis = + "Conditional: Returns the data following '?' if true else the data following ':'", + .syntax = "IF(<expr>?[<true>][:<false>])", + .read = acf_if, +}; + +static struct ast_custom_function if_time_function = { + .name = "IFTIME", + .synopsis = + "Temporal Conditional: Returns the data following '?' if true else the data following ':'", + .syntax = "IFTIME(<timespec>?[<true>][:<false>])", + .read = iftime, +}; + +static int unload_module(void) +{ + int res = 0; + + res |= ast_custom_function_unregister(&isnull_function); + res |= ast_custom_function_unregister(&set_function); + res |= ast_custom_function_unregister(&exists_function); + res |= ast_custom_function_unregister(&if_function); + res |= ast_custom_function_unregister(&if_time_function); + + return res; +} + +static int load_module(void) +{ + int res = 0; + + res |= ast_custom_function_register(&isnull_function); + res |= ast_custom_function_register(&set_function); + res |= ast_custom_function_register(&exists_function); + res |= ast_custom_function_register(&if_function); + res |= ast_custom_function_register(&if_time_function); + + return res; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Logical dialplan functions"); diff --git a/1.4.26.1/funcs/func_math.c b/1.4.26.1/funcs/func_math.c new file mode 100644 index 000000000..76d9deff6 --- /dev/null +++ b/1.4.26.1/funcs/func_math.c @@ -0,0 +1,268 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2004 - 2006, Andy Powell + * + * Updated by Mark Spencer <markster@digium.com> + * + * 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 Math related dialplan function + * + * \author Andy Powell + * \author Mark Spencer <markster@digium.com> + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/logger.h" +#include "asterisk/utils.h" +#include "asterisk/app.h" +#include "asterisk/config.h" + +enum TypeOfFunctions { + ADDFUNCTION, + DIVIDEFUNCTION, + MULTIPLYFUNCTION, + SUBTRACTFUNCTION, + MODULUSFUNCTION, + GTFUNCTION, + LTFUNCTION, + GTEFUNCTION, + LTEFUNCTION, + EQFUNCTION +}; + +enum TypeOfResult { + FLOAT_RESULT, + INT_RESULT, + HEX_RESULT, + CHAR_RESULT +}; + +static int math(struct ast_channel *chan, char *cmd, char *parse, + char *buf, size_t len) +{ + double fnum1; + double fnum2; + double ftmp = 0; + char *op; + int iaction = -1; + int type_of_result = FLOAT_RESULT; + char *mvalue1, *mvalue2 = NULL, *mtype_of_result; + int negvalue1 = 0; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(argv0); + AST_APP_ARG(argv1); + ); + + if (ast_strlen_zero(parse)) { + ast_log(LOG_WARNING, "Syntax: MATH(<number1><op><number 2>[,<type_of_result>]) - missing argument!\n"); + return -1; + } + + AST_STANDARD_APP_ARGS(args, parse); + + if (args.argc < 1) { + ast_log(LOG_WARNING, "Syntax: MATH(<number1><op><number 2>[,<type_of_result>]) - missing argument!\n"); + return -1; + } + + mvalue1 = args.argv0; + + if (mvalue1[0] == '-') { + negvalue1 = 1; + mvalue1++; + } + + if ((op = strchr(mvalue1, '*'))) { + iaction = MULTIPLYFUNCTION; + *op = '\0'; + } else if ((op = strchr(mvalue1, '/'))) { + iaction = DIVIDEFUNCTION; + *op = '\0'; + } else if ((op = strchr(mvalue1, '%'))) { + iaction = MODULUSFUNCTION; + *op = '\0'; + } else if ((op = strchr(mvalue1, '>'))) { + iaction = GTFUNCTION; + *op = '\0'; + if (*(op + 1) == '=') { + *++op = '\0'; + iaction = GTEFUNCTION; + } + } else if ((op = strchr(mvalue1, '<'))) { + iaction = LTFUNCTION; + *op = '\0'; + if (*(op + 1) == '=') { + *++op = '\0'; + iaction = LTEFUNCTION; + } + } else if ((op = strchr(mvalue1, '='))) { + *op = '\0'; + if (*(op + 1) == '=') { + *++op = '\0'; + iaction = EQFUNCTION; + } else + op = NULL; + } else if ((op = strchr(mvalue1, '+'))) { + iaction = ADDFUNCTION; + *op = '\0'; + } else if ((op = strchr(mvalue1, '-'))) { /* subtraction MUST always be last, in case we have a negative first number */ + iaction = SUBTRACTFUNCTION; + *op = '\0'; + } + + if (op) + mvalue2 = op + 1; + + /* detect wanted type of result */ + mtype_of_result = args.argv1; + if (mtype_of_result) { + if (!strcasecmp(mtype_of_result, "float") + || !strcasecmp(mtype_of_result, "f")) + type_of_result = FLOAT_RESULT; + else if (!strcasecmp(mtype_of_result, "int") + || !strcasecmp(mtype_of_result, "i")) + type_of_result = INT_RESULT; + else if (!strcasecmp(mtype_of_result, "hex") + || !strcasecmp(mtype_of_result, "h")) + type_of_result = HEX_RESULT; + else if (!strcasecmp(mtype_of_result, "char") + || !strcasecmp(mtype_of_result, "c")) + type_of_result = CHAR_RESULT; + else { + ast_log(LOG_WARNING, "Unknown type of result requested '%s'.\n", + mtype_of_result); + return -1; + } + } + + if (!mvalue1 || !mvalue2) { + ast_log(LOG_WARNING, + "Supply all the parameters - just this once, please\n"); + return -1; + } + + if (sscanf(mvalue1, "%30lf", &fnum1) != 1) { + ast_log(LOG_WARNING, "'%s' is not a valid number\n", mvalue1); + return -1; + } + + if (sscanf(mvalue2, "%30lf", &fnum2) != 1) { + ast_log(LOG_WARNING, "'%s' is not a valid number\n", mvalue2); + return -1; + } + + if (negvalue1) + fnum1 = 0 - fnum1; + + switch (iaction) { + case ADDFUNCTION: + ftmp = fnum1 + fnum2; + break; + case DIVIDEFUNCTION: + if (fnum2 <= 0) + ftmp = 0; /* can't do a divide by 0 */ + else + ftmp = (fnum1 / fnum2); + break; + case MULTIPLYFUNCTION: + ftmp = (fnum1 * fnum2); + break; + case SUBTRACTFUNCTION: + ftmp = (fnum1 - fnum2); + break; + case MODULUSFUNCTION: + { + int inum1 = fnum1; + int inum2 = fnum2; + + ftmp = (inum1 % inum2); + + break; + } + case GTFUNCTION: + ast_copy_string(buf, (fnum1 > fnum2) ? "TRUE" : "FALSE", len); + break; + case LTFUNCTION: + ast_copy_string(buf, (fnum1 < fnum2) ? "TRUE" : "FALSE", len); + break; + case GTEFUNCTION: + ast_copy_string(buf, (fnum1 >= fnum2) ? "TRUE" : "FALSE", len); + break; + case LTEFUNCTION: + ast_copy_string(buf, (fnum1 <= fnum2) ? "TRUE" : "FALSE", len); + break; + case EQFUNCTION: + ast_copy_string(buf, (fnum1 == fnum2) ? "TRUE" : "FALSE", len); + break; + default: + ast_log(LOG_WARNING, + "Something happened that neither of us should be proud of %d\n", + iaction); + return -1; + } + + if (iaction < GTFUNCTION || iaction > EQFUNCTION) { + if (type_of_result == FLOAT_RESULT) + snprintf(buf, len, "%f", ftmp); + else if (type_of_result == INT_RESULT) + snprintf(buf, len, "%i", (int) ftmp); + else if (type_of_result == HEX_RESULT) + snprintf(buf, len, "%x", (unsigned int) ftmp); + else if (type_of_result == CHAR_RESULT) + snprintf(buf, len, "%c", (unsigned char) ftmp); + } + + return 0; +} + +static struct ast_custom_function math_function = { + .name = "MATH", + .synopsis = "Performs Mathematical Functions", + .syntax = "MATH(<number1><op><number 2>[,<type_of_result>])", + .desc = "Perform calculation on number 1 to number 2. Valid ops are: \n" + " +,-,/,*,%,<,>,>=,<=,==\n" + "and behave as their C equivalents.\n" + "<type_of_result> - wanted type of result:\n" + " f, float - float(default)\n" + " i, int - integer,\n" + " h, hex - hex,\n" + " c, char - char\n" + "Example: Set(i=${MATH(123%16,int)}) - sets var i=11", + .read = math +}; + +static int unload_module(void) +{ + return ast_custom_function_unregister(&math_function); +} + +static int load_module(void) +{ + return ast_custom_function_register(&math_function); +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Mathematical dialplan function"); diff --git a/1.4.26.1/funcs/func_md5.c b/1.4.26.1/funcs/func_md5.c new file mode 100644 index 000000000..db6be8f7b --- /dev/null +++ b/1.4.26.1/funcs/func_md5.c @@ -0,0 +1,120 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2005-2006, Digium, Inc. + * Copyright (C) 2005, Olle E. Johansson, Edvina.net + * Copyright (C) 2005, Russell Bryant <russelb@clemson.edu> + * + * 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 MD5 digest related dialplan functions + * + * \author Olle E. Johansson <oej@edvina.net> + * \author Russell Bryant <russelb@clemson.edu> + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/logger.h" +#include "asterisk/utils.h" +#include "asterisk/app.h" + +static int md5(struct ast_channel *chan, char *cmd, char *data, + char *buf, size_t len) +{ + if (ast_strlen_zero(data)) { + ast_log(LOG_WARNING, "Syntax: MD5(<data>) - missing argument!\n"); + return -1; + } + + ast_md5_hash(buf, data); + buf[32] = '\0'; + + return 0; +} + +static int checkmd5(struct ast_channel *chan, char *cmd, char *parse, + char *buf, size_t len) +{ + char newmd5[33]; + static int deprecated = 0; + AST_DECLARE_APP_ARGS(args, AST_APP_ARG(digest); AST_APP_ARG(data);); + + if (ast_strlen_zero(parse)) { + ast_log(LOG_WARNING, + "Syntax: CHECK_MD5(<digest>,<data>) - missing argument!\n"); + return -1; + } + + AST_STANDARD_APP_ARGS(args, parse); + + if (args.argc < 2) { + ast_log(LOG_WARNING, + "Syntax: CHECK_MD5(<digest>,<data>) - missing argument!\n"); + return -1; + } + + if (!deprecated) { + deprecated = 1; + ast_log(LOG_WARNING, "CHECK_MD5() is deprecated in Asterisk 1.4 and later.\n"); + } + + ast_md5_hash(newmd5, args.data); + + if (!strcasecmp(newmd5, args.digest)) /* they match */ + ast_copy_string(buf, "1", len); + else + ast_copy_string(buf, "0", len); + + return 0; +} + +static struct ast_custom_function md5_function = { + .name = "MD5", + .synopsis = "Computes an MD5 digest", + .syntax = "MD5(<data>)", + .read = md5, +}; + +static struct ast_custom_function checkmd5_function = { + .name = "CHECK_MD5", + .synopsis = "Checks an MD5 digest", + .desc = "Returns 1 on a match, 0 otherwise\n", + .syntax = "CHECK_MD5(<digest>,<data>)", + .read = checkmd5, +}; + +static int unload_module(void) +{ + return ast_custom_function_unregister(&md5_function) | + ast_custom_function_unregister(&checkmd5_function); +} + +static int load_module(void) +{ + return ast_custom_function_register(&md5_function) | + ast_custom_function_register(&checkmd5_function); +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "MD5 digest dialplan functions"); diff --git a/1.4.26.1/funcs/func_moh.c b/1.4.26.1/funcs/func_moh.c new file mode 100644 index 000000000..86701b161 --- /dev/null +++ b/1.4.26.1/funcs/func_moh.c @@ -0,0 +1,87 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 1999 - 2006, Digium, Inc. + * + * Russell Bryant <russelb@clemson.edu> + * + * 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 Functions for reading or setting the MusicOnHold class + * + * \author Russell Bryant <russelb@clemson.edu> + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdio.h> +#include <stdlib.h> + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/utils.h" +#include "asterisk/stringfields.h" + +static int depwarning = 0; + +static int moh_read(struct ast_channel *chan, char *cmd, char *data, + char *buf, size_t len) +{ + if (!depwarning) { + depwarning = 1; + ast_log(LOG_WARNING, "MUSICCLASS() is deprecated; use CHANNEL(musicclass) instead.\n"); + } + + ast_copy_string(buf, chan ? chan->musicclass : "", len); + + return 0; +} + +static int moh_write(struct ast_channel *chan, char *cmd, char *data, + const char *value) +{ + if (!depwarning) { + depwarning = 1; + ast_log(LOG_WARNING, "MUSICCLASS() is deprecated; use CHANNEL(musicclass) instead.\n"); + } + + if (chan) + ast_string_field_set(chan, musicclass, value); + + return 0; +} + +static struct ast_custom_function moh_function = { + .name = "MUSICCLASS", + .synopsis = "Read or Set the MusicOnHold class", + .syntax = "MUSICCLASS()", + .desc = "Deprecated. Use CHANNEL(musicclass) instead.\n", + .read = moh_read, + .write = moh_write, +}; + +static int unload_module(void) +{ + return ast_custom_function_unregister(&moh_function); +} + +static int load_module(void) +{ + return ast_custom_function_register(&moh_function); +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Music-on-hold dialplan function"); diff --git a/1.4.26.1/funcs/func_odbc.c b/1.4.26.1/funcs/func_odbc.c new file mode 100644 index 000000000..49007d792 --- /dev/null +++ b/1.4.26.1/funcs/func_odbc.c @@ -0,0 +1,672 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (c) 2005, 2006 Tilghman Lesher + * + * Tilghman Lesher <func_odbc__200508@the-tilghman.com> + * + * 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 ODBC lookups + * + * \author Tilghman Lesher <func_odbc__200508@the-tilghman.com> + */ + +/*** MODULEINFO + <depend>unixodbc</depend> + <depend>ltdl</depend> + <depend>res_odbc</depend> + ***/ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include "asterisk/module.h" +#include "asterisk/file.h" +#include "asterisk/logger.h" +#include "asterisk/options.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/module.h" +#include "asterisk/config.h" +#include "asterisk/res_odbc.h" +#include "asterisk/app.h" + +static char *config = "func_odbc.conf"; + +enum { + OPT_ESCAPECOMMAS = (1 << 0), +} odbc_option_flags; + +struct acf_odbc_query { + AST_LIST_ENTRY(acf_odbc_query) list; + char dsn[30]; + char sql_read[2048]; + char sql_write[2048]; + unsigned int flags; + struct ast_custom_function *acf; +}; + +AST_LIST_HEAD_STATIC(queries, acf_odbc_query); + +static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data) +{ + int res; + char *sql = data; + SQLHSTMT stmt; + + res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n"); + return NULL; + } + + res = SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql); + SQLCloseCursor(stmt); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + return NULL; + } + + return stmt; +} + +/* + * Master control routine + */ +static int acf_odbc_write(struct ast_channel *chan, char *cmd, char *s, const char *value) +{ + struct odbc_obj *obj; + struct acf_odbc_query *query; + char *t, buf[2048]="", varname[15]; + int i, bogus_chan = 0; + AST_DECLARE_APP_ARGS(values, + AST_APP_ARG(field)[100]; + ); + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(field)[100]; + ); + SQLHSTMT stmt; + SQLLEN rows=0; + + AST_LIST_LOCK(&queries); + AST_LIST_TRAVERSE(&queries, query, list) { + if (!strcmp(query->acf->name, cmd)) { + break; + } + } + + if (!query) { + ast_log(LOG_ERROR, "No such function '%s'\n", cmd); + AST_LIST_UNLOCK(&queries); + return -1; + } + + obj = ast_odbc_request_obj(query->dsn, 0); + + if (!obj) { + ast_log(LOG_ERROR, "No database handle available with the name of '%s' (check res_odbc.conf)\n", query->dsn); + AST_LIST_UNLOCK(&queries); + return -1; + } + + if (!chan) { + if ((chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc"))) + bogus_chan = 1; + } + + if (chan) + ast_autoservice_start(chan); + + /* Parse our arguments */ + t = value ? ast_strdupa(value) : ""; + + if (!s || !t) { + ast_log(LOG_ERROR, "Out of memory\n"); + AST_LIST_UNLOCK(&queries); + if (chan) + ast_autoservice_stop(chan); + if (bogus_chan) + ast_channel_free(chan); + return -1; + } + + AST_STANDARD_APP_ARGS(args, s); + for (i = 0; i < args.argc; i++) { + snprintf(varname, sizeof(varname), "ARG%d", i + 1); + pbx_builtin_pushvar_helper(chan, varname, args.field[i]); + } + + /* Parse values, just like arguments */ + /* Can't use the pipe, because app Set removes them */ + AST_NONSTANDARD_APP_ARGS(values, t, ','); + for (i = 0; i < values.argc; i++) { + snprintf(varname, sizeof(varname), "VAL%d", i + 1); + pbx_builtin_pushvar_helper(chan, varname, values.field[i]); + } + + /* Additionally set the value as a whole (but push an empty string if value is NULL) */ + pbx_builtin_pushvar_helper(chan, "VALUE", value ? value : ""); + + pbx_substitute_variables_helper(chan, query->sql_write, buf, sizeof(buf) - 1); + + /* Restore prior values */ + for (i = 0; i < args.argc; i++) { + snprintf(varname, sizeof(varname), "ARG%d", i + 1); + pbx_builtin_setvar_helper(chan, varname, NULL); + } + + for (i = 0; i < values.argc; i++) { + snprintf(varname, sizeof(varname), "VAL%d", i + 1); + pbx_builtin_setvar_helper(chan, varname, NULL); + } + pbx_builtin_setvar_helper(chan, "VALUE", NULL); + + AST_LIST_UNLOCK(&queries); + + stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, buf); + + if (stmt) { + /* Rows affected */ + SQLRowCount(stmt, &rows); + } + + /* Output the affected rows, for all cases. In the event of failure, we + * flag this as -1 rows. Note that this is different from 0 affected rows + * which would be the case if we succeeded in our query, but the values did + * not change. */ + snprintf(varname, sizeof(varname), "%d", (int)rows); + pbx_builtin_setvar_helper(chan, "ODBCROWS", varname); + + if (stmt) { + SQLCloseCursor(stmt); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + } + if (obj) + ast_odbc_release_obj(obj); + + if (chan) + ast_autoservice_stop(chan); + if (bogus_chan) + ast_channel_free(chan); + + return 0; +} + +static int acf_odbc_read(struct ast_channel *chan, char *cmd, char *s, char *buf, size_t len) +{ + struct odbc_obj *obj; + struct acf_odbc_query *query; + char sql[2048] = "", varname[15]; + int res, x, buflen = 1, escapecommas, bogus_chan = 0; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(field)[100]; + ); + SQLHSTMT stmt; + SQLSMALLINT colcount=0; + SQLLEN indicator; + + AST_LIST_LOCK(&queries); + AST_LIST_TRAVERSE(&queries, query, list) { + if (!strcmp(query->acf->name, cmd)) { + break; + } + } + + if (!query) { + ast_log(LOG_ERROR, "No such function '%s'\n", cmd); + AST_LIST_UNLOCK(&queries); + return -1; + } + + obj = ast_odbc_request_obj(query->dsn, 0); + + if (!obj) { + ast_log(LOG_ERROR, "No such DSN registered (or out of connections): %s (check res_odbc.conf)\n", query->dsn); + AST_LIST_UNLOCK(&queries); + return -1; + } + + if (!chan) { + if ((chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc"))) + bogus_chan = 1; + } + + if (chan) + ast_autoservice_start(chan); + + AST_STANDARD_APP_ARGS(args, s); + for (x = 0; x < args.argc; x++) { + snprintf(varname, sizeof(varname), "ARG%d", x + 1); + pbx_builtin_pushvar_helper(chan, varname, args.field[x]); + } + + pbx_substitute_variables_helper(chan, query->sql_read, sql, sizeof(sql) - 1); + + /* Restore prior values */ + for (x = 0; x < args.argc; x++) { + snprintf(varname, sizeof(varname), "ARG%d", x + 1); + pbx_builtin_setvar_helper(chan, varname, NULL); + } + + /* Save this flag, so we can release the lock */ + escapecommas = ast_test_flag(query, OPT_ESCAPECOMMAS); + + AST_LIST_UNLOCK(&queries); + + stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, sql); + + if (!stmt) { + ast_odbc_release_obj(obj); + if (chan) + ast_autoservice_stop(chan); + if (bogus_chan) + ast_channel_free(chan); + return -1; + } + + res = SQLNumResultCols(stmt, &colcount); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql); + SQLCloseCursor(stmt); + SQLFreeHandle (SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + if (chan) + ast_autoservice_stop(chan); + if (bogus_chan) + ast_channel_free(chan); + return -1; + } + + *buf = '\0'; + + res = SQLFetch(stmt); + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + int res1 = -1; + if (res == SQL_NO_DATA) { + if (option_verbose > 3) { + ast_verbose(VERBOSE_PREFIX_4 "Found no rows [%s]\n", sql); + } + res1 = 0; + } else if (option_verbose > 3) { + ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, sql); + } + SQLCloseCursor(stmt); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + if (chan) + ast_autoservice_stop(chan); + if (bogus_chan) + ast_channel_free(chan); + return res1; + } + + for (x = 0; x < colcount; x++) { + int i; + char coldata[256]; + + buflen = strlen(buf); + res = SQLGetData(stmt, x + 1, SQL_CHAR, coldata, sizeof(coldata), &indicator); + if (indicator == SQL_NULL_DATA) { + coldata[0] = '\0'; + res = SQL_SUCCESS; + } + + if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) { + ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql); + SQLCloseCursor(stmt); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + if (chan) + ast_autoservice_stop(chan); + if (bogus_chan) + ast_channel_free(chan); + return -1; + } + + /* Copy data, encoding '\' and ',' for the argument parser */ + for (i = 0; i < sizeof(coldata); i++) { + if (escapecommas && (coldata[i] == '\\' || coldata[i] == ',')) { + buf[buflen++] = '\\'; + } + buf[buflen++] = coldata[i]; + + if (buflen >= len - 2) + break; + + if (coldata[i] == '\0') + break; + } + + buf[buflen - 1] = ','; + buf[buflen] = '\0'; + } + /* Trim trailing comma */ + buf[buflen - 1] = '\0'; + + SQLCloseCursor(stmt); + SQLFreeHandle(SQL_HANDLE_STMT, stmt); + ast_odbc_release_obj(obj); + if (chan) + ast_autoservice_stop(chan); + if (bogus_chan) + ast_channel_free(chan); + return 0; +} + +static int acf_escape(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) +{ + char *out = buf; + + for (; *data && out - buf < len; data++) { + if (*data == '\'') { + *out = '\''; + out++; + } + *out++ = *data; + } + *out = '\0'; + + return 0; +} + +static struct ast_custom_function escape_function = { + .name = "SQL_ESC", + .synopsis = "Escapes single ticks for use in SQL statements", + .syntax = "SQL_ESC(<string>)", + .desc = +"Used in SQL templates to escape data which may contain single ticks (') which\n" +"are otherwise used to delimit data. For example:\n" +"SELECT foo FROM bar WHERE baz='${SQL_ESC(${ARG1})}'\n", + .read = acf_escape, + .write = NULL, +}; + +static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_query **query) +{ + const char *tmp; + int res; + + if (!cfg || !catg) { + return -1; + } + + *query = ast_calloc(1, sizeof(struct acf_odbc_query)); + if (! (*query)) + return -1; + + if ((tmp = ast_variable_retrieve(cfg, catg, "dsn"))) { + ast_copy_string((*query)->dsn, tmp, sizeof((*query)->dsn)); + } else if ((tmp = ast_variable_retrieve(cfg, catg, "writehandle")) || (tmp = ast_variable_retrieve(cfg, catg, "readhandle"))) { + ast_log(LOG_WARNING, "Separate read and write handles are not supported in this version of func_odbc.so\n"); + ast_copy_string((*query)->dsn, tmp, sizeof((*query)->dsn)); + } else { + free(*query); + *query = NULL; + ast_log(LOG_ERROR, "No database handle was specified for func_odbc class '%s'\n", catg); + return -1; + } + + if ((tmp = ast_variable_retrieve(cfg, catg, "read")) || (tmp = ast_variable_retrieve(cfg, catg, "readsql"))) { + ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read)); + } + + if ((tmp = ast_variable_retrieve(cfg, catg, "write")) || (tmp = ast_variable_retrieve(cfg, catg, "writesql"))) { + ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write)); + } + + /* Allow escaping of embedded commas in fields to be turned off */ + ast_set_flag((*query), OPT_ESCAPECOMMAS); + if ((tmp = ast_variable_retrieve(cfg, catg, "escapecommas"))) { + if (ast_false(tmp)) + ast_clear_flag((*query), OPT_ESCAPECOMMAS); + } + + (*query)->acf = ast_calloc(1, sizeof(struct ast_custom_function)); + if (! (*query)->acf) { + free(*query); + *query = NULL; + return -1; + } + + if ((tmp = ast_variable_retrieve(cfg, catg, "prefix")) && !ast_strlen_zero(tmp)) { + if (asprintf((char **)&((*query)->acf->name), "%s_%s", tmp, catg) < 0) { + ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); + } + } else { + if (asprintf((char **)&((*query)->acf->name), "ODBC_%s", catg) < 0) { + ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); + } + } + + if (!((*query)->acf->name)) { + free((*query)->acf); + free(*query); + *query = NULL; + return -1; + } + + if (asprintf((char **)&((*query)->acf->syntax), "%s(<arg1>[...[,<argN>]])", (*query)->acf->name) < 0) { + ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); + (*query)->acf->syntax = NULL; + } + + if (!((*query)->acf->syntax)) { + free((char *)(*query)->acf->name); + free((*query)->acf); + free(*query); + *query = NULL; + return -1; + } + + res = 0; + (*query)->acf->synopsis = "Runs the referenced query with the specified arguments"; + if (!ast_strlen_zero((*query)->sql_read) && !ast_strlen_zero((*query)->sql_write)) { + res = asprintf((char **)&((*query)->acf->desc), + "Runs the following query, as defined in func_odbc.conf, performing\n" + "substitution of the arguments into the query as specified by ${ARG1},\n" + "${ARG2}, ... ${ARGn}. When setting the function, the values are provided\n" + "either in whole as ${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n" + "\nRead:\n%s\n\nWrite:\n%s\n", + (*query)->sql_read, + (*query)->sql_write); + } else if (!ast_strlen_zero((*query)->sql_read)) { + res = asprintf((char **)&((*query)->acf->desc), + "Runs the following query, as defined in func_odbc.conf, performing\n" + "substitution of the arguments into the query as specified by ${ARG1},\n" + "${ARG2}, ... ${ARGn}. This function may only be read, not set.\n\nSQL:\n%s\n", + (*query)->sql_read); + } else if (!ast_strlen_zero((*query)->sql_write)) { + res = asprintf((char **)&((*query)->acf->desc), + "Runs the following query, as defined in func_odbc.conf, performing\n" + "substitution of the arguments into the query as specified by ${ARG1},\n" + "${ARG2}, ... ${ARGn}. The values are provided either in whole as\n" + "${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n" + "This function may only be set.\nSQL:\n%s\n", + (*query)->sql_write); + } else { + ast_log(LOG_ERROR, "No SQL was found for func_odbc class '%s'\n", catg); + } + + if (res < 0) { + ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno)); + (*query)->acf->desc = NULL; + } + + /* Could be out of memory, or could be we have neither sql_read nor sql_write */ + if (!((*query)->acf->desc)) { + free((char *)(*query)->acf->syntax); + free((char *)(*query)->acf->name); + free((*query)->acf); + free(*query); + *query = NULL; + return -1; + } + + if (ast_strlen_zero((*query)->sql_read)) { + (*query)->acf->read = NULL; + } else { + (*query)->acf->read = acf_odbc_read; + } + + if (ast_strlen_zero((*query)->sql_write)) { + (*query)->acf->write = NULL; + } else { + (*query)->acf->write = acf_odbc_write; + } + + return 0; +} + +static int free_acf_query(struct acf_odbc_query *query) +{ + if (query) { + if (query->acf) { + if (query->acf->name) + free((char *)query->acf->name); + if (query->acf->syntax) + free((char *)query->acf->syntax); + if (query->acf->desc) + free((char *)query->acf->desc); + free(query->acf); + } + free(query); + } + return 0; +} + +static int odbc_load_module(void) +{ + int res = 0; + struct ast_config *cfg; + char *catg; + + AST_LIST_LOCK(&queries); + + cfg = ast_config_load(config); + if (!cfg) { + ast_log(LOG_NOTICE, "Unable to load config for func_odbc: %s\n", config); + AST_LIST_UNLOCK(&queries); + return AST_MODULE_LOAD_DECLINE; + } + + for (catg = ast_category_browse(cfg, NULL); + catg; + catg = ast_category_browse(cfg, catg)) { + struct acf_odbc_query *query = NULL; + + if (init_acf_query(cfg, catg, &query)) { + free_acf_query(query); + } else { + AST_LIST_INSERT_HEAD(&queries, query, list); + ast_custom_function_register(query->acf); + } + } + + ast_config_destroy(cfg); + ast_custom_function_register(&escape_function); + + AST_LIST_UNLOCK(&queries); + return res; +} + +static int odbc_unload_module(void) +{ + struct acf_odbc_query *query; + + AST_LIST_LOCK(&queries); + while (!AST_LIST_EMPTY(&queries)) { + query = AST_LIST_REMOVE_HEAD(&queries, list); + ast_custom_function_unregister(query->acf); + free_acf_query(query); + } + + ast_custom_function_unregister(&escape_function); + + /* Allow any threads waiting for this lock to pass (avoids a race) */ + AST_LIST_UNLOCK(&queries); + AST_LIST_LOCK(&queries); + + AST_LIST_UNLOCK(&queries); + return 0; +} + +static int reload(void) +{ + int res = 0; + struct ast_config *cfg; + struct acf_odbc_query *oldquery; + char *catg; + + AST_LIST_LOCK(&queries); + + while (!AST_LIST_EMPTY(&queries)) { + oldquery = AST_LIST_REMOVE_HEAD(&queries, list); + ast_custom_function_unregister(oldquery->acf); + free_acf_query(oldquery); + } + + cfg = ast_config_load(config); + if (!cfg) { + ast_log(LOG_WARNING, "Unable to load config for func_odbc: %s\n", config); + goto reload_out; + } + + for (catg = ast_category_browse(cfg, NULL); + catg; + catg = ast_category_browse(cfg, catg)) { + struct acf_odbc_query *query = NULL; + + if (init_acf_query(cfg, catg, &query)) { + ast_log(LOG_ERROR, "Cannot initialize query %s\n", catg); + } else { + AST_LIST_INSERT_HEAD(&queries, query, list); + ast_custom_function_register(query->acf); + } + } + + ast_config_destroy(cfg); +reload_out: + AST_LIST_UNLOCK(&queries); + return res; +} + +static int unload_module(void) +{ + return odbc_unload_module(); +} + +static int load_module(void) +{ + return odbc_load_module(); +} + +/* XXX need to revise usecount - set if query_lock is set */ + +AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ODBC lookups", + .load = load_module, + .unload = unload_module, + .reload = reload, + ); + diff --git a/1.4.26.1/funcs/func_rand.c b/1.4.26.1/funcs/func_rand.c new file mode 100644 index 000000000..ea6d7d393 --- /dev/null +++ b/1.4.26.1/funcs/func_rand.c @@ -0,0 +1,104 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2006, Digium, Inc. + * Copyright (C) 2006, Claude Patry + * + * 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 Generate Random Number + * + * \author Claude Patry <cpatry@gmail.com> + * \author Tilghman Lesher ( http://asterisk.drunkcoder.com/ ) + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <sys/types.h> + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/logger.h" +#include "asterisk/utils.h" +#include "asterisk/app.h" + +static int acf_rand_exec(struct ast_channel *chan, char *cmd, + char *parse, char *buffer, size_t buflen) +{ + struct ast_module_user *u; + int min_int, response_int, max_int; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(min); + AST_APP_ARG(max); + ); + + u = ast_module_user_add(chan); + + AST_STANDARD_APP_ARGS(args, parse); + + if (ast_strlen_zero(args.min) || sscanf(args.min, "%30d", &min_int) != 1) + min_int = 0; + + if (ast_strlen_zero(args.max) || sscanf(args.max, "%30d", &max_int) != 1) + max_int = RAND_MAX; + + if (max_int < min_int) { + int tmp = max_int; + + max_int = min_int; + min_int = tmp; + ast_log(LOG_DEBUG, "max<min\n"); + } + + response_int = min_int + (ast_random() % (max_int - min_int + 1)); + ast_log(LOG_DEBUG, "%d was the lucky number in range [%d,%d]\n", + response_int, min_int, max_int); + snprintf(buffer, buflen, "%d", response_int); + + ast_module_user_remove(u); + + return 0; +} + +static struct ast_custom_function acf_rand = { + .name = "RAND", + .synopsis = "Choose a random number in a range", + .syntax = "RAND([min][|max])", + .desc = + "Choose a random number between min and max. Min defaults to 0, if not\n" + "specified, while max defaults to RAND_MAX (2147483647 on many systems).\n" + " Example: Set(junky=${RAND(1|8)}); \n" + " Sets junky to a random number between 1 and 8, inclusive.\n", + .read = acf_rand_exec, +}; + +static int unload_module(void) +{ + ast_custom_function_unregister(&acf_rand); + + return 0; +} + +static int load_module(void) +{ + return ast_custom_function_register(&acf_rand); +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Random number dialplan function"); diff --git a/1.4.26.1/funcs/func_realtime.c b/1.4.26.1/funcs/func_realtime.c new file mode 100644 index 000000000..6941b224e --- /dev/null +++ b/1.4.26.1/funcs/func_realtime.c @@ -0,0 +1,175 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2005-2006, BJ Weschke. All rights reserved. + * + * BJ Weschke <bweschke@btwtech.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. + * + */ + +/*! \file + * + * \brief REALTIME dialplan function + * + * \author BJ Weschke <bweschke@btwtech.com> + * + * \ingroup functions + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/types.h> + +#include "asterisk/file.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/options.h" +#include "asterisk/config.h" +#include "asterisk/module.h" +#include "asterisk/lock.h" +#include "asterisk/logger.h" +#include "asterisk/utils.h" +#include "asterisk/app.h" + +static int function_realtime_read(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) +{ + struct ast_variable *var, *head; + struct ast_module_user *u; + char *results, *result_begin; + size_t resultslen = 0; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(family); + AST_APP_ARG(fieldmatch); + AST_APP_ARG(value); + AST_APP_ARG(delim1); + AST_APP_ARG(delim2); + ); + + + if (ast_strlen_zero(data)) { + ast_log(LOG_WARNING, "Syntax: REALTIME(family|fieldmatch[|value[|delim1[|delim2]]]) - missing argument!\n"); + return -1; + } + + u = ast_module_user_add(chan); + + AST_STANDARD_APP_ARGS(args, data); + + if (!args.delim1) + args.delim1 = "|"; + if (!args.delim2) + args.delim2 = "="; + + if (chan) + ast_autoservice_start(chan); + + head = ast_load_realtime(args.family, args.fieldmatch, args.value, NULL); + + if (!head) { + ast_module_user_remove(u); + if (chan) + ast_autoservice_stop(chan); + return -1; + } + for (var = head; var; var = var->next) + resultslen += strlen(var->name) + strlen(var->value) + strlen(args.delim1) + strlen(args.delim2); + + result_begin = results = alloca(resultslen); + for (var = head; var; var = var->next) + ast_build_string(&results, &resultslen, "%s%s%s%s", var->name, args.delim2, var->value, args.delim1); + ast_copy_string(buf, result_begin, len); + + ast_module_user_remove(u); + + if (chan) + ast_autoservice_stop(chan); + + return 0; +} + +static int function_realtime_write(struct ast_channel *chan, char *cmd, char *data, const char *value) +{ + struct ast_module_user *u = NULL; + int res = 0; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(family); + AST_APP_ARG(fieldmatch); + AST_APP_ARG(value); + AST_APP_ARG(field); + ); + + if (ast_strlen_zero(data)) { + ast_log(LOG_WARNING, "Syntax: REALTIME(family|fieldmatch|value|newcol) - missing argument!\n"); + return -1; + } + + if (chan) { + ast_autoservice_start(chan); + u = ast_module_user_add(chan); + } + + AST_STANDARD_APP_ARGS(args, data); + + res = ast_update_realtime(args.family, args.fieldmatch, args.value, args.field, (char *)value, NULL); + + if (res < 0) { + ast_log(LOG_WARNING, "Failed to update. Check the debug log for possible data repository related entries.\n"); + } + + if (chan) { + ast_module_user_remove(u); + ast_autoservice_stop(chan); + } + + return 0; +} + +struct ast_custom_function realtime_function = { + .name = "REALTIME", + .synopsis = "RealTime Read/Write Functions", + .syntax = "REALTIME(family|fieldmatch[|value[|delim1[|delim2]]]) on read\n" + "REALTIME(family|fieldmatch|value|field) on write\n", + .desc = "This function will read or write values from/to a RealTime repository.\n" + "REALTIME(....) will read names/values from the repository, and \n" + "REALTIME(....)= will write a new value/field to the repository. On a\n" + "read, this function returns a delimited text string. The name/value \n" + "pairs are delimited by delim1, and the name and value are delimited \n" + "between each other with delim2. The default for delim1 is '|' and \n" + "the default for delim2 is '='. If there is no match, NULL will be \n" + "returned by the function. On a write, this function will always \n" + "return NULL. \n", + .read = function_realtime_read, + .write = function_realtime_write, +}; + +static int unload_module(void) +{ + int res = ast_custom_function_unregister(&realtime_function); + + ast_module_user_hangup_all(); + + return res; +} + +static int load_module(void) +{ + int res = ast_custom_function_register(&realtime_function); + + return res; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Read/Write values from a RealTime repository"); diff --git a/1.4.26.1/funcs/func_sha1.c b/1.4.26.1/funcs/func_sha1.c new file mode 100644 index 000000000..01c7eb023 --- /dev/null +++ b/1.4.26.1/funcs/func_sha1.c @@ -0,0 +1,83 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2006, Digium, Inc. + * Copyright (C) 2006, Claude Patry + * + * 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 SHA1 digest related dialplan functions + * + * \author Claude Patry <cpatry@gmail.com> + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/logger.h" +#include "asterisk/utils.h" +#include "asterisk/app.h" + +static int sha1(struct ast_channel *chan, char *cmd, char *data, + char *buf, size_t len) +{ + *buf = '\0'; + + if (ast_strlen_zero(data)) { + ast_log(LOG_WARNING, "Syntax: SHA1(<data>) - missing argument!\n"); + return -1; + } + + if (len >= 41) + ast_sha1_hash(buf, data); + else { + ast_log(LOG_ERROR, + "Insufficient space to produce SHA1 hash result (%d < 41)\n", + (int) len); + } + + return 0; +} + +static struct ast_custom_function sha1_function = { + .name = "SHA1", + .synopsis = "Computes a SHA1 digest", + .syntax = "SHA1(<data>)", + .read = sha1, + .desc = "Generate a SHA1 digest via the SHA1 algorythm.\n" + " Example: Set(sha1hash=${SHA1(junky)})\n" + " Sets the asterisk variable sha1hash to the string '60fa5675b9303eb62f99a9cd47f9f5837d18f9a0'\n" + " which is known as his hash\n", +}; + +static int unload_module(void) +{ + return ast_custom_function_unregister(&sha1_function); +} + +static int load_module(void) +{ + return ast_custom_function_register(&sha1_function); +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SHA-1 computation dialplan function"); diff --git a/1.4.26.1/funcs/func_strings.c b/1.4.26.1/funcs/func_strings.c new file mode 100644 index 000000000..39b647913 --- /dev/null +++ b/1.4.26.1/funcs/func_strings.c @@ -0,0 +1,636 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 2005-2006, Digium, Inc. + * Portions Copyright (C) 2005, Tilghman Lesher. All rights reserved. + * Portions Copyright (C) 2005, Anthony Minessale II + * + * 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 String manipulation dialplan functions + * + * \author Tilghman Lesher + * \author Anothony Minessale II + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <regex.h> + +#include "asterisk/module.h" +#include "asterisk/options.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/logger.h" +#include "asterisk/utils.h" +#include "asterisk/app.h" +#include "asterisk/localtime.h" + +static int function_fieldqty(struct ast_channel *chan, char *cmd, + char *parse, char *buf, size_t len) +{ + char *varsubst, varval[8192] = "", *varval2 = varval; + int fieldcount = 0; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(varname); + AST_APP_ARG(delim); + ); + + AST_STANDARD_APP_ARGS(args, parse); + if (args.delim) { + varsubst = alloca(strlen(args.varname) + 4); + + sprintf(varsubst, "${%s}", args.varname); + pbx_substitute_variables_helper(chan, varsubst, varval, sizeof(varval) - 1); + if (ast_strlen_zero(varval2)) + fieldcount = 0; + else { + while (strsep(&varval2, args.delim)) + fieldcount++; + } + } else { + fieldcount = 1; + } + snprintf(buf, len, "%d", fieldcount); + + return 0; +} + +static struct ast_custom_function fieldqty_function = { + .name = "FIELDQTY", + .synopsis = "Count the fields, with an arbitrary delimiter", + .syntax = "FIELDQTY(<varname>|<delim>)", + .read = function_fieldqty, +}; + +static int filter(struct ast_channel *chan, char *cmd, char *parse, char *buf, + size_t len) +{ + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(allowed); + AST_APP_ARG(string); + ); + char *outbuf = buf; + + AST_STANDARD_APP_ARGS(args, parse); + + if (!args.string) { + ast_log(LOG_ERROR, "Usage: FILTER(<allowed-chars>|<string>)\n"); + return -1; + } + + for (; *(args.string) && (buf + len - 1 > outbuf); (args.string)++) { + if (strchr(args.allowed, *(args.string))) + *outbuf++ = *(args.string); + } + *outbuf = '\0'; + + return 0; +} + +static struct ast_custom_function filter_function = { + .name = "FILTER", + .synopsis = "Filter the string to include only the allowed characters", + .syntax = "FILTER(<allowed-chars>|<string>)", + .read = filter, +}; + +static int regex(struct ast_channel *chan, char *cmd, char *parse, char *buf, + size_t len) +{ + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(null); + AST_APP_ARG(reg); + AST_APP_ARG(str); + ); + int errcode; + regex_t regexbuf; + + buf[0] = '\0'; + + AST_NONSTANDARD_APP_ARGS(args, parse, '"'); + + if (args.argc != 3) { + ast_log(LOG_ERROR, "Unexpected arguments: should have been in the form '\"<regex>\" <string>'\n"); + return -1; + } + if ((*args.str == ' ') || (*args.str == '\t')) + args.str++; + + if (option_debug) + ast_log(LOG_DEBUG, "FUNCTION REGEX (%s)(%s)\n", args.reg, args.str); + + if ((errcode = regcomp(®exbuf, args.reg, REG_EXTENDED | REG_NOSUB))) { + regerror(errcode, ®exbuf, buf, len); + ast_log(LOG_WARNING, "Malformed input %s(%s): %s\n", cmd, parse, buf); + return -1; + } + + strcpy(buf, regexec(®exbuf, args.str, 0, NULL, 0) ? "0" : "1"); + + regfree(®exbuf); + + return 0; +} + +static struct ast_custom_function regex_function = { + .name = "REGEX", + .synopsis = "Regular Expression", + .desc = + "Returns 1 if data matches regular expression, or 0 otherwise.\n" + "Please note that the space following the double quotes separating the regex from the data\n" + "is optional and if present, is skipped. If a space is desired at the beginning of the data,\n" + "then put two spaces there; the second will not be skipped.\n", + .syntax = "REGEX(\"<regular expression>\" <data>)", + .read = regex, +}; + +static int array(struct ast_channel *chan, char *cmd, char *var, + const char *value) +{ + AST_DECLARE_APP_ARGS(arg1, + AST_APP_ARG(var)[100]; + ); + AST_DECLARE_APP_ARGS(arg2, + AST_APP_ARG(val)[100]; + ); + char *value2; + int i; + + value2 = ast_strdupa(value); + if (!var || !value2) + return -1; + + /* The functions this will generally be used with are SORT and ODBC_*, which + * both return comma-delimited lists. However, if somebody uses literal lists, + * their commas will be translated to vertical bars by the load, and I don't + * want them to be surprised by the result. Hence, we prefer commas as the + * delimiter, but we'll fall back to vertical bars if commas aren't found. + */ + if (option_debug) + ast_log(LOG_DEBUG, "array (%s=%s)\n", var, value2); + if (strchr(var, ',')) + AST_NONSTANDARD_APP_ARGS(arg1, var, ','); + else + AST_STANDARD_APP_ARGS(arg1, var); + + if (strchr(value2, ',')) + AST_NONSTANDARD_APP_ARGS(arg2, value2, ','); + else + AST_STANDARD_APP_ARGS(arg2, value2); + + for (i = 0; i < arg1.argc; i++) { + if (option_debug) + ast_log(LOG_DEBUG, "array set value (%s=%s)\n", arg1.var[i], + arg2.val[i]); + if (i < arg2.argc) { + pbx_builtin_setvar_helper(chan, arg1.var[i], arg2.val[i]); + } else { + /* We could unset the variable, by passing a NULL, but due to + * pushvar semantics, that could create some undesired behavior. */ + pbx_builtin_setvar_helper(chan, arg1.var[i], ""); + } + } + + return 0; +} + +static struct ast_custom_function array_function = { + .name = "ARRAY", + .synopsis = "Allows setting multiple variables at once", + .syntax = "ARRAY(var1[|var2[...][|varN]])", + .write = array, + .desc = + "The comma-separated list passed as a value to which the function is set will\n" + "be interpreted as a set of values to which the comma-separated list of\n" + "variable names in the argument should be set.\n" + "Hence, Set(ARRAY(var1|var2)=1\\,2) will set var1 to 1 and var2 to 2\n" + "Note: remember to either backslash your commas in extensions.conf or quote the\n" + "entire argument, since Set can take multiple arguments itself.\n", +}; + +static int acf_sprintf(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) +{ +#define SPRINTF_FLAG 0 +#define SPRINTF_WIDTH 1 +#define SPRINTF_PRECISION 2 +#define SPRINTF_LENGTH 3 +#define SPRINTF_CONVERSION 4 + int i, state = -1, argcount = 0; + char *formatstart = NULL, *bufptr = buf; + char formatbuf[256] = ""; + int tmpi; + double tmpd; + AST_DECLARE_APP_ARGS(arg, + AST_APP_ARG(format); + AST_APP_ARG(var)[100]; + ); + + AST_STANDARD_APP_ARGS(arg, data); + + /* Scan the format, converting each argument into the requisite format type. */ + for (i = 0; arg.format[i]; i++) { + switch (state) { + case SPRINTF_FLAG: + if (strchr("#0- +'I", arg.format[i])) + break; + state = SPRINTF_WIDTH; + case SPRINTF_WIDTH: + if (arg.format[i] >= '0' && arg.format[i] <= '9') + break; + + /* Next character must be a period to go into a precision */ + if (arg.format[i] == '.') { + state = SPRINTF_PRECISION; + } else { + state = SPRINTF_LENGTH; + i--; + } + break; + case SPRINTF_PRECISION: + if (arg.format[i] >= '0' && arg.format[i] <= '9') + break; + state = SPRINTF_LENGTH; + case SPRINTF_LENGTH: + if (strchr("hl", arg.format[i])) { + if (arg.format[i + 1] == arg.format[i]) + i++; + state = SPRINTF_CONVERSION; + break; + } else if (strchr("Lqjzt", arg.format[i])) { + state = SPRINTF_CONVERSION; + break; + } + state = SPRINTF_CONVERSION; + case SPRINTF_CONVERSION: + if (strchr("diouxXc", arg.format[i])) { + /* Integer */ + + /* Isolate this format alone */ + ast_copy_string(formatbuf, formatstart, sizeof(formatbuf)); + formatbuf[&arg.format[i] - formatstart + 1] = '\0'; + + /* Convert the argument into the required type */ + if (arg.var[argcount]) { + if (sscanf(arg.var[argcount++], "%30d", &tmpi) != 1) { + ast_log(LOG_ERROR, "Argument '%s' is not an integer number for format '%s'\n", arg.var[argcount - 1], formatbuf); + goto sprintf_fail; + } + } else { + ast_log(LOG_ERROR, "SPRINTF() has more format specifiers than arguments!\n"); + goto sprintf_fail; + } + + /* Format the argument */ + snprintf(bufptr, buf + len - bufptr, formatbuf, tmpi); + + /* Update the position of the next parameter to print */ + bufptr = strchr(buf, '\0'); + } else if (strchr("eEfFgGaA", arg.format[i])) { + /* Double */ + + /* Isolate this format alone */ + ast_copy_string(formatbuf, formatstart, sizeof(formatbuf)); + formatbuf[&arg.format[i] - formatstart + 1] = '\0'; + + /* Convert the argument into the required type */ + if (arg.var[argcount]) { + if (sscanf(arg.var[argcount++], "%30lf", &tmpd) != 1) { + ast_log(LOG_ERROR, "Argument '%s' is not a floating point number for format '%s'\n", arg.var[argcount - 1], formatbuf); + goto sprintf_fail; + } + } else { + ast_log(LOG_ERROR, "SPRINTF() has more format specifiers than arguments!\n"); + goto sprintf_fail; + } + + /* Format the argument */ + snprintf(bufptr, buf + len - bufptr, formatbuf, tmpd); + + /* Update the position of the next parameter to print */ + bufptr = strchr(buf, '\0'); + } else if (arg.format[i] == 's') { + /* String */ + + /* Isolate this format alone */ + ast_copy_string(formatbuf, formatstart, sizeof(formatbuf)); + formatbuf[&arg.format[i] - formatstart + 1] = '\0'; + + /* Format the argument */ + snprintf(bufptr, buf + len - bufptr, formatbuf, arg.var[argcount++]); + + /* Update the position of the next parameter to print */ + bufptr = strchr(buf, '\0'); + } else if (arg.format[i] == '%') { + /* Literal data to copy */ + *bufptr++ = arg.format[i]; + } else { + /* Not supported */ + + /* Isolate this format alone */ + ast_copy_string(formatbuf, formatstart, sizeof(formatbuf)); + formatbuf[&arg.format[i] - formatstart + 1] = '\0'; + + ast_log(LOG_ERROR, "Format type not supported: '%s' with argument '%s'\n", formatbuf, arg.var[argcount++]); + goto sprintf_fail; + } + state = -1; + break; + default: + if (arg.format[i] == '%') { + state = SPRINTF_FLAG; + formatstart = &arg.format[i]; + break; + } else { + /* Literal data to copy */ + *bufptr++ = arg.format[i]; + } + } + } + *bufptr = '\0'; + return 0; +sprintf_fail: + return -1; +} + +static struct ast_custom_function sprintf_function = { + .name = "SPRINTF", + .synopsis = "Format a variable according to a format string", + .syntax = "SPRINTF(<format>|<arg1>[|...<argN>])", + .read = acf_sprintf, + .desc = +"Parses the format string specified and returns a string matching that format.\n" +"Supports most options supported by sprintf(3). Returns a shortened string if\n" +"a format specifier is not recognized.\n", +}; + +static int quote(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) +{ + char *bufptr = buf, *dataptr = data; + *bufptr++ = '"'; + for (; bufptr < buf + len - 1; dataptr++) { + if (*dataptr == '\\') { + *bufptr++ = '\\'; + *bufptr++ = '\\'; + } else if (*dataptr == '"') { + *bufptr++ = '\\'; + *bufptr++ = '"'; + } else if (*dataptr == '\0') { + break; + } else { + *bufptr++ = *dataptr; + } + } + *bufptr++ = '"'; + *bufptr = '\0'; + return 0; +} + +static struct ast_custom_function quote_function = { + .name = "QUOTE", + .synopsis = "Quotes a given string, escaping embedded quotes as necessary", + .syntax = "QUOTE(<string>)", + .read = quote, +}; + + +static int len(struct ast_channel *chan, char *cmd, char *data, char *buf, + size_t len) +{ + int length = 0; + + if (data) + length = strlen(data); + + snprintf(buf, len, "%d", length); + + return 0; +} + +static struct ast_custom_function len_function = { + .name = "LEN", + .synopsis = "Returns the length of the argument given", + .syntax = "LEN(<string>)", + .read = len, +}; + +static int acf_strftime(struct ast_channel *chan, char *cmd, char *parse, + char *buf, size_t len) +{ + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(epoch); + AST_APP_ARG(timezone); + AST_APP_ARG(format); + ); + time_t epochi; + struct tm tm; + + buf[0] = '\0'; + + AST_STANDARD_APP_ARGS(args, parse); + + ast_get_time_t(args.epoch, &epochi, time(NULL), NULL); + ast_localtime(&epochi, &tm, args.timezone); + + if (!args.format) + args.format = "%c"; + + if (!strftime(buf, len, args.format, &tm)) + ast_log(LOG_WARNING, "C function strftime() output nothing?!!\n"); + + buf[len - 1] = '\0'; + + return 0; +} + +static struct ast_custom_function strftime_function = { + .name = "STRFTIME", + .synopsis = "Returns the current date/time in a specified format.", + .syntax = "STRFTIME([<epoch>][|[timezone][|format]])", + .read = acf_strftime, +}; + +static int acf_strptime(struct ast_channel *chan, char *cmd, char *data, + char *buf, size_t len) +{ + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(timestring); + AST_APP_ARG(timezone); + AST_APP_ARG(format); + ); + struct tm time; + + memset(&time, 0, sizeof(struct tm)); + + buf[0] = '\0'; + + if (!data) { + ast_log(LOG_ERROR, + "Asterisk function STRPTIME() requires an argument.\n"); + return -1; + } + + AST_STANDARD_APP_ARGS(args, data); + + if (ast_strlen_zero(args.format)) { + ast_log(LOG_ERROR, + "No format supplied to STRPTIME(<timestring>|<timezone>|<format>)"); + return -1; + } + + if (!strptime(args.timestring, args.format, &time)) { + ast_log(LOG_WARNING, "C function strptime() output nothing?!!\n"); + } else { + /* Since strptime(3) does not check DST, force ast_mktime() to calculate it. */ + time.tm_isdst = -1; + snprintf(buf, len, "%d", (int) ast_mktime(&time, args.timezone)); + } + + return 0; +} + +static struct ast_custom_function strptime_function = { + .name = "STRPTIME", + .synopsis = + "Returns the epoch of the arbitrary date/time string structured as described in the format.", + .syntax = "STRPTIME(<datetime>|<timezone>|<format>)", + .desc = + "This is useful for converting a date into an EPOCH time, possibly to pass to\n" + "an application like SayUnixTime or to calculate the difference between two\n" + "date strings.\n" + "\n" + "Example:\n" + " ${STRPTIME(2006-03-01 07:30:35|America/Chicago|%Y-%m-%d %H:%M:%S)} returns 1141219835\n", + .read = acf_strptime, +}; + +static int function_eval(struct ast_channel *chan, char *cmd, char *data, + char *buf, size_t len) +{ + memset(buf, 0, len); + + if (ast_strlen_zero(data)) { + ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n"); + return -1; + } + + pbx_substitute_variables_helper(chan, data, buf, len - 1); + + return 0; +} + +static struct ast_custom_function eval_function = { + .name = "EVAL", + .synopsis = "Evaluate stored variables.", + .syntax = "EVAL(<variable>)", + .desc = "Using EVAL basically causes a string to be evaluated twice.\n" + "When a variable or expression is in the dialplan, it will be\n" + "evaluated at runtime. However, if the result of the evaluation\n" + "is in fact a variable or expression, using EVAL will have it\n" + "evaluated a second time. For example, if the variable ${MYVAR}\n" + "contains \"${OTHERVAR}\", then the result of putting ${EVAL(${MYVAR})}\n" + "in the dialplan will be the contents of the variable, OTHERVAR.\n" + "Normally, by just putting ${MYVAR} in the dialplan, you would be\n" + "left with \"${OTHERVAR}\".\n", + .read = function_eval, +}; + +static int keypadhash(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) +{ + char *bufptr, *dataptr; + + for (bufptr = buf, dataptr = data; bufptr < buf + len - 1; dataptr++) { + if (*dataptr == '\0') { + *bufptr++ = '\0'; + break; + } else if (*dataptr == '1') { + *bufptr++ = '1'; + } else if (strchr("AaBbCc2", *dataptr)) { + *bufptr++ = '2'; + } else if (strchr("DdEeFf3", *dataptr)) { + *bufptr++ = '3'; + } else if (strchr("GgHhIi4", *dataptr)) { + *bufptr++ = '4'; + } else if (strchr("JjKkLl5", *dataptr)) { + *bufptr++ = '5'; + } else if (strchr("MmNnOo6", *dataptr)) { + *bufptr++ = '6'; + } else if (strchr("PpQqRrSs7", *dataptr)) { + *bufptr++ = '7'; + } else if (strchr("TtUuVv8", *dataptr)) { + *bufptr++ = '8'; + } else if (strchr("WwXxYyZz9", *dataptr)) { + *bufptr++ = '9'; + } else if (*dataptr == '0') { + *bufptr++ = '0'; + } + } + buf[len - 1] = '\0'; + + return 0; +} + +static struct ast_custom_function keypadhash_function = { + .name = "KEYPADHASH", + .synopsis = "Hash the letters in the string into the equivalent keypad numbers.", + .syntax = "KEYPADHASH(<string>)", + .read = keypadhash, + .desc = "Example: ${KEYPADHASH(Les)} returns \"537\"\n", +}; + +static int unload_module(void) +{ + int res = 0; + + res |= ast_custom_function_unregister(&fieldqty_function); + res |= ast_custom_function_unregister(&filter_function); + res |= ast_custom_function_unregister(®ex_function); + res |= ast_custom_function_unregister(&array_function); + res |= ast_custom_function_unregister("e_function); + res |= ast_custom_function_unregister(&len_function); + res |= ast_custom_function_unregister(&strftime_function); + res |= ast_custom_function_unregister(&strptime_function); + res |= ast_custom_function_unregister(&eval_function); + res |= ast_custom_function_unregister(&keypadhash_function); + res |= ast_custom_function_unregister(&sprintf_function); + + return res; +} + +static int load_module(void) +{ + int res = 0; + + res |= ast_custom_function_register(&fieldqty_function); + res |= ast_custom_function_register(&filter_function); + res |= ast_custom_function_register(®ex_function); + res |= ast_custom_function_register(&array_function); + res |= ast_custom_function_register("e_function); + res |= ast_custom_function_register(&len_function); + res |= ast_custom_function_register(&strftime_function); + res |= ast_custom_function_register(&strptime_function); + res |= ast_custom_function_register(&eval_function); + res |= ast_custom_function_register(&keypadhash_function); + res |= ast_custom_function_register(&sprintf_function); + + return res; +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "String handling dialplan functions"); diff --git a/1.4.26.1/funcs/func_timeout.c b/1.4.26.1/funcs/func_timeout.c new file mode 100644 index 000000000..5b935605a --- /dev/null +++ b/1.4.26.1/funcs/func_timeout.c @@ -0,0 +1,194 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 1999 - 2006, Digium, Inc. + * + * Mark Spencer <markster@digium.com> + * + * 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 Channel timeout related dialplan functions + * + * \author Mark Spencer <markster@digium.com> + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/logger.h" +#include "asterisk/utils.h" +#include "asterisk/app.h" +#include "asterisk/options.h" + +static int timeout_read(struct ast_channel *chan, char *cmd, char *data, + char *buf, size_t len) +{ + time_t myt; + + if (!chan) + return -1; + + if (!data) { + ast_log(LOG_ERROR, "Must specify type of timeout to get.\n"); + return -1; + } + + switch (*data) { + case 'a': + case 'A': + if (chan->whentohangup == 0) { + ast_copy_string(buf, "0", len); + } else { + time(&myt); + snprintf(buf, len, "%d", (int) (chan->whentohangup - myt)); + } + break; + + case 'r': + case 'R': + if (chan->pbx) { + snprintf(buf, len, "%d", chan->pbx->rtimeout); + } + break; + + case 'd': + case 'D': + if (chan->pbx) { + snprintf(buf, len, "%d", chan->pbx->dtimeout); + } + break; + + default: + ast_log(LOG_ERROR, "Unknown timeout type specified.\n"); + return -1; + } + + return 0; +} + +static int timeout_write(struct ast_channel *chan, char *cmd, char *data, + const char *value) +{ + int x; + char timestr[64]; + struct tm myt; + + if (!chan) + return -1; + + if (!data) { + ast_log(LOG_ERROR, "Must specify type of timeout to set.\n"); + return -1; + } + + if (!value) + return -1; + + x = atoi(value); + if (x < 0) + x = 0; + + switch (*data) { + case 'a': + case 'A': + ast_channel_setwhentohangup(chan, x); + if (option_verbose > 2) { + if (chan->whentohangup) { + strftime(timestr, sizeof(timestr), "%Y-%m-%d %H:%M:%S UTC", + gmtime_r(&chan->whentohangup, &myt)); + ast_verbose(VERBOSE_PREFIX_3 "Channel will hangup at %s.\n", + timestr); + } else { + ast_verbose(VERBOSE_PREFIX_3 "Channel hangup cancelled.\n"); + } + } + break; + + case 'r': + case 'R': + if (chan->pbx) { + chan->pbx->rtimeout = x; + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "Response timeout set to %d\n", + chan->pbx->rtimeout); + } + break; + + case 'd': + case 'D': + if (chan->pbx) { + chan->pbx->dtimeout = x; + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "Digit timeout set to %d\n", + chan->pbx->dtimeout); + } + break; + + default: + ast_log(LOG_ERROR, "Unknown timeout type specified.\n"); + break; + } + + return 0; +} + +static struct ast_custom_function timeout_function = { + .name = "TIMEOUT", + .synopsis = "Gets or sets timeouts on the channel.", + .syntax = "TIMEOUT(timeouttype)", + .desc = + "Gets or sets various channel timeouts. The timeouts that can be\n" + "manipulated are:\n" "\n" + "absolute: The absolute maximum amount of time permitted for a call. A\n" + " setting of 0 disables the timeout.\n" "\n" + "digit: The maximum amount of time permitted between digits when the\n" + " user is typing in an extension. When this timeout expires,\n" + " after the user has started to type in an extension, the\n" + " extension will be considered complete, and will be\n" + " interpreted. Note that if an extension typed in is valid,\n" + " it will not have to timeout to be tested, so typically at\n" + " the expiry of this timeout, the extension will be considered\n" + " invalid (and thus control would be passed to the 'i'\n" + " extension, or if it doesn't exist the call would be\n" + " terminated). The default timeout is 5 seconds.\n" "\n" + "response: The maximum amount of time permitted after falling through a\n" + " series of priorities for a channel in which the user may\n" + " begin typing an extension. If the user does not type an\n" + " extension in this amount of time, control will pass to the\n" + " 't' extension if it exists, and if not the call would be\n" + " terminated. The default timeout is 10 seconds.\n", + .read = timeout_read, + .write = timeout_write, +}; + +static int unload_module(void) +{ + return ast_custom_function_unregister(&timeout_function); +} + +static int load_module(void) +{ + return ast_custom_function_register(&timeout_function); +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Channel timeout dialplan functions"); diff --git a/1.4.26.1/funcs/func_uri.c b/1.4.26.1/funcs/func_uri.c new file mode 100644 index 000000000..2680dd678 --- /dev/null +++ b/1.4.26.1/funcs/func_uri.c @@ -0,0 +1,101 @@ +/* + * Asterisk -- An open source telephony toolkit. + * + * Copyright (C) 1999 - 2006, Digium, Inc. + * + * Created by Olle E. Johansson, Edvina.net + * + * 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 URI encoding / decoding + * + * \author Olle E. Johansson <oej@edvina.net> + * + * \note For now this code only supports 8 bit characters, not unicode, + which we ultimately will need to support. + * + */ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision$") + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> + +#include "asterisk/module.h" +#include "asterisk/channel.h" +#include "asterisk/pbx.h" +#include "asterisk/logger.h" +#include "asterisk/utils.h" +#include "asterisk/app.h" + +/*! \brief uriencode: Encode URL according to RFC 2396 */ +static int uriencode(struct ast_channel *chan, char *cmd, char *data, + char *buf, size_t len) +{ + if (ast_strlen_zero(data)) { + ast_log(LOG_WARNING, "Syntax: URIENCODE(<data>) - missing argument!\n"); + return -1; + } + + ast_uri_encode(data, buf, len, 1); + + return 0; +} + +/*!\brief uridecode: Decode URI according to RFC 2396 */ +static int uridecode(struct ast_channel *chan, char *cmd, char *data, + char *buf, size_t len) +{ + if (ast_strlen_zero(data)) { + ast_log(LOG_WARNING, "Syntax: URIDECODE(<data>) - missing argument!\n"); + return -1; + } + + ast_copy_string(buf, data, len); + ast_uri_decode(buf); + + return 0; +} + +static struct ast_custom_function urldecode_function = { + .name = "URIDECODE", + .synopsis = "Decodes a URI-encoded string according to RFC 2396.", + .syntax = "URIDECODE(<data>)", + .read = uridecode, +}; + +static struct ast_custom_function urlencode_function = { + .name = "URIENCODE", + .synopsis = "Encodes a string to URI-safe encoding according to RFC 2396.", + .syntax = "URIENCODE(<data>)", + .read = uriencode, +}; + +static int unload_module(void) +{ + return ast_custom_function_unregister(&urldecode_function) + || ast_custom_function_unregister(&urlencode_function); +} + +static int load_module(void) +{ + return ast_custom_function_register(&urldecode_function) + || ast_custom_function_register(&urlencode_function); +} + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "URI encode/decode dialplan functions"); |