Enable warnings on atypical conditions for the FILTER function (suggested by mmichels...
[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         if (args.allowed[0] == '"' && !ast_opt_dont_warn) {
607                 ast_log(LOG_WARNING, "FILTER allowed characters includes the quote (\") character.  This may not be what you want.\n");
608         }
609
610         /* Expand ranges */
611         for (; *(args.allowed) && allowedlen < sizeof(allowed); ) {
612                 char c1 = 0, c2 = 0;
613                 size_t consumed = 0;
614
615                 if (ast_get_encoded_char(args.allowed, &c1, &consumed))
616                         return -1;
617                 args.allowed += consumed;
618
619                 if (*(args.allowed) == '-') {
620                         if (ast_get_encoded_char(args.allowed + 1, &c2, &consumed))
621                                 c2 = -1;
622                         args.allowed += consumed + 1;
623
624                         if ((c2 < c1 || c2 == -1) && !ast_opt_dont_warn) {
625                                 ast_log(LOG_WARNING, "Range wrapping in FILTER(%s,%s).  This may not be what you want.\n", parse, args.string);
626                         }
627
628                         /*!\note
629                          * Looks a little strange, until you realize that we can overflow
630                          * the size of a char.
631                          */
632                         for (ac = c1; ac != c2; ac++) {
633                                 bitfield[ac / 32] |= 1 << (ac % 32);
634                         }
635
636                         ast_debug(4, "c1=%d, c2=%d\n", c1, c2);
637
638                         /* Decrement before the loop increment */
639                         (args.allowed)--;
640                 } else {
641                         bitfield[c1 / 32] |= 1 << (c1 % 32);
642                 }
643         }
644
645         for (ac = 1; ac != 0; ac++) {
646                 if (bitfield[ac / 32] & (1 << (ac % 32))) {
647                         allowed[allowedlen++] = ac;
648                 }
649         }
650
651         ast_debug(1, "Allowed: %s\n", allowed);
652
653         for (; *(args.string) && (buf + len - 1 > outbuf); (args.string)++) {
654                 if (strchr(allowed, *(args.string)))
655                         *outbuf++ = *(args.string);
656         }
657         *outbuf = '\0';
658
659         return 0;
660 }
661
662 static struct ast_custom_function filter_function = {
663         .name = "FILTER",
664         .read = filter,
665 };
666
667 static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
668 {
669         AST_DECLARE_APP_ARGS(args,
670                 AST_APP_ARG(varname);
671                 AST_APP_ARG(find);
672                 AST_APP_ARG(replace);
673         );
674         char *strptr, *varsubst;
675         struct ast_str *str = ast_str_thread_get(&result_buf, 16);
676         char find[256]; /* Only 256 characters possible */
677         char replace[2] = "";
678         size_t unused;
679
680         AST_STANDARD_APP_ARGS(args, data);
681
682         if (!str) {
683                 return -1;
684         }
685
686         if (args.argc < 2) {
687                 ast_log(LOG_ERROR, "Usage: %s(<varname>,<search-chars>[,<replace-char>])\n", cmd);
688                 return -1;
689         }
690
691         /* Decode escapes */
692         ast_get_encoded_str(args.find, find, sizeof(find));
693         ast_get_encoded_char(args.replace, replace, &unused);
694
695         if (ast_strlen_zero(find) || ast_strlen_zero(args.varname)) {
696                 ast_log(LOG_ERROR, "The characters to search for and the variable name must not be empty.\n");
697                 return -1;
698         }
699
700         varsubst = alloca(strlen(args.varname) + 4);
701         sprintf(varsubst, "${%s}", args.varname);
702         ast_str_substitute_variables(&str, 0, chan, varsubst);
703
704         if (!ast_str_strlen(str)) {
705                 /* Blank, nothing to replace */
706                 return -1;
707         }
708
709         ast_debug(3, "String to search: (%s)\n", ast_str_buffer(str));
710         ast_debug(3, "Characters to find: (%s)\n", find);
711         ast_debug(3, "Character to replace with: (%s)\n", replace);
712
713         for (strptr = ast_str_buffer(str); *strptr; strptr++) {
714                 /* buf is already a mutable buffer, so we construct the result
715                  * directly there */
716                 if (strchr(find, *strptr)) {
717                         if (ast_strlen_zero(replace)) {
718                                 /* Remove character */
719                                 strcpy(strptr, strptr + 1); /* SAFE */
720                                 strptr--;
721                         } else {
722                                 /* Replace character */
723                                 *strptr = *replace;
724                         }
725                 }
726         }
727
728         ast_str_set(buf, len, "%s", ast_str_buffer(str));
729         return 0;
730 }
731
732 static struct ast_custom_function replace_function = {
733         .name = "REPLACE",
734         .read2 = replace,
735 };
736
737 static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf,
738                  size_t len)
739 {
740         AST_DECLARE_APP_ARGS(args,
741                              AST_APP_ARG(null);
742                              AST_APP_ARG(reg);
743                              AST_APP_ARG(str);
744         );
745         int errcode;
746         regex_t regexbuf;
747
748         buf[0] = '\0';
749
750         AST_NONSTANDARD_APP_ARGS(args, parse, '"');
751
752         if (args.argc != 3) {
753                 ast_log(LOG_ERROR, "Unexpected arguments: should have been in the form '\"<regex>\" <string>'\n");
754                 return -1;
755         }
756         if ((*args.str == ' ') || (*args.str == '\t'))
757                 args.str++;
758
759         ast_debug(1, "FUNCTION REGEX (%s)(%s)\n", args.reg, args.str);
760
761         if ((errcode = regcomp(&regexbuf, args.reg, REG_EXTENDED | REG_NOSUB))) {
762                 regerror(errcode, &regexbuf, buf, len);
763                 ast_log(LOG_WARNING, "Malformed input %s(%s): %s\n", cmd, parse, buf);
764                 return -1;
765         }
766         
767         strcpy(buf, regexec(&regexbuf, args.str, 0, NULL, 0) ? "0" : "1");
768
769         regfree(&regexbuf);
770
771         return 0;
772 }
773
774 static struct ast_custom_function regex_function = {
775         .name = "REGEX",
776         .read = regex,
777 };
778
779 #define HASH_PREFIX     "~HASH~%s~"
780 #define HASH_FORMAT     HASH_PREFIX "%s~"
781
782 static char *app_clearhash = "ClearHash";
783
784 /* This function probably should migrate to main/pbx.c, as pbx_builtin_clearvar_prefix() */
785 static void clearvar_prefix(struct ast_channel *chan, const char *prefix)
786 {
787         struct ast_var_t *var;
788         int len = strlen(prefix);
789         AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->varshead, var, entries) {
790                 if (strncasecmp(prefix, ast_var_name(var), len) == 0) {
791                         AST_LIST_REMOVE_CURRENT(entries);
792                         ast_free(var);
793                 }
794         }
795         AST_LIST_TRAVERSE_SAFE_END
796 }
797
798 static int exec_clearhash(struct ast_channel *chan, const char *data)
799 {
800         char prefix[80];
801         snprintf(prefix, sizeof(prefix), HASH_PREFIX, data ? (char *)data : "null");
802         clearvar_prefix(chan, prefix);
803         return 0;
804 }
805
806 static int array(struct ast_channel *chan, const char *cmd, char *var,
807                  const char *value)
808 {
809         AST_DECLARE_APP_ARGS(arg1,
810                              AST_APP_ARG(var)[100];
811         );
812         AST_DECLARE_APP_ARGS(arg2,
813                              AST_APP_ARG(val)[100];
814         );
815         char *origvar = "", *value2, varname[256];
816         int i, ishash = 0;
817
818         value2 = ast_strdupa(value);
819         if (!var || !value2)
820                 return -1;
821
822         if (!strcmp(cmd, "HASH")) {
823                 const char *var2 = pbx_builtin_getvar_helper(chan, "~ODBCFIELDS~");
824                 origvar = var;
825                 if (var2)
826                         var = ast_strdupa(var2);
827                 else {
828                         if (chan)
829                                 ast_autoservice_stop(chan);
830                         return -1;
831                 }
832                 ishash = 1;
833         }
834
835         /* The functions this will generally be used with are SORT and ODBC_*, which
836          * both return comma-delimited lists.  However, if somebody uses literal lists,
837          * their commas will be translated to vertical bars by the load, and I don't
838          * want them to be surprised by the result.  Hence, we prefer commas as the
839          * delimiter, but we'll fall back to vertical bars if commas aren't found.
840          */
841         ast_debug(1, "array (%s=%s)\n", var, value2);
842         AST_STANDARD_APP_ARGS(arg1, var);
843
844         AST_STANDARD_APP_ARGS(arg2, value2);
845
846         for (i = 0; i < arg1.argc; i++) {
847                 ast_debug(1, "array set value (%s=%s)\n", arg1.var[i],
848                                 arg2.val[i]);
849                 if (i < arg2.argc) {
850                         if (ishash) {
851                                 if (origvar[0] == '_') {
852                                         if (origvar[1] == '_') {
853                                                 snprintf(varname, sizeof(varname), "__" HASH_FORMAT, origvar + 2, arg1.var[i]);
854                                         } else {
855                                                 snprintf(varname, sizeof(varname), "_" HASH_FORMAT, origvar + 1, arg1.var[i]);
856                                         }
857                                 } else {
858                                         snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
859                                 }
860
861                                 pbx_builtin_setvar_helper(chan, varname, arg2.val[i]);
862                         } else {
863                                 pbx_builtin_setvar_helper(chan, arg1.var[i], arg2.val[i]);
864                         }
865                 } else {
866                         /* We could unset the variable, by passing a NULL, but due to
867                          * pushvar semantics, that could create some undesired behavior. */
868                         if (ishash) {
869                                 snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
870                                 pbx_builtin_setvar_helper(chan, varname, "");
871                         } else {
872                                 pbx_builtin_setvar_helper(chan, arg1.var[i], "");
873                         }
874                 }
875         }
876
877         return 0;
878 }
879
880 static int hashkeys_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
881 {
882         struct ast_var_t *newvar;
883         struct ast_str *prefix = ast_str_alloca(80);
884
885         ast_str_set(&prefix, -1, HASH_PREFIX, data);
886         memset(buf, 0, len);
887
888         AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) {
889                 if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
890                         /* Copy everything after the prefix */
891                         strncat(buf, ast_var_name(newvar) + ast_str_strlen(prefix), len - strlen(buf) - 1);
892                         /* Trim the trailing ~ */
893                         buf[strlen(buf) - 1] = ',';
894                 }
895         }
896         /* Trim the trailing comma */
897         buf[strlen(buf) - 1] = '\0';
898         return 0;
899 }
900
901 static int hashkeys_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
902 {
903         struct ast_var_t *newvar;
904         struct ast_str *prefix = ast_str_alloca(80);
905         char *tmp;
906
907         ast_str_set(&prefix, -1, HASH_PREFIX, data);
908
909         AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) {
910                 if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
911                         /* Copy everything after the prefix */
912                         ast_str_append(buf, len, "%s", ast_var_name(newvar) + ast_str_strlen(prefix));
913                         /* Trim the trailing ~ */
914                         tmp = ast_str_buffer(*buf);
915                         tmp[ast_str_strlen(*buf) - 1] = ',';
916                 }
917         }
918         /* Trim the trailing comma */
919         tmp = ast_str_buffer(*buf);
920         tmp[ast_str_strlen(*buf) - 1] = '\0';
921         return 0;
922 }
923
924 static int hash_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
925 {
926         char varname[256];
927         AST_DECLARE_APP_ARGS(arg,
928                 AST_APP_ARG(hashname);
929                 AST_APP_ARG(hashkey);
930         );
931
932         if (!strchr(var, ',')) {
933                 /* Single argument version */
934                 return array(chan, "HASH", var, value);
935         }
936
937         AST_STANDARD_APP_ARGS(arg, var);
938         if (arg.hashname[0] == '_') {
939                 if (arg.hashname[1] == '_') {
940                         snprintf(varname, sizeof(varname), "__" HASH_FORMAT, arg.hashname + 2, arg.hashkey);
941                 } else {
942                         snprintf(varname, sizeof(varname), "_" HASH_FORMAT, arg.hashname + 1, arg.hashkey);
943                 }
944         } else {
945                 snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
946         }
947         pbx_builtin_setvar_helper(chan, varname, value);
948
949         return 0;
950 }
951
952 static int hash_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
953 {
954         char varname[256];
955         const char *varvalue;
956         AST_DECLARE_APP_ARGS(arg,
957                 AST_APP_ARG(hashname);
958                 AST_APP_ARG(hashkey);
959         );
960
961         AST_STANDARD_APP_ARGS(arg, data);
962         if (arg.argc == 2) {
963                 snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
964                 varvalue = pbx_builtin_getvar_helper(chan, varname);
965                 if (varvalue)
966                         ast_copy_string(buf, varvalue, len);
967                 else
968                         *buf = '\0';
969         } else if (arg.argc == 1) {
970                 char colnames[4096];
971                 int i;
972                 AST_DECLARE_APP_ARGS(arg2,
973                         AST_APP_ARG(col)[100];
974                 );
975
976                 /* Get column names, in no particular order */
977                 hashkeys_read(chan, "HASHKEYS", arg.hashname, colnames, sizeof(colnames));
978                 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames);
979
980                 AST_STANDARD_APP_ARGS(arg2, colnames);
981                 *buf = '\0';
982
983                 /* Now get the corresponding column values, in exactly the same order */
984                 for (i = 0; i < arg2.argc; i++) {
985                         snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg2.col[i]);
986                         varvalue = pbx_builtin_getvar_helper(chan, varname);
987                         strncat(buf, varvalue, len - strlen(buf) - 1);
988                         strncat(buf, ",", len - strlen(buf) - 1);
989                 }
990
991                 /* Strip trailing comma */
992                 buf[strlen(buf) - 1] = '\0';
993         }
994
995         return 0;
996 }
997
998 static struct ast_custom_function hash_function = {
999         .name = "HASH",
1000         .write = hash_write,
1001         .read = hash_read,
1002 };
1003
1004 static struct ast_custom_function hashkeys_function = {
1005         .name = "HASHKEYS",
1006         .read = hashkeys_read,
1007         .read2 = hashkeys_read2,
1008 };
1009
1010 static struct ast_custom_function array_function = {
1011         .name = "ARRAY",
1012         .write = array,
1013 };
1014
1015 static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1016 {
1017         char *bufptr = buf, *dataptr = data;
1018
1019         if (len < 3){ /* at least two for quotes and one for binary zero */
1020                 ast_log(LOG_ERROR, "Not enough buffer");
1021                 return -1;
1022         }
1023
1024         if (ast_strlen_zero(data)) {
1025                 ast_log(LOG_WARNING, "No argument specified!\n");
1026                 ast_copy_string(buf, "\"\"", len);
1027                 return 0;
1028         }
1029
1030         *bufptr++ = '"';
1031         for (; bufptr < buf + len - 3; dataptr++) {
1032                 if (*dataptr == '\\') {
1033                         *bufptr++ = '\\';
1034                         *bufptr++ = '\\';
1035                 } else if (*dataptr == '"') {
1036                         *bufptr++ = '\\';
1037                         *bufptr++ = '"';
1038                 } else if (*dataptr == '\0') {
1039                         break;
1040                 } else {
1041                         *bufptr++ = *dataptr;
1042                 }
1043         }
1044         *bufptr++ = '"';
1045         *bufptr = '\0';
1046         return 0;
1047 }
1048
1049 static struct ast_custom_function quote_function = {
1050         .name = "QUOTE",
1051         .read = quote,
1052 };
1053
1054 static int csv_quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1055 {
1056         char *bufptr = buf, *dataptr = data;
1057
1058         if (len < 3){ /* at least two for quotes and one for binary zero */
1059                 ast_log(LOG_ERROR, "Not enough buffer");
1060                 return -1;
1061         }
1062
1063         if (ast_strlen_zero(data)) {
1064                 ast_log(LOG_WARNING, "No argument specified!\n");
1065                 ast_copy_string(buf,"\"\"",len);
1066                 return 0;
1067         }
1068
1069         *bufptr++ = '"';
1070         for (; bufptr < buf + len - 3; dataptr++){
1071                 if (*dataptr == '"') {
1072                         *bufptr++ = '"';
1073                         *bufptr++ = '"';
1074                 } else if (*dataptr == '\0') {
1075                         break;
1076                 } else {
1077                         *bufptr++ = *dataptr;
1078                 }
1079         }
1080         *bufptr++ = '"';
1081         *bufptr='\0';
1082         return 0;
1083 }
1084
1085 static struct ast_custom_function csv_quote_function = {
1086         .name = "CSV_QUOTE",
1087         .read = csv_quote,
1088 };
1089
1090 static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1091 {
1092         int length = 0;
1093
1094         if (data)
1095                 length = strlen(data);
1096
1097         snprintf(buf, buflen, "%d", length);
1098
1099         return 0;
1100 }
1101
1102 static struct ast_custom_function len_function = {
1103         .name = "LEN",
1104         .read = len,
1105         .read_max = 12,
1106 };
1107
1108 static int acf_strftime(struct ast_channel *chan, const char *cmd, char *parse,
1109                         char *buf, size_t buflen)
1110 {
1111         AST_DECLARE_APP_ARGS(args,
1112                              AST_APP_ARG(epoch);
1113                              AST_APP_ARG(timezone);
1114                              AST_APP_ARG(format);
1115         );
1116         struct timeval when;
1117         struct ast_tm tm;
1118
1119         buf[0] = '\0';
1120
1121         AST_STANDARD_APP_ARGS(args, parse);
1122
1123         ast_get_timeval(args.epoch, &when, ast_tvnow(), NULL);
1124         ast_localtime(&when, &tm, args.timezone);
1125
1126         if (!args.format)
1127                 args.format = "%c";
1128
1129         if (ast_strftime(buf, buflen, args.format, &tm) <= 0)
1130                 ast_log(LOG_WARNING, "C function strftime() output nothing?!!\n");
1131
1132         buf[buflen - 1] = '\0';
1133
1134         return 0;
1135 }
1136
1137 static struct ast_custom_function strftime_function = {
1138         .name = "STRFTIME",
1139         .read = acf_strftime,
1140 };
1141
1142 static int acf_strptime(struct ast_channel *chan, const char *cmd, char *data,
1143                         char *buf, size_t buflen)
1144 {
1145         AST_DECLARE_APP_ARGS(args,
1146                              AST_APP_ARG(timestring);
1147                              AST_APP_ARG(timezone);
1148                              AST_APP_ARG(format);
1149         );
1150         struct ast_tm tm;
1151
1152         buf[0] = '\0';
1153
1154         if (!data) {
1155                 ast_log(LOG_ERROR,
1156                                 "Asterisk function STRPTIME() requires an argument.\n");
1157                 return -1;
1158         }
1159
1160         AST_STANDARD_APP_ARGS(args, data);
1161
1162         if (ast_strlen_zero(args.format)) {
1163                 ast_log(LOG_ERROR,
1164                                 "No format supplied to STRPTIME(<timestring>,<timezone>,<format>)");
1165                 return -1;
1166         }
1167
1168         if (!ast_strptime(args.timestring, args.format, &tm)) {
1169                 ast_log(LOG_WARNING, "STRPTIME() found no time specified within the string\n");
1170         } else {
1171                 struct timeval when;
1172                 when = ast_mktime(&tm, args.timezone);
1173                 snprintf(buf, buflen, "%d", (int) when.tv_sec);
1174         }
1175
1176         return 0;
1177 }
1178
1179 static struct ast_custom_function strptime_function = {
1180         .name = "STRPTIME",
1181         .read = acf_strptime,
1182 };
1183
1184 static int function_eval(struct ast_channel *chan, const char *cmd, char *data,
1185                          char *buf, size_t buflen)
1186 {
1187         if (ast_strlen_zero(data)) {
1188                 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
1189                 return -1;
1190         }
1191
1192         pbx_substitute_variables_helper(chan, data, buf, buflen - 1);
1193
1194         return 0;
1195 }
1196
1197 static int function_eval2(struct ast_channel *chan, const char *cmd, char *data,
1198                          struct ast_str **buf, ssize_t buflen)
1199 {
1200         if (ast_strlen_zero(data)) {
1201                 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
1202                 return -1;
1203         }
1204
1205         ast_str_substitute_variables(buf, buflen, chan, data);
1206
1207         return 0;
1208 }
1209
1210 static struct ast_custom_function eval_function = {
1211         .name = "EVAL",
1212         .read = function_eval,
1213         .read2 = function_eval2,
1214 };
1215
1216 static int keypadhash(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1217 {
1218         char *bufptr, *dataptr;
1219
1220         for (bufptr = buf, dataptr = data; bufptr < buf + buflen - 1; dataptr++) {
1221                 if (*dataptr == '\0') {
1222                         *bufptr++ = '\0';
1223                         break;
1224                 } else if (*dataptr == '1') {
1225                         *bufptr++ = '1';
1226                 } else if (strchr("AaBbCc2", *dataptr)) {
1227                         *bufptr++ = '2';
1228                 } else if (strchr("DdEeFf3", *dataptr)) {
1229                         *bufptr++ = '3';
1230                 } else if (strchr("GgHhIi4", *dataptr)) {
1231                         *bufptr++ = '4';
1232                 } else if (strchr("JjKkLl5", *dataptr)) {
1233                         *bufptr++ = '5';
1234                 } else if (strchr("MmNnOo6", *dataptr)) {
1235                         *bufptr++ = '6';
1236                 } else if (strchr("PpQqRrSs7", *dataptr)) {
1237                         *bufptr++ = '7';
1238                 } else if (strchr("TtUuVv8", *dataptr)) {
1239                         *bufptr++ = '8';
1240                 } else if (strchr("WwXxYyZz9", *dataptr)) {
1241                         *bufptr++ = '9';
1242                 } else if (*dataptr == '0') {
1243                         *bufptr++ = '0';
1244                 }
1245         }
1246         buf[buflen - 1] = '\0';
1247
1248         return 0;
1249 }
1250
1251 static struct ast_custom_function keypadhash_function = {
1252         .name = "KEYPADHASH",
1253         .read = keypadhash,
1254 };
1255
1256 static int string_toupper(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1257 {
1258         char *bufptr = buf, *dataptr = data;
1259
1260         while ((bufptr < buf + buflen - 1) && (*bufptr++ = toupper(*dataptr++)));
1261
1262         return 0;
1263 }
1264
1265 static int string_toupper2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
1266 {
1267         char *bufptr, *dataptr = data;
1268
1269         if (buflen > -1) {
1270                 ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
1271         }
1272         bufptr = ast_str_buffer(*buf);
1273         while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = toupper(*dataptr++)));
1274         ast_str_update(*buf);
1275
1276         return 0;
1277 }
1278
1279 static struct ast_custom_function toupper_function = {
1280         .name = "TOUPPER",
1281         .read = string_toupper,
1282         .read2 = string_toupper2,
1283 };
1284
1285 static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1286 {
1287         char *bufptr = buf, *dataptr = data;
1288
1289         while ((bufptr < buf + buflen - 1) && (*bufptr++ = tolower(*dataptr++)));
1290
1291         return 0;
1292 }
1293
1294 static int string_tolower2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
1295 {
1296         char *bufptr, *dataptr = data;
1297
1298         if (buflen > -1) {
1299                 ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
1300         }
1301         bufptr = ast_str_buffer(*buf);
1302         while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = tolower(*dataptr++)));
1303         ast_str_update(*buf);
1304
1305         return 0;
1306 }
1307
1308 static struct ast_custom_function tolower_function = {
1309         .name = "TOLOWER",
1310         .read = string_tolower,
1311         .read2 = string_tolower2,
1312 };
1313
1314 static int shift_pop(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
1315 {
1316 #define beginning       (cmd[0] == 'S') /* SHIFT */
1317         char *after, delimiter[2] = ",", *varsubst;
1318         size_t unused;
1319         struct ast_str *before = ast_str_thread_get(&result_buf, 16);
1320         char *(*search_func)(const char *s, int c) = (beginning ? strchr : strrchr);
1321         AST_DECLARE_APP_ARGS(args,
1322                 AST_APP_ARG(var);
1323                 AST_APP_ARG(delimiter);
1324         );
1325
1326         if (!before) {
1327                 return -1;
1328         }
1329
1330         AST_STANDARD_APP_ARGS(args, data);
1331
1332         if (ast_strlen_zero(args.var)) {
1333                 ast_log(LOG_WARNING, "%s requires a variable name\n", cmd);
1334                 return -1;
1335         }
1336
1337         varsubst = alloca(strlen(args.var) + 4);
1338         sprintf(varsubst, "${%s}", args.var);
1339         ast_str_substitute_variables(&before, 0, chan, varsubst);
1340
1341         if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
1342                 ast_get_encoded_char(args.delimiter, delimiter, &unused);
1343         }
1344
1345         if (!ast_str_strlen(before)) {
1346                 /* Nothing to pop */
1347                 return -1;
1348         }
1349
1350         if (!(after = search_func(ast_str_buffer(before), delimiter[0]))) {
1351                 /* Only one entry in array */
1352                 ast_str_set(buf, len, "%s", ast_str_buffer(before));
1353                 pbx_builtin_setvar_helper(chan, args.var, "");
1354         } else {
1355                 *after++ = '\0';
1356                 ast_str_set(buf, len, "%s", beginning ? ast_str_buffer(before) : after);
1357                 pbx_builtin_setvar_helper(chan, args.var, beginning ? after : ast_str_buffer(before));
1358         }
1359
1360         return 0;
1361 #undef beginning
1362 }
1363
1364 static struct ast_custom_function shift_function = {
1365         .name = "SHIFT",
1366         .read2 = shift_pop,
1367 };
1368
1369 static struct ast_custom_function pop_function = {
1370         .name = "POP",
1371         .read2 = shift_pop,
1372 };
1373
1374 static int unshift_push(struct ast_channel *chan, const char *cmd, char *data, const char *new_value)
1375 {
1376 #define beginning       (cmd[0] == 'U') /* UNSHIFT */
1377         char delimiter[2] = ",", *varsubst;
1378         size_t unused;
1379         struct ast_str *buf, *previous_value;
1380         AST_DECLARE_APP_ARGS(args,
1381                 AST_APP_ARG(var);
1382                 AST_APP_ARG(delimiter);
1383         );
1384
1385         if (!(buf = ast_str_thread_get(&result_buf, 16)) ||
1386                 !(previous_value = ast_str_thread_get(&tmp_buf, 16))) {
1387                 return -1;
1388         }
1389
1390         AST_STANDARD_APP_ARGS(args, data);
1391
1392         if (ast_strlen_zero(args.var)) {
1393                 ast_log(LOG_WARNING, "%s requires a variable name\n", cmd);
1394                 return -1;
1395         }
1396
1397         if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
1398                 ast_get_encoded_char(args.delimiter, delimiter, &unused);
1399         }
1400
1401         varsubst = alloca(strlen(args.var) + 4);
1402         sprintf(varsubst, "${%s}", args.var);
1403         ast_str_substitute_variables(&previous_value, 0, chan, varsubst);
1404
1405         if (!ast_str_strlen(previous_value)) {
1406                 ast_str_set(&buf, 0, "%s", new_value);
1407         } else {
1408                 ast_str_set(&buf, 0, "%s%c%s",
1409                         beginning ? new_value : ast_str_buffer(previous_value),
1410                         delimiter[0],
1411                         beginning ? ast_str_buffer(previous_value) : new_value);
1412         }
1413
1414         pbx_builtin_setvar_helper(chan, args.var, ast_str_buffer(buf));
1415
1416         return 0;
1417 #undef beginning
1418 }
1419
1420 static struct ast_custom_function push_function = {
1421         .name = "PUSH",
1422         .write = unshift_push,
1423 };
1424
1425 static struct ast_custom_function unshift_function = {
1426         .name = "UNSHIFT",
1427         .write = unshift_push,
1428 };
1429
1430 static int passthru(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
1431 {
1432         ast_str_set(buf, len, "%s", data);
1433         return 0;
1434 }
1435
1436 static struct ast_custom_function passthru_function = {
1437         .name = "PASSTHRU",
1438         .read2 = passthru,
1439 };
1440
1441 #ifdef TEST_FRAMEWORK
1442 AST_TEST_DEFINE(test_FILTER)
1443 {
1444         int i, res = AST_TEST_PASS;
1445         const char *test_strings[][2] = {
1446                 {"A-R",            "DAHDI"},
1447                 {"A\\-R",          "A"},
1448                 {"\\x41-R",        "DAHDI"},
1449                 {"0-9A-Ca-c",      "0042133333A12212"},
1450                 {"0-9a-cA-C_+\\-", "0042133333A12212"},
1451                 {NULL,             NULL},
1452         };
1453
1454         switch (cmd) {
1455         case TEST_INIT:
1456                 info->name = "func_FILTER_test";
1457                 info->category = "funcs/func_strings/";
1458                 info->summary = "Test FILTER function";
1459                 info->description = "Verify FILTER behavior";
1460                 return AST_TEST_NOT_RUN;
1461         case TEST_EXECUTE:
1462                 break;
1463         }
1464
1465         for (i = 0; test_strings[i][0]; i++) {
1466                 char tmp[256], tmp2[256] = "";
1467                 snprintf(tmp, sizeof(tmp), "${FILTER(%s,0042133333&DAHDI/g1/2212)}", test_strings[i][0]);
1468                 pbx_substitute_variables_helper(NULL, tmp, tmp2, sizeof(tmp2) - 1);
1469                 if (strcmp(test_strings[i][1], tmp2)) {
1470                         ast_test_status_update(test, "Format string '%s' substituted to '%s'.  Expected '%s'.\n", test_strings[i][0], tmp2, test_strings[i][1]);
1471                         res = AST_TEST_FAIL;
1472                 }
1473         }
1474         return res;
1475 }
1476 #endif
1477
1478 static int unload_module(void)
1479 {
1480         int res = 0;
1481
1482         AST_TEST_UNREGISTER(test_FILTER);
1483         res |= ast_custom_function_unregister(&fieldqty_function);
1484         res |= ast_custom_function_unregister(&filter_function);
1485         res |= ast_custom_function_unregister(&replace_function);
1486         res |= ast_custom_function_unregister(&listfilter_function);
1487         res |= ast_custom_function_unregister(&regex_function);
1488         res |= ast_custom_function_unregister(&array_function);
1489         res |= ast_custom_function_unregister(&quote_function);
1490         res |= ast_custom_function_unregister(&csv_quote_function);
1491         res |= ast_custom_function_unregister(&len_function);
1492         res |= ast_custom_function_unregister(&strftime_function);
1493         res |= ast_custom_function_unregister(&strptime_function);
1494         res |= ast_custom_function_unregister(&eval_function);
1495         res |= ast_custom_function_unregister(&keypadhash_function);
1496         res |= ast_custom_function_unregister(&hashkeys_function);
1497         res |= ast_custom_function_unregister(&hash_function);
1498         res |= ast_unregister_application(app_clearhash);
1499         res |= ast_custom_function_unregister(&toupper_function);
1500         res |= ast_custom_function_unregister(&tolower_function);
1501         res |= ast_custom_function_unregister(&shift_function);
1502         res |= ast_custom_function_unregister(&pop_function);
1503         res |= ast_custom_function_unregister(&push_function);
1504         res |= ast_custom_function_unregister(&unshift_function);
1505         res |= ast_custom_function_unregister(&passthru_function);
1506
1507         return res;
1508 }
1509
1510 static int load_module(void)
1511 {
1512         int res = 0;
1513
1514         AST_TEST_REGISTER(test_FILTER);
1515         res |= ast_custom_function_register(&fieldqty_function);
1516         res |= ast_custom_function_register(&filter_function);
1517         res |= ast_custom_function_register(&replace_function);
1518         res |= ast_custom_function_register(&listfilter_function);
1519         res |= ast_custom_function_register(&regex_function);
1520         res |= ast_custom_function_register(&array_function);
1521         res |= ast_custom_function_register(&quote_function);
1522         res |= ast_custom_function_register(&csv_quote_function);
1523         res |= ast_custom_function_register(&len_function);
1524         res |= ast_custom_function_register(&strftime_function);
1525         res |= ast_custom_function_register(&strptime_function);
1526         res |= ast_custom_function_register(&eval_function);
1527         res |= ast_custom_function_register(&keypadhash_function);
1528         res |= ast_custom_function_register(&hashkeys_function);
1529         res |= ast_custom_function_register(&hash_function);
1530         res |= ast_register_application_xml(app_clearhash, exec_clearhash);
1531         res |= ast_custom_function_register(&toupper_function);
1532         res |= ast_custom_function_register(&tolower_function);
1533         res |= ast_custom_function_register(&shift_function);
1534         res |= ast_custom_function_register(&pop_function);
1535         res |= ast_custom_function_register(&push_function);
1536         res |= ast_custom_function_register(&unshift_function);
1537         res |= ast_custom_function_register(&passthru_function);
1538
1539         return res;
1540 }
1541
1542 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "String handling dialplan functions");