Merged revisions 138023 via svnmerge from
[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 - strlen(buf) - 1);
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 - strlen(buf) - 1);
391                         strncat(buf, ",", len - strlen(buf) - 1);
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                         }
489                         state = SPRINTF_CONVERSION;
490                 case SPRINTF_CONVERSION:
491                         if (strchr("diouxXc", arg.format[i])) {
492                                 /* Integer */
493
494                                 /* Isolate this format alone */
495                                 ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
496                                 formatbuf[&arg.format[i] - formatstart + 1] = '\0';
497
498                                 /* Convert the argument into the required type */
499                                 if (arg.var[argcount]) {
500                                         if (sscanf(arg.var[argcount++], "%d", &tmpi) != 1) {
501                                                 ast_log(LOG_ERROR, "Argument '%s' is not an integer number for format '%s'\n", arg.var[argcount - 1], formatbuf);
502                                                 goto sprintf_fail;
503                                         }
504                                 } else {
505                                         ast_log(LOG_ERROR, "SPRINTF() has more format specifiers than arguments!\n");
506                                         goto sprintf_fail;
507                                 }
508
509                                 /* Format the argument */
510                                 snprintf(bufptr, buf + len - bufptr, formatbuf, tmpi);
511
512                                 /* Update the position of the next parameter to print */
513                                 bufptr = strchr(buf, '\0');
514                         } else if (strchr("eEfFgGaA", arg.format[i])) {
515                                 /* Double */
516
517                                 /* Isolate this format alone */
518                                 ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
519                                 formatbuf[&arg.format[i] - formatstart + 1] = '\0';
520
521                                 /* Convert the argument into the required type */
522                                 if (arg.var[argcount]) {
523                                         if (sscanf(arg.var[argcount++], "%lf", &tmpd) != 1) {
524                                                 ast_log(LOG_ERROR, "Argument '%s' is not a floating point number for format '%s'\n", arg.var[argcount - 1], formatbuf);
525                                                 goto sprintf_fail;
526                                         }
527                                 } else {
528                                         ast_log(LOG_ERROR, "SPRINTF() has more format specifiers than arguments!\n");
529                                         goto sprintf_fail;
530                                 }
531
532                                 /* Format the argument */
533                                 snprintf(bufptr, buf + len - bufptr, formatbuf, tmpd);
534
535                                 /* Update the position of the next parameter to print */
536                                 bufptr = strchr(buf, '\0');
537                         } else if (arg.format[i] == 's') {
538                                 /* String */
539
540                                 /* Isolate this format alone */
541                                 ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
542                                 formatbuf[&arg.format[i] - formatstart + 1] = '\0';
543
544                                 /* Format the argument */
545                                 snprintf(bufptr, buf + len - bufptr, formatbuf, arg.var[argcount++]);
546
547                                 /* Update the position of the next parameter to print */
548                                 bufptr = strchr(buf, '\0');
549                         } else if (arg.format[i] == '%') {
550                                 /* Literal data to copy */
551                                 *bufptr++ = arg.format[i];
552                         } else {
553                                 /* Not supported */
554
555                                 /* Isolate this format alone */
556                                 ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
557                                 formatbuf[&arg.format[i] - formatstart + 1] = '\0';
558
559                                 ast_log(LOG_ERROR, "Format type not supported: '%s' with argument '%s'\n", formatbuf, arg.var[argcount++]);
560                                 goto sprintf_fail;
561                         }
562                         state = -1;
563                         break;
564                 default:
565                         if (arg.format[i] == '%') {
566                                 state = SPRINTF_FLAG;
567                                 formatstart = &arg.format[i];
568                                 break;
569                         } else {
570                                 /* Literal data to copy */
571                                 *bufptr++ = arg.format[i];
572                         }
573                 }
574         }
575         *bufptr = '\0';
576         return 0;
577 sprintf_fail:
578         return -1;
579 }
580
581 static struct ast_custom_function sprintf_function = {
582         .name = "SPRINTF",
583         .synopsis = "Format a variable according to a format string",
584         .syntax = "SPRINTF(<format>,<arg1>[,...<argN>])",
585         .read = acf_sprintf,
586         .desc =
587 "Parses the format string specified and returns a string matching that format.\n"
588 "Supports most options supported by sprintf(3).  Returns a shortened string if\n"
589 "a format specifier is not recognized.\n",
590 };
591
592 static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
593 {
594         char *bufptr = buf, *dataptr = data;
595         *bufptr++ = '"';
596         for (; bufptr < buf + len - 1; dataptr++) {
597                 if (*dataptr == '\\') {
598                         *bufptr++ = '\\';
599                         *bufptr++ = '\\';
600                 } else if (*dataptr == '"') {
601                         *bufptr++ = '\\';
602                         *bufptr++ = '"';
603                 } else if (*dataptr == '\0') {
604                         break;
605                 } else {
606                         *bufptr++ = *dataptr;
607                 }
608         }
609         *bufptr++ = '"';
610         *bufptr = '\0';
611         return 0;
612 }
613
614 static struct ast_custom_function quote_function = {
615         .name = "QUOTE",
616         .synopsis = "Quotes a given string, escaping embedded quotes as necessary",
617         .syntax = "QUOTE(<string>)",
618         .read = quote,
619 };
620
621
622 static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf,
623                size_t buflen)
624 {
625         int length = 0;
626
627         if (data)
628                 length = strlen(data);
629
630         snprintf(buf, buflen, "%d", length);
631
632         return 0;
633 }
634
635 static struct ast_custom_function len_function = {
636         .name = "LEN",
637         .synopsis = "Returns the length of the argument given",
638         .syntax = "LEN(<string>)",
639         .read = len,
640 };
641
642 static int acf_strftime(struct ast_channel *chan, const char *cmd, char *parse,
643                         char *buf, size_t buflen)
644 {
645         AST_DECLARE_APP_ARGS(args,
646                              AST_APP_ARG(epoch);
647                              AST_APP_ARG(timezone);
648                              AST_APP_ARG(format);
649         );
650         struct timeval when;
651         struct ast_tm tm;
652
653         buf[0] = '\0';
654
655         AST_STANDARD_APP_ARGS(args, parse);
656
657         ast_get_timeval(args.epoch, &when, ast_tvnow(), NULL);
658         ast_localtime(&when, &tm, args.timezone);
659
660         if (!args.format)
661                 args.format = "%c";
662
663         if (ast_strftime(buf, buflen, args.format, &tm) <= 0)
664                 ast_log(LOG_WARNING, "C function strftime() output nothing?!!\n");
665
666         buf[buflen - 1] = '\0';
667
668         return 0;
669 }
670
671 static struct ast_custom_function strftime_function = {
672         .name = "STRFTIME",
673         .synopsis = "Returns the current date/time in a specified format.",
674         .syntax = "STRFTIME([<epoch>][,[timezone][,format]])",
675         .desc =
676 "STRFTIME sports all of the same formats as the underlying C function\n"
677 "strftime(3) - see the man page for details.  It also supports the\n"
678 "following format:\n"
679 " %[n]q - fractions of a second, with leading zeroes.  For example, %3q will\n"
680 "         give milliseconds and %1q will give tenths of a second.  The default\n"
681 "         is to output milliseconds (n=3).  The common case is to use it in\n"
682 "         combination with %S, as in \"%S.%3q\".\n",
683         .read = acf_strftime,
684 };
685
686 static int acf_strptime(struct ast_channel *chan, const char *cmd, char *data,
687                         char *buf, size_t buflen)
688 {
689         AST_DECLARE_APP_ARGS(args,
690                              AST_APP_ARG(timestring);
691                              AST_APP_ARG(timezone);
692                              AST_APP_ARG(format);
693         );
694         union {
695                 struct ast_tm atm;
696                 struct tm time;
697         } t = { { 0, }, };
698
699         buf[0] = '\0';
700
701         if (!data) {
702                 ast_log(LOG_ERROR,
703                                 "Asterisk function STRPTIME() requires an argument.\n");
704                 return -1;
705         }
706
707         AST_STANDARD_APP_ARGS(args, data);
708
709         if (ast_strlen_zero(args.format)) {
710                 ast_log(LOG_ERROR,
711                                 "No format supplied to STRPTIME(<timestring>,<timezone>,<format>)");
712                 return -1;
713         }
714
715         if (!strptime(args.timestring, args.format, &t.time)) {
716                 ast_log(LOG_WARNING, "C function strptime() output nothing?!!\n");
717         } else {
718                 struct timeval when;
719                 /* Since strptime(3) does not check DST, force ast_mktime() to calculate it. */
720                 t.atm.tm_isdst = -1;
721                 when = ast_mktime(&t.atm, args.timezone);
722                 snprintf(buf, buflen, "%d", (int) when.tv_sec);
723         }
724
725         return 0;
726 }
727
728 static struct ast_custom_function strptime_function = {
729         .name = "STRPTIME",
730         .synopsis =
731                 "Returns the epoch of the arbitrary date/time string structured as described in the format.",
732         .syntax = "STRPTIME(<datetime>,<timezone>,<format>)",
733         .desc =
734                 "This is useful for converting a date into an EPOCH time, possibly to pass to\n"
735                 "an application like SayUnixTime or to calculate the difference between two\n"
736                 "date strings.\n"
737                 "\n"
738                 "Example:\n"
739                 "  ${STRPTIME(2006-03-01 07:30:35,America/Chicago,%Y-%m-%d %H:%M:%S)} returns 1141219835\n",
740         .read = acf_strptime,
741 };
742
743 static int function_eval(struct ast_channel *chan, const char *cmd, char *data,
744                          char *buf, size_t buflen)
745 {
746         if (ast_strlen_zero(data)) {
747                 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
748                 return -1;
749         }
750
751         if (chan)
752                 ast_autoservice_start(chan);
753         pbx_substitute_variables_helper(chan, data, buf, buflen - 1);
754         if (chan)
755                 ast_autoservice_stop(chan);
756
757         return 0;
758 }
759
760 static struct ast_custom_function eval_function = {
761         .name = "EVAL",
762         .synopsis = "Evaluate stored variables.",
763         .syntax = "EVAL(<variable>)",
764         .desc = "Using EVAL basically causes a string to be evaluated twice.\n"
765                 "When a variable or expression is in the dialplan, it will be\n"
766                 "evaluated at runtime. However, if the result of the evaluation\n"
767                 "is in fact a variable or expression, using EVAL will have it\n"
768                 "evaluated a second time. For example, if the variable ${MYVAR}\n"
769                 "contains \"${OTHERVAR}\", then the result of putting ${EVAL(${MYVAR})}\n"
770                 "in the dialplan will be the contents of the variable, OTHERVAR.\n"
771                 "Normally, by just putting ${MYVAR} in the dialplan, you would be\n"
772                 "left with \"${OTHERVAR}\".\n",
773         .read = function_eval,
774 };
775
776 static int keypadhash(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
777 {
778         char *bufptr, *dataptr;
779
780         for (bufptr = buf, dataptr = data; bufptr < buf + buflen - 1; dataptr++) {
781                 if (*dataptr == '1') {
782                         *bufptr++ = '1';
783                 } else if (strchr("AaBbCc2", *dataptr)) {
784                         *bufptr++ = '2';
785                 } else if (strchr("DdEeFf3", *dataptr)) {
786                         *bufptr++ = '3';
787                 } else if (strchr("GgHhIi4", *dataptr)) {
788                         *bufptr++ = '4';
789                 } else if (strchr("JjKkLl5", *dataptr)) {
790                         *bufptr++ = '5';
791                 } else if (strchr("MmNnOo6", *dataptr)) {
792                         *bufptr++ = '6';
793                 } else if (strchr("PpQqRrSs7", *dataptr)) {
794                         *bufptr++ = '7';
795                 } else if (strchr("TtUuVv8", *dataptr)) {
796                         *bufptr++ = '8';
797                 } else if (strchr("WwXxYyZz9", *dataptr)) {
798                         *bufptr++ = '9';
799                 } else if (*dataptr == '0') {
800                         *bufptr++ = '0';
801                 } else if (*dataptr == '\0') {
802                         *bufptr++ = '\0';
803                         break;
804                 }
805         }
806         buf[buflen - 1] = '\0';
807
808         return 0;
809 }
810
811 static struct ast_custom_function keypadhash_function = {
812         .name = "KEYPADHASH",
813         .synopsis = "Hash the letters in the string into the equivalent keypad numbers.",
814         .syntax = "KEYPADHASH(<string>)",
815         .read = keypadhash,
816         .desc = "Example:  ${KEYPADHASH(Les)} returns \"537\"\n",
817 };
818
819 static int string_toupper(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
820 {
821         char *bufptr = buf, *dataptr = data;
822
823         while ((bufptr < buf + buflen - 1) && (*bufptr++ = toupper(*dataptr++)));
824
825         return 0;
826 }
827
828 static struct ast_custom_function toupper_function = {
829         .name = "TOUPPER",
830         .synopsis = "Convert the string to upper case.",
831         .syntax = "TOUPPER(<string>)",
832         .read = string_toupper,
833         .desc = "Example: ${TOUPPER(Example)} returns \"EXAMPLE\"\n",
834 };
835
836 static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
837 {
838         char *bufptr = buf, *dataptr = data;
839
840         while ((bufptr < buf + buflen - 1) && (*bufptr++ = tolower(*dataptr++)));
841
842         return 0;
843 }
844
845 static struct ast_custom_function tolower_function = {
846         .name = "TOLOWER",
847         .synopsis = "Convert the string to lower case.",
848         .syntax = "TOLOWER(<string>)",
849         .read = string_tolower,
850         .desc = "Example: ${TOLOWER(Example)} returns \"example\"\n",
851 };
852
853 static int unload_module(void)
854 {
855         int res = 0;
856
857         res |= ast_custom_function_unregister(&fieldqty_function);
858         res |= ast_custom_function_unregister(&filter_function);
859         res |= ast_custom_function_unregister(&regex_function);
860         res |= ast_custom_function_unregister(&array_function);
861         res |= ast_custom_function_unregister(&quote_function);
862         res |= ast_custom_function_unregister(&len_function);
863         res |= ast_custom_function_unregister(&strftime_function);
864         res |= ast_custom_function_unregister(&strptime_function);
865         res |= ast_custom_function_unregister(&eval_function);
866         res |= ast_custom_function_unregister(&keypadhash_function);
867         res |= ast_custom_function_unregister(&sprintf_function);
868         res |= ast_custom_function_unregister(&hashkeys_function);
869         res |= ast_custom_function_unregister(&hash_function);
870         res |= ast_unregister_application(app_clearhash);
871         res |= ast_custom_function_unregister(&toupper_function);
872         res |= ast_custom_function_unregister(&tolower_function);
873
874         return res;
875 }
876
877 static int load_module(void)
878 {
879         int res = 0;
880
881         res |= ast_custom_function_register(&fieldqty_function);
882         res |= ast_custom_function_register(&filter_function);
883         res |= ast_custom_function_register(&regex_function);
884         res |= ast_custom_function_register(&array_function);
885         res |= ast_custom_function_register(&quote_function);
886         res |= ast_custom_function_register(&len_function);
887         res |= ast_custom_function_register(&strftime_function);
888         res |= ast_custom_function_register(&strptime_function);
889         res |= ast_custom_function_register(&eval_function);
890         res |= ast_custom_function_register(&keypadhash_function);
891         res |= ast_custom_function_register(&sprintf_function);
892         res |= ast_custom_function_register(&hashkeys_function);
893         res |= ast_custom_function_register(&hash_function);
894         res |= ast_register_application(app_clearhash, exec_clearhash, syn_clearhash, desc_clearhash);
895         res |= ast_custom_function_register(&toupper_function);
896         res |= ast_custom_function_register(&tolower_function);
897
898         return res;
899 }
900
901 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "String handling dialplan functions");