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