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