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