ami_testhooks.c automatically registers hook
[asterisk/asterisk.git] / funcs / func_strings.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2005-2006, Digium, Inc.
5  * Portions Copyright (C) 2005, Tilghman Lesher.  All rights reserved.
6  * Portions Copyright (C) 2005, Anthony Minessale II
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief String manipulation dialplan functions
22  *
23  * \author Tilghman Lesher
24  * \author Anothony Minessale II 
25  * \ingroup functions
26  */
27
28 #include "asterisk.h"
29
30 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
31
32 #include <regex.h>
33 #include <ctype.h>
34
35 #include "asterisk/module.h"
36 #include "asterisk/channel.h"
37 #include "asterisk/pbx.h"
38 #include "asterisk/utils.h"
39 #include "asterisk/app.h"
40 #include "asterisk/localtime.h"
41
42 AST_THREADSTORAGE(result_buf);
43
44 /*** DOCUMENTATION
45         <function name="FIELDQTY" language="en_US">
46                 <synopsis>
47                         Count the fields with an arbitrary delimiter
48                 </synopsis>
49                 <syntax>
50                         <parameter name="varname" required="true" />
51                         <parameter name="delim" required="true" />
52                 </syntax>
53                 <description>
54                         <para>The delimiter may be specified as a special or extended ASCII character, by encoding it.  The characters
55                         <literal>\n</literal>, <literal>\r</literal>, and <literal>\t</literal> are all recognized as the newline,
56                         carriage return, and tab characters, respectively.  Also, octal and hexadecimal specifications are recognized
57                         by the patterns <literal>\0nnn</literal> and <literal>\xHH</literal>, respectively.  For example, if you wanted
58                         to encode a comma as the delimiter, you could use either <literal>\054</literal> or <literal>\x2C</literal>.</para>
59                         <para>Example: If ${example} contains <literal>ex-amp-le</literal>, then ${FIELDQTY(example,-)} returns 3.</para>
60                 </description>
61         </function>
62         <function name="LISTFILTER" language="en_US">
63                 <synopsis>Remove an item from a list, by name.</synopsis>
64                 <syntax>
65                         <parameter name="varname" required="true" />
66                         <parameter name="delim" required="true" default="," />
67                         <parameter name="value" required="true" />
68                 </syntax>
69                 <description>
70                         <para>Remove <replaceable>value</replaceable> from the list contained in the <replaceable>varname</replaceable>
71                         variable, where the list delimiter is specified by the <replaceable>delim</replaceable> parameter.  This is
72                         very useful for removing a single channel name from a list of channels, for example.</para>
73                 </description>
74         </function>
75         <function name="FILTER" language="en_US">
76                 <synopsis>
77                         Filter the string to include only the allowed characters
78                 </synopsis>
79                 <syntax>
80                         <parameter name="allowed-chars" required="true" />
81                         <parameter name="string" required="true" />
82                 </syntax>
83                 <description>
84                         <para>Permits all characters listed in <replaceable>allowed-chars</replaceable>, 
85                         filtering all others outs. In addition to literally listing the characters, 
86                         you may also use ranges of characters (delimited by a <literal>-</literal></para>
87                         <para>Hexadecimal characters started with a <literal>\x</literal>(i.e. \x20)</para>
88                         <para>Octal characters started with a <literal>\0</literal> (i.e. \040)</para>
89                         <para>Also <literal>\t</literal>,<literal>\n</literal> and <literal>\r</literal> are recognized.</para> 
90                         <note><para>If you want the <literal>-</literal> character it needs to be prefixed with a 
91                         <literal>\</literal></para></note>
92                 </description>
93         </function>
94         <function name="REGEX" language="en_US">
95                 <synopsis>
96                         Check string against a regular expression.
97                 </synopsis>
98                 <syntax argsep=" ">
99                         <parameter name="&quot;regular expression&quot;" required="true" />
100                         <parameter name="string" required="true" />
101                 </syntax>
102                 <description>
103                         <para>Return <literal>1</literal> on regular expression match or <literal>0</literal> otherwise</para>
104                         <para>Please note that the space following the double quotes separating the 
105                         regex from the data is optional and if present, is skipped. If a space is 
106                         desired at the beginning of the data, then put two spaces there; the second 
107                         will not be skipped.</para>
108                 </description>
109         </function>
110         <application name="ClearHash" language="en_US">
111                 <synopsis>
112                         Clear the keys from a specified hashname.
113                 </synopsis>
114                 <syntax>
115                         <parameter name="hashname" required="true" />
116                 </syntax>
117                 <description>
118                         <para>Clears all keys out of the specified <replaceable>hashname</replaceable>.</para>
119                 </description>
120         </application>
121         <function name="HASH" language="en_US">
122                 <synopsis>
123                         Implementation of a dialplan associative array
124                 </synopsis>
125                 <syntax>
126                         <parameter name="hashname" required="true" />
127                         <parameter name="hashkey" />
128                 </syntax>
129                 <description>
130                         <para>In two arguments mode, gets and sets values to corresponding keys within
131                         a named associative array. The single-argument mode will only work when assigned
132                         to from a function defined by func_odbc</para>
133                 </description>
134         </function>
135         <function name="HASHKEYS" language="en_US">
136                 <synopsis>
137                         Retrieve the keys of the HASH() function.
138                 </synopsis>
139                 <syntax>
140                         <parameter name="hashname" required="true" />
141                 </syntax>
142                 <description>
143                         <para>Returns a comma-delimited list of the current keys of the associative array 
144                         defined by the HASH() function. Note that if you iterate over the keys of 
145                         the result, adding keys during iteration will cause the result of the HASHKEYS()
146                         function to change.</para>
147                 </description>
148         </function>
149         <function name="KEYPADHASH" language="en_US">
150                 <synopsis>
151                         Hash the letters in string into equivalent keypad numbers.
152                 </synopsis>
153                 <syntax>
154                         <parameter name="string" required="true" />
155                 </syntax>
156                 <description>
157                         <para>Example: ${KEYPADHASH(Les)} returns "537"</para>
158                 </description>
159         </function>
160         <function name="ARRAY" language="en_US">
161                 <synopsis>
162                         Allows setting multiple variables at once.
163                 </synopsis>
164                 <syntax>
165                         <parameter name="var1" required="true" />
166                         <parameter name="var2" required="false" multiple="true" />
167                         <parameter name="varN" required="false" />
168                 </syntax>
169                 <description>
170                         <para>The comma-delimited list passed as a value to which the function is set will 
171                         be interpreted as a set of values to which the comma-delimited list of 
172                         variable names in the argument should be set.</para>
173                         <para>Example: Set(ARRAY(var1,var2)=1,2) will set var1 to 1 and var2 to 2</para>
174                 </description>
175         </function>
176         <function name="STRPTIME" language="en_US">
177                 <synopsis>
178                         Returns the epoch of the arbitrary date/time string structured as described by the format.
179                 </synopsis>
180                 <syntax>
181                         <parameter name="datetime" required="true" />
182                         <parameter name="timezone" required="true" />
183                         <parameter name="format" required="true" />
184                 </syntax>
185                 <description>
186                         <para>This is useful for converting a date into <literal>EPOCH</literal> time, 
187                         possibly to pass to an application like SayUnixTime or to calculate the difference
188                         between the two date strings</para>
189                         <para>Example: ${STRPTIME(2006-03-01 07:30:35,America/Chicago,%Y-%m-%d %H:%M:%S)} returns 1141219835</para>
190                 </description>
191         </function>
192         <function name="STRFTIME" language="en_US">
193                 <synopsis>
194                         Returns the current date/time in the specified format.
195                 </synopsis>
196                 <syntax>
197                         <parameter name="epoch" />
198                         <parameter name="timezone" />
199                         <parameter name="format" />
200                 </syntax>
201                 <description>
202                         <para>STRFTIME supports all of the same formats as the underlying C function
203                         <emphasis>strftime(3)</emphasis>.
204                         It also supports the following format: <literal>%[n]q</literal> - fractions of a second,
205                         with leading zeros.</para>
206                         <para>Example: <literal>%3q</literal> will give milliseconds and <literal>%1q</literal>
207                         will give tenths of a second. The default is set at milliseconds (n=3).
208                         The common case is to use it in combination with %S, as in <literal>%S.%3q</literal>.</para>
209                 </description>
210                 <see-also>
211                         <ref type="manpage">strftime(3)</ref>
212                 </see-also>
213         </function>
214         <function name="EVAL" language="en_US">
215                 <synopsis>
216                         Evaluate stored variables
217                 </synopsis>
218                 <syntax>
219                         <parameter name="variable" required="true" />
220                 </syntax>
221                 <description>
222                         <para>Using EVAL basically causes a string to be evaluated twice.
223                         When a variable or expression is in the dialplan, it will be
224                         evaluated at runtime. However, if the results of the evaluation
225                         is in fact another variable or expression, using EVAL will have it
226                         evaluated a second time.</para>
227                         <para>Example: If the <variable>MYVAR</variable> contains
228                         <variable>OTHERVAR</variable>, then the result of ${EVAL(
229                         <variable>MYVAR</variable>)} in the dialplan will be the
230                         contents of <variable>OTHERVAR</variable>. Normally just
231                         putting <variable>MYVAR</variable> in the dialplan the result
232                         would be <variable>OTHERVAR</variable>.</para>
233                 </description>
234         </function>
235         <function name="TOUPPER" language="en_US">
236                 <synopsis>
237                         Convert string to all uppercase letters.
238                 </synopsis>
239                 <syntax>
240                         <parameter name="string" required="true" />
241                 </syntax>
242                 <description>
243                         <para>Example: ${TOUPPER(Example)} returns "EXAMPLE"</para>
244                 </description>
245         </function>
246         <function name="TOLOWER" language="en_US">
247                 <synopsis>
248                         Convert string to all lowercase letters.
249                 </synopsis>
250                 <syntax>
251                         <parameter name="string" required="true" />
252                 </syntax>
253                 <description>
254                         <para>Example: ${TOLOWER(Example)} returns "example"</para>
255                 </description>
256         </function>
257         <function name="LEN" language="en_US">
258                 <synopsis>
259                         Return the length of the string given.
260                 </synopsis>
261                 <syntax>
262                         <parameter name="string" required="true" />
263                 </syntax>
264                 <description>
265                         <para>Example: ${LEN(example)} returns 7</para>
266                 </description>
267         </function>
268         <function name="QUOTE" language="en_US">
269                 <synopsis>
270                         Quotes a given string, escaping embedded quotes as necessary
271                 </synopsis>
272                 <syntax>
273                         <parameter name="string" required="true" />
274                 </syntax>
275                 <description>
276                         <para>Example: ${QUOTE(ab"c"de)} will return "abcde"</para>
277                 </description>
278         </function>
279         <function name="CSV_QUOTE" language="en_US">
280                 <synopsis>
281                         Quotes a given string for use in a CSV file, escaping embedded quotes as necessary
282                 </synopsis>
283                 <syntax>
284                         <parameter name="string" required="true" />
285                 </syntax>
286                 <description>
287                         <para>Example: ${CSV_QUOTE("a,b" 123)} will return """a,b"" 123"</para>
288                 </description>
289         </function>
290         <function name="SHIFT" language="en_US">
291                 <synopsis>
292                         Removes and returns the first item off of a variable containing delimited text
293                 </synopsis>
294                 <syntax>
295                         <parameter name="varname" required="true" />
296                         <parameter name="delimiter" required="false" default="," />
297                 </syntax>
298                 <description>
299                         <para>Example:</para>
300                         <para>exten => s,1,Set(array=one,two,three)</para>
301                         <para>exten => s,n,While($["${SET(var=${SHIFT(array)})}" != ""])</para>
302                         <para>exten => s,n,NoOp(var is ${var})</para>
303                         <para>exten => s,n,EndWhile</para>
304                         <para>This would iterate over each value in array, left to right, and
305                                 would result in NoOp(var is one), NoOp(var is two), and
306                                 NoOp(var is three) being executed.
307                         </para>
308                 </description>
309         </function>     
310         <function name="POP" language="en_US">
311                 <synopsis>
312                         Removes and returns the last item off of a variable containing delimited text
313                 </synopsis>
314                 <syntax>
315                         <parameter name="varname" required="true" />
316                         <parameter name="delimiter" required="false" default="," />
317                 </syntax>
318                 <description>
319                         <para>Example:</para>
320                         <para>exten => s,1,Set(array=one,two,three)</para>
321                         <para>exten => s,n,While($["${SET(var=${POP(array)})}" != ""])</para>
322                         <para>exten => s,n,NoOp(var is ${var})</para>
323                         <para>exten => s,n,EndWhile</para>
324                         <para>This would iterate over each value in array, right to left, and
325                                 would result in NoOp(var is three), NoOp(var is two), and
326                                 NoOp(var is one) being executed.
327                         </para>
328                 </description>
329         </function>     
330         <function name="PUSH" language="en_US">
331                 <synopsis>
332                         Appends one or more values to the end of a variable containing delimited text
333                 </synopsis>
334                 <syntax>
335                         <parameter name="varname" required="true" />
336                         <parameter name="delimiter" required="false" default="," />
337                 </syntax>
338                 <description>
339                         <para>Example: Set(PUSH(array)=one,two,three) would append one,
340                                 two, and three to the end of the values stored in the variable
341                                 "array".
342                         </para>
343                 </description>
344         </function>
345         <function name="UNSHIFT" language="en_US">
346                 <synopsis>
347                         Inserts one or more values to the beginning of a variable containing delimited text
348                 </synopsis>
349                 <syntax>
350                         <parameter name="varname" required="true" />
351                         <parameter name="delimiter" required="false" default="," />
352                 </syntax>
353                 <description>
354                         <para>Example: Set(UNSHIFT(array)=one,two,three) would insert one,
355                                 two, and three before the values stored in the variable
356                                 "array".
357                         </para>
358                 </description>
359         </function>
360  ***/
361
362 static int function_fieldqty_helper(struct ast_channel *chan, const char *cmd,
363                              char *parse, char *buf, struct ast_str **sbuf, ssize_t len)
364 {
365         char *varsubst;
366         struct ast_str *str = ast_str_create(16);
367         int fieldcount = 0;
368         AST_DECLARE_APP_ARGS(args,
369                              AST_APP_ARG(varname);
370                              AST_APP_ARG(delim);
371                 );
372         char delim[2] = "";
373         size_t delim_used;
374
375         if (!str) {
376                 return -1;
377         }
378
379         AST_STANDARD_APP_ARGS(args, parse);
380         if (args.delim) {
381                 ast_get_encoded_char(args.delim, delim, &delim_used);
382
383                 varsubst = alloca(strlen(args.varname) + 4);
384
385                 sprintf(varsubst, "${%s}", args.varname);
386                 ast_str_substitute_variables(&str, 0, chan, varsubst);
387                 if (ast_str_strlen(str) == 0) {
388                         fieldcount = 0;
389                 } else {
390                         char *varval = ast_str_buffer(str);
391                         while (strsep(&varval, delim)) {
392                                 fieldcount++;
393                         }
394                 }
395         } else {
396                 fieldcount = 1;
397         }
398         if (sbuf) {
399                 ast_str_set(sbuf, len, "%d", fieldcount);
400         } else {
401                 snprintf(buf, len, "%d", fieldcount);
402         }
403
404         ast_free(str);
405         return 0;
406 }
407
408 static int function_fieldqty(struct ast_channel *chan, const char *cmd,
409                              char *parse, char *buf, size_t len)
410 {
411         return function_fieldqty_helper(chan, cmd, parse, buf, NULL, len);
412 }
413
414 static int function_fieldqty_str(struct ast_channel *chan, const char *cmd,
415                                  char *parse, struct ast_str **buf, ssize_t len)
416 {
417         return function_fieldqty_helper(chan, cmd, parse, NULL, buf, len);
418 }
419
420 static struct ast_custom_function fieldqty_function = {
421         .name = "FIELDQTY",
422         .read = function_fieldqty,
423         .read2 = function_fieldqty_str,
424 };
425
426 static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, struct ast_str **bufstr, ssize_t len)
427 {
428         AST_DECLARE_APP_ARGS(args,
429                 AST_APP_ARG(listname);
430                 AST_APP_ARG(delimiter);
431                 AST_APP_ARG(fieldvalue);
432         );
433         const char *orig_list, *ptr;
434         const char *begin, *cur, *next;
435         int dlen, flen, first = 1;
436         struct ast_str *result, **result_ptr = &result;
437         char *delim;
438
439         AST_STANDARD_APP_ARGS(args, parse);
440
441         if (buf) {
442                 result = ast_str_thread_get(&result_buf, 16);
443         } else {
444                 /* Place the result directly into the output buffer */
445                 result_ptr = bufstr;
446         }
447
448         if (args.argc < 3) {
449                 ast_log(LOG_ERROR, "Usage: LISTFILTER(<listname>,<delimiter>,<fieldvalue>)\n");
450                 return -1;
451         }
452
453         /* If we don't lock the channel, the variable could disappear out from underneath us. */
454         if (chan) {
455                 ast_channel_lock(chan);
456         }
457         if (!(orig_list = pbx_builtin_getvar_helper(chan, args.listname))) {
458                 ast_log(LOG_ERROR, "List variable '%s' not found\n", args.listname);
459                 if (chan) {
460                         ast_channel_unlock(chan);
461                 }
462                 return -1;
463         }
464
465         /* If the string isn't there, just copy out the string and be done with it. */
466         if (!(ptr = strstr(orig_list, args.fieldvalue))) {
467                 if (buf) {
468                         ast_copy_string(buf, orig_list, len);
469                 } else {
470                         ast_str_set(result_ptr, len, "%s", orig_list);
471                 }
472                 if (chan) {
473                         ast_channel_unlock(chan);
474                 }
475                 return 0;
476         }
477
478         dlen = strlen(args.delimiter);
479         delim = alloca(dlen + 1);
480         ast_get_encoded_str(args.delimiter, delim, dlen + 1);
481
482         if ((dlen = strlen(delim)) == 0) {
483                 delim = ",";
484                 dlen = 1;
485         }
486
487         flen = strlen(args.fieldvalue);
488
489         ast_str_reset(result);
490         /* Enough space for any result */
491         if (len > -1) {
492                 ast_str_make_space(result_ptr, len ? len : strlen(orig_list) + 1);
493         }
494
495         begin = orig_list;
496         next = strstr(begin, delim);
497
498         do {
499                 /* Find next boundary */
500                 if (next) {
501                         cur = next;
502                         next = strstr(cur + dlen, delim);
503                 } else {
504                         cur = strchr(begin + dlen, '\0');
505                 }
506
507                 if (flen == cur - begin && !strncmp(begin, args.fieldvalue, flen)) {
508                         /* Skip field */
509                         begin += flen + dlen;
510                 } else {
511                         /* Copy field to output */
512                         if (!first) {
513                                 ast_str_append(result_ptr, len, "%s", delim);
514                         }
515
516                         ast_str_append_substr(result_ptr, len, begin, cur - begin + 1);
517                         first = 0;
518                         begin = cur + dlen;
519                 }
520         } while (*cur != '\0');
521         if (chan) {
522                 ast_channel_unlock(chan);
523         }
524
525         if (buf) {
526                 ast_copy_string(buf, ast_str_buffer(result), len);
527         }
528
529         return 0;
530 }
531
532 static int listfilter_read(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
533 {
534         return listfilter(chan, cmd, parse, buf, NULL, len);
535 }
536
537 static int listfilter_read2(struct ast_channel *chan, const char *cmd, char *parse, struct ast_str **buf, ssize_t len)
538 {
539         return listfilter(chan, cmd, parse, NULL, buf, len);
540 }
541
542 static struct ast_custom_function listfilter_function = {
543         .name = "LISTFILTER",
544         .read = listfilter_read,
545         .read2 = listfilter_read2,
546 };
547
548 static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf,
549                   size_t len)
550 {
551         AST_DECLARE_APP_ARGS(args,
552                              AST_APP_ARG(allowed);
553                              AST_APP_ARG(string);
554         );
555         char *outbuf = buf, ac;
556         char allowed[256] = "";
557         size_t allowedlen = 0;
558
559         AST_STANDARD_APP_ARGS(args, parse);
560
561         if (!args.string) {
562                 ast_log(LOG_ERROR, "Usage: FILTER(<allowed-chars>,<string>)\n");
563                 return -1;
564         }
565
566         /* Expand ranges */
567         for (; *(args.allowed) && allowedlen < sizeof(allowed); ) {
568                 char c1 = 0, c2 = 0;
569                 size_t consumed = 0;
570
571                 if (ast_get_encoded_char(args.allowed, &c1, &consumed))
572                         return -1;
573                 args.allowed += consumed;
574
575                 if (*(args.allowed) == '-') {
576                         if (ast_get_encoded_char(args.allowed + 1, &c2, &consumed))
577                                 c2 = -1;
578                         args.allowed += consumed + 1;
579
580                         /*!\note
581                          * Looks a little strange, until you realize that we can overflow
582                          * the size of a char.
583                          */
584                         for (ac = c1; ac != c2 && allowedlen < sizeof(allowed) - 1; ac++)
585                                 allowed[allowedlen++] = ac;
586                         allowed[allowedlen++] = ac;
587
588                         ast_debug(4, "c1=%d, c2=%d\n", c1, c2);
589
590                         /* Decrement before the loop increment */
591                         (args.allowed)--;
592                 } else
593                         allowed[allowedlen++] = c1;
594         }
595
596         ast_debug(1, "Allowed: %s\n", allowed);
597
598         for (; *(args.string) && (buf + len - 1 > outbuf); (args.string)++) {
599                 if (strchr(allowed, *(args.string)))
600                         *outbuf++ = *(args.string);
601         }
602         *outbuf = '\0';
603
604         return 0;
605 }
606
607 static struct ast_custom_function filter_function = {
608         .name = "FILTER",
609         .read = filter,
610 };
611
612 static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf,
613                  size_t len)
614 {
615         AST_DECLARE_APP_ARGS(args,
616                              AST_APP_ARG(null);
617                              AST_APP_ARG(reg);
618                              AST_APP_ARG(str);
619         );
620         int errcode;
621         regex_t regexbuf;
622
623         buf[0] = '\0';
624
625         AST_NONSTANDARD_APP_ARGS(args, parse, '"');
626
627         if (args.argc != 3) {
628                 ast_log(LOG_ERROR, "Unexpected arguments: should have been in the form '\"<regex>\" <string>'\n");
629                 return -1;
630         }
631         if ((*args.str == ' ') || (*args.str == '\t'))
632                 args.str++;
633
634         ast_debug(1, "FUNCTION REGEX (%s)(%s)\n", args.reg, args.str);
635
636         if ((errcode = regcomp(&regexbuf, args.reg, REG_EXTENDED | REG_NOSUB))) {
637                 regerror(errcode, &regexbuf, buf, len);
638                 ast_log(LOG_WARNING, "Malformed input %s(%s): %s\n", cmd, parse, buf);
639                 return -1;
640         }
641         
642         strcpy(buf, regexec(&regexbuf, args.str, 0, NULL, 0) ? "0" : "1");
643
644         regfree(&regexbuf);
645
646         return 0;
647 }
648
649 static struct ast_custom_function regex_function = {
650         .name = "REGEX",
651         .read = regex,
652 };
653
654 #define HASH_PREFIX     "~HASH~%s~"
655 #define HASH_FORMAT     HASH_PREFIX "%s~"
656
657 static char *app_clearhash = "ClearHash";
658
659 /* This function probably should migrate to main/pbx.c, as pbx_builtin_clearvar_prefix() */
660 static void clearvar_prefix(struct ast_channel *chan, const char *prefix)
661 {
662         struct ast_var_t *var;
663         int len = strlen(prefix);
664         AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->varshead, var, entries) {
665                 if (strncasecmp(prefix, ast_var_name(var), len) == 0) {
666                         AST_LIST_REMOVE_CURRENT(entries);
667                         ast_free(var);
668                 }
669         }
670         AST_LIST_TRAVERSE_SAFE_END
671 }
672
673 static int exec_clearhash(struct ast_channel *chan, const char *data)
674 {
675         char prefix[80];
676         snprintf(prefix, sizeof(prefix), HASH_PREFIX, data ? (char *)data : "null");
677         clearvar_prefix(chan, prefix);
678         return 0;
679 }
680
681 static int array(struct ast_channel *chan, const char *cmd, char *var,
682                  const char *value)
683 {
684         AST_DECLARE_APP_ARGS(arg1,
685                              AST_APP_ARG(var)[100];
686         );
687         AST_DECLARE_APP_ARGS(arg2,
688                              AST_APP_ARG(val)[100];
689         );
690         char *origvar = "", *value2, varname[256];
691         int i, ishash = 0;
692
693         value2 = ast_strdupa(value);
694         if (!var || !value2)
695                 return -1;
696
697         if (!strcmp(cmd, "HASH")) {
698                 const char *var2 = pbx_builtin_getvar_helper(chan, "~ODBCFIELDS~");
699                 origvar = var;
700                 if (var2)
701                         var = ast_strdupa(var2);
702                 else {
703                         if (chan)
704                                 ast_autoservice_stop(chan);
705                         return -1;
706                 }
707                 ishash = 1;
708         }
709
710         /* The functions this will generally be used with are SORT and ODBC_*, which
711          * both return comma-delimited lists.  However, if somebody uses literal lists,
712          * their commas will be translated to vertical bars by the load, and I don't
713          * want them to be surprised by the result.  Hence, we prefer commas as the
714          * delimiter, but we'll fall back to vertical bars if commas aren't found.
715          */
716         ast_debug(1, "array (%s=%s)\n", var, value2);
717         AST_STANDARD_APP_ARGS(arg1, var);
718
719         AST_STANDARD_APP_ARGS(arg2, value2);
720
721         for (i = 0; i < arg1.argc; i++) {
722                 ast_debug(1, "array set value (%s=%s)\n", arg1.var[i],
723                                 arg2.val[i]);
724                 if (i < arg2.argc) {
725                         if (ishash) {
726                                 snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
727                                 pbx_builtin_setvar_helper(chan, varname, arg2.val[i]);
728                         } else {
729                                 pbx_builtin_setvar_helper(chan, arg1.var[i], arg2.val[i]);
730                         }
731                 } else {
732                         /* We could unset the variable, by passing a NULL, but due to
733                          * pushvar semantics, that could create some undesired behavior. */
734                         if (ishash) {
735                                 snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
736                                 pbx_builtin_setvar_helper(chan, varname, "");
737                         } else {
738                                 pbx_builtin_setvar_helper(chan, arg1.var[i], "");
739                         }
740                 }
741         }
742
743         return 0;
744 }
745
746 static int hashkeys_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
747 {
748         struct ast_var_t *newvar;
749         struct ast_str *prefix = ast_str_alloca(80);
750
751         ast_str_set(&prefix, -1, HASH_PREFIX, data);
752         memset(buf, 0, len);
753
754         AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) {
755                 if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
756                         /* Copy everything after the prefix */
757                         strncat(buf, ast_var_name(newvar) + ast_str_strlen(prefix), len - strlen(buf) - 1);
758                         /* Trim the trailing ~ */
759                         buf[strlen(buf) - 1] = ',';
760                 }
761         }
762         /* Trim the trailing comma */
763         buf[strlen(buf) - 1] = '\0';
764         return 0;
765 }
766
767 static int hashkeys_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
768 {
769         struct ast_var_t *newvar;
770         struct ast_str *prefix = ast_str_alloca(80);
771         char *tmp;
772
773         ast_str_set(&prefix, -1, HASH_PREFIX, data);
774
775         AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) {
776                 if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
777                         /* Copy everything after the prefix */
778                         ast_str_append(buf, len, "%s", ast_var_name(newvar) + ast_str_strlen(prefix));
779                         /* Trim the trailing ~ */
780                         tmp = ast_str_buffer(*buf);
781                         tmp[ast_str_strlen(*buf) - 1] = ',';
782                 }
783         }
784         /* Trim the trailing comma */
785         tmp = ast_str_buffer(*buf);
786         tmp[ast_str_strlen(*buf) - 1] = '\0';
787         return 0;
788 }
789
790 static int hash_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
791 {
792         char varname[256];
793         AST_DECLARE_APP_ARGS(arg,
794                 AST_APP_ARG(hashname);
795                 AST_APP_ARG(hashkey);
796         );
797
798         if (!strchr(var, ',')) {
799                 /* Single argument version */
800                 return array(chan, "HASH", var, value);
801         }
802
803         AST_STANDARD_APP_ARGS(arg, var);
804         snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
805         pbx_builtin_setvar_helper(chan, varname, value);
806
807         return 0;
808 }
809
810 static int hash_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
811 {
812         char varname[256];
813         const char *varvalue;
814         AST_DECLARE_APP_ARGS(arg,
815                 AST_APP_ARG(hashname);
816                 AST_APP_ARG(hashkey);
817         );
818
819         AST_STANDARD_APP_ARGS(arg, data);
820         if (arg.argc == 2) {
821                 snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
822                 varvalue = pbx_builtin_getvar_helper(chan, varname);
823                 if (varvalue)
824                         ast_copy_string(buf, varvalue, len);
825                 else
826                         *buf = '\0';
827         } else if (arg.argc == 1) {
828                 char colnames[4096];
829                 int i;
830                 AST_DECLARE_APP_ARGS(arg2,
831                         AST_APP_ARG(col)[100];
832                 );
833
834                 /* Get column names, in no particular order */
835                 hashkeys_read(chan, "HASHKEYS", arg.hashname, colnames, sizeof(colnames));
836                 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames);
837
838                 AST_STANDARD_APP_ARGS(arg2, colnames);
839                 *buf = '\0';
840
841                 /* Now get the corresponding column values, in exactly the same order */
842                 for (i = 0; i < arg2.argc; i++) {
843                         snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg2.col[i]);
844                         varvalue = pbx_builtin_getvar_helper(chan, varname);
845                         strncat(buf, varvalue, len - strlen(buf) - 1);
846                         strncat(buf, ",", len - strlen(buf) - 1);
847                 }
848
849                 /* Strip trailing comma */
850                 buf[strlen(buf) - 1] = '\0';
851         }
852
853         return 0;
854 }
855
856 static struct ast_custom_function hash_function = {
857         .name = "HASH",
858         .write = hash_write,
859         .read = hash_read,
860 };
861
862 static struct ast_custom_function hashkeys_function = {
863         .name = "HASHKEYS",
864         .read = hashkeys_read,
865         .read2 = hashkeys_read2,
866 };
867
868 static struct ast_custom_function array_function = {
869         .name = "ARRAY",
870         .write = array,
871 };
872
873 static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
874 {
875         char *bufptr = buf, *dataptr = data;
876
877         if (len < 3){ /* at least two for quotes and one for binary zero */
878                 ast_log(LOG_ERROR, "Not enough buffer");
879                 return -1;
880         }
881
882         if (ast_strlen_zero(data)) {
883                 ast_log(LOG_WARNING, "No argument specified!\n");
884                 ast_copy_string(buf, "\"\"", len);
885                 return 0;
886         }
887
888         *bufptr++ = '"';
889         for (; bufptr < buf + len - 3; dataptr++) {
890                 if (*dataptr == '\\') {
891                         *bufptr++ = '\\';
892                         *bufptr++ = '\\';
893                 } else if (*dataptr == '"') {
894                         *bufptr++ = '\\';
895                         *bufptr++ = '"';
896                 } else if (*dataptr == '\0') {
897                         break;
898                 } else {
899                         *bufptr++ = *dataptr;
900                 }
901         }
902         *bufptr++ = '"';
903         *bufptr = '\0';
904         return 0;
905 }
906
907 static struct ast_custom_function quote_function = {
908         .name = "QUOTE",
909         .read = quote,
910 };
911
912 static int csv_quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
913 {
914         char *bufptr = buf, *dataptr = data;
915
916         if (len < 3){ /* at least two for quotes and one for binary zero */
917                 ast_log(LOG_ERROR, "Not enough buffer");
918                 return -1;
919         }
920
921         if (ast_strlen_zero(data)) {
922                 ast_log(LOG_WARNING, "No argument specified!\n");
923                 ast_copy_string(buf,"\"\"",len);
924                 return 0;
925         }
926
927         *bufptr++ = '"';
928         for (; bufptr < buf + len - 3; dataptr++){
929                 if (*dataptr == '"') {
930                         *bufptr++ = '"';
931                         *bufptr++ = '"';
932                 } else if (*dataptr == '\0') {
933                         break;
934                 } else {
935                         *bufptr++ = *dataptr;
936                 }
937         }
938         *bufptr++ = '"';
939         *bufptr='\0';
940         return 0;
941 }
942
943 static struct ast_custom_function csv_quote_function = {
944         .name = "CSV_QUOTE",
945         .read = csv_quote,
946 };
947
948 static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
949 {
950         int length = 0;
951
952         if (data)
953                 length = strlen(data);
954
955         snprintf(buf, buflen, "%d", length);
956
957         return 0;
958 }
959
960 static struct ast_custom_function len_function = {
961         .name = "LEN",
962         .read = len,
963         .read_max = 12,
964 };
965
966 static int acf_strftime(struct ast_channel *chan, const char *cmd, char *parse,
967                         char *buf, size_t buflen)
968 {
969         AST_DECLARE_APP_ARGS(args,
970                              AST_APP_ARG(epoch);
971                              AST_APP_ARG(timezone);
972                              AST_APP_ARG(format);
973         );
974         struct timeval when;
975         struct ast_tm tm;
976
977         buf[0] = '\0';
978
979         AST_STANDARD_APP_ARGS(args, parse);
980
981         ast_get_timeval(args.epoch, &when, ast_tvnow(), NULL);
982         ast_localtime(&when, &tm, args.timezone);
983
984         if (!args.format)
985                 args.format = "%c";
986
987         if (ast_strftime(buf, buflen, args.format, &tm) <= 0)
988                 ast_log(LOG_WARNING, "C function strftime() output nothing?!!\n");
989
990         buf[buflen - 1] = '\0';
991
992         return 0;
993 }
994
995 static struct ast_custom_function strftime_function = {
996         .name = "STRFTIME",
997         .read = acf_strftime,
998 };
999
1000 static int acf_strptime(struct ast_channel *chan, const char *cmd, char *data,
1001                         char *buf, size_t buflen)
1002 {
1003         AST_DECLARE_APP_ARGS(args,
1004                              AST_APP_ARG(timestring);
1005                              AST_APP_ARG(timezone);
1006                              AST_APP_ARG(format);
1007         );
1008         struct ast_tm tm;
1009
1010         buf[0] = '\0';
1011
1012         if (!data) {
1013                 ast_log(LOG_ERROR,
1014                                 "Asterisk function STRPTIME() requires an argument.\n");
1015                 return -1;
1016         }
1017
1018         AST_STANDARD_APP_ARGS(args, data);
1019
1020         if (ast_strlen_zero(args.format)) {
1021                 ast_log(LOG_ERROR,
1022                                 "No format supplied to STRPTIME(<timestring>,<timezone>,<format>)");
1023                 return -1;
1024         }
1025
1026         if (!ast_strptime(args.timestring, args.format, &tm)) {
1027                 ast_log(LOG_WARNING, "STRPTIME() found no time specified within the string\n");
1028         } else {
1029                 struct timeval when;
1030                 when = ast_mktime(&tm, args.timezone);
1031                 snprintf(buf, buflen, "%d", (int) when.tv_sec);
1032         }
1033
1034         return 0;
1035 }
1036
1037 static struct ast_custom_function strptime_function = {
1038         .name = "STRPTIME",
1039         .read = acf_strptime,
1040 };
1041
1042 static int function_eval(struct ast_channel *chan, const char *cmd, char *data,
1043                          char *buf, size_t buflen)
1044 {
1045         if (ast_strlen_zero(data)) {
1046                 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
1047                 return -1;
1048         }
1049
1050         pbx_substitute_variables_helper(chan, data, buf, buflen - 1);
1051
1052         return 0;
1053 }
1054
1055 static int function_eval2(struct ast_channel *chan, const char *cmd, char *data,
1056                          struct ast_str **buf, ssize_t buflen)
1057 {
1058         if (ast_strlen_zero(data)) {
1059                 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
1060                 return -1;
1061         }
1062
1063         ast_str_substitute_variables(buf, buflen, chan, data);
1064
1065         return 0;
1066 }
1067
1068 static struct ast_custom_function eval_function = {
1069         .name = "EVAL",
1070         .read = function_eval,
1071         .read2 = function_eval2,
1072 };
1073
1074 static int keypadhash(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1075 {
1076         char *bufptr, *dataptr;
1077
1078         for (bufptr = buf, dataptr = data; bufptr < buf + buflen - 1; dataptr++) {
1079                 if (*dataptr == '\0') {
1080                         *bufptr++ = '\0';
1081                         break;
1082                 } else if (*dataptr == '1') {
1083                         *bufptr++ = '1';
1084                 } else if (strchr("AaBbCc2", *dataptr)) {
1085                         *bufptr++ = '2';
1086                 } else if (strchr("DdEeFf3", *dataptr)) {
1087                         *bufptr++ = '3';
1088                 } else if (strchr("GgHhIi4", *dataptr)) {
1089                         *bufptr++ = '4';
1090                 } else if (strchr("JjKkLl5", *dataptr)) {
1091                         *bufptr++ = '5';
1092                 } else if (strchr("MmNnOo6", *dataptr)) {
1093                         *bufptr++ = '6';
1094                 } else if (strchr("PpQqRrSs7", *dataptr)) {
1095                         *bufptr++ = '7';
1096                 } else if (strchr("TtUuVv8", *dataptr)) {
1097                         *bufptr++ = '8';
1098                 } else if (strchr("WwXxYyZz9", *dataptr)) {
1099                         *bufptr++ = '9';
1100                 } else if (*dataptr == '0') {
1101                         *bufptr++ = '0';
1102                 }
1103         }
1104         buf[buflen - 1] = '\0';
1105
1106         return 0;
1107 }
1108
1109 static struct ast_custom_function keypadhash_function = {
1110         .name = "KEYPADHASH",
1111         .read = keypadhash,
1112 };
1113
1114 static int string_toupper(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1115 {
1116         char *bufptr = buf, *dataptr = data;
1117
1118         while ((bufptr < buf + buflen - 1) && (*bufptr++ = toupper(*dataptr++)));
1119
1120         return 0;
1121 }
1122
1123 static int string_toupper2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
1124 {
1125         char *bufptr, *dataptr = data;
1126
1127         if (buflen > -1) {
1128                 ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
1129         }
1130         bufptr = ast_str_buffer(*buf);
1131         while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = toupper(*dataptr++)));
1132         ast_str_update(*buf);
1133
1134         return 0;
1135 }
1136
1137 static struct ast_custom_function toupper_function = {
1138         .name = "TOUPPER",
1139         .read = string_toupper,
1140         .read2 = string_toupper2,
1141 };
1142
1143 static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1144 {
1145         char *bufptr = buf, *dataptr = data;
1146
1147         while ((bufptr < buf + buflen - 1) && (*bufptr++ = tolower(*dataptr++)));
1148
1149         return 0;
1150 }
1151
1152 static int string_tolower2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
1153 {
1154         char *bufptr, *dataptr = data;
1155
1156         if (buflen > -1) {
1157                 ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
1158         }
1159         bufptr = ast_str_buffer(*buf);
1160         while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = tolower(*dataptr++)));
1161         ast_str_update(*buf);
1162
1163         return 0;
1164 }
1165
1166 static struct ast_custom_function tolower_function = {
1167         .name = "TOLOWER",
1168         .read = string_tolower,
1169         .read2 = string_tolower2,
1170 };
1171
1172 static int array_remove(struct ast_channel *chan, const char *cmd, char *var, char *buf, size_t len, int beginning)
1173 {
1174         const char *tmp;
1175         char *after, *before;
1176         char *(*search_func)(const char *s, int c) = beginning ? strchr : strrchr;
1177         AST_DECLARE_APP_ARGS(args,
1178                 AST_APP_ARG(var);
1179                 AST_APP_ARG(delimiter);
1180         );
1181
1182         if (!chan) {
1183                 ast_log(LOG_WARNING, "%s requires a channel\n", cmd);
1184                 return -1;
1185         }
1186
1187         AST_STANDARD_APP_ARGS(args, var);
1188
1189         if (ast_strlen_zero(args.var)) {
1190                 ast_log(LOG_WARNING, "%s requires a channel variable name\n", cmd);
1191                 return -1;
1192         }
1193
1194         if (args.delimiter && strlen(args.delimiter) != 1) {
1195                 ast_log(LOG_WARNING, "%s delimeters should be a single character\n", cmd);
1196                 return -1;
1197         }
1198
1199         ast_channel_lock(chan);
1200         if (ast_strlen_zero(tmp = pbx_builtin_getvar_helper(chan, args.var))) {
1201                 ast_channel_unlock(chan);
1202                 return 0;
1203         }
1204
1205         before = ast_strdupa(tmp);
1206         ast_channel_unlock(chan);
1207
1208         /* Only one entry in array */
1209         if (!(after = search_func(before, S_OR(args.delimiter, ",")[0]))) {
1210                 ast_copy_string(buf, before, len);
1211                 pbx_builtin_setvar_helper(chan, args.var, "");
1212         } else {
1213                 *after++ = '\0';
1214                 ast_copy_string(buf, beginning ? before : after, len);
1215                 pbx_builtin_setvar_helper(chan, args.var, beginning ? after : before);
1216         }
1217
1218         return 0;
1219
1220 }
1221
1222 static int shift(struct ast_channel *chan, const char *cmd, char *var, char *buf, size_t len)
1223 {
1224         return array_remove(chan, cmd, var, buf, len, 1);
1225 }
1226 static struct ast_custom_function shift_function = {
1227         .name = "SHIFT",
1228         .read = shift,
1229 };
1230
1231 static int pop(struct ast_channel *chan, const char *cmd, char *var, char *buf, size_t len)
1232 {
1233         return array_remove(chan, cmd, var, buf, len, 0);
1234 }
1235
1236 static struct ast_custom_function pop_function = {
1237         .name = "POP",
1238         .read = pop,
1239 };
1240
1241 static int array_insert(struct ast_channel *chan, const char *cmd, char *var, const char *val, int beginning)
1242 {
1243         const char *tmp;
1244         struct ast_str *buf;
1245         AST_DECLARE_APP_ARGS(args,
1246                 AST_APP_ARG(var);
1247                 AST_APP_ARG(delimiter);
1248         );
1249
1250         if (!chan) {
1251                 ast_log(LOG_WARNING, "%s requires a channel\n", cmd);
1252                 return -1;
1253         }
1254
1255         AST_STANDARD_APP_ARGS(args, var);
1256
1257         if (ast_strlen_zero(args.var) || ast_strlen_zero(val)) {
1258                 ast_log(LOG_WARNING, "%s requires a variable, and at least one value\n", cmd);
1259                 return -1;
1260         }
1261
1262         if (args.delimiter && strlen(args.delimiter) != 1) {
1263                 ast_log(LOG_WARNING, "%s delimeters should be a single character\n", cmd);
1264                 return -1;
1265         }
1266
1267         if (!(buf = ast_str_create(32))) {
1268                 ast_log(LOG_ERROR, "Unable to allocate memory for buffer!\n");
1269                 return -1;
1270         }
1271
1272         ast_channel_lock(chan);
1273         if (!(tmp = pbx_builtin_getvar_helper(chan, args.var))) {
1274                 ast_str_set(&buf, 0, "%s", val);
1275         } else {
1276                 ast_str_append(&buf, 0, "%s%s%s", beginning ? val : tmp, S_OR(args.delimiter, ","), beginning ? tmp : val);
1277         }
1278         ast_channel_unlock(chan);
1279
1280         pbx_builtin_setvar_helper(chan, args.var, ast_str_buffer(buf));
1281         ast_free(buf);
1282
1283         return 0;
1284 }
1285
1286 static int push(struct ast_channel *chan, const char *cmd, char *var, const char *val)
1287 {
1288         return array_insert(chan, cmd, var, val, 0);
1289 }
1290
1291 static struct ast_custom_function push_function = {
1292         .name = "PUSH",
1293         .write = push,
1294 };
1295
1296 static int unshift(struct ast_channel *chan, const char *cmd, char *var, const char *val)
1297 {
1298         return array_insert(chan, cmd, var, val, 1);
1299 }
1300
1301 static struct ast_custom_function unshift_function = {
1302         .name = "UNSHIFT",
1303         .write = unshift,
1304 };
1305
1306 static int unload_module(void)
1307 {
1308         int res = 0;
1309
1310         res |= ast_custom_function_unregister(&fieldqty_function);
1311         res |= ast_custom_function_unregister(&filter_function);
1312         res |= ast_custom_function_unregister(&listfilter_function);
1313         res |= ast_custom_function_unregister(&regex_function);
1314         res |= ast_custom_function_unregister(&array_function);
1315         res |= ast_custom_function_unregister(&quote_function);
1316         res |= ast_custom_function_unregister(&csv_quote_function);
1317         res |= ast_custom_function_unregister(&len_function);
1318         res |= ast_custom_function_unregister(&strftime_function);
1319         res |= ast_custom_function_unregister(&strptime_function);
1320         res |= ast_custom_function_unregister(&eval_function);
1321         res |= ast_custom_function_unregister(&keypadhash_function);
1322         res |= ast_custom_function_unregister(&hashkeys_function);
1323         res |= ast_custom_function_unregister(&hash_function);
1324         res |= ast_unregister_application(app_clearhash);
1325         res |= ast_custom_function_unregister(&toupper_function);
1326         res |= ast_custom_function_unregister(&tolower_function);
1327         res |= ast_custom_function_unregister(&shift_function);
1328         res |= ast_custom_function_unregister(&pop_function);
1329         res |= ast_custom_function_unregister(&push_function);
1330         res |= ast_custom_function_unregister(&unshift_function);
1331
1332         return res;
1333 }
1334
1335 static int load_module(void)
1336 {
1337         int res = 0;
1338
1339         res |= ast_custom_function_register(&fieldqty_function);
1340         res |= ast_custom_function_register(&filter_function);
1341         res |= ast_custom_function_register(&listfilter_function);
1342         res |= ast_custom_function_register(&regex_function);
1343         res |= ast_custom_function_register(&array_function);
1344         res |= ast_custom_function_register(&quote_function);
1345         res |= ast_custom_function_register(&csv_quote_function);
1346         res |= ast_custom_function_register(&len_function);
1347         res |= ast_custom_function_register(&strftime_function);
1348         res |= ast_custom_function_register(&strptime_function);
1349         res |= ast_custom_function_register(&eval_function);
1350         res |= ast_custom_function_register(&keypadhash_function);
1351         res |= ast_custom_function_register(&hashkeys_function);
1352         res |= ast_custom_function_register(&hash_function);
1353         res |= ast_register_application_xml(app_clearhash, exec_clearhash);
1354         res |= ast_custom_function_register(&toupper_function);
1355         res |= ast_custom_function_register(&tolower_function);
1356         res |= ast_custom_function_register(&shift_function);
1357         res |= ast_custom_function_register(&pop_function);
1358         res |= ast_custom_function_register(&push_function);
1359         res |= ast_custom_function_register(&unshift_function);
1360
1361         return res;
1362 }
1363
1364 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "String handling dialplan functions");