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