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