de711f62f44757b0a9fe4d137432e26982263b82
[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         *bufptr++ = '"';
866         for (; bufptr < buf + len - 1; dataptr++) {
867                 if (*dataptr == '\\') {
868                         *bufptr++ = '\\';
869                         *bufptr++ = '\\';
870                 } else if (*dataptr == '"') {
871                         *bufptr++ = '\\';
872                         *bufptr++ = '"';
873                 } else if (*dataptr == '\0') {
874                         break;
875                 } else {
876                         *bufptr++ = *dataptr;
877                 }
878         }
879         *bufptr++ = '"';
880         *bufptr = '\0';
881         return 0;
882 }
883
884 static struct ast_custom_function quote_function = {
885         .name = "QUOTE",
886         .read = quote,
887 };
888
889
890 static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf,
891                size_t buflen)
892 {
893         int length = 0;
894
895         if (data)
896                 length = strlen(data);
897
898         snprintf(buf, buflen, "%d", length);
899
900         return 0;
901 }
902
903 static struct ast_custom_function len_function = {
904         .name = "LEN",
905         .read = len,
906         .read_max = 12,
907 };
908
909 static int acf_strftime(struct ast_channel *chan, const char *cmd, char *parse,
910                         char *buf, size_t buflen)
911 {
912         AST_DECLARE_APP_ARGS(args,
913                              AST_APP_ARG(epoch);
914                              AST_APP_ARG(timezone);
915                              AST_APP_ARG(format);
916         );
917         struct timeval when;
918         struct ast_tm tm;
919
920         buf[0] = '\0';
921
922         AST_STANDARD_APP_ARGS(args, parse);
923
924         ast_get_timeval(args.epoch, &when, ast_tvnow(), NULL);
925         ast_localtime(&when, &tm, args.timezone);
926
927         if (!args.format)
928                 args.format = "%c";
929
930         if (ast_strftime(buf, buflen, args.format, &tm) <= 0)
931                 ast_log(LOG_WARNING, "C function strftime() output nothing?!!\n");
932
933         buf[buflen - 1] = '\0';
934
935         return 0;
936 }
937
938 static struct ast_custom_function strftime_function = {
939         .name = "STRFTIME",
940         .read = acf_strftime,
941 };
942
943 static int acf_strptime(struct ast_channel *chan, const char *cmd, char *data,
944                         char *buf, size_t buflen)
945 {
946         AST_DECLARE_APP_ARGS(args,
947                              AST_APP_ARG(timestring);
948                              AST_APP_ARG(timezone);
949                              AST_APP_ARG(format);
950         );
951         struct ast_tm tm;
952
953         buf[0] = '\0';
954
955         if (!data) {
956                 ast_log(LOG_ERROR,
957                                 "Asterisk function STRPTIME() requires an argument.\n");
958                 return -1;
959         }
960
961         AST_STANDARD_APP_ARGS(args, data);
962
963         if (ast_strlen_zero(args.format)) {
964                 ast_log(LOG_ERROR,
965                                 "No format supplied to STRPTIME(<timestring>,<timezone>,<format>)");
966                 return -1;
967         }
968
969         if (!ast_strptime(args.timestring, args.format, &tm)) {
970                 ast_log(LOG_WARNING, "STRPTIME() found no time specified within the string\n");
971         } else {
972                 struct timeval when;
973                 when = ast_mktime(&tm, args.timezone);
974                 snprintf(buf, buflen, "%d", (int) when.tv_sec);
975         }
976
977         return 0;
978 }
979
980 static struct ast_custom_function strptime_function = {
981         .name = "STRPTIME",
982         .read = acf_strptime,
983 };
984
985 static int function_eval(struct ast_channel *chan, const char *cmd, char *data,
986                          char *buf, size_t buflen)
987 {
988         if (ast_strlen_zero(data)) {
989                 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
990                 return -1;
991         }
992
993         pbx_substitute_variables_helper(chan, data, buf, buflen - 1);
994
995         return 0;
996 }
997
998 static int function_eval2(struct ast_channel *chan, const char *cmd, char *data,
999                          struct ast_str **buf, ssize_t buflen)
1000 {
1001         if (ast_strlen_zero(data)) {
1002                 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
1003                 return -1;
1004         }
1005
1006         ast_str_substitute_variables(buf, buflen, chan, data);
1007
1008         return 0;
1009 }
1010
1011 static struct ast_custom_function eval_function = {
1012         .name = "EVAL",
1013         .read = function_eval,
1014         .read2 = function_eval2,
1015 };
1016
1017 static int keypadhash(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1018 {
1019         char *bufptr, *dataptr;
1020
1021         for (bufptr = buf, dataptr = data; bufptr < buf + buflen - 1; dataptr++) {
1022                 if (*dataptr == '\0') {
1023                         *bufptr++ = '\0';
1024                         break;
1025                 } else if (*dataptr == '1') {
1026                         *bufptr++ = '1';
1027                 } else if (strchr("AaBbCc2", *dataptr)) {
1028                         *bufptr++ = '2';
1029                 } else if (strchr("DdEeFf3", *dataptr)) {
1030                         *bufptr++ = '3';
1031                 } else if (strchr("GgHhIi4", *dataptr)) {
1032                         *bufptr++ = '4';
1033                 } else if (strchr("JjKkLl5", *dataptr)) {
1034                         *bufptr++ = '5';
1035                 } else if (strchr("MmNnOo6", *dataptr)) {
1036                         *bufptr++ = '6';
1037                 } else if (strchr("PpQqRrSs7", *dataptr)) {
1038                         *bufptr++ = '7';
1039                 } else if (strchr("TtUuVv8", *dataptr)) {
1040                         *bufptr++ = '8';
1041                 } else if (strchr("WwXxYyZz9", *dataptr)) {
1042                         *bufptr++ = '9';
1043                 } else if (*dataptr == '0') {
1044                         *bufptr++ = '0';
1045                 }
1046         }
1047         buf[buflen - 1] = '\0';
1048
1049         return 0;
1050 }
1051
1052 static struct ast_custom_function keypadhash_function = {
1053         .name = "KEYPADHASH",
1054         .read = keypadhash,
1055 };
1056
1057 static int string_toupper(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1058 {
1059         char *bufptr = buf, *dataptr = data;
1060
1061         while ((bufptr < buf + buflen - 1) && (*bufptr++ = toupper(*dataptr++)));
1062
1063         return 0;
1064 }
1065
1066 static int string_toupper2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
1067 {
1068         char *bufptr, *dataptr = data;
1069
1070         if (buflen > -1) {
1071                 ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
1072         }
1073         bufptr = ast_str_buffer(*buf);
1074         while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = toupper(*dataptr++)));
1075         ast_str_update(*buf);
1076
1077         return 0;
1078 }
1079
1080 static struct ast_custom_function toupper_function = {
1081         .name = "TOUPPER",
1082         .read = string_toupper,
1083         .read2 = string_toupper2,
1084 };
1085
1086 static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1087 {
1088         char *bufptr = buf, *dataptr = data;
1089
1090         while ((bufptr < buf + buflen - 1) && (*bufptr++ = tolower(*dataptr++)));
1091
1092         return 0;
1093 }
1094
1095 static int string_tolower2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
1096 {
1097         char *bufptr, *dataptr = data;
1098
1099         if (buflen > -1) {
1100                 ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
1101         }
1102         bufptr = ast_str_buffer(*buf);
1103         while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = tolower(*dataptr++)));
1104         ast_str_update(*buf);
1105
1106         return 0;
1107 }
1108
1109 static struct ast_custom_function tolower_function = {
1110         .name = "TOLOWER",
1111         .read = string_tolower,
1112         .read2 = string_tolower2,
1113 };
1114
1115 static int array_remove(struct ast_channel *chan, const char *cmd, char *var, char *buf, size_t len, int beginning)
1116 {
1117         const char *tmp;
1118         char *after, *before;
1119         char *(*search_func)(const char *s, int c) = beginning ? strchr : strrchr;
1120         AST_DECLARE_APP_ARGS(args,
1121                 AST_APP_ARG(var);
1122                 AST_APP_ARG(delimiter);
1123         );
1124
1125         if (!chan) {
1126                 ast_log(LOG_WARNING, "%s requires a channel\n", cmd);
1127                 return -1;
1128         }
1129
1130         AST_STANDARD_APP_ARGS(args, var);
1131
1132         if (ast_strlen_zero(args.var)) {
1133                 ast_log(LOG_WARNING, "%s requires a channel variable name\n", cmd);
1134                 return -1;
1135         }
1136
1137         if (args.delimiter && strlen(args.delimiter) != 1) {
1138                 ast_log(LOG_WARNING, "%s delimeters should be a single character\n", cmd);
1139                 return -1;
1140         }
1141
1142         ast_channel_lock(chan);
1143         if (ast_strlen_zero(tmp = pbx_builtin_getvar_helper(chan, args.var))) {
1144                 ast_channel_unlock(chan);
1145                 return 0;
1146         }
1147
1148         before = ast_strdupa(tmp);
1149         ast_channel_unlock(chan);
1150
1151         /* Only one entry in array */
1152         if (!(after = search_func(before, S_OR(args.delimiter, ",")[0]))) {
1153                 ast_copy_string(buf, before, len);
1154                 pbx_builtin_setvar_helper(chan, args.var, "");
1155         } else {
1156                 *after++ = '\0';
1157                 ast_copy_string(buf, beginning ? before : after, len);
1158                 pbx_builtin_setvar_helper(chan, args.var, beginning ? after : before);
1159         }
1160
1161         return 0;
1162
1163 }
1164
1165 static int shift(struct ast_channel *chan, const char *cmd, char *var, char *buf, size_t len)
1166 {
1167         return array_remove(chan, cmd, var, buf, len, 1);
1168 }
1169 static struct ast_custom_function shift_function = {
1170         .name = "SHIFT",
1171         .read = shift,
1172 };
1173
1174 static int pop(struct ast_channel *chan, const char *cmd, char *var, char *buf, size_t len)
1175 {
1176         return array_remove(chan, cmd, var, buf, len, 0);
1177 }
1178
1179 static struct ast_custom_function pop_function = {
1180         .name = "POP",
1181         .read = pop,
1182 };
1183
1184 static int array_insert(struct ast_channel *chan, const char *cmd, char *var, const char *val, int beginning)
1185 {
1186         const char *tmp;
1187         struct ast_str *buf;
1188         AST_DECLARE_APP_ARGS(args,
1189                 AST_APP_ARG(var);
1190                 AST_APP_ARG(delimiter);
1191         );
1192
1193         if (!chan) {
1194                 ast_log(LOG_WARNING, "%s requires a channel\n", cmd);
1195                 return -1;
1196         }
1197
1198         AST_STANDARD_APP_ARGS(args, var);
1199
1200         if (ast_strlen_zero(args.var) || ast_strlen_zero(val)) {
1201                 ast_log(LOG_WARNING, "%s requires a variable, and at least one value\n", cmd);
1202                 return -1;
1203         }
1204
1205         if (args.delimiter && strlen(args.delimiter) != 1) {
1206                 ast_log(LOG_WARNING, "%s delimeters should be a single character\n", cmd);
1207                 return -1;
1208         }
1209
1210         if (!(buf = ast_str_create(32))) {
1211                 ast_log(LOG_ERROR, "Unable to allocate memory for buffer!\n");
1212                 return -1;
1213         }
1214
1215         ast_channel_lock(chan);
1216         if (!(tmp = pbx_builtin_getvar_helper(chan, args.var))) {
1217                 ast_str_set(&buf, 0, "%s", val);
1218         } else {
1219                 ast_str_append(&buf, 0, "%s%s%s", beginning ? val : tmp, S_OR(args.delimiter, ","), beginning ? tmp : val);
1220         }
1221         ast_channel_unlock(chan);
1222
1223         pbx_builtin_setvar_helper(chan, args.var, ast_str_buffer(buf));
1224         ast_free(buf);
1225
1226         return 0;
1227 }
1228
1229 static int push(struct ast_channel *chan, const char *cmd, char *var, const char *val)
1230 {
1231         return array_insert(chan, cmd, var, val, 0);
1232 }
1233
1234 static struct ast_custom_function push_function = {
1235         .name = "PUSH",
1236         .write = push,
1237 };
1238
1239 static int unshift(struct ast_channel *chan, const char *cmd, char *var, const char *val)
1240 {
1241         return array_insert(chan, cmd, var, val, 1);
1242 }
1243
1244 static struct ast_custom_function unshift_function = {
1245         .name = "UNSHIFT",
1246         .write = unshift,
1247 };
1248
1249 static int unload_module(void)
1250 {
1251         int res = 0;
1252
1253         res |= ast_custom_function_unregister(&fieldqty_function);
1254         res |= ast_custom_function_unregister(&filter_function);
1255         res |= ast_custom_function_unregister(&listfilter_function);
1256         res |= ast_custom_function_unregister(&regex_function);
1257         res |= ast_custom_function_unregister(&array_function);
1258         res |= ast_custom_function_unregister(&quote_function);
1259         res |= ast_custom_function_unregister(&len_function);
1260         res |= ast_custom_function_unregister(&strftime_function);
1261         res |= ast_custom_function_unregister(&strptime_function);
1262         res |= ast_custom_function_unregister(&eval_function);
1263         res |= ast_custom_function_unregister(&keypadhash_function);
1264         res |= ast_custom_function_unregister(&hashkeys_function);
1265         res |= ast_custom_function_unregister(&hash_function);
1266         res |= ast_unregister_application(app_clearhash);
1267         res |= ast_custom_function_unregister(&toupper_function);
1268         res |= ast_custom_function_unregister(&tolower_function);
1269         res |= ast_custom_function_unregister(&shift_function);
1270         res |= ast_custom_function_unregister(&pop_function);
1271         res |= ast_custom_function_unregister(&push_function);
1272         res |= ast_custom_function_unregister(&unshift_function);
1273
1274         return res;
1275 }
1276
1277 static int load_module(void)
1278 {
1279         int res = 0;
1280
1281         res |= ast_custom_function_register(&fieldqty_function);
1282         res |= ast_custom_function_register(&filter_function);
1283         res |= ast_custom_function_register(&listfilter_function);
1284         res |= ast_custom_function_register(&regex_function);
1285         res |= ast_custom_function_register(&array_function);
1286         res |= ast_custom_function_register(&quote_function);
1287         res |= ast_custom_function_register(&len_function);
1288         res |= ast_custom_function_register(&strftime_function);
1289         res |= ast_custom_function_register(&strptime_function);
1290         res |= ast_custom_function_register(&eval_function);
1291         res |= ast_custom_function_register(&keypadhash_function);
1292         res |= ast_custom_function_register(&hashkeys_function);
1293         res |= ast_custom_function_register(&hash_function);
1294         res |= ast_register_application_xml(app_clearhash, exec_clearhash);
1295         res |= ast_custom_function_register(&toupper_function);
1296         res |= ast_custom_function_register(&tolower_function);
1297         res |= ast_custom_function_register(&shift_function);
1298         res |= ast_custom_function_register(&pop_function);
1299         res |= ast_custom_function_register(&push_function);
1300         res |= ast_custom_function_register(&unshift_function);
1301
1302         return res;
1303 }
1304
1305 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "String handling dialplan functions");