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