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