git migration: Refactor the ASTERISK_FILE_VERSION macro
[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_REGISTER_FILE()
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 ""ab\"c\"de""</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         RAII_VAR(struct ast_str *, str, ast_str_create(16), ast_free);
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                                 memmove(strptr, strptr + 1, strlen(strptr + 1) + 1);
845                                 strptr--;
846                         } else {
847                                 /* Replace character */
848                                 *strptr = *replace;
849                         }
850                 }
851         }
852
853         ast_str_set(buf, len, "%s", ast_str_buffer(str));
854         return 0;
855 }
856
857 static struct ast_custom_function replace_function = {
858         .name = "REPLACE",
859         .read2 = replace,
860 };
861
862 static int strreplace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
863 {
864         char *varsubstr; /* substring for input var */
865         char *start; /* Starting pos of substring search. */
866         char *end; /* Ending pos of substring search. */
867         int find_size; /* length of given find-string */
868         unsigned max_matches; /* number of matches we find before terminating search */
869         unsigned count; /* loop counter */
870         struct ast_str *str = ast_str_thread_get(&result_buf, 16); /* Holds the data obtained from varname */
871
872         AST_DECLARE_APP_ARGS(args,
873                 AST_APP_ARG(varname);
874                 AST_APP_ARG(find_string);
875                 AST_APP_ARG(replace_string);
876                 AST_APP_ARG(max_replacements);
877                 AST_APP_ARG(other);     /* Any remining unused arguments */
878         );
879
880         /* Guarantee output string is empty to start with. */
881         ast_str_reset(*buf);
882
883         if (!str) {
884                 /* We failed to allocate str, forget it.  We failed. */
885                 return -1;
886         }
887
888         /* Parse the arguments. */
889         AST_STANDARD_APP_ARGS(args, data);
890
891         if (args.argc < 2) {
892                 /* Didn't receive enough arguments to do anything */
893                 ast_log(LOG_ERROR,
894                         "Usage: %s(<varname>,<find-string>[,<replace-string>,[<max-replacements>]])\n",
895                         cmd);
896                 return -1;
897         }
898
899         /* No var name specified. Return failure, string is already empty. */
900         if (ast_strlen_zero(args.varname)) {
901                 return -1;
902         }
903
904         /* Zero length find strings are a no-no. Kill the function if we run into one. */
905         if (ast_strlen_zero(args.find_string)) {
906                 ast_log(LOG_ERROR, "No <find-string> specified\n");
907                 return -1;
908         }
909         find_size = strlen(args.find_string);
910
911         /* set varsubstr to the matching variable */
912         varsubstr = ast_alloca(strlen(args.varname) + 4);
913         sprintf(varsubstr, "${%s}", args.varname);
914         ast_str_substitute_variables(&str, 0, chan, varsubstr);
915
916         /* Determine how many replacements are allowed. */
917         if (!args.max_replacements
918                 || (max_matches = atoi(args.max_replacements)) <= 0) {
919                 /* Unlimited replacements are allowed. */
920                 max_matches = -1;
921         }
922
923         /* Generate the search and replaced string. */
924         start = ast_str_buffer(str);
925         for (count = 0; count < max_matches; ++count) {
926                 end = strstr(start, args.find_string);
927                 if (!end) {
928                         /* Did not find a matching substring in the remainder. */
929                         break;
930                 }
931
932                 /* Replace the found substring. */
933                 *end = '\0';
934                 ast_str_append(buf, len, "%s", start);
935                 if (args.replace_string) {
936                         /* Append the replacement string */
937                         ast_str_append(buf, len, "%s", args.replace_string);
938                 }
939                 start = end + find_size;
940         }
941         ast_str_append(buf, len, "%s", start);
942
943         return 0;
944 }
945
946 static struct ast_custom_function strreplace_function = {
947         .name = "STRREPLACE",
948         .read2 = strreplace,
949 };
950
951 static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf,
952                  size_t len)
953 {
954         AST_DECLARE_APP_ARGS(args,
955                              AST_APP_ARG(null);
956                              AST_APP_ARG(reg);
957                              AST_APP_ARG(str);
958         );
959         int errcode;
960         regex_t regexbuf;
961
962         buf[0] = '\0';
963
964         AST_NONSTANDARD_APP_ARGS(args, parse, '"');
965
966         if (args.argc != 3) {
967                 ast_log(LOG_ERROR, "Unexpected arguments: should have been in the form '\"<regex>\" <string>'\n");
968                 return -1;
969         }
970         if ((*args.str == ' ') || (*args.str == '\t'))
971                 args.str++;
972
973         ast_debug(1, "FUNCTION REGEX (%s)(%s)\n", args.reg, args.str);
974
975         if ((errcode = regcomp(&regexbuf, args.reg, REG_EXTENDED | REG_NOSUB))) {
976                 regerror(errcode, &regexbuf, buf, len);
977                 ast_log(LOG_WARNING, "Malformed input %s(%s): %s\n", cmd, parse, buf);
978                 return -1;
979         }
980         
981         strcpy(buf, regexec(&regexbuf, args.str, 0, NULL, 0) ? "0" : "1");
982
983         regfree(&regexbuf);
984
985         return 0;
986 }
987
988 static struct ast_custom_function regex_function = {
989         .name = "REGEX",
990         .read = regex,
991 };
992
993 #define HASH_PREFIX     "~HASH~%s~"
994 #define HASH_FORMAT     HASH_PREFIX "%s~"
995
996 static char *app_clearhash = "ClearHash";
997
998 /* This function probably should migrate to main/pbx.c, as pbx_builtin_clearvar_prefix() */
999 static void clearvar_prefix(struct ast_channel *chan, const char *prefix)
1000 {
1001         struct ast_var_t *var;
1002         int len = strlen(prefix);
1003         AST_LIST_TRAVERSE_SAFE_BEGIN(ast_channel_varshead(chan), var, entries) {
1004                 if (strncmp(prefix, ast_var_name(var), len) == 0) {
1005                         AST_LIST_REMOVE_CURRENT(entries);
1006                         ast_free(var);
1007                 }
1008         }
1009         AST_LIST_TRAVERSE_SAFE_END
1010 }
1011
1012 static int exec_clearhash(struct ast_channel *chan, const char *data)
1013 {
1014         char prefix[80];
1015         snprintf(prefix, sizeof(prefix), HASH_PREFIX, data ? (char *)data : "null");
1016         clearvar_prefix(chan, prefix);
1017         return 0;
1018 }
1019
1020 static int array(struct ast_channel *chan, const char *cmd, char *var,
1021                  const char *value)
1022 {
1023         AST_DECLARE_APP_ARGS(arg1,
1024                              AST_APP_ARG(var)[100];
1025         );
1026         AST_DECLARE_APP_ARGS(arg2,
1027                              AST_APP_ARG(val)[100];
1028         );
1029         char *origvar = "", *value2, varname[256];
1030         int i, ishash = 0;
1031
1032         if (!var) {
1033                 return -1;
1034         }
1035         value2 = ast_strdupa(value);
1036
1037         if (!strcmp(cmd, "HASH")) {
1038                 const char *var2 = pbx_builtin_getvar_helper(chan, "~ODBCFIELDS~");
1039                 origvar = var;
1040                 if (var2)
1041                         var = ast_strdupa(var2);
1042                 else {
1043                         if (chan)
1044                                 ast_autoservice_stop(chan);
1045                         return -1;
1046                 }
1047                 ishash = 1;
1048         }
1049
1050         /* The functions this will generally be used with are SORT and ODBC_*, which
1051          * both return comma-delimited lists.  However, if somebody uses literal lists,
1052          * their commas will be translated to vertical bars by the load, and I don't
1053          * want them to be surprised by the result.  Hence, we prefer commas as the
1054          * delimiter, but we'll fall back to vertical bars if commas aren't found.
1055          */
1056         ast_debug(1, "array (%s=%s)\n", var, S_OR(value2, ""));
1057         AST_STANDARD_APP_ARGS(arg1, var);
1058
1059         AST_STANDARD_APP_ARGS(arg2, value2);
1060
1061         for (i = 0; i < arg1.argc; i++) {
1062                 ast_debug(1, "array set value (%s=%s)\n", arg1.var[i],
1063                                 S_OR(arg2.val[i], ""));
1064                 if (i < arg2.argc) {
1065                         if (ishash) {
1066                                 if (origvar[0] == '_') {
1067                                         if (origvar[1] == '_') {
1068                                                 snprintf(varname, sizeof(varname), "__" HASH_FORMAT, origvar + 2, arg1.var[i]);
1069                                         } else {
1070                                                 snprintf(varname, sizeof(varname), "_" HASH_FORMAT, origvar + 1, arg1.var[i]);
1071                                         }
1072                                 } else {
1073                                         snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
1074                                 }
1075
1076                                 pbx_builtin_setvar_helper(chan, varname, arg2.val[i]);
1077                         } else {
1078                                 pbx_builtin_setvar_helper(chan, arg1.var[i], arg2.val[i]);
1079                         }
1080                 } else {
1081                         /* We could unset the variable, by passing a NULL, but due to
1082                          * pushvar semantics, that could create some undesired behavior. */
1083                         if (ishash) {
1084                                 snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
1085                                 pbx_builtin_setvar_helper(chan, varname, "");
1086                         } else {
1087                                 pbx_builtin_setvar_helper(chan, arg1.var[i], "");
1088                         }
1089                 }
1090         }
1091
1092         return 0;
1093 }
1094
1095 static int hashkeys_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1096 {
1097         struct ast_var_t *newvar;
1098         struct ast_str *prefix = ast_str_alloca(80);
1099
1100         if (!chan) {
1101                 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1102                 return -1;
1103         }
1104
1105         ast_str_set(&prefix, -1, HASH_PREFIX, data);
1106         memset(buf, 0, len);
1107
1108         AST_LIST_TRAVERSE(ast_channel_varshead(chan), newvar, entries) {
1109                 if (strncmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
1110                         /* Copy everything after the prefix */
1111                         strncat(buf, ast_var_name(newvar) + ast_str_strlen(prefix), len - strlen(buf) - 1);
1112                         /* Trim the trailing ~ */
1113                         buf[strlen(buf) - 1] = ',';
1114                 }
1115         }
1116         /* Trim the trailing comma */
1117         buf[strlen(buf) - 1] = '\0';
1118         return 0;
1119 }
1120
1121 static int hashkeys_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
1122 {
1123         struct ast_var_t *newvar;
1124         struct ast_str *prefix = ast_str_alloca(80);
1125         char *tmp;
1126
1127         if (!chan) {
1128                 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1129                 return -1;
1130         }
1131
1132         ast_str_set(&prefix, -1, HASH_PREFIX, data);
1133
1134         AST_LIST_TRAVERSE(ast_channel_varshead(chan), newvar, entries) {
1135                 if (strncmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
1136                         /* Copy everything after the prefix */
1137                         ast_str_append(buf, len, "%s", ast_var_name(newvar) + ast_str_strlen(prefix));
1138                         /* Trim the trailing ~ */
1139                         tmp = ast_str_buffer(*buf);
1140                         tmp[ast_str_strlen(*buf) - 1] = ',';
1141                 }
1142         }
1143         /* Trim the trailing comma */
1144         tmp = ast_str_buffer(*buf);
1145         tmp[ast_str_strlen(*buf) - 1] = '\0';
1146         return 0;
1147 }
1148
1149 static int hash_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
1150 {
1151         char varname[256];
1152         AST_DECLARE_APP_ARGS(arg,
1153                 AST_APP_ARG(hashname);
1154                 AST_APP_ARG(hashkey);
1155         );
1156
1157         if (!strchr(var, ',')) {
1158                 /* Single argument version */
1159                 return array(chan, "HASH", var, value);
1160         }
1161
1162         AST_STANDARD_APP_ARGS(arg, var);
1163         if (arg.hashname[0] == '_') {
1164                 if (arg.hashname[1] == '_') {
1165                         snprintf(varname, sizeof(varname), "__" HASH_FORMAT, arg.hashname + 2, arg.hashkey);
1166                 } else {
1167                         snprintf(varname, sizeof(varname), "_" HASH_FORMAT, arg.hashname + 1, arg.hashkey);
1168                 }
1169         } else {
1170                 snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
1171         }
1172         pbx_builtin_setvar_helper(chan, varname, value);
1173
1174         return 0;
1175 }
1176
1177 static int hash_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1178 {
1179         char varname[256];
1180         const char *varvalue;
1181         AST_DECLARE_APP_ARGS(arg,
1182                 AST_APP_ARG(hashname);
1183                 AST_APP_ARG(hashkey);
1184         );
1185
1186         AST_STANDARD_APP_ARGS(arg, data);
1187         if (arg.argc == 2) {
1188                 snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
1189                 varvalue = pbx_builtin_getvar_helper(chan, varname);
1190                 if (varvalue)
1191                         ast_copy_string(buf, varvalue, len);
1192                 else
1193                         *buf = '\0';
1194         } else if (arg.argc == 1) {
1195                 char colnames[4096];
1196                 int i;
1197                 AST_DECLARE_APP_ARGS(arg2,
1198                         AST_APP_ARG(col)[100];
1199                 );
1200
1201                 if (!chan) {
1202                         ast_log(LOG_WARNING, "No channel and only 1 parameter was provided to %s function.\n", cmd);
1203                         return -1;
1204                 }
1205
1206                 /* Get column names, in no particular order */
1207                 hashkeys_read(chan, "HASHKEYS", arg.hashname, colnames, sizeof(colnames));
1208                 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames);
1209
1210                 AST_STANDARD_APP_ARGS(arg2, colnames);
1211                 *buf = '\0';
1212
1213                 /* Now get the corresponding column values, in exactly the same order */
1214                 for (i = 0; i < arg2.argc; i++) {
1215                         snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg2.col[i]);
1216                         varvalue = pbx_builtin_getvar_helper(chan, varname);
1217                         strncat(buf, varvalue, len - strlen(buf) - 1);
1218                         strncat(buf, ",", len - strlen(buf) - 1);
1219                 }
1220
1221                 /* Strip trailing comma */
1222                 buf[strlen(buf) - 1] = '\0';
1223         }
1224
1225         return 0;
1226 }
1227
1228 static struct ast_custom_function hash_function = {
1229         .name = "HASH",
1230         .write = hash_write,
1231         .read = hash_read,
1232 };
1233
1234 static struct ast_custom_function hashkeys_function = {
1235         .name = "HASHKEYS",
1236         .read = hashkeys_read,
1237         .read2 = hashkeys_read2,
1238 };
1239
1240 static struct ast_custom_function array_function = {
1241         .name = "ARRAY",
1242         .write = array,
1243 };
1244
1245 static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1246 {
1247         char *bufptr = buf, *dataptr = data;
1248
1249         if (len < 3){ /* at least two for quotes and one for binary zero */
1250                 ast_log(LOG_ERROR, "Not enough buffer\n");
1251                 return -1;
1252         }
1253
1254         if (ast_strlen_zero(data)) {
1255                 ast_log(LOG_WARNING, "No argument specified!\n");
1256                 ast_copy_string(buf, "\"\"", len);
1257                 return 0;
1258         }
1259
1260         *bufptr++ = '"';
1261         for (; bufptr < buf + len - 3; dataptr++) {
1262                 if (*dataptr == '\\') {
1263                         *bufptr++ = '\\';
1264                         *bufptr++ = '\\';
1265                 } else if (*dataptr == '"') {
1266                         *bufptr++ = '\\';
1267                         *bufptr++ = '"';
1268                 } else if (*dataptr == '\0') {
1269                         break;
1270                 } else {
1271                         *bufptr++ = *dataptr;
1272                 }
1273         }
1274         *bufptr++ = '"';
1275         *bufptr = '\0';
1276         return 0;
1277 }
1278
1279 static struct ast_custom_function quote_function = {
1280         .name = "QUOTE",
1281         .read = quote,
1282 };
1283
1284 static int csv_quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1285 {
1286         char *bufptr = buf, *dataptr = data;
1287
1288         if (len < 3) { /* at least two for quotes and one for binary zero */
1289                 ast_log(LOG_ERROR, "Not enough buffer\n");
1290                 return -1;
1291         }
1292
1293         if (ast_strlen_zero(data)) {
1294                 ast_copy_string(buf, "\"\"", len);
1295                 return 0;
1296         }
1297
1298         *bufptr++ = '"';
1299         for (; bufptr < buf + len - 3; dataptr++){
1300                 if (*dataptr == '"') {
1301                         *bufptr++ = '"';
1302                         *bufptr++ = '"';
1303                 } else if (*dataptr == '\0') {
1304                         break;
1305                 } else {
1306                         *bufptr++ = *dataptr;
1307                 }
1308         }
1309         *bufptr++ = '"';
1310         *bufptr='\0';
1311         return 0;
1312 }
1313
1314 static struct ast_custom_function csv_quote_function = {
1315         .name = "CSV_QUOTE",
1316         .read = csv_quote,
1317 };
1318
1319 static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1320 {
1321         int length = 0;
1322
1323         if (data)
1324                 length = strlen(data);
1325
1326         snprintf(buf, buflen, "%d", length);
1327
1328         return 0;
1329 }
1330
1331 static struct ast_custom_function len_function = {
1332         .name = "LEN",
1333         .read = len,
1334         .read_max = 12,
1335 };
1336
1337 static int acf_strftime(struct ast_channel *chan, const char *cmd, char *parse,
1338                         char *buf, size_t buflen)
1339 {
1340         AST_DECLARE_APP_ARGS(args,
1341                              AST_APP_ARG(epoch);
1342                              AST_APP_ARG(timezone);
1343                              AST_APP_ARG(format);
1344         );
1345         struct timeval when;
1346         struct ast_tm tm;
1347
1348         buf[0] = '\0';
1349
1350         AST_STANDARD_APP_ARGS(args, parse);
1351
1352         ast_get_timeval(args.epoch, &when, ast_tvnow(), NULL);
1353         ast_localtime(&when, &tm, args.timezone);
1354
1355         if (!args.format)
1356                 args.format = "%c";
1357
1358         if (ast_strftime(buf, buflen, args.format, &tm) <= 0)
1359                 ast_log(LOG_WARNING, "C function strftime() output nothing?!!\n");
1360
1361         buf[buflen - 1] = '\0';
1362
1363         return 0;
1364 }
1365
1366 static struct ast_custom_function strftime_function = {
1367         .name = "STRFTIME",
1368         .read = acf_strftime,
1369 };
1370
1371 static int acf_strptime(struct ast_channel *chan, const char *cmd, char *data,
1372                         char *buf, size_t buflen)
1373 {
1374         AST_DECLARE_APP_ARGS(args,
1375                              AST_APP_ARG(timestring);
1376                              AST_APP_ARG(timezone);
1377                              AST_APP_ARG(format);
1378         );
1379         struct ast_tm tm;
1380
1381         buf[0] = '\0';
1382
1383         if (!data) {
1384                 ast_log(LOG_ERROR,
1385                                 "Asterisk function STRPTIME() requires an argument.\n");
1386                 return -1;
1387         }
1388
1389         AST_STANDARD_APP_ARGS(args, data);
1390
1391         if (ast_strlen_zero(args.format)) {
1392                 ast_log(LOG_ERROR,
1393                                 "No format supplied to STRPTIME(<timestring>,<timezone>,<format>)");
1394                 return -1;
1395         }
1396
1397         if (!ast_strptime(args.timestring, args.format, &tm)) {
1398                 ast_log(LOG_WARNING, "STRPTIME() found no time specified within the string\n");
1399         } else {
1400                 struct timeval when;
1401                 when = ast_mktime(&tm, args.timezone);
1402                 snprintf(buf, buflen, "%d", (int) when.tv_sec);
1403         }
1404
1405         return 0;
1406 }
1407
1408 static struct ast_custom_function strptime_function = {
1409         .name = "STRPTIME",
1410         .read = acf_strptime,
1411 };
1412
1413 static int function_eval(struct ast_channel *chan, const char *cmd, char *data,
1414                          char *buf, size_t buflen)
1415 {
1416         if (ast_strlen_zero(data)) {
1417                 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
1418                 return -1;
1419         }
1420
1421         pbx_substitute_variables_helper(chan, data, buf, buflen - 1);
1422
1423         return 0;
1424 }
1425
1426 static int function_eval2(struct ast_channel *chan, const char *cmd, char *data,
1427                          struct ast_str **buf, ssize_t buflen)
1428 {
1429         if (ast_strlen_zero(data)) {
1430                 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
1431                 return -1;
1432         }
1433
1434         ast_str_substitute_variables(buf, buflen, chan, data);
1435
1436         return 0;
1437 }
1438
1439 static struct ast_custom_function eval_function = {
1440         .name = "EVAL",
1441         .read = function_eval,
1442         .read2 = function_eval2,
1443 };
1444
1445 static int keypadhash(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1446 {
1447         char *bufptr, *dataptr;
1448
1449         for (bufptr = buf, dataptr = data; bufptr < buf + buflen - 1; dataptr++) {
1450                 if (*dataptr == '\0') {
1451                         *bufptr++ = '\0';
1452                         break;
1453                 } else if (*dataptr == '1') {
1454                         *bufptr++ = '1';
1455                 } else if (strchr("AaBbCc2", *dataptr)) {
1456                         *bufptr++ = '2';
1457                 } else if (strchr("DdEeFf3", *dataptr)) {
1458                         *bufptr++ = '3';
1459                 } else if (strchr("GgHhIi4", *dataptr)) {
1460                         *bufptr++ = '4';
1461                 } else if (strchr("JjKkLl5", *dataptr)) {
1462                         *bufptr++ = '5';
1463                 } else if (strchr("MmNnOo6", *dataptr)) {
1464                         *bufptr++ = '6';
1465                 } else if (strchr("PpQqRrSs7", *dataptr)) {
1466                         *bufptr++ = '7';
1467                 } else if (strchr("TtUuVv8", *dataptr)) {
1468                         *bufptr++ = '8';
1469                 } else if (strchr("WwXxYyZz9", *dataptr)) {
1470                         *bufptr++ = '9';
1471                 } else if (*dataptr == '0') {
1472                         *bufptr++ = '0';
1473                 }
1474         }
1475         buf[buflen - 1] = '\0';
1476
1477         return 0;
1478 }
1479
1480 static struct ast_custom_function keypadhash_function = {
1481         .name = "KEYPADHASH",
1482         .read = keypadhash,
1483 };
1484
1485 static int string_toupper(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1486 {
1487         char *bufptr = buf, *dataptr = data;
1488
1489         while ((bufptr < buf + buflen - 1) && (*bufptr++ = toupper(*dataptr++)));
1490
1491         return 0;
1492 }
1493
1494 static int string_toupper2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
1495 {
1496         char *bufptr, *dataptr = data;
1497
1498         if (buflen > -1) {
1499                 ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
1500         }
1501         bufptr = ast_str_buffer(*buf);
1502         while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = toupper(*dataptr++)));
1503         ast_str_update(*buf);
1504
1505         return 0;
1506 }
1507
1508 static struct ast_custom_function toupper_function = {
1509         .name = "TOUPPER",
1510         .read = string_toupper,
1511         .read2 = string_toupper2,
1512 };
1513
1514 static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1515 {
1516         char *bufptr = buf, *dataptr = data;
1517
1518         while ((bufptr < buf + buflen - 1) && (*bufptr++ = tolower(*dataptr++)));
1519
1520         return 0;
1521 }
1522
1523 static int string_tolower2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
1524 {
1525         char *bufptr, *dataptr = data;
1526
1527         if (buflen > -1) {
1528                 ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
1529         }
1530         bufptr = ast_str_buffer(*buf);
1531         while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = tolower(*dataptr++)));
1532         ast_str_update(*buf);
1533
1534         return 0;
1535 }
1536
1537 static struct ast_custom_function tolower_function = {
1538         .name = "TOLOWER",
1539         .read = string_tolower,
1540         .read2 = string_tolower2,
1541 };
1542
1543 static int shift_pop(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
1544 {
1545 #define beginning       (cmd[0] == 'S') /* SHIFT */
1546         char *after, delimiter[2] = ",", *varsubst;
1547         size_t unused;
1548         struct ast_str *before = ast_str_thread_get(&result_buf, 16);
1549         char *(*search_func)(const char *s, int c) = (beginning ? strchr : strrchr);
1550         AST_DECLARE_APP_ARGS(args,
1551                 AST_APP_ARG(var);
1552                 AST_APP_ARG(delimiter);
1553         );
1554
1555         if (!before) {
1556                 return -1;
1557         }
1558
1559         AST_STANDARD_APP_ARGS(args, data);
1560
1561         if (ast_strlen_zero(args.var)) {
1562                 ast_log(LOG_WARNING, "%s requires a variable name\n", cmd);
1563                 return -1;
1564         }
1565
1566         varsubst = ast_alloca(strlen(args.var) + 4);
1567         sprintf(varsubst, "${%s}", args.var);
1568         ast_str_substitute_variables(&before, 0, chan, varsubst);
1569
1570         if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
1571                 ast_get_encoded_char(args.delimiter, delimiter, &unused);
1572         }
1573
1574         if (!ast_str_strlen(before)) {
1575                 /* Nothing to pop */
1576                 return -1;
1577         }
1578
1579         if (!(after = search_func(ast_str_buffer(before), delimiter[0]))) {
1580                 /* Only one entry in array */
1581                 ast_str_set(buf, len, "%s", ast_str_buffer(before));
1582                 pbx_builtin_setvar_helper(chan, args.var, "");
1583         } else {
1584                 *after++ = '\0';
1585                 ast_str_set(buf, len, "%s", beginning ? ast_str_buffer(before) : after);
1586                 pbx_builtin_setvar_helper(chan, args.var, beginning ? after : ast_str_buffer(before));
1587         }
1588
1589         return 0;
1590 #undef beginning
1591 }
1592
1593 static struct ast_custom_function shift_function = {
1594         .name = "SHIFT",
1595         .read2 = shift_pop,
1596 };
1597
1598 static struct ast_custom_function pop_function = {
1599         .name = "POP",
1600         .read2 = shift_pop,
1601 };
1602
1603 static int unshift_push(struct ast_channel *chan, const char *cmd, char *data, const char *new_value)
1604 {
1605 #define beginning       (cmd[0] == 'U') /* UNSHIFT */
1606         char delimiter[2] = ",", *varsubst;
1607         size_t unused;
1608         struct ast_str *buf, *previous_value;
1609         AST_DECLARE_APP_ARGS(args,
1610                 AST_APP_ARG(var);
1611                 AST_APP_ARG(delimiter);
1612         );
1613         const char *stripped_var;
1614
1615         if (!(buf = ast_str_thread_get(&result_buf, 16)) ||
1616                 !(previous_value = ast_str_thread_get(&tmp_buf, 16))) {
1617                 return -1;
1618         }
1619
1620         AST_STANDARD_APP_ARGS(args, data);
1621
1622         if (ast_strlen_zero(args.var)) {
1623                 ast_log(LOG_WARNING, "%s requires a variable name\n", cmd);
1624                 return -1;
1625         }
1626
1627         if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
1628                 ast_get_encoded_char(args.delimiter, delimiter, &unused);
1629         }
1630
1631         /* UNSHIFT and PUSH act as ways of setting a variable, so we need to be
1632          * sure to skip leading underscores if they appear. However, we only want
1633          * to skip up to two since that is the maximum number that can be used to
1634          * indicate variable inheritance. Any further underscores are part of the
1635          * variable name.
1636          */
1637         stripped_var = args.var + MIN(strspn(args.var, "_"), 2);
1638         varsubst = ast_alloca(strlen(stripped_var) + 4);
1639         sprintf(varsubst, "${%s}", stripped_var);
1640         ast_str_substitute_variables(&previous_value, 0, chan, varsubst);
1641
1642         if (!ast_str_strlen(previous_value)) {
1643                 ast_str_set(&buf, 0, "%s", new_value);
1644         } else {
1645                 ast_str_set(&buf, 0, "%s%c%s",
1646                         beginning ? new_value : ast_str_buffer(previous_value),
1647                         delimiter[0],
1648                         beginning ? ast_str_buffer(previous_value) : new_value);
1649         }
1650
1651         pbx_builtin_setvar_helper(chan, args.var, ast_str_buffer(buf));
1652
1653         return 0;
1654 #undef beginning
1655 }
1656
1657 static struct ast_custom_function push_function = {
1658         .name = "PUSH",
1659         .write = unshift_push,
1660 };
1661
1662 static struct ast_custom_function unshift_function = {
1663         .name = "UNSHIFT",
1664         .write = unshift_push,
1665 };
1666
1667 static int passthru(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
1668 {
1669         ast_str_set(buf, len, "%s", data);
1670         return 0;
1671 }
1672
1673 static struct ast_custom_function passthru_function = {
1674         .name = "PASSTHRU",
1675         .read2 = passthru,
1676 };
1677
1678 #ifdef TEST_FRAMEWORK
1679 AST_TEST_DEFINE(test_FIELDNUM)
1680 {
1681         int i, res = AST_TEST_PASS;
1682         struct ast_channel *chan;
1683         struct ast_str *str;
1684         char expression[256];
1685         struct {
1686                 const char *fields;
1687                 const char *delim;
1688                 const char *field;
1689                 const char *expected;
1690         } test_args[] = {
1691                 {"abc,def,ghi,jkl", "\\,",     "ghi", "3"},
1692                 {"abc def ghi jkl", " ",       "abc", "1"},
1693                 {"abc/def/ghi/jkl", "\\\\x2f", "def", "2"},
1694                 {"abc$def$ghi$jkl", "",        "ghi", "0"},
1695                 {"abc,def,ghi,jkl", "-",       "",    "0"},
1696                 {"abc-def-ghi-jkl", "-",       "mno", "0"}
1697         };
1698
1699         switch (cmd) {
1700         case TEST_INIT:
1701                 info->name = "func_FIELDNUM_test";
1702                 info->category = "/funcs/func_strings/";
1703                 info->summary = "Test FIELDNUM function";
1704                 info->description = "Verify FIELDNUM behavior";
1705                 return AST_TEST_NOT_RUN;
1706         case TEST_EXECUTE:
1707                 break;
1708         }
1709
1710         if (!(chan = ast_dummy_channel_alloc())) {
1711                 ast_test_status_update(test, "Unable to allocate dummy channel\n");
1712                 return AST_TEST_FAIL;
1713         }
1714
1715         if (!(str = ast_str_create(16))) {
1716                 ast_test_status_update(test, "Unable to allocate dynamic string buffer\n");
1717                 ast_channel_release(chan);
1718                 return AST_TEST_FAIL;
1719         }
1720
1721         for (i = 0; i < ARRAY_LEN(test_args); i++) {
1722                 struct ast_var_t *var = ast_var_assign("FIELDS", test_args[i].fields);
1723                 if (!var) {
1724                         ast_test_status_update(test, "Out of memory\n");
1725                         res = AST_TEST_FAIL;
1726                         break;
1727                 }
1728
1729                 AST_LIST_INSERT_HEAD(ast_channel_varshead(chan), var, entries);
1730
1731                 snprintf(expression, sizeof(expression), "${FIELDNUM(%s,%s,%s)}", var->name, test_args[i].delim, test_args[i].field);
1732                 ast_str_substitute_variables(&str, 0, chan, expression);
1733
1734                 AST_LIST_REMOVE(ast_channel_varshead(chan), var, entries);
1735                 ast_var_delete(var);
1736
1737                 if (strcasecmp(ast_str_buffer(str), test_args[i].expected)) {
1738                         ast_test_status_update(test, "Evaluation of '%s' returned '%s' instead of the expected value '%s'\n",
1739                                 expression, ast_str_buffer(str), test_args[i].expected);
1740                         res = AST_TEST_FAIL;
1741                         break;
1742                 }
1743         }
1744
1745         ast_free(str);
1746         ast_channel_release(chan);
1747
1748         return res;
1749 }
1750
1751 AST_TEST_DEFINE(test_REPLACE)
1752 {
1753         int i, res = AST_TEST_PASS;
1754         struct ast_channel *chan;
1755         struct ast_str *str;
1756         char expression[256];
1757         struct {
1758                 const char *test_string;
1759                 const char *find_chars;
1760                 const char *replace_char;
1761                 const char *expected;
1762         } test_args[] = {
1763                 {"abc,def", "\\,", "-", "abc-def"},
1764                 {"abc,abc", "bc",  "a", "aaa,aaa"},
1765                 {"abc,def", "x",   "?", "abc,def"},
1766                 {"abc,def", "\\,", "",  "abcdef"}
1767         };
1768
1769         switch (cmd) {
1770         case TEST_INIT:
1771                 info->name = "func_REPLACE_test";
1772                 info->category = "/funcs/func_strings/";
1773                 info->summary = "Test REPLACE function";
1774                 info->description = "Verify REPLACE behavior";
1775                 return AST_TEST_NOT_RUN;
1776         case TEST_EXECUTE:
1777                 break;
1778         }
1779
1780         if (!(chan = ast_dummy_channel_alloc())) {
1781                 ast_test_status_update(test, "Unable to allocate dummy channel\n");
1782                 return AST_TEST_FAIL;
1783         }
1784
1785         if (!(str = ast_str_create(16))) {
1786                 ast_test_status_update(test, "Unable to allocate dynamic string buffer\n");
1787                 ast_channel_release(chan);
1788                 return AST_TEST_FAIL;
1789         }
1790
1791         for (i = 0; i < ARRAY_LEN(test_args); i++) {
1792                 struct ast_var_t *var = ast_var_assign("TEST_STRING", test_args[i].test_string);
1793                 if (!var) {
1794                         ast_test_status_update(test, "Out of memory\n");
1795                         res = AST_TEST_FAIL;
1796                         break;
1797                 }
1798
1799                 AST_LIST_INSERT_HEAD(ast_channel_varshead(chan), var, entries);
1800
1801                 snprintf(expression, sizeof(expression), "${REPLACE(%s,%s,%s)}", var->name, test_args[i].find_chars, test_args[i].replace_char);
1802                 ast_str_substitute_variables(&str, 0, chan, expression);
1803
1804                 AST_LIST_REMOVE(ast_channel_varshead(chan), var, entries);
1805                 ast_var_delete(var);
1806
1807                 if (strcasecmp(ast_str_buffer(str), test_args[i].expected)) {
1808                         ast_test_status_update(test, "Evaluation of '%s' returned '%s' instead of the expected value '%s'\n",
1809                                 expression, ast_str_buffer(str), test_args[i].expected);
1810                         res = AST_TEST_FAIL;
1811                         break;
1812                 }
1813         }
1814
1815         ast_free(str);
1816         ast_channel_release(chan);
1817
1818         return res;
1819 }
1820
1821 AST_TEST_DEFINE(test_FILTER)
1822 {
1823         int i, res = AST_TEST_PASS;
1824         const char *test_strings[][2] = {
1825                 {"A-R",            "DAHDI"},
1826                 {"A\\-R",          "A"},
1827                 {"\\x41-R",        "DAHDI"},
1828                 {"0-9A-Ca-c",      "0042133333A12212"},
1829                 {"0-9a-cA-C_+\\-", "0042133333A12212"},
1830                 {NULL,             NULL},
1831         };
1832
1833         switch (cmd) {
1834         case TEST_INIT:
1835                 info->name = "func_FILTER_test";
1836                 info->category = "/funcs/func_strings/";
1837                 info->summary = "Test FILTER function";
1838                 info->description = "Verify FILTER behavior";
1839                 return AST_TEST_NOT_RUN;
1840         case TEST_EXECUTE:
1841                 break;
1842         }
1843
1844         for (i = 0; test_strings[i][0]; i++) {
1845                 char tmp[256], tmp2[256] = "";
1846                 snprintf(tmp, sizeof(tmp), "${FILTER(%s,0042133333&DAHDI/g1/2212)}", test_strings[i][0]);
1847                 pbx_substitute_variables_helper(NULL, tmp, tmp2, sizeof(tmp2) - 1);
1848                 if (strcmp(test_strings[i][1], tmp2)) {
1849                         ast_test_status_update(test, "Format string '%s' substituted to '%s'.  Expected '%s'.\n", test_strings[i][0], tmp2, test_strings[i][1]);
1850                         res = AST_TEST_FAIL;
1851                 }
1852         }
1853         return res;
1854 }
1855
1856 AST_TEST_DEFINE(test_STRREPLACE)
1857 {
1858         int i, res = AST_TEST_PASS;
1859         struct ast_channel *chan; /* dummy channel */
1860         struct ast_str *str; /* fancy string for holding comparing value */
1861
1862         const char *test_strings[][5] = {
1863                 {"Weasels have eaten my telephone system", "have eaten my", "are eating our", "", "Weasels are eating our telephone system"}, /*Test normal conditions */
1864                 {"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 */
1865                 {"foofoofoofoofoofoofoo", "foofoo", "bar", NULL, "barbarbarfoo"}, /* Found string within previous match */
1866                 {"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."},
1867                 {"One and one and one is three", "and", "plus", "1", "One plus one and one is three"}, /* Test <max-replacements> = 1*/
1868                 {"", "fhqwagads", "spelunker", NULL, ""}, /* Empty primary string */
1869                 {"Part of this string is missing.", "missing", NULL, NULL, "Part of this string is ."}, /* Empty replace string */
1870                 {"'Accidentally' left off a bunch of stuff.", NULL, NULL, NULL, ""}, /* Deliberate error test from too few args */
1871                 {"This test will also error.", "", "", "", ""}, /* Deliberate error test from blank find string */
1872                 {"This is an \"escape character\" test.", "\\\"escape character\\\"", "evil", NULL, "This is an evil test."}
1873         };
1874
1875         switch (cmd) {
1876         case TEST_INIT:
1877                 info->name = "func_STRREPLACE_test";
1878                 info->category = "/funcs/func_strings/";
1879                 info->summary = "Test STRREPLACE function";
1880                 info->description = "Verify STRREPLACE behavior";
1881                 return AST_TEST_NOT_RUN;
1882         case TEST_EXECUTE:
1883                 break;
1884         }
1885
1886         if (!(chan = ast_dummy_channel_alloc())) {
1887                 ast_test_status_update(test, "Unable to allocate dummy channel\n");
1888                 return AST_TEST_FAIL;
1889         }
1890
1891         if (!(str = ast_str_create(64))) {
1892                 ast_test_status_update(test, "Unable to allocate dynamic string buffer\n");
1893                 ast_channel_release(chan);
1894                 return AST_TEST_FAIL;
1895         }
1896
1897         for (i = 0; i < ARRAY_LEN(test_strings); i++) {
1898                 char tmp[512], tmp2[512] = "";
1899
1900                 struct ast_var_t *var = ast_var_assign("test_string", test_strings[i][0]);
1901                 if (!var) {
1902                         ast_test_status_update(test, "Unable to allocate variable\n");
1903                         ast_free(str);
1904                         ast_channel_release(chan);
1905                         return AST_TEST_FAIL;
1906                 }
1907                         
1908                 AST_LIST_INSERT_HEAD(ast_channel_varshead(chan), var, entries);
1909
1910                 if (test_strings[i][3]) {
1911                         snprintf(tmp, sizeof(tmp), "${STRREPLACE(%s,%s,%s,%s)}", "test_string", test_strings[i][1], test_strings[i][2], test_strings[i][3]);
1912                 } else if (test_strings[i][2]) {
1913                         snprintf(tmp, sizeof(tmp), "${STRREPLACE(%s,%s,%s)}", "test_string", test_strings[i][1], test_strings[i][2]);
1914                 } else if (test_strings[i][1]) {
1915                         snprintf(tmp, sizeof(tmp), "${STRREPLACE(%s,%s)}", "test_string", test_strings[i][1]);
1916                 } else {
1917                         snprintf(tmp, sizeof(tmp), "${STRREPLACE(%s)}", "test_string");
1918                 }
1919                 ast_str_substitute_variables(&str, 0, chan, tmp);
1920                 if (strcmp(test_strings[i][4], ast_str_buffer(str))) {
1921                         ast_test_status_update(test, "Format string '%s' substituted to '%s'.  Expected '%s'.\n", test_strings[i][0], tmp2, test_strings[i][4]);
1922                         res = AST_TEST_FAIL;
1923                 }
1924         }
1925
1926         ast_free(str);
1927         ast_channel_release(chan);
1928
1929         return res;
1930 }
1931 #endif
1932
1933 static int unload_module(void)
1934 {
1935         int res = 0;
1936
1937         AST_TEST_UNREGISTER(test_FIELDNUM);
1938         AST_TEST_UNREGISTER(test_REPLACE);
1939         AST_TEST_UNREGISTER(test_FILTER);
1940         AST_TEST_UNREGISTER(test_STRREPLACE);
1941         res |= ast_custom_function_unregister(&fieldqty_function);
1942         res |= ast_custom_function_unregister(&fieldnum_function);
1943         res |= ast_custom_function_unregister(&filter_function);
1944         res |= ast_custom_function_unregister(&replace_function);
1945         res |= ast_custom_function_unregister(&strreplace_function);
1946         res |= ast_custom_function_unregister(&listfilter_function);
1947         res |= ast_custom_function_unregister(&regex_function);
1948         res |= ast_custom_function_unregister(&array_function);
1949         res |= ast_custom_function_unregister(&quote_function);
1950         res |= ast_custom_function_unregister(&csv_quote_function);
1951         res |= ast_custom_function_unregister(&len_function);
1952         res |= ast_custom_function_unregister(&strftime_function);
1953         res |= ast_custom_function_unregister(&strptime_function);
1954         res |= ast_custom_function_unregister(&eval_function);
1955         res |= ast_custom_function_unregister(&keypadhash_function);
1956         res |= ast_custom_function_unregister(&hashkeys_function);
1957         res |= ast_custom_function_unregister(&hash_function);
1958         res |= ast_unregister_application(app_clearhash);
1959         res |= ast_custom_function_unregister(&toupper_function);
1960         res |= ast_custom_function_unregister(&tolower_function);
1961         res |= ast_custom_function_unregister(&shift_function);
1962         res |= ast_custom_function_unregister(&pop_function);
1963         res |= ast_custom_function_unregister(&push_function);
1964         res |= ast_custom_function_unregister(&unshift_function);
1965         res |= ast_custom_function_unregister(&passthru_function);
1966
1967         return res;
1968 }
1969
1970 static int load_module(void)
1971 {
1972         int res = 0;
1973
1974         AST_TEST_REGISTER(test_FIELDNUM);
1975         AST_TEST_REGISTER(test_REPLACE);
1976         AST_TEST_REGISTER(test_FILTER);
1977         AST_TEST_REGISTER(test_STRREPLACE);
1978         res |= ast_custom_function_register(&fieldqty_function);
1979         res |= ast_custom_function_register(&fieldnum_function);
1980         res |= ast_custom_function_register(&filter_function);
1981         res |= ast_custom_function_register(&replace_function);
1982         res |= ast_custom_function_register(&strreplace_function);
1983         res |= ast_custom_function_register(&listfilter_function);
1984         res |= ast_custom_function_register(&regex_function);
1985         res |= ast_custom_function_register(&array_function);
1986         res |= ast_custom_function_register(&quote_function);
1987         res |= ast_custom_function_register(&csv_quote_function);
1988         res |= ast_custom_function_register(&len_function);
1989         res |= ast_custom_function_register(&strftime_function);
1990         res |= ast_custom_function_register(&strptime_function);
1991         res |= ast_custom_function_register(&eval_function);
1992         res |= ast_custom_function_register(&keypadhash_function);
1993         res |= ast_custom_function_register(&hashkeys_function);
1994         res |= ast_custom_function_register(&hash_function);
1995         res |= ast_register_application_xml(app_clearhash, exec_clearhash);
1996         res |= ast_custom_function_register(&toupper_function);
1997         res |= ast_custom_function_register(&tolower_function);
1998         res |= ast_custom_function_register(&shift_function);
1999         res |= ast_custom_function_register(&pop_function);
2000         res |= ast_custom_function_register(&push_function);
2001         res |= ast_custom_function_register(&unshift_function);
2002         res |= ast_custom_function_register(&passthru_function);
2003
2004         return res;
2005 }
2006
2007 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "String handling dialplan functions");