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