5dbd83af3c076bd88a87741928780e63d13f83f9
[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                                 snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
835                                 pbx_builtin_setvar_helper(chan, varname, arg2.val[i]);
836                         } else {
837                                 pbx_builtin_setvar_helper(chan, arg1.var[i], arg2.val[i]);
838                         }
839                 } else {
840                         /* We could unset the variable, by passing a NULL, but due to
841                          * pushvar semantics, that could create some undesired behavior. */
842                         if (ishash) {
843                                 snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
844                                 pbx_builtin_setvar_helper(chan, varname, "");
845                         } else {
846                                 pbx_builtin_setvar_helper(chan, arg1.var[i], "");
847                         }
848                 }
849         }
850
851         return 0;
852 }
853
854 static int hashkeys_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
855 {
856         struct ast_var_t *newvar;
857         struct ast_str *prefix = ast_str_alloca(80);
858
859         ast_str_set(&prefix, -1, HASH_PREFIX, data);
860         memset(buf, 0, len);
861
862         AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) {
863                 if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
864                         /* Copy everything after the prefix */
865                         strncat(buf, ast_var_name(newvar) + ast_str_strlen(prefix), len - strlen(buf) - 1);
866                         /* Trim the trailing ~ */
867                         buf[strlen(buf) - 1] = ',';
868                 }
869         }
870         /* Trim the trailing comma */
871         buf[strlen(buf) - 1] = '\0';
872         return 0;
873 }
874
875 static int hashkeys_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
876 {
877         struct ast_var_t *newvar;
878         struct ast_str *prefix = ast_str_alloca(80);
879         char *tmp;
880
881         ast_str_set(&prefix, -1, HASH_PREFIX, data);
882
883         AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) {
884                 if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
885                         /* Copy everything after the prefix */
886                         ast_str_append(buf, len, "%s", ast_var_name(newvar) + ast_str_strlen(prefix));
887                         /* Trim the trailing ~ */
888                         tmp = ast_str_buffer(*buf);
889                         tmp[ast_str_strlen(*buf) - 1] = ',';
890                 }
891         }
892         /* Trim the trailing comma */
893         tmp = ast_str_buffer(*buf);
894         tmp[ast_str_strlen(*buf) - 1] = '\0';
895         return 0;
896 }
897
898 static int hash_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
899 {
900         char varname[256];
901         AST_DECLARE_APP_ARGS(arg,
902                 AST_APP_ARG(hashname);
903                 AST_APP_ARG(hashkey);
904         );
905
906         if (!strchr(var, ',')) {
907                 /* Single argument version */
908                 return array(chan, "HASH", var, value);
909         }
910
911         AST_STANDARD_APP_ARGS(arg, var);
912         snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
913         pbx_builtin_setvar_helper(chan, varname, value);
914
915         return 0;
916 }
917
918 static int hash_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
919 {
920         char varname[256];
921         const char *varvalue;
922         AST_DECLARE_APP_ARGS(arg,
923                 AST_APP_ARG(hashname);
924                 AST_APP_ARG(hashkey);
925         );
926
927         AST_STANDARD_APP_ARGS(arg, data);
928         if (arg.argc == 2) {
929                 snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
930                 varvalue = pbx_builtin_getvar_helper(chan, varname);
931                 if (varvalue)
932                         ast_copy_string(buf, varvalue, len);
933                 else
934                         *buf = '\0';
935         } else if (arg.argc == 1) {
936                 char colnames[4096];
937                 int i;
938                 AST_DECLARE_APP_ARGS(arg2,
939                         AST_APP_ARG(col)[100];
940                 );
941
942                 /* Get column names, in no particular order */
943                 hashkeys_read(chan, "HASHKEYS", arg.hashname, colnames, sizeof(colnames));
944                 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames);
945
946                 AST_STANDARD_APP_ARGS(arg2, colnames);
947                 *buf = '\0';
948
949                 /* Now get the corresponding column values, in exactly the same order */
950                 for (i = 0; i < arg2.argc; i++) {
951                         snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg2.col[i]);
952                         varvalue = pbx_builtin_getvar_helper(chan, varname);
953                         strncat(buf, varvalue, len - strlen(buf) - 1);
954                         strncat(buf, ",", len - strlen(buf) - 1);
955                 }
956
957                 /* Strip trailing comma */
958                 buf[strlen(buf) - 1] = '\0';
959         }
960
961         return 0;
962 }
963
964 static struct ast_custom_function hash_function = {
965         .name = "HASH",
966         .write = hash_write,
967         .read = hash_read,
968 };
969
970 static struct ast_custom_function hashkeys_function = {
971         .name = "HASHKEYS",
972         .read = hashkeys_read,
973         .read2 = hashkeys_read2,
974 };
975
976 static struct ast_custom_function array_function = {
977         .name = "ARRAY",
978         .write = array,
979 };
980
981 static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
982 {
983         char *bufptr = buf, *dataptr = data;
984
985         if (len < 3){ /* at least two for quotes and one for binary zero */
986                 ast_log(LOG_ERROR, "Not enough buffer");
987                 return -1;
988         }
989
990         if (ast_strlen_zero(data)) {
991                 ast_log(LOG_WARNING, "No argument specified!\n");
992                 ast_copy_string(buf, "\"\"", len);
993                 return 0;
994         }
995
996         *bufptr++ = '"';
997         for (; bufptr < buf + len - 3; dataptr++) {
998                 if (*dataptr == '\\') {
999                         *bufptr++ = '\\';
1000                         *bufptr++ = '\\';
1001                 } else if (*dataptr == '"') {
1002                         *bufptr++ = '\\';
1003                         *bufptr++ = '"';
1004                 } else if (*dataptr == '\0') {
1005                         break;
1006                 } else {
1007                         *bufptr++ = *dataptr;
1008                 }
1009         }
1010         *bufptr++ = '"';
1011         *bufptr = '\0';
1012         return 0;
1013 }
1014
1015 static struct ast_custom_function quote_function = {
1016         .name = "QUOTE",
1017         .read = quote,
1018 };
1019
1020 static int csv_quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1021 {
1022         char *bufptr = buf, *dataptr = data;
1023
1024         if (len < 3){ /* at least two for quotes and one for binary zero */
1025                 ast_log(LOG_ERROR, "Not enough buffer");
1026                 return -1;
1027         }
1028
1029         if (ast_strlen_zero(data)) {
1030                 ast_log(LOG_WARNING, "No argument specified!\n");
1031                 ast_copy_string(buf,"\"\"",len);
1032                 return 0;
1033         }
1034
1035         *bufptr++ = '"';
1036         for (; bufptr < buf + len - 3; dataptr++){
1037                 if (*dataptr == '"') {
1038                         *bufptr++ = '"';
1039                         *bufptr++ = '"';
1040                 } else if (*dataptr == '\0') {
1041                         break;
1042                 } else {
1043                         *bufptr++ = *dataptr;
1044                 }
1045         }
1046         *bufptr++ = '"';
1047         *bufptr='\0';
1048         return 0;
1049 }
1050
1051 static struct ast_custom_function csv_quote_function = {
1052         .name = "CSV_QUOTE",
1053         .read = csv_quote,
1054 };
1055
1056 static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1057 {
1058         int length = 0;
1059
1060         if (data)
1061                 length = strlen(data);
1062
1063         snprintf(buf, buflen, "%d", length);
1064
1065         return 0;
1066 }
1067
1068 static struct ast_custom_function len_function = {
1069         .name = "LEN",
1070         .read = len,
1071         .read_max = 12,
1072 };
1073
1074 static int acf_strftime(struct ast_channel *chan, const char *cmd, char *parse,
1075                         char *buf, size_t buflen)
1076 {
1077         AST_DECLARE_APP_ARGS(args,
1078                              AST_APP_ARG(epoch);
1079                              AST_APP_ARG(timezone);
1080                              AST_APP_ARG(format);
1081         );
1082         struct timeval when;
1083         struct ast_tm tm;
1084
1085         buf[0] = '\0';
1086
1087         AST_STANDARD_APP_ARGS(args, parse);
1088
1089         ast_get_timeval(args.epoch, &when, ast_tvnow(), NULL);
1090         ast_localtime(&when, &tm, args.timezone);
1091
1092         if (!args.format)
1093                 args.format = "%c";
1094
1095         if (ast_strftime(buf, buflen, args.format, &tm) <= 0)
1096                 ast_log(LOG_WARNING, "C function strftime() output nothing?!!\n");
1097
1098         buf[buflen - 1] = '\0';
1099
1100         return 0;
1101 }
1102
1103 static struct ast_custom_function strftime_function = {
1104         .name = "STRFTIME",
1105         .read = acf_strftime,
1106 };
1107
1108 static int acf_strptime(struct ast_channel *chan, const char *cmd, char *data,
1109                         char *buf, size_t buflen)
1110 {
1111         AST_DECLARE_APP_ARGS(args,
1112                              AST_APP_ARG(timestring);
1113                              AST_APP_ARG(timezone);
1114                              AST_APP_ARG(format);
1115         );
1116         struct ast_tm tm;
1117
1118         buf[0] = '\0';
1119
1120         if (!data) {
1121                 ast_log(LOG_ERROR,
1122                                 "Asterisk function STRPTIME() requires an argument.\n");
1123                 return -1;
1124         }
1125
1126         AST_STANDARD_APP_ARGS(args, data);
1127
1128         if (ast_strlen_zero(args.format)) {
1129                 ast_log(LOG_ERROR,
1130                                 "No format supplied to STRPTIME(<timestring>,<timezone>,<format>)");
1131                 return -1;
1132         }
1133
1134         if (!ast_strptime(args.timestring, args.format, &tm)) {
1135                 ast_log(LOG_WARNING, "STRPTIME() found no time specified within the string\n");
1136         } else {
1137                 struct timeval when;
1138                 when = ast_mktime(&tm, args.timezone);
1139                 snprintf(buf, buflen, "%d", (int) when.tv_sec);
1140         }
1141
1142         return 0;
1143 }
1144
1145 static struct ast_custom_function strptime_function = {
1146         .name = "STRPTIME",
1147         .read = acf_strptime,
1148 };
1149
1150 static int function_eval(struct ast_channel *chan, const char *cmd, char *data,
1151                          char *buf, size_t buflen)
1152 {
1153         if (ast_strlen_zero(data)) {
1154                 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
1155                 return -1;
1156         }
1157
1158         pbx_substitute_variables_helper(chan, data, buf, buflen - 1);
1159
1160         return 0;
1161 }
1162
1163 static int function_eval2(struct ast_channel *chan, const char *cmd, char *data,
1164                          struct ast_str **buf, ssize_t buflen)
1165 {
1166         if (ast_strlen_zero(data)) {
1167                 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
1168                 return -1;
1169         }
1170
1171         ast_str_substitute_variables(buf, buflen, chan, data);
1172
1173         return 0;
1174 }
1175
1176 static struct ast_custom_function eval_function = {
1177         .name = "EVAL",
1178         .read = function_eval,
1179         .read2 = function_eval2,
1180 };
1181
1182 static int keypadhash(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1183 {
1184         char *bufptr, *dataptr;
1185
1186         for (bufptr = buf, dataptr = data; bufptr < buf + buflen - 1; dataptr++) {
1187                 if (*dataptr == '\0') {
1188                         *bufptr++ = '\0';
1189                         break;
1190                 } else if (*dataptr == '1') {
1191                         *bufptr++ = '1';
1192                 } else if (strchr("AaBbCc2", *dataptr)) {
1193                         *bufptr++ = '2';
1194                 } else if (strchr("DdEeFf3", *dataptr)) {
1195                         *bufptr++ = '3';
1196                 } else if (strchr("GgHhIi4", *dataptr)) {
1197                         *bufptr++ = '4';
1198                 } else if (strchr("JjKkLl5", *dataptr)) {
1199                         *bufptr++ = '5';
1200                 } else if (strchr("MmNnOo6", *dataptr)) {
1201                         *bufptr++ = '6';
1202                 } else if (strchr("PpQqRrSs7", *dataptr)) {
1203                         *bufptr++ = '7';
1204                 } else if (strchr("TtUuVv8", *dataptr)) {
1205                         *bufptr++ = '8';
1206                 } else if (strchr("WwXxYyZz9", *dataptr)) {
1207                         *bufptr++ = '9';
1208                 } else if (*dataptr == '0') {
1209                         *bufptr++ = '0';
1210                 }
1211         }
1212         buf[buflen - 1] = '\0';
1213
1214         return 0;
1215 }
1216
1217 static struct ast_custom_function keypadhash_function = {
1218         .name = "KEYPADHASH",
1219         .read = keypadhash,
1220 };
1221
1222 static int string_toupper(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1223 {
1224         char *bufptr = buf, *dataptr = data;
1225
1226         while ((bufptr < buf + buflen - 1) && (*bufptr++ = toupper(*dataptr++)));
1227
1228         return 0;
1229 }
1230
1231 static int string_toupper2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
1232 {
1233         char *bufptr, *dataptr = data;
1234
1235         if (buflen > -1) {
1236                 ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
1237         }
1238         bufptr = ast_str_buffer(*buf);
1239         while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = toupper(*dataptr++)));
1240         ast_str_update(*buf);
1241
1242         return 0;
1243 }
1244
1245 static struct ast_custom_function toupper_function = {
1246         .name = "TOUPPER",
1247         .read = string_toupper,
1248         .read2 = string_toupper2,
1249 };
1250
1251 static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1252 {
1253         char *bufptr = buf, *dataptr = data;
1254
1255         while ((bufptr < buf + buflen - 1) && (*bufptr++ = tolower(*dataptr++)));
1256
1257         return 0;
1258 }
1259
1260 static int string_tolower2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
1261 {
1262         char *bufptr, *dataptr = data;
1263
1264         if (buflen > -1) {
1265                 ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
1266         }
1267         bufptr = ast_str_buffer(*buf);
1268         while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = tolower(*dataptr++)));
1269         ast_str_update(*buf);
1270
1271         return 0;
1272 }
1273
1274 static struct ast_custom_function tolower_function = {
1275         .name = "TOLOWER",
1276         .read = string_tolower,
1277         .read2 = string_tolower2,
1278 };
1279
1280 static int shift_pop(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
1281 {
1282 #define beginning       (cmd[0] == 'S') /* SHIFT */
1283         char *after, delimiter[2] = ",", *varsubst;
1284         size_t unused;
1285         struct ast_str *before = ast_str_thread_get(&result_buf, 16);
1286         char *(*search_func)(const char *s, int c) = (beginning ? strchr : strrchr);
1287         AST_DECLARE_APP_ARGS(args,
1288                 AST_APP_ARG(var);
1289                 AST_APP_ARG(delimiter);
1290         );
1291
1292         if (!before) {
1293                 return -1;
1294         }
1295
1296         AST_STANDARD_APP_ARGS(args, data);
1297
1298         if (ast_strlen_zero(args.var)) {
1299                 ast_log(LOG_WARNING, "%s requires a variable name\n", cmd);
1300                 return -1;
1301         }
1302
1303         varsubst = alloca(strlen(args.var) + 4);
1304         sprintf(varsubst, "${%s}", args.var);
1305         ast_str_substitute_variables(&before, 0, chan, varsubst);
1306
1307         if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
1308                 ast_get_encoded_char(args.delimiter, delimiter, &unused);
1309         }
1310
1311         if (!ast_str_strlen(before)) {
1312                 /* Nothing to pop */
1313                 return -1;
1314         }
1315
1316         if (!(after = search_func(ast_str_buffer(before), delimiter[0]))) {
1317                 /* Only one entry in array */
1318                 ast_str_set(buf, len, "%s", ast_str_buffer(before));
1319                 pbx_builtin_setvar_helper(chan, args.var, "");
1320         } else {
1321                 *after++ = '\0';
1322                 ast_str_set(buf, len, "%s", beginning ? ast_str_buffer(before) : after);
1323                 pbx_builtin_setvar_helper(chan, args.var, beginning ? after : ast_str_buffer(before));
1324         }
1325
1326         return 0;
1327 #undef beginning
1328 }
1329
1330 static struct ast_custom_function shift_function = {
1331         .name = "SHIFT",
1332         .read2 = shift_pop,
1333 };
1334
1335 static struct ast_custom_function pop_function = {
1336         .name = "POP",
1337         .read2 = shift_pop,
1338 };
1339
1340 static int unshift_push(struct ast_channel *chan, const char *cmd, char *data, const char *new_value)
1341 {
1342 #define beginning       (cmd[0] == 'U') /* UNSHIFT */
1343         char delimiter[2] = ",", *varsubst;
1344         size_t unused;
1345         struct ast_str *buf, *previous_value;
1346         AST_DECLARE_APP_ARGS(args,
1347                 AST_APP_ARG(var);
1348                 AST_APP_ARG(delimiter);
1349         );
1350
1351         if (!(buf = ast_str_thread_get(&result_buf, 16)) ||
1352                 !(previous_value = ast_str_thread_get(&tmp_buf, 16))) {
1353                 return -1;
1354         }
1355
1356         AST_STANDARD_APP_ARGS(args, data);
1357
1358         if (ast_strlen_zero(args.var)) {
1359                 ast_log(LOG_WARNING, "%s requires a variable name\n", cmd);
1360                 return -1;
1361         }
1362
1363         if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
1364                 ast_get_encoded_char(args.delimiter, delimiter, &unused);
1365         }
1366
1367         varsubst = alloca(strlen(args.var) + 4);
1368         sprintf(varsubst, "${%s}", args.var);
1369         ast_str_substitute_variables(&previous_value, 0, chan, varsubst);
1370
1371         if (!ast_str_strlen(previous_value)) {
1372                 ast_str_set(&buf, 0, "%s", new_value);
1373         } else {
1374                 ast_str_set(&buf, 0, "%s%c%s",
1375                         beginning ? new_value : ast_str_buffer(previous_value),
1376                         delimiter[0],
1377                         beginning ? ast_str_buffer(previous_value) : new_value);
1378         }
1379
1380         pbx_builtin_setvar_helper(chan, args.var, ast_str_buffer(buf));
1381
1382         return 0;
1383 #undef beginning
1384 }
1385
1386 static struct ast_custom_function push_function = {
1387         .name = "PUSH",
1388         .write = unshift_push,
1389 };
1390
1391 static struct ast_custom_function unshift_function = {
1392         .name = "UNSHIFT",
1393         .write = unshift_push,
1394 };
1395
1396 static int passthru(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
1397 {
1398         ast_str_set(buf, len, "%s", data);
1399         return 0;
1400 }
1401
1402 static struct ast_custom_function passthru_function = {
1403         .name = "PASSTHRU",
1404         .read2 = passthru,
1405 };
1406
1407 static int unload_module(void)
1408 {
1409         int res = 0;
1410
1411         res |= ast_custom_function_unregister(&fieldqty_function);
1412         res |= ast_custom_function_unregister(&filter_function);
1413         res |= ast_custom_function_unregister(&replace_function);
1414         res |= ast_custom_function_unregister(&listfilter_function);
1415         res |= ast_custom_function_unregister(&regex_function);
1416         res |= ast_custom_function_unregister(&array_function);
1417         res |= ast_custom_function_unregister(&quote_function);
1418         res |= ast_custom_function_unregister(&csv_quote_function);
1419         res |= ast_custom_function_unregister(&len_function);
1420         res |= ast_custom_function_unregister(&strftime_function);
1421         res |= ast_custom_function_unregister(&strptime_function);
1422         res |= ast_custom_function_unregister(&eval_function);
1423         res |= ast_custom_function_unregister(&keypadhash_function);
1424         res |= ast_custom_function_unregister(&hashkeys_function);
1425         res |= ast_custom_function_unregister(&hash_function);
1426         res |= ast_unregister_application(app_clearhash);
1427         res |= ast_custom_function_unregister(&toupper_function);
1428         res |= ast_custom_function_unregister(&tolower_function);
1429         res |= ast_custom_function_unregister(&shift_function);
1430         res |= ast_custom_function_unregister(&pop_function);
1431         res |= ast_custom_function_unregister(&push_function);
1432         res |= ast_custom_function_unregister(&unshift_function);
1433         res |= ast_custom_function_unregister(&passthru_function);
1434
1435         return res;
1436 }
1437
1438 static int load_module(void)
1439 {
1440         int res = 0;
1441
1442         res |= ast_custom_function_register(&fieldqty_function);
1443         res |= ast_custom_function_register(&filter_function);
1444         res |= ast_custom_function_register(&replace_function);
1445         res |= ast_custom_function_register(&listfilter_function);
1446         res |= ast_custom_function_register(&regex_function);
1447         res |= ast_custom_function_register(&array_function);
1448         res |= ast_custom_function_register(&quote_function);
1449         res |= ast_custom_function_register(&csv_quote_function);
1450         res |= ast_custom_function_register(&len_function);
1451         res |= ast_custom_function_register(&strftime_function);
1452         res |= ast_custom_function_register(&strptime_function);
1453         res |= ast_custom_function_register(&eval_function);
1454         res |= ast_custom_function_register(&keypadhash_function);
1455         res |= ast_custom_function_register(&hashkeys_function);
1456         res |= ast_custom_function_register(&hash_function);
1457         res |= ast_register_application_xml(app_clearhash, exec_clearhash);
1458         res |= ast_custom_function_register(&toupper_function);
1459         res |= ast_custom_function_register(&tolower_function);
1460         res |= ast_custom_function_register(&shift_function);
1461         res |= ast_custom_function_register(&pop_function);
1462         res |= ast_custom_function_register(&push_function);
1463         res |= ast_custom_function_register(&unshift_function);
1464         res |= ast_custom_function_register(&passthru_function);
1465
1466         return res;
1467 }
1468
1469 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "String handling dialplan functions");