Added a new module, res_phoneprov, which allows auto-provisioning of phones
[asterisk/asterisk.git] / funcs / func_strings.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2005-2006, Digium, Inc.
5  * Portions Copyright (C) 2005, Tilghman Lesher.  All rights reserved.
6  * Portions Copyright (C) 2005, Anthony Minessale II
7  *
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.
13  *
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.
17  */
18
19 /*! \file
20  *
21  * \brief String manipulation dialplan functions
22  *
23  * \author Tilghman Lesher
24  * \author Anothony Minessale II 
25  * \ingroup functions
26  */
27
28 #include "asterisk.h"
29
30 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
31
32 #include <regex.h>
33 #include <ctype.h>
34
35 #include "asterisk/module.h"
36 #include "asterisk/channel.h"
37 #include "asterisk/pbx.h"
38 #include "asterisk/utils.h"
39 #include "asterisk/app.h"
40 #include "asterisk/localtime.h"
41
42 static int function_fieldqty(struct ast_channel *chan, const char *cmd,
43                              char *parse, char *buf, size_t len)
44 {
45         char *varsubst, varval[8192], *varval2 = varval;
46         int fieldcount = 0;
47         AST_DECLARE_APP_ARGS(args,
48                              AST_APP_ARG(varname);
49                              AST_APP_ARG(delim);
50                 );
51         char delim[2] = "";
52         size_t delim_used;
53
54         if (chan)
55                 ast_autoservice_start(chan);
56
57         AST_STANDARD_APP_ARGS(args, parse);
58         if (args.delim) {
59                 ast_get_encoded_char(args.delim, delim, &delim_used);
60
61                 varsubst = alloca(strlen(args.varname) + 4);
62
63                 sprintf(varsubst, "${%s}", args.varname);
64                 pbx_substitute_variables_helper(chan, varsubst, varval, sizeof(varval) - 1);
65                 if (ast_strlen_zero(varval2))
66                         fieldcount = 0;
67                 else {
68                         while (strsep(&varval2, delim))
69                                 fieldcount++;
70                 }
71         } else {
72                 fieldcount = 1;
73         }
74         snprintf(buf, len, "%d", fieldcount);
75
76         if (chan)
77                 ast_autoservice_stop(chan);
78
79         return 0;
80 }
81
82 static struct ast_custom_function fieldqty_function = {
83         .name = "FIELDQTY",
84         .synopsis = "Count the fields, with an arbitrary delimiter",
85         .syntax = "FIELDQTY(<varname>,<delim>)",
86         .read = function_fieldqty,
87 };
88
89 static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf,
90                   size_t len)
91 {
92         AST_DECLARE_APP_ARGS(args,
93                              AST_APP_ARG(allowed);
94                              AST_APP_ARG(string);
95         );
96         char *outbuf = buf, ac;
97         char allowed[256] = "";
98         size_t allowedlen = 0;
99
100         AST_STANDARD_APP_ARGS(args, parse);
101
102         if (!args.string) {
103                 ast_log(LOG_ERROR, "Usage: FILTER(<allowed-chars>,<string>)\n");
104                 return -1;
105         }
106
107         /* Expand ranges */
108         for (; *(args.allowed) && allowedlen < sizeof(allowed); (args.allowed)++) {
109                 char c1 = 0, c2 = 0;
110                 size_t consumed = 0;
111
112                 if (ast_get_encoded_char(args.allowed, &c1, &consumed))
113                         return -1;
114                 args.allowed += consumed;
115
116                 if (*(args.allowed) == '-') {
117                         if (ast_get_encoded_char(args.allowed + 1, &c2, &consumed))
118                                 c2 = -1;
119                         args.allowed += consumed + 1;
120
121                         /*!\note
122                          * Looks a little strange, until you realize that we can overflow
123                          * the size of a char.
124                          */
125                         for (ac = c1; ac != c2 && allowedlen < sizeof(allowed) - 1; ac++)
126                                 allowed[allowedlen++] = ac;
127                         allowed[allowedlen++] = ac;
128
129                         ast_debug(4, "c1=%d, c2=%d\n", c1, c2);
130
131                         /* Decrement before the loop increment */
132                         (args.allowed)--;
133                 } else
134                         allowed[allowedlen++] = c1;
135         }
136
137         ast_debug(1, "Allowed: %s\n", allowed);
138
139         for (; *(args.string) && (buf + len - 1 > outbuf); (args.string)++) {
140                 if (strchr(allowed, *(args.string)))
141                         *outbuf++ = *(args.string);
142         }
143         *outbuf = '\0';
144
145         return 0;
146 }
147
148 static struct ast_custom_function filter_function = {
149         .name = "FILTER",
150         .synopsis = "Filter the string to include only the allowed characters",
151         .syntax = "FILTER(<allowed-chars>,<string>)",
152         .read = filter,
153         .desc =
154 "Permits all characters listed in <allowed-chars>, filtering all others out.\n"
155 "In addition to literally listing the characters, you may also use ranges of\n"
156 "characters (delimited by a '-'), as well as hexadecimal characters started\n"
157 "with a \\x (i.e. \\x20) and octal characters started with \\0 (i.e. \\040).\n"
158 "Also, \\t, \\n, and \\r are recognized.  If you want a literal '-' character,\n"
159 "simply prefix it with a '\\'\n",
160 };
161
162 static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf,
163                  size_t len)
164 {
165         AST_DECLARE_APP_ARGS(args,
166                              AST_APP_ARG(null);
167                              AST_APP_ARG(reg);
168                              AST_APP_ARG(str);
169         );
170         int errcode;
171         regex_t regexbuf;
172
173         buf[0] = '\0';
174
175         AST_NONSTANDARD_APP_ARGS(args, parse, '"');
176
177         if (args.argc != 3) {
178                 ast_log(LOG_ERROR, "Unexpected arguments: should have been in the form '\"<regex>\" <string>'\n");
179                 return -1;
180         }
181         if ((*args.str == ' ') || (*args.str == '\t'))
182                 args.str++;
183
184         ast_debug(1, "FUNCTION REGEX (%s)(%s)\n", args.reg, args.str);
185
186         if ((errcode = regcomp(&regexbuf, args.reg, REG_EXTENDED | REG_NOSUB))) {
187                 regerror(errcode, &regexbuf, buf, len);
188                 ast_log(LOG_WARNING, "Malformed input %s(%s): %s\n", cmd, parse, buf);
189                 return -1;
190         }
191         
192         strcpy(buf, regexec(&regexbuf, args.str, 0, NULL, 0) ? "0" : "1");
193
194         regfree(&regexbuf);
195
196         return 0;
197 }
198
199 static struct ast_custom_function regex_function = {
200         .name = "REGEX",
201         .synopsis = "Regular Expression",
202         .desc =  
203                 "Returns 1 if data matches regular expression, or 0 otherwise.\n"
204                 "Please note that the space following the double quotes separating the regex from the data\n"
205                 "is optional and if present, is skipped. If a space is desired at the beginning of the data,\n"
206                 "then put two spaces there; the second will not be skipped.\n",
207         .syntax = "REGEX(\"<regular expression>\" <data>)",
208         .read = regex,
209 };
210
211 #define HASH_PREFIX     "~HASH~%s~"
212 #define HASH_FORMAT     HASH_PREFIX "%s~"
213
214 static char *app_clearhash = "ClearHash";
215 static char *syn_clearhash = "Clear the keys from a specified hashname";
216 static char *desc_clearhash =
217 "ClearHash(<hashname>)\n"
218 "  Clears all keys out of the specified hashname\n";
219
220 /* This function probably should migrate to main/pbx.c, as pbx_builtin_clearvar_prefix() */
221 static void clearvar_prefix(struct ast_channel *chan, const char *prefix)
222 {
223         struct ast_var_t *var;
224         int len = strlen(prefix);
225         AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->varshead, var, entries) {
226                 if (strncasecmp(prefix, ast_var_name(var), len) == 0) {
227                         AST_LIST_REMOVE_CURRENT(entries);
228                         ast_free(var);
229                 }
230         }
231         AST_LIST_TRAVERSE_SAFE_END
232 }
233
234 static int exec_clearhash(struct ast_channel *chan, void *data)
235 {
236         char prefix[80];
237         snprintf(prefix, sizeof(prefix), HASH_PREFIX, data ? (char *)data : "null");
238         clearvar_prefix(chan, prefix);
239         return 0;
240 }
241
242 static int array(struct ast_channel *chan, const char *cmd, char *var,
243                  const char *value)
244 {
245         AST_DECLARE_APP_ARGS(arg1,
246                              AST_APP_ARG(var)[100];
247         );
248         AST_DECLARE_APP_ARGS(arg2,
249                              AST_APP_ARG(val)[100];
250         );
251         char *origvar = "", *value2, varname[256];
252         int i, ishash = 0;
253
254         value2 = ast_strdupa(value);
255         if (!var || !value2)
256                 return -1;
257
258         if (chan)
259                 ast_autoservice_start(chan);
260
261         if (!strcmp(cmd, "HASH")) {
262                 const char *var2 = pbx_builtin_getvar_helper(chan, "~ODBCFIELDS~");
263                 origvar = var;
264                 if (var2)
265                         var = ast_strdupa(var2);
266                 else {
267                         if (chan)
268                                 ast_autoservice_stop(chan);
269                         return -1;
270                 }
271                 ishash = 1;
272         }
273
274         /* The functions this will generally be used with are SORT and ODBC_*, which
275          * both return comma-delimited lists.  However, if somebody uses literal lists,
276          * their commas will be translated to vertical bars by the load, and I don't
277          * want them to be surprised by the result.  Hence, we prefer commas as the
278          * delimiter, but we'll fall back to vertical bars if commas aren't found.
279          */
280         ast_debug(1, "array (%s=%s)\n", var, value2);
281         AST_STANDARD_APP_ARGS(arg1, var);
282
283         AST_STANDARD_APP_ARGS(arg2, value2);
284
285         for (i = 0; i < arg1.argc; i++) {
286                 ast_debug(1, "array set value (%s=%s)\n", arg1.var[i],
287                                 arg2.val[i]);
288                 if (i < arg2.argc) {
289                         if (ishash) {
290                                 snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
291                                 pbx_builtin_setvar_helper(chan, varname, arg2.val[i]);
292                         } else {
293                                 pbx_builtin_setvar_helper(chan, arg1.var[i], arg2.val[i]);
294                         }
295                 } else {
296                         /* We could unset the variable, by passing a NULL, but due to
297                          * pushvar semantics, that could create some undesired behavior. */
298                         if (ishash) {
299                                 snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
300                                 pbx_builtin_setvar_helper(chan, varname, "");
301                         } else {
302                                 pbx_builtin_setvar_helper(chan, arg1.var[i], "");
303                         }
304                 }
305         }
306
307         if (chan)
308                 ast_autoservice_stop(chan);
309
310         return 0;
311 }
312
313 static int hashkeys_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
314 {
315         struct ast_var_t *newvar;
316         int plen;
317         char prefix[80];
318         snprintf(prefix, sizeof(prefix), HASH_PREFIX, data);
319         plen = strlen(prefix);
320
321         memset(buf, 0, len);
322         AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) {
323                 if (strncasecmp(prefix, ast_var_name(newvar), plen) == 0) {
324                         /* Copy everything after the prefix */
325                         strncat(buf, ast_var_name(newvar) + plen, len);
326                         /* Trim the trailing ~ */
327                         buf[strlen(buf) - 1] = ',';
328                 }
329         }
330         /* Trim the trailing comma */
331         buf[strlen(buf) - 1] = '\0';
332         return 0;
333 }
334
335 static int hash_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
336 {
337         char varname[256];
338         AST_DECLARE_APP_ARGS(arg,
339                 AST_APP_ARG(hashname);
340                 AST_APP_ARG(hashkey);
341         );
342
343         if (!strchr(var, ',')) {
344                 /* Single argument version */
345                 return array(chan, "HASH", var, value);
346         }
347
348         AST_STANDARD_APP_ARGS(arg, var);
349         snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
350         pbx_builtin_setvar_helper(chan, varname, value);
351
352         return 0;
353 }
354
355 static int hash_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
356 {
357         char varname[256];
358         const char *varvalue;
359         AST_DECLARE_APP_ARGS(arg,
360                 AST_APP_ARG(hashname);
361                 AST_APP_ARG(hashkey);
362         );
363
364         AST_STANDARD_APP_ARGS(arg, data);
365         if (arg.argc == 2) {
366                 snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
367                 varvalue = pbx_builtin_getvar_helper(chan, varname);
368                 if (varvalue)
369                         ast_copy_string(buf, varvalue, len);
370                 else
371                         *buf = '\0';
372         } else if (arg.argc == 1) {
373                 char colnames[4096];
374                 int i;
375                 AST_DECLARE_APP_ARGS(arg2,
376                         AST_APP_ARG(col)[100];
377                 );
378
379                 /* Get column names, in no particular order */
380                 hashkeys_read(chan, "HASHKEYS", arg.hashname, colnames, sizeof(colnames));
381                 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames);
382
383                 AST_STANDARD_APP_ARGS(arg2, colnames);
384                 *buf = '\0';
385
386                 /* Now get the corresponding column values, in exactly the same order */
387                 for (i = 0; i < arg2.argc; i++) {
388                         snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg2.col[i]);
389                         varvalue = pbx_builtin_getvar_helper(chan, varname);
390                         strncat(buf, varvalue, len);
391                         strncat(buf, ",", len);
392                 }
393
394                 /* Strip trailing comma */
395                 buf[strlen(buf) - 1] = '\0';
396         }
397
398         return 0;
399 }
400
401 static struct ast_custom_function hash_function = {
402         .name = "HASH",
403         .synopsis = "Implementation of a dialplan associative array",
404         .syntax = "HASH(hashname[,hashkey])",
405         .write = hash_write,
406         .read = hash_read,
407         .desc =
408                 "In two argument mode, gets and sets values to corresponding keys within a named\n"
409                 "associative array.  The single-argument mode will only work when assigned to from\n"
410                 "a function defined by func_odbc.so.\n",
411 };
412
413 static struct ast_custom_function hashkeys_function = {
414         .name = "HASHKEYS",
415         .synopsis = "Retrieve the keys of a HASH()",
416         .syntax = "HASHKEYS(<hashname>)",
417         .read = hashkeys_read,
418         .desc =
419                 "Returns a comma-delimited list of the current keys of an associative array\n"
420                 "defined by the HASH() function.  Note that if you iterate over the keys of\n"
421                 "the result, adding keys during iteration will cause the result of the HASHKEYS\n"
422                 "function to change.\n",
423 };
424
425 static struct ast_custom_function array_function = {
426         .name = "ARRAY",
427         .synopsis = "Allows setting multiple variables at once",
428         .syntax = "ARRAY(var1[,var2[...][,varN]])",
429         .write = array,
430         .desc =
431                 "The comma-separated list passed as a value to which the function is set will\n"
432                 "be interpreted as a set of values to which the comma-separated list of\n"
433                 "variable names in the argument should be set.\n"
434                 "Hence, Set(ARRAY(var1,var2)=1,2) will set var1 to 1 and var2 to 2.\n",
435 };
436
437 static int acf_sprintf(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
438 {
439 #define SPRINTF_FLAG    0
440 #define SPRINTF_WIDTH   1
441 #define SPRINTF_PRECISION       2
442 #define SPRINTF_LENGTH  3
443 #define SPRINTF_CONVERSION      4
444         int i, state = -1, argcount = 0;
445         char *formatstart = NULL, *bufptr = buf;
446         char formatbuf[256] = "";
447         int tmpi;
448         double tmpd;
449         AST_DECLARE_APP_ARGS(arg,
450                                 AST_APP_ARG(format);
451                                 AST_APP_ARG(var)[100];
452         );
453
454         AST_STANDARD_APP_ARGS(arg, data);
455
456         /* Scan the format, converting each argument into the requisite format type. */
457         for (i = 0; arg.format[i]; i++) {
458                 switch (state) {
459                 case SPRINTF_FLAG:
460                         if (strchr("#0- +'I", arg.format[i]))
461                                 break;
462                         state = SPRINTF_WIDTH;
463                 case SPRINTF_WIDTH:
464                         if (arg.format[i] >= '0' && arg.format[i] <= '9')
465                                 break;
466
467                         /* Next character must be a period to go into a precision */
468                         if (arg.format[i] == '.') {
469                                 state = SPRINTF_PRECISION;
470                         } else {
471                                 state = SPRINTF_LENGTH;
472                                 i--;
473                         }
474                         break;
475                 case SPRINTF_PRECISION:
476                         if (arg.format[i] >= '0' && arg.format[i] <= '9')
477                                 break;
478                         state = SPRINTF_LENGTH;
479                 case SPRINTF_LENGTH:
480                         if (strchr("hl", arg.format[i])) {
481                                 if (arg.format[i + 1] == arg.format[i])
482                                         i++;
483                                 state = SPRINTF_CONVERSION;
484                                 break;
485                         } else if (strchr("Lqjzt", arg.format[i]))
486                                 state = SPRINTF_CONVERSION;
487                                 break;
488                         state = SPRINTF_CONVERSION;
489                 case SPRINTF_CONVERSION:
490                         if (strchr("diouxXc", arg.format[i])) {
491                                 /* Integer */
492
493                                 /* Isolate this format alone */
494                                 ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
495                                 formatbuf[&arg.format[i] - formatstart + 1] = '\0';
496
497                                 /* Convert the argument into the required type */
498                                 if (sscanf(arg.var[argcount++], "%d", &tmpi) != 1) {
499                                         ast_log(LOG_ERROR, "Argument '%s' is not an integer number for format '%s'\n", arg.var[argcount - 1], formatbuf);
500                                         goto sprintf_fail;
501                                 }
502
503                                 /* Format the argument */
504                                 snprintf(bufptr, buf + len - bufptr, formatbuf, tmpi);
505
506                                 /* Update the position of the next parameter to print */
507                                 bufptr = strchr(buf, '\0');
508                         } else if (strchr("eEfFgGaA", arg.format[i])) {
509                                 /* Double */
510
511                                 /* Isolate this format alone */
512                                 ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
513                                 formatbuf[&arg.format[i] - formatstart + 1] = '\0';
514
515                                 /* Convert the argument into the required type */
516                                 if (sscanf(arg.var[argcount++], "%lf", &tmpd) != 1) {
517                                         ast_log(LOG_ERROR, "Argument '%s' is not a floating point number for format '%s'\n", arg.var[argcount - 1], formatbuf);
518                                         goto sprintf_fail;
519                                 }
520
521                                 /* Format the argument */
522                                 snprintf(bufptr, buf + len - bufptr, formatbuf, tmpd);
523
524                                 /* Update the position of the next parameter to print */
525                                 bufptr = strchr(buf, '\0');
526                         } else if (arg.format[i] == 's') {
527                                 /* String */
528
529                                 /* Isolate this format alone */
530                                 ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
531                                 formatbuf[&arg.format[i] - formatstart + 1] = '\0';
532
533                                 /* Format the argument */
534                                 snprintf(bufptr, buf + len - bufptr, formatbuf, arg.var[argcount++]);
535
536                                 /* Update the position of the next parameter to print */
537                                 bufptr = strchr(buf, '\0');
538                         } else if (arg.format[i] == '%') {
539                                 /* Literal data to copy */
540                                 *bufptr++ = arg.format[i];
541                         } else {
542                                 /* Not supported */
543
544                                 /* Isolate this format alone */
545                                 ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
546                                 formatbuf[&arg.format[i] - formatstart + 1] = '\0';
547
548                                 ast_log(LOG_ERROR, "Format type not supported: '%s' with argument '%s'\n", formatbuf, arg.var[argcount++]);
549                                 goto sprintf_fail;
550                         }
551                         state = -1;
552                         break;
553                 default:
554                         if (arg.format[i] == '%') {
555                                 state = SPRINTF_FLAG;
556                                 formatstart = &arg.format[i];
557                                 break;
558                         } else {
559                                 /* Literal data to copy */
560                                 *bufptr++ = arg.format[i];
561                         }
562                 }
563         }
564         return 0;
565 sprintf_fail:
566         return -1;
567 }
568
569 static struct ast_custom_function sprintf_function = {
570         .name = "SPRINTF",
571         .synopsis = "Format a variable according to a format string",
572         .syntax = "SPRINTF(<format>,<arg1>[,...<argN>])",
573         .read = acf_sprintf,
574         .desc =
575 "Parses the format string specified and returns a string matching that format.\n"
576 "Supports most options supported by sprintf(3).  Returns a shortened string if\n"
577 "a format specifier is not recognized.\n",
578 };
579
580 static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
581 {
582         char *bufptr = buf, *dataptr = data;
583         *bufptr++ = '"';
584         for (; bufptr < buf + len - 1; dataptr++) {
585                 if (*dataptr == '\\') {
586                         *bufptr++ = '\\';
587                         *bufptr++ = '\\';
588                 } else if (*dataptr == '"') {
589                         *bufptr++ = '\\';
590                         *bufptr++ = '"';
591                 } else if (*dataptr == '\0') {
592                         break;
593                 } else {
594                         *bufptr++ = *dataptr;
595                 }
596         }
597         *bufptr++ = '"';
598         *bufptr = '\0';
599         return 0;
600 }
601
602 static struct ast_custom_function quote_function = {
603         .name = "QUOTE",
604         .synopsis = "Quotes a given string, escaping embedded quotes as necessary",
605         .syntax = "QUOTE(<string>)",
606         .read = quote,
607 };
608
609
610 static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf,
611                size_t len)
612 {
613         int length = 0;
614
615         if (data)
616                 length = strlen(data);
617
618         snprintf(buf, len, "%d", length);
619
620         return 0;
621 }
622
623 static struct ast_custom_function len_function = {
624         .name = "LEN",
625         .synopsis = "Returns the length of the argument given",
626         .syntax = "LEN(<string>)",
627         .read = len,
628 };
629
630 static int acf_strftime(struct ast_channel *chan, const char *cmd, char *parse,
631                         char *buf, size_t len)
632 {
633         AST_DECLARE_APP_ARGS(args,
634                              AST_APP_ARG(epoch);
635                              AST_APP_ARG(timezone);
636                              AST_APP_ARG(format);
637         );
638         struct timeval tv;
639         struct ast_tm tm;
640
641         buf[0] = '\0';
642
643         AST_STANDARD_APP_ARGS(args, parse);
644
645         ast_get_timeval(args.epoch, &tv, ast_tvnow(), NULL);
646         ast_localtime(&tv, &tm, args.timezone);
647
648         if (!args.format)
649                 args.format = "%c";
650
651         if (ast_strftime(buf, len, args.format, &tm) <= 0)
652                 ast_log(LOG_WARNING, "C function strftime() output nothing?!!\n");
653
654         buf[len - 1] = '\0';
655
656         return 0;
657 }
658
659 static struct ast_custom_function strftime_function = {
660         .name = "STRFTIME",
661         .synopsis = "Returns the current date/time in a specified format.",
662         .syntax = "STRFTIME([<epoch>][,[timezone][,format]])",
663         .desc =
664 "STRFTIME sports all of the same formats as the underlying C function\n"
665 "strftime(3) - see the man page for details.  It also supports the\n"
666 "following format:\n"
667 " %[n]q - fractions of a second, with leading zeroes.  For example, %3q will\n"
668 "         give milliseconds and %1q will give tenths of a second.  The default\n"
669 "         is to output milliseconds (n=3).  The common case is to use it in\n"
670 "         combination with %S, as in \"%S.%3q\".\n",
671         .read = acf_strftime,
672 };
673
674 static int acf_strptime(struct ast_channel *chan, const char *cmd, char *data,
675                         char *buf, size_t len)
676 {
677         AST_DECLARE_APP_ARGS(args,
678                              AST_APP_ARG(timestring);
679                              AST_APP_ARG(timezone);
680                              AST_APP_ARG(format);
681         );
682         union {
683                 struct ast_tm atm;
684                 struct tm time;
685         } t = { { 0, }, };
686
687         buf[0] = '\0';
688
689         if (!data) {
690                 ast_log(LOG_ERROR,
691                                 "Asterisk function STRPTIME() requires an argument.\n");
692                 return -1;
693         }
694
695         AST_STANDARD_APP_ARGS(args, data);
696
697         if (ast_strlen_zero(args.format)) {
698                 ast_log(LOG_ERROR,
699                                 "No format supplied to STRPTIME(<timestring>,<timezone>,<format>)");
700                 return -1;
701         }
702
703         if (!strptime(args.timestring, args.format, &t.time)) {
704                 ast_log(LOG_WARNING, "C function strptime() output nothing?!!\n");
705         } else {
706                 struct timeval tv = ast_mktime(&t.atm, args.timezone);
707                 snprintf(buf, len, "%d", (int) tv.tv_sec);
708         }
709
710         return 0;
711 }
712
713 static struct ast_custom_function strptime_function = {
714         .name = "STRPTIME",
715         .synopsis =
716                 "Returns the epoch of the arbitrary date/time string structured as described in the format.",
717         .syntax = "STRPTIME(<datetime>,<timezone>,<format>)",
718         .desc =
719                 "This is useful for converting a date into an EPOCH time, possibly to pass to\n"
720                 "an application like SayUnixTime or to calculate the difference between two\n"
721                 "date strings.\n"
722                 "\n"
723                 "Example:\n"
724                 "  ${STRPTIME(2006-03-01 07:30:35,America/Chicago,%Y-%m-%d %H:%M:%S)} returns 1141219835\n",
725         .read = acf_strptime,
726 };
727
728 static int function_eval(struct ast_channel *chan, const char *cmd, char *data,
729                          char *buf, size_t len)
730 {
731         if (ast_strlen_zero(data)) {
732                 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
733                 return -1;
734         }
735
736         if (chan)
737                 ast_autoservice_start(chan);
738         pbx_substitute_variables_helper(chan, data, buf, len - 1);
739         if (chan)
740                 ast_autoservice_stop(chan);
741
742         return 0;
743 }
744
745 static struct ast_custom_function eval_function = {
746         .name = "EVAL",
747         .synopsis = "Evaluate stored variables.",
748         .syntax = "EVAL(<variable>)",
749         .desc = "Using EVAL basically causes a string to be evaluated twice.\n"
750                 "When a variable or expression is in the dialplan, it will be\n"
751                 "evaluated at runtime. However, if the result of the evaluation\n"
752                 "is in fact a variable or expression, using EVAL will have it\n"
753                 "evaluated a second time. For example, if the variable ${MYVAR}\n"
754                 "contains \"${OTHERVAR}\", then the result of putting ${EVAL(${MYVAR})}\n"
755                 "in the dialplan will be the contents of the variable, OTHERVAR.\n"
756                 "Normally, by just putting ${MYVAR} in the dialplan, you would be\n"
757                 "left with \"${OTHERVAR}\".\n",
758         .read = function_eval,
759 };
760
761 static int keypadhash(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
762 {
763         char *bufptr, *dataptr;
764
765         for (bufptr = buf, dataptr = data; bufptr < buf + len - 1; dataptr++) {
766                 if (*dataptr == '1') {
767                         *bufptr++ = '1';
768                 } else if (strchr("AaBbCc2", *dataptr)) {
769                         *bufptr++ = '2';
770                 } else if (strchr("DdEeFf3", *dataptr)) {
771                         *bufptr++ = '3';
772                 } else if (strchr("GgHhIi4", *dataptr)) {
773                         *bufptr++ = '4';
774                 } else if (strchr("JjKkLl5", *dataptr)) {
775                         *bufptr++ = '5';
776                 } else if (strchr("MmNnOo6", *dataptr)) {
777                         *bufptr++ = '6';
778                 } else if (strchr("PpQqRrSs7", *dataptr)) {
779                         *bufptr++ = '7';
780                 } else if (strchr("TtUuVv8", *dataptr)) {
781                         *bufptr++ = '8';
782                 } else if (strchr("WwXxYyZz9", *dataptr)) {
783                         *bufptr++ = '9';
784                 } else if (*dataptr == '0') {
785                         *bufptr++ = '0';
786                 } else if (*dataptr == '\0') {
787                         *bufptr++ = '\0';
788                         break;
789                 }
790         }
791         buf[len - 1] = '\0';
792
793         return 0;
794 }
795
796 static struct ast_custom_function keypadhash_function = {
797         .name = "KEYPADHASH",
798         .synopsis = "Hash the letters in the string into the equivalent keypad numbers.",
799         .syntax = "KEYPADHASH(<string>)",
800         .read = keypadhash,
801         .desc = "Example:  ${KEYPADHASH(Les)} returns \"537\"\n",
802 };
803
804 static int string_toupper(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
805 {
806         char *bufptr = buf, *dataptr = data;
807
808         while ((bufptr < buf + len - 1) && (*bufptr++ = toupper(*dataptr++)));
809
810         return 0;
811 }
812
813 static struct ast_custom_function toupper_function = {
814         .name = "TOUPPER",
815         .synopsis = "Convert the string to upper case.",
816         .syntax = "TOUPPER(<string>)",
817         .read = string_toupper,
818         .desc = "Example: ${TOUPPER(Example)} returns \"EXAMPLE\"\n",
819 };
820
821 static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
822 {
823         char *bufptr = buf, *dataptr = data;
824
825         while ((bufptr < buf + len - 1) && (*bufptr++ = tolower(*dataptr++)));
826
827         return 0;
828 }
829
830 static struct ast_custom_function tolower_function = {
831         .name = "TOLOWER",
832         .synopsis = "Convert the string to lower case.",
833         .syntax = "TOLOWER(<string>)",
834         .read = string_tolower,
835         .desc = "Example: ${TOLOWER(Example)} returns \"example\"\n",
836 };
837
838 static int unload_module(void)
839 {
840         int res = 0;
841
842         res |= ast_custom_function_unregister(&fieldqty_function);
843         res |= ast_custom_function_unregister(&filter_function);
844         res |= ast_custom_function_unregister(&regex_function);
845         res |= ast_custom_function_unregister(&array_function);
846         res |= ast_custom_function_unregister(&quote_function);
847         res |= ast_custom_function_unregister(&len_function);
848         res |= ast_custom_function_unregister(&strftime_function);
849         res |= ast_custom_function_unregister(&strptime_function);
850         res |= ast_custom_function_unregister(&eval_function);
851         res |= ast_custom_function_unregister(&keypadhash_function);
852         res |= ast_custom_function_unregister(&sprintf_function);
853         res |= ast_custom_function_unregister(&hashkeys_function);
854         res |= ast_custom_function_unregister(&hash_function);
855         res |= ast_unregister_application(app_clearhash);
856         res |= ast_custom_function_unregister(&toupper_function);
857         res |= ast_custom_function_unregister(&tolower_function);
858
859         return res;
860 }
861
862 static int load_module(void)
863 {
864         int res = 0;
865
866         res |= ast_custom_function_register(&fieldqty_function);
867         res |= ast_custom_function_register(&filter_function);
868         res |= ast_custom_function_register(&regex_function);
869         res |= ast_custom_function_register(&array_function);
870         res |= ast_custom_function_register(&quote_function);
871         res |= ast_custom_function_register(&len_function);
872         res |= ast_custom_function_register(&strftime_function);
873         res |= ast_custom_function_register(&strptime_function);
874         res |= ast_custom_function_register(&eval_function);
875         res |= ast_custom_function_register(&keypadhash_function);
876         res |= ast_custom_function_register(&sprintf_function);
877         res |= ast_custom_function_register(&hashkeys_function);
878         res |= ast_custom_function_register(&hash_function);
879         res |= ast_register_application(app_clearhash, exec_clearhash, syn_clearhash, desc_clearhash);
880         res |= ast_custom_function_register(&toupper_function);
881         res |= ast_custom_function_register(&tolower_function);
882
883         return res;
884 }
885
886 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "String handling dialplan functions");