2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2005, Digium, Inc.
5 * Portions Copyright (C) 2005, Tilghman Lesher. All rights reserved.
6 * Portions Copyright (C) 2005, Anthony Minessale II
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief String manipulation dialplan functions
23 * \author Tilghman Lesher
24 * \author Anothony Minessale II
30 #include <sys/types.h>
35 /* ASTERISK_FILE_VERSION(__FILE__, "$Revision$") */
37 #include "asterisk/channel.h"
38 #include "asterisk/pbx.h"
39 #include "asterisk/logger.h"
40 #include "asterisk/utils.h"
41 #include "asterisk/app.h"
42 #include "asterisk/localtime.h"
44 static char *function_fieldqty(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
46 char *varname, *varval, workspace[256];
47 char *delim = ast_strdupa(data);
51 varname = strsep(&delim, "|");
52 pbx_retrieve_variable(chan, varname, &varval, workspace, sizeof(workspace), NULL);
54 while (strsep(&varval, delim))
56 } else if (!ast_strlen_zero(varval)) {
59 snprintf(buf, len, "%d", fieldcount);
61 ast_log(LOG_ERROR, "Out of memory\n");
62 strncpy(buf, "1", len);
70 struct ast_custom_function fieldqty_function = {
72 .synopsis = "Count the fields, with an arbitrary delimiter",
73 .syntax = "FIELDQTY(<varname>,<delim>)",
74 .read = function_fieldqty,
77 static char *builtin_function_filter(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
79 char *allowed, *string, *outbuf=buf;
81 string = ast_strdupa(data);
83 ast_log(LOG_ERROR, "Out of memory");
87 allowed = strsep(&string, "|");
90 ast_log(LOG_ERROR, "Usage: FILTER(<allowed-chars>,<string>)\n");
94 for ( ; *string && (buf + len - 1 > outbuf); string++) {
95 if (strchr(allowed, *string)) {
108 struct ast_custom_function filter_function = {
110 .synopsis = "Filter the string to include only the allowed characters",
111 .syntax = "FILTER(<allowed-chars>,<string>)",
112 .read = builtin_function_filter,
115 static char *builtin_function_regex(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
117 char *arg, *earg = NULL, *tmp, errstr[256] = "";
121 ast_copy_string(buf, "0", len);
123 tmp = ast_strdupa(data);
125 ast_log(LOG_ERROR, "Out of memory in %s(%s)\n", cmd, data);
129 /* Regex in quotes */
130 arg = strchr(tmp, '"');
133 earg = strrchr(arg, '"');
136 /* Skip over any spaces before the data we are checking */
144 if ((errcode = regcomp(®exbuf, arg, REG_EXTENDED | REG_NOSUB))) {
145 regerror(errcode, ®exbuf, errstr, sizeof(errstr));
146 ast_log(LOG_WARNING, "Malformed input %s(%s): %s\n", cmd, data, errstr);
148 if (!regexec(®exbuf, earg ? earg : "", 0, NULL, 0))
149 ast_copy_string(buf, "1", len);
159 struct ast_custom_function regex_function = {
161 .synopsis = "Regular Expression: Returns 1 if data matches regular expression.",
162 .syntax = "REGEX(\"<regular expression>\" <data>)",
163 .read = builtin_function_regex,
166 static void builtin_function_array(struct ast_channel *chan, char *cmd, char *data, const char *value)
171 int varcount, valuecount, i;
173 var = ast_strdupa(data);
174 value2 = ast_strdupa(value);
175 if (!var || !value2) {
176 ast_log(LOG_ERROR, "Out of memory\n");
180 /* The functions this will generally be used with are SORT and ODBC_*, which
181 * both return comma-delimited lists. However, if somebody uses literal lists,
182 * their commas will be translated to vertical bars by the load, and I don't
183 * want them to be surprised by the result. Hence, we prefer commas as the
184 * delimiter, but we'll fall back to vertical bars if commas aren't found.
186 if (strchr(var, ',')) {
187 varcount = ast_app_separate_args(var, ',', varv, 100);
189 varcount = ast_app_separate_args(var, '|', varv, 100);
192 if (strchr(value2, ',')) {
193 valuecount = ast_app_separate_args(value2, ',', valuev, 100);
195 valuecount = ast_app_separate_args(value2, '|', valuev, 100);
198 for (i = 0; i < varcount; i++) {
199 if (i < valuecount) {
200 pbx_builtin_setvar_helper(chan, varv[i], valuev[i]);
202 /* We could unset the variable, by passing a NULL, but due to
203 * pushvar semantics, that could create some undesired behavior. */
204 pbx_builtin_setvar_helper(chan, varv[i], "");
212 struct ast_custom_function array_function = {
214 .synopsis = "Allows setting multiple variables at once",
215 .syntax = "ARRAY(var1[,var2[...][,varN]])",
216 .write = builtin_function_array,
218 "The comma-separated list passed as a value to which the function is set\n"
219 "will be interpreted as a set of values to which the comma-separated list\n"
220 "of variable names in the argument should be set.\n"
221 "Hence, Set(ARRAY(var1,var2)=1,2) will set var1 to 1 and var2 to 2\n",
224 static char *builtin_function_len(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
228 length = strlen(data);
230 snprintf(buf, len, "%d", length);
237 struct ast_custom_function len_function = {
239 .synopsis = "Returns the length of the argument given",
240 .syntax = "LEN(<string>)",
241 .read = builtin_function_len,
244 static char *acf_strftime(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
246 char *format, *epoch, *timezone = NULL;
253 ast_log(LOG_ERROR, "Asterisk function STRFTIME() requires an argument.\n");
257 format = ast_strdupa(data);
259 ast_log(LOG_ERROR, "Out of memory\n");
263 epoch = strsep(&format, "|");
264 timezone = strsep(&format, "|");
266 if (ast_strlen_zero(epoch) || !sscanf(epoch, "%ld", &epochi)) {
267 struct timeval tv = ast_tvnow();
271 ast_localtime(&epochi, &time, timezone);
277 if (!strftime(buf, len, format, &time)) {
278 ast_log(LOG_WARNING, "C function strftime() output nothing?!!\n");
288 struct ast_custom_function strftime_function = {
290 .synopsis = "Returns the current date/time in a specified format.",
291 .syntax = "STRFTIME([<epoch>][,[timezone][,format]])",
292 .read = acf_strftime,
295 static char *function_eval(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
299 if (ast_strlen_zero(data)) {
300 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
304 pbx_substitute_variables_helper(chan, data, buf, len - 1);
312 struct ast_custom_function eval_function = {
314 .synopsis = "Evaluate stored variables.",
315 .syntax = "EVAL(<variable>)",
316 .desc = "Using EVAL basically causes a string to be evaluated twice.\n"
317 "When a variable or expression is in the dialplan, it will be\n"
318 "evaluated at runtime. However, if the result of the evaluation\n"
319 "is in fact a variable or expression, using EVAL will have it\n"
320 "evaluated a second time. For example, if the variable ${MYVAR}\n"
321 "contains \"${OTHERVAR}\", then the result of putting ${EVAL(${MYVAR})}\n"
322 "in the dialplan will be the contents of the variable, OTHERVAR.\n"
323 "Normally, by just putting ${MYVAR} in the dialplan, you would be\n"
324 "left with \"${OTHERVAR}\".\n",
325 .read = function_eval,