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