Asterisk - The Open Source Telephony Project  18.5.0
func_strings.c
Go to the documentation of this file.
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 
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;
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 
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;
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 
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 {
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 
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 {
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 
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 {
793  AST_APP_ARG(varname);
794  AST_APP_ARG(find);
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 
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 
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 
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. */
887 
888  if (args.argc < 2) {
889  /* Didn't receive enough arguments to do anything */
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 
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 {
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 
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);
1001  if (strncmp(prefix, ast_var_name(var), len) == 0) {
1003  ast_free(var);
1004  }
1005  }
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 const char *get_key(const struct ast_str *prefix, const struct ast_var_t *var)
1093 {
1094  const char *prefix_name = ast_str_buffer(prefix);
1095  const char *var_name = ast_var_name(var);
1096  int prefix_len;
1097  int var_len;
1098 
1099  if (ast_strlen_zero(var_name)) {
1100  return NULL;
1101  }
1102 
1103  prefix_len = ast_str_strlen(prefix);
1104  var_len = strlen(var_name);
1105 
1106  /*
1107  * Make sure we only match on non-empty, hash function created keys. If valid
1108  * then return a pointer to the variable that's just after the prefix.
1109  */
1110  return var_len > (prefix_len + 1) && var_name[var_len - 1] == '~' &&
1111  strncmp(prefix_name, var_name, prefix_len) == 0 ? var_name + prefix_len : NULL;
1112 }
1113 
1114 static int hashkeys_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1115 {
1116  struct ast_var_t *newvar;
1117  struct ast_str *prefix = ast_str_alloca(80);
1118  size_t buf_len;
1119 
1120  if (!chan) {
1121  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1122  return -1;
1123  }
1124 
1125  ast_str_set(&prefix, -1, HASH_PREFIX, data);
1126  memset(buf, 0, len);
1127 
1128  AST_LIST_TRAVERSE(ast_channel_varshead(chan), newvar, entries) {
1129  const char *key = get_key(prefix, newvar);
1130 
1131  if (key) {
1132  strncat(buf, key, len - strlen(buf) - 1);
1133  /* Replace the trailing ~ */
1134  buf[strlen(buf) - 1] = ',';
1135  }
1136  }
1137  /* Trim the trailing comma */
1138  buf_len = strlen(buf);
1139  if (buf_len) {
1140  buf[buf_len - 1] = '\0';
1141  }
1142  return 0;
1143 }
1144 
1145 static int hashkeys_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
1146 {
1147  struct ast_var_t *newvar;
1148  struct ast_str *prefix = ast_str_alloca(80);
1149 
1150  if (!chan) {
1151  ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
1152  return -1;
1153  }
1154 
1155  ast_str_set(&prefix, -1, HASH_PREFIX, data);
1156 
1157  AST_LIST_TRAVERSE(ast_channel_varshead(chan), newvar, entries) {
1158  const char *key = get_key(prefix, newvar);
1159 
1160  if (key) {
1161  char *tmp;
1162 
1163  ast_str_append(buf, len, "%s", key);
1164  /* Replace the trailing ~ */
1165  tmp = ast_str_buffer(*buf);
1166  tmp[ast_str_strlen(*buf) - 1] = ',';
1167  }
1168  }
1169 
1170  ast_str_truncate(*buf, -1);
1171  return 0;
1172 }
1173 
1174 static int hash_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
1175 {
1176  char varname[256];
1178  AST_APP_ARG(hashname);
1179  AST_APP_ARG(hashkey);
1180  );
1181 
1182  if (!strchr(var, ',')) {
1183  /* Single argument version */
1184  return array(chan, "HASH", var, value);
1185  }
1186 
1187  AST_STANDARD_APP_ARGS(arg, var);
1188  if (arg.hashname[0] == '_') {
1189  if (arg.hashname[1] == '_') {
1190  snprintf(varname, sizeof(varname), "__" HASH_FORMAT, arg.hashname + 2, arg.hashkey);
1191  } else {
1192  snprintf(varname, sizeof(varname), "_" HASH_FORMAT, arg.hashname + 1, arg.hashkey);
1193  }
1194  } else {
1195  snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
1196  }
1197  pbx_builtin_setvar_helper(chan, varname, value);
1198 
1199  return 0;
1200 }
1201 
1202 static int hash_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1203 {
1204  char varname[256];
1205  const char *varvalue;
1207  AST_APP_ARG(hashname);
1208  AST_APP_ARG(hashkey);
1209  );
1210 
1211  AST_STANDARD_APP_ARGS(arg, data);
1212  if (arg.argc == 2) {
1213  snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
1214  varvalue = pbx_builtin_getvar_helper(chan, varname);
1215  if (varvalue)
1216  ast_copy_string(buf, varvalue, len);
1217  else
1218  *buf = '\0';
1219  } else if (arg.argc == 1) {
1220  char colnames[4096];
1221  int i;
1222  AST_DECLARE_APP_ARGS(arg2,
1223  AST_APP_ARG(col)[100];
1224  );
1225 
1226  if (!chan) {
1227  ast_log(LOG_WARNING, "No channel and only 1 parameter was provided to %s function.\n", cmd);
1228  return -1;
1229  }
1230 
1231  /* Get column names, in no particular order */
1232  hashkeys_read(chan, "HASHKEYS", arg.hashname, colnames, sizeof(colnames));
1233  pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames);
1234 
1235  AST_STANDARD_APP_ARGS(arg2, colnames);
1236  *buf = '\0';
1237 
1238  /* Now get the corresponding column values, in exactly the same order */
1239  for (i = 0; i < arg2.argc; i++) {
1240  snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg2.col[i]);
1241  varvalue = pbx_builtin_getvar_helper(chan, varname);
1242  strncat(buf, varvalue, len - strlen(buf) - 1);
1243  strncat(buf, ",", len - strlen(buf) - 1);
1244  }
1245 
1246  /* Strip trailing comma */
1247  buf[strlen(buf) - 1] = '\0';
1248  }
1249 
1250  return 0;
1251 }
1252 
1254  .name = "HASH",
1255  .write = hash_write,
1256  .read = hash_read,
1257 };
1258 
1260  .name = "HASHKEYS",
1261  .read = hashkeys_read,
1262  .read2 = hashkeys_read2,
1263 };
1264 
1266  .name = "ARRAY",
1267  .write = array,
1268 };
1269 
1270 static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1271 {
1272  char *bufptr = buf, *dataptr = data;
1273 
1274  if (len < 3){ /* at least two for quotes and one for binary zero */
1275  ast_log(LOG_ERROR, "Not enough buffer\n");
1276  return -1;
1277  }
1278 
1279  if (ast_strlen_zero(data)) {
1280  ast_log(LOG_WARNING, "No argument specified!\n");
1281  ast_copy_string(buf, "\"\"", len);
1282  return 0;
1283  }
1284 
1285  *bufptr++ = '"';
1286  for (; bufptr < buf + len - 3; dataptr++) {
1287  if (*dataptr == '\\') {
1288  *bufptr++ = '\\';
1289  *bufptr++ = '\\';
1290  } else if (*dataptr == '"') {
1291  *bufptr++ = '\\';
1292  *bufptr++ = '"';
1293  } else if (*dataptr == '\0') {
1294  break;
1295  } else {
1296  *bufptr++ = *dataptr;
1297  }
1298  }
1299  *bufptr++ = '"';
1300  *bufptr = '\0';
1301  return 0;
1302 }
1303 
1305  .name = "QUOTE",
1306  .read = quote,
1307 };
1308 
1309 static int csv_quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
1310 {
1311  char *bufptr = buf, *dataptr = data;
1312 
1313  if (len < 3) { /* at least two for quotes and one for binary zero */
1314  ast_log(LOG_ERROR, "Not enough buffer\n");
1315  return -1;
1316  }
1317 
1318  if (ast_strlen_zero(data)) {
1319  ast_copy_string(buf, "\"\"", len);
1320  return 0;
1321  }
1322 
1323  *bufptr++ = '"';
1324  for (; bufptr < buf + len - 3; dataptr++){
1325  if (*dataptr == '"') {
1326  *bufptr++ = '"';
1327  *bufptr++ = '"';
1328  } else if (*dataptr == '\0') {
1329  break;
1330  } else {
1331  *bufptr++ = *dataptr;
1332  }
1333  }
1334  *bufptr++ = '"';
1335  *bufptr='\0';
1336  return 0;
1337 }
1338 
1340  .name = "CSV_QUOTE",
1341  .read = csv_quote,
1342 };
1343 
1344 static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1345 {
1346  int length = 0;
1347 
1348  if (data)
1349  length = strlen(data);
1350 
1351  snprintf(buf, buflen, "%d", length);
1352 
1353  return 0;
1354 }
1355 
1357  .name = "LEN",
1358  .read = len,
1359  .read_max = 12,
1360 };
1361 
1362 static int acf_strftime(struct ast_channel *chan, const char *cmd, char *parse,
1363  char *buf, size_t buflen)
1364 {
1366  AST_APP_ARG(epoch);
1367  AST_APP_ARG(timezone);
1369  );
1370  struct timeval when;
1371  struct ast_tm tm;
1372 
1373  buf[0] = '\0';
1374 
1375  AST_STANDARD_APP_ARGS(args, parse);
1376 
1377  ast_get_timeval(args.epoch, &when, ast_tvnow(), NULL);
1378  ast_localtime(&when, &tm, args.timezone);
1379 
1380  if (!args.format)
1381  args.format = "%c";
1382 
1383  if (ast_strftime(buf, buflen, args.format, &tm) <= 0)
1384  ast_log(LOG_WARNING, "C function strftime() output nothing?!!\n");
1385 
1386  buf[buflen - 1] = '\0';
1387 
1388  return 0;
1389 }
1390 
1392  .name = "STRFTIME",
1393  .read = acf_strftime,
1394 };
1395 
1396 static int acf_strptime(struct ast_channel *chan, const char *cmd, char *data,
1397  char *buf, size_t buflen)
1398 {
1400  AST_APP_ARG(timestring);
1401  AST_APP_ARG(timezone);
1403  );
1404  struct ast_tm tm;
1405 
1406  buf[0] = '\0';
1407 
1408  if (!data) {
1410  "Asterisk function STRPTIME() requires an argument.\n");
1411  return -1;
1412  }
1413 
1414  AST_STANDARD_APP_ARGS(args, data);
1415 
1416  if (ast_strlen_zero(args.format)) {
1418  "No format supplied to STRPTIME(<timestring>,<timezone>,<format>)");
1419  return -1;
1420  }
1421 
1422  if (!ast_strptime(args.timestring, args.format, &tm)) {
1423  ast_log(LOG_WARNING, "STRPTIME() found no time specified within the string\n");
1424  } else {
1425  struct timeval when;
1426  when = ast_mktime(&tm, args.timezone);
1427  snprintf(buf, buflen, "%d", (int) when.tv_sec);
1428  }
1429 
1430  return 0;
1431 }
1432 
1434  .name = "STRPTIME",
1435  .read = acf_strptime,
1436 };
1437 
1438 static int function_eval(struct ast_channel *chan, const char *cmd, char *data,
1439  char *buf, size_t buflen)
1440 {
1441  if (ast_strlen_zero(data)) {
1442  ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
1443  return -1;
1444  }
1445 
1446  pbx_substitute_variables_helper(chan, data, buf, buflen - 1);
1447 
1448  return 0;
1449 }
1450 
1451 static int function_eval2(struct ast_channel *chan, const char *cmd, char *data,
1452  struct ast_str **buf, ssize_t buflen)
1453 {
1454  if (ast_strlen_zero(data)) {
1455  ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
1456  return -1;
1457  }
1458 
1459  ast_str_substitute_variables(buf, buflen, chan, data);
1460 
1461  return 0;
1462 }
1463 
1465  .name = "EVAL",
1466  .read = function_eval,
1467  .read2 = function_eval2,
1468 };
1469 
1470 static int keypadhash(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1471 {
1472  char *bufptr, *dataptr;
1473 
1474  for (bufptr = buf, dataptr = data; bufptr < buf + buflen - 1; dataptr++) {
1475  if (*dataptr == '\0') {
1476  *bufptr++ = '\0';
1477  break;
1478  } else if (*dataptr == '1') {
1479  *bufptr++ = '1';
1480  } else if (strchr("AaBbCc2", *dataptr)) {
1481  *bufptr++ = '2';
1482  } else if (strchr("DdEeFf3", *dataptr)) {
1483  *bufptr++ = '3';
1484  } else if (strchr("GgHhIi4", *dataptr)) {
1485  *bufptr++ = '4';
1486  } else if (strchr("JjKkLl5", *dataptr)) {
1487  *bufptr++ = '5';
1488  } else if (strchr("MmNnOo6", *dataptr)) {
1489  *bufptr++ = '6';
1490  } else if (strchr("PpQqRrSs7", *dataptr)) {
1491  *bufptr++ = '7';
1492  } else if (strchr("TtUuVv8", *dataptr)) {
1493  *bufptr++ = '8';
1494  } else if (strchr("WwXxYyZz9", *dataptr)) {
1495  *bufptr++ = '9';
1496  } else if (*dataptr == '0') {
1497  *bufptr++ = '0';
1498  }
1499  }
1500  buf[buflen - 1] = '\0';
1501 
1502  return 0;
1503 }
1504 
1506  .name = "KEYPADHASH",
1507  .read = keypadhash,
1508 };
1509 
1510 static int string_toupper(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1511 {
1512  char *bufptr = buf, *dataptr = data;
1513 
1514  while ((bufptr < buf + buflen - 1) && (*bufptr++ = toupper(*dataptr++)));
1515 
1516  return 0;
1517 }
1518 
1519 static int string_toupper2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
1520 {
1521  char *bufptr, *dataptr = data;
1522 
1523  if (buflen > -1) {
1524  ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
1525  }
1526  bufptr = ast_str_buffer(*buf);
1527  while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = toupper(*dataptr++)));
1528  ast_str_update(*buf);
1529 
1530  return 0;
1531 }
1532 
1534  .name = "TOUPPER",
1535  .read = string_toupper,
1536  .read2 = string_toupper2,
1537 };
1538 
1539 static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
1540 {
1541  char *bufptr = buf, *dataptr = data;
1542 
1543  while ((bufptr < buf + buflen - 1) && (*bufptr++ = tolower(*dataptr++)));
1544 
1545  return 0;
1546 }
1547 
1548 static int string_tolower2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
1549 {
1550  char *bufptr, *dataptr = data;
1551 
1552  if (buflen > -1) {
1553  ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
1554  }
1555  bufptr = ast_str_buffer(*buf);
1556  while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = tolower(*dataptr++)));
1557  ast_str_update(*buf);
1558 
1559  return 0;
1560 }
1561 
1563  .name = "TOLOWER",
1564  .read = string_tolower,
1565  .read2 = string_tolower2,
1566 };
1567 
1568 static int shift_pop(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
1569 {
1570 #define beginning (cmd[0] == 'S') /* SHIFT */
1571  char *after, delimiter[2] = ",", *varsubst;
1572  size_t unused;
1573  struct ast_str *before = ast_str_thread_get(&result_buf, 16);
1574  char *(*search_func)(const char *s, int c) = (beginning ? strchr : strrchr);
1576  AST_APP_ARG(var);
1577  AST_APP_ARG(delimiter);
1578  );
1579 
1580  if (!before) {
1581  return -1;
1582  }
1583 
1584  AST_STANDARD_APP_ARGS(args, data);
1585 
1586  if (ast_strlen_zero(args.var)) {
1587  ast_log(LOG_WARNING, "%s requires a variable name\n", cmd);
1588  return -1;
1589  }
1590 
1591  varsubst = ast_alloca(strlen(args.var) + 4);
1592  sprintf(varsubst, "${%s}", args.var);
1593  ast_str_substitute_variables(&before, 0, chan, varsubst);
1594 
1595  if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
1596  ast_get_encoded_char(args.delimiter, delimiter, &unused);
1597  }
1598 
1599  if (!ast_str_strlen(before)) {
1600  /* Nothing to pop */
1601  return -1;
1602  }
1603 
1604  if (!(after = search_func(ast_str_buffer(before), delimiter[0]))) {
1605  /* Only one entry in array */
1606  ast_str_set(buf, len, "%s", ast_str_buffer(before));
1607  pbx_builtin_setvar_helper(chan, args.var, "");
1608  } else {
1609  *after++ = '\0';
1610  ast_str_set(buf, len, "%s", beginning ? ast_str_buffer(before) : after);
1611  pbx_builtin_setvar_helper(chan, args.var, beginning ? after : ast_str_buffer(before));
1612  }
1613 
1614  return 0;
1615 #undef beginning
1616 }
1617 
1619  .name = "SHIFT",
1620  .read2 = shift_pop,
1621 };
1622 
1624  .name = "POP",
1625  .read2 = shift_pop,
1626 };
1627 
1628 static int unshift_push(struct ast_channel *chan, const char *cmd, char *data, const char *new_value)
1629 {
1630 #define beginning (cmd[0] == 'U') /* UNSHIFT */
1631  char delimiter[2] = ",", *varsubst;
1632  size_t unused;
1633  struct ast_str *buf, *previous_value;
1635  AST_APP_ARG(var);
1636  AST_APP_ARG(delimiter);
1637  );
1638  const char *stripped_var;
1639 
1640  if (!(buf = ast_str_thread_get(&result_buf, 16)) ||
1641  !(previous_value = ast_str_thread_get(&tmp_buf, 16))) {
1642  return -1;
1643  }
1644 
1645  AST_STANDARD_APP_ARGS(args, data);
1646 
1647  if (ast_strlen_zero(args.var)) {
1648  ast_log(LOG_WARNING, "%s requires a variable name\n", cmd);
1649  return -1;
1650  }
1651 
1652  if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
1653  ast_get_encoded_char(args.delimiter, delimiter, &unused);
1654  }
1655 
1656  /* UNSHIFT and PUSH act as ways of setting a variable, so we need to be
1657  * sure to skip leading underscores if they appear. However, we only want
1658  * to skip up to two since that is the maximum number that can be used to
1659  * indicate variable inheritance. Any further underscores are part of the
1660  * variable name.
1661  */
1662  stripped_var = args.var + MIN(strspn(args.var, "_"), 2);
1663  varsubst = ast_alloca(strlen(stripped_var) + 4);
1664  sprintf(varsubst, "${%s}", stripped_var);
1665  ast_str_substitute_variables(&previous_value, 0, chan, varsubst);
1666 
1667  if (!ast_str_strlen(previous_value)) {
1668  ast_str_set(&buf, 0, "%s", new_value);
1669  } else {
1670  ast_str_set(&buf, 0, "%s%c%s",
1671  beginning ? new_value : ast_str_buffer(previous_value),
1672  delimiter[0],
1673  beginning ? ast_str_buffer(previous_value) : new_value);
1674  }
1675 
1677 
1678  return 0;
1679 #undef beginning
1680 }
1681 
1683  .name = "PUSH",
1684  .write = unshift_push,
1685 };
1686 
1688  .name = "UNSHIFT",
1689  .write = unshift_push,
1690 };
1691 
1692 static int passthru(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
1693 {
1694  ast_str_set(buf, len, "%s", data);
1695  return 0;
1696 }
1697 
1699  .name = "PASSTHRU",
1700  .read2 = passthru,
1701 };
1702 
1703 #ifdef TEST_FRAMEWORK
1704 AST_TEST_DEFINE(test_FIELDNUM)
1705 {
1706  int i, res = AST_TEST_PASS;
1707  struct ast_channel *chan;
1708  struct ast_str *str;
1709  char expression[256];
1710  struct {
1711  const char *fields;
1712  const char *delim;
1713  const char *field;
1714  const char *expected;
1715  } test_args[] = {
1716  {"abc,def,ghi,jkl", "\\,", "ghi", "3"},
1717  {"abc def ghi jkl", " ", "abc", "1"},
1718  {"abc/def/ghi/jkl", "\\\\x2f", "def", "2"},
1719  {"abc$def$ghi$jkl", "", "ghi", "0"},
1720  {"abc,def,ghi,jkl", "-", "", "0"},
1721  {"abc-def-ghi-jkl", "-", "mno", "0"}
1722  };
1723 
1724  switch (cmd) {
1725  case TEST_INIT:
1726  info->name = "func_FIELDNUM_test";
1727  info->category = "/funcs/func_strings/";
1728  info->summary = "Test FIELDNUM function";
1729  info->description = "Verify FIELDNUM behavior";
1730  return AST_TEST_NOT_RUN;
1731  case TEST_EXECUTE:
1732  break;
1733  }
1734 
1735  if (!(chan = ast_dummy_channel_alloc())) {
1736  ast_test_status_update(test, "Unable to allocate dummy channel\n");
1737  return AST_TEST_FAIL;
1738  }
1739 
1740  if (!(str = ast_str_create(16))) {
1741  ast_test_status_update(test, "Unable to allocate dynamic string buffer\n");
1742  ast_channel_release(chan);
1743  return AST_TEST_FAIL;
1744  }
1745 
1746  for (i = 0; i < ARRAY_LEN(test_args); i++) {
1747  struct ast_var_t *var = ast_var_assign("FIELDS", test_args[i].fields);
1748  if (!var) {
1749  ast_test_status_update(test, "Out of memory\n");
1750  res = AST_TEST_FAIL;
1751  break;
1752  }
1753 
1755 
1756  snprintf(expression, sizeof(expression), "${FIELDNUM(%s,%s,%s)}", var->name, test_args[i].delim, test_args[i].field);
1757  ast_str_substitute_variables(&str, 0, chan, expression);
1758 
1760  ast_var_delete(var);
1761 
1762  if (strcasecmp(ast_str_buffer(str), test_args[i].expected)) {
1763  ast_test_status_update(test, "Evaluation of '%s' returned '%s' instead of the expected value '%s'\n",
1764  expression, ast_str_buffer(str), test_args[i].expected);
1765  res = AST_TEST_FAIL;
1766  break;
1767  }
1768  }
1769 
1770  ast_free(str);
1771  ast_channel_release(chan);
1772 
1773  return res;
1774 }
1775 
1776 AST_TEST_DEFINE(test_REPLACE)
1777 {
1778  int i, res = AST_TEST_PASS;
1779  struct ast_channel *chan;
1780  struct ast_str *str;
1781  char expression[256];
1782  struct {
1783  const char *test_string;
1784  const char *find_chars;
1785  const char *replace_char;
1786  const char *expected;
1787  } test_args[] = {
1788  {"abc,def", "\\,", "-", "abc-def"},
1789  {"abc,abc", "bc", "a", "aaa,aaa"},
1790  {"abc,def", "x", "?", "abc,def"},
1791  {"abc,def", "\\,", "", "abcdef"}
1792  };
1793 
1794  switch (cmd) {
1795  case TEST_INIT:
1796  info->name = "func_REPLACE_test";
1797  info->category = "/funcs/func_strings/";
1798  info->summary = "Test REPLACE function";
1799  info->description = "Verify REPLACE behavior";
1800  return AST_TEST_NOT_RUN;
1801  case TEST_EXECUTE:
1802  break;
1803  }
1804 
1805  if (!(chan = ast_dummy_channel_alloc())) {
1806  ast_test_status_update(test, "Unable to allocate dummy channel\n");
1807  return AST_TEST_FAIL;
1808  }
1809 
1810  if (!(str = ast_str_create(16))) {
1811  ast_test_status_update(test, "Unable to allocate dynamic string buffer\n");
1812  ast_channel_release(chan);
1813  return AST_TEST_FAIL;
1814  }
1815 
1816  for (i = 0; i < ARRAY_LEN(test_args); i++) {
1817  struct ast_var_t *var = ast_var_assign("TEST_STRING", test_args[i].test_string);
1818  if (!var) {
1819  ast_test_status_update(test, "Out of memory\n");
1820  res = AST_TEST_FAIL;
1821  break;
1822  }
1823 
1825 
1826  snprintf(expression, sizeof(expression), "${REPLACE(%s,%s,%s)}", var->name, test_args[i].find_chars, test_args[i].replace_char);
1827  ast_str_substitute_variables(&str, 0, chan, expression);
1828 
1830  ast_var_delete(var);
1831 
1832  if (strcasecmp(ast_str_buffer(str), test_args[i].expected)) {
1833  ast_test_status_update(test, "Evaluation of '%s' returned '%s' instead of the expected value '%s'\n",
1834  expression, ast_str_buffer(str), test_args[i].expected);
1835  res = AST_TEST_FAIL;
1836  break;
1837  }
1838  }
1839 
1840  ast_free(str);
1841  ast_channel_release(chan);
1842 
1843  return res;
1844 }
1845 
1846 AST_TEST_DEFINE(test_FILTER)
1847 {
1848  int i, res = AST_TEST_PASS;
1849  const char *test_strings[][2] = {
1850  {"A-R", "DAHDI"},
1851  {"A\\-R", "A"},
1852  {"\\x41-R", "DAHDI"},
1853  {"0-9A-Ca-c", "0042133333A12212"},
1854  {"0-9a-cA-C_+\\-", "0042133333A12212"},
1855  {NULL, NULL},
1856  };
1857 
1858  switch (cmd) {
1859  case TEST_INIT:
1860  info->name = "func_FILTER_test";
1861  info->category = "/funcs/func_strings/";
1862  info->summary = "Test FILTER function";
1863  info->description = "Verify FILTER behavior";
1864  return AST_TEST_NOT_RUN;
1865  case TEST_EXECUTE:
1866  break;
1867  }
1868 
1869  for (i = 0; test_strings[i][0]; i++) {
1870  char tmp[256], tmp2[256] = "";
1871  snprintf(tmp, sizeof(tmp), "${FILTER(%s,0042133333&DAHDI/g1/2212)}", test_strings[i][0]);
1872  pbx_substitute_variables_helper(NULL, tmp, tmp2, sizeof(tmp2) - 1);
1873  if (strcmp(test_strings[i][1], tmp2)) {
1874  ast_test_status_update(test, "Format string '%s' substituted to '%s'. Expected '%s'.\n", test_strings[i][0], tmp2, test_strings[i][1]);
1875  res = AST_TEST_FAIL;
1876  }
1877  }
1878  return res;
1879 }
1880 
1881 AST_TEST_DEFINE(test_STRREPLACE)
1882 {
1883  int i, res = AST_TEST_PASS;
1884  struct ast_channel *chan; /* dummy channel */
1885  struct ast_str *str; /* fancy string for holding comparing value */
1886 
1887  const char *test_strings[][5] = {
1888  {"Weasels have eaten my telephone system", "have eaten my", "are eating our", "", "Weasels are eating our telephone system"}, /*Test normal conditions */
1889  {"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 */
1890  {"foofoofoofoofoofoofoo", "foofoo", "bar", NULL, "barbarbarfoo"}, /* Found string within previous match */
1891  {"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."},
1892  {"One and one and one is three", "and", "plus", "1", "One plus one and one is three"}, /* Test <max-replacements> = 1*/
1893  {"", "fhqwagads", "spelunker", NULL, ""}, /* Empty primary string */
1894  {"Part of this string is missing.", "missing", NULL, NULL, "Part of this string is ."}, /* Empty replace string */
1895  {"'Accidentally' left off a bunch of stuff.", NULL, NULL, NULL, ""}, /* Deliberate error test from too few args */
1896  {"This test will also error.", "", "", "", ""}, /* Deliberate error test from blank find string */
1897  {"This is an \"escape character\" test.", "\\\"escape character\\\"", "evil", NULL, "This is an evil test."}
1898  };
1899 
1900  switch (cmd) {
1901  case TEST_INIT:
1902  info->name = "func_STRREPLACE_test";
1903  info->category = "/funcs/func_strings/";
1904  info->summary = "Test STRREPLACE function";
1905  info->description = "Verify STRREPLACE behavior";
1906  return AST_TEST_NOT_RUN;
1907  case TEST_EXECUTE:
1908  break;
1909  }
1910 
1911  if (!(chan = ast_dummy_channel_alloc())) {
1912  ast_test_status_update(test, "Unable to allocate dummy channel\n");
1913  return AST_TEST_FAIL;
1914  }
1915 
1916  if (!(str = ast_str_create(64))) {
1917  ast_test_status_update(test, "Unable to allocate dynamic string buffer\n");
1918  ast_channel_release(chan);
1919  return AST_TEST_FAIL;
1920  }
1921 
1922  for (i = 0; i < ARRAY_LEN(test_strings); i++) {
1923  char tmp[512], tmp2[512] = "";
1924 
1925  struct ast_var_t *var = ast_var_assign("test_string", test_strings[i][0]);
1926  if (!var) {
1927  ast_test_status_update(test, "Unable to allocate variable\n");
1928  ast_free(str);
1929  ast_channel_release(chan);
1930  return AST_TEST_FAIL;
1931  }
1932 
1934 
1935  if (test_strings[i][3]) {
1936  snprintf(tmp, sizeof(tmp), "${STRREPLACE(%s,%s,%s,%s)}", "test_string", test_strings[i][1], test_strings[i][2], test_strings[i][3]);
1937  } else if (test_strings[i][2]) {
1938  snprintf(tmp, sizeof(tmp), "${STRREPLACE(%s,%s,%s)}", "test_string", test_strings[i][1], test_strings[i][2]);
1939  } else if (test_strings[i][1]) {
1940  snprintf(tmp, sizeof(tmp), "${STRREPLACE(%s,%s)}", "test_string", test_strings[i][1]);
1941  } else {
1942  snprintf(tmp, sizeof(tmp), "${STRREPLACE(%s)}", "test_string");
1943  }
1944  ast_str_substitute_variables(&str, 0, chan, tmp);
1945  if (strcmp(test_strings[i][4], ast_str_buffer(str))) {
1946  ast_test_status_update(test, "Format string '%s' substituted to '%s'. Expected '%s'.\n", test_strings[i][0], tmp2, test_strings[i][4]);
1947  res = AST_TEST_FAIL;
1948  }
1949  }
1950 
1951  ast_free(str);
1952  ast_channel_release(chan);
1953 
1954  return res;
1955 }
1956 #endif
1957 
1958 static int unload_module(void)
1959 {
1960  int res = 0;
1961 
1962  AST_TEST_UNREGISTER(test_FIELDNUM);
1963  AST_TEST_UNREGISTER(test_REPLACE);
1964  AST_TEST_UNREGISTER(test_FILTER);
1965  AST_TEST_UNREGISTER(test_STRREPLACE);
1966  res |= ast_custom_function_unregister(&fieldqty_function);
1967  res |= ast_custom_function_unregister(&fieldnum_function);
1968  res |= ast_custom_function_unregister(&filter_function);
1969  res |= ast_custom_function_unregister(&replace_function);
1970  res |= ast_custom_function_unregister(&strreplace_function);
1971  res |= ast_custom_function_unregister(&listfilter_function);
1972  res |= ast_custom_function_unregister(&regex_function);
1973  res |= ast_custom_function_unregister(&array_function);
1974  res |= ast_custom_function_unregister(&quote_function);
1975  res |= ast_custom_function_unregister(&csv_quote_function);
1976  res |= ast_custom_function_unregister(&len_function);
1977  res |= ast_custom_function_unregister(&strftime_function);
1978  res |= ast_custom_function_unregister(&strptime_function);
1979  res |= ast_custom_function_unregister(&eval_function);
1980  res |= ast_custom_function_unregister(&keypadhash_function);
1981  res |= ast_custom_function_unregister(&hashkeys_function);
1982  res |= ast_custom_function_unregister(&hash_function);
1984  res |= ast_custom_function_unregister(&toupper_function);
1985  res |= ast_custom_function_unregister(&tolower_function);
1986  res |= ast_custom_function_unregister(&shift_function);
1987  res |= ast_custom_function_unregister(&pop_function);
1988  res |= ast_custom_function_unregister(&push_function);
1989  res |= ast_custom_function_unregister(&unshift_function);
1990  res |= ast_custom_function_unregister(&passthru_function);
1991 
1992  return res;
1993 }
1994 
1995 static int load_module(void)
1996 {
1997  int res = 0;
1998 
1999  AST_TEST_REGISTER(test_FIELDNUM);
2000  AST_TEST_REGISTER(test_REPLACE);
2001  AST_TEST_REGISTER(test_FILTER);
2002  AST_TEST_REGISTER(test_STRREPLACE);
2003  res |= ast_custom_function_register(&fieldqty_function);
2004  res |= ast_custom_function_register(&fieldnum_function);
2005  res |= ast_custom_function_register(&filter_function);
2006  res |= ast_custom_function_register(&replace_function);
2007  res |= ast_custom_function_register(&strreplace_function);
2008  res |= ast_custom_function_register(&listfilter_function);
2009  res |= ast_custom_function_register(&regex_function);
2010  res |= ast_custom_function_register(&array_function);
2011  res |= ast_custom_function_register(&quote_function);
2012  res |= ast_custom_function_register(&csv_quote_function);
2013  res |= ast_custom_function_register(&len_function);
2014  res |= ast_custom_function_register(&strftime_function);
2015  res |= ast_custom_function_register(&strptime_function);
2016  res |= ast_custom_function_register(&eval_function);
2017  res |= ast_custom_function_register(&keypadhash_function);
2018  res |= ast_custom_function_register(&hashkeys_function);
2019  res |= ast_custom_function_register(&hash_function);
2021  res |= ast_custom_function_register(&toupper_function);
2022  res |= ast_custom_function_register(&tolower_function);
2023  res |= ast_custom_function_register(&shift_function);
2024  res |= ast_custom_function_register(&pop_function);
2025  res |= ast_custom_function_register(&push_function);
2026  res |= ast_custom_function_register(&unshift_function);
2027  res |= ast_custom_function_register(&passthru_function);
2028 
2029  return res;
2030 }
2031 
2032 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "String handling dialplan functions");
const char * name
Definition: pbx.h:119
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Definition: threadstorage.h:84
static int function_fieldqty(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
Definition: func_strings.c:485
static struct ast_custom_function hashkeys_function
static const char * get_key(const struct ast_str *prefix, const struct ast_var_t *var)
static int hash_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
#define ast_channel_lock(chan)
Definition: channel.h:2945
Main Channel structure associated with a channel.
static struct ast_custom_function len_function
static int strreplace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
Definition: func_strings.c:859
#define AST_MODULE_INFO_STANDARD(keystr, desc)
Definition: module.h:567
static int load_module(void)
Asterisk main include file. File version handling, generic pbx functions.
static int acf_strptime(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static struct ast_custom_function shift_function
static int listfilter_read(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
Definition: func_strings.c:693
char * ast_get_encoded_str(const char *stream, char *result, size_t result_len)
Decode a stream of encoded control or extended ASCII characters.
Definition: main/app.c:3002
#define beginning
Definition: ast_expr2.c:325
static int function_fieldqty_helper(struct ast_channel *chan, const char *cmd, char *parse, char *buf, struct ast_str **sbuf, ssize_t len)
Definition: func_strings.c:440
static int function_fieldnum(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
Definition: func_strings.c:564
static struct ast_custom_function strftime_function
static int acf_strftime(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t buflen)
size_t ast_str_size(const struct ast_str *buf)
Returns the current maximum length (without reallocation) of the current buffer.
Definition: strings.h:699
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static struct ast_custom_function passthru_function
struct ast_channel * ast_channel_release(struct ast_channel *chan)
Unlink and release reference to a channel.
Definition: channel.c:1584
const char * ast_var_name(const struct ast_var_t *var)
Definition: chanvars.c:60
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
#define ast_str_make_space(buf, new_len)
Definition: strings.h:780
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
static void clearvar_prefix(struct ast_channel *chan, const char *prefix)
Definition: func_strings.c:996
static int tmp()
Definition: bt_open.c:389
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
#define var
Definition: ast_expr2f.c:614
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
Test Framework API.
#define HASH_FORMAT
Definition: func_strings.c:991
#define AST_TEST_REGISTER(cb)
Definition: test.h:127
#define AST_STANDARD_RAW_ARGS(args, parse)
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1091
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
static struct ast_custom_function eval_function
static struct ast_custom_function fieldnum_function
Definition: func_strings.c:576
static char * test_strings[][2]
static struct test_val c
#define ast_str_alloca(init_len)
Definition: strings.h:800
static struct ast_custom_function push_function
static struct ast_custom_function unshift_function
const char * str
Definition: app_jack.c:147
struct varshead * ast_channel_varshead(struct ast_channel *chan)
const char * args
#define NULL
Definition: resample.c:96
char * end
Definition: eagi_proxy.c:73
int value
Definition: syslog.c:37
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:855
int ast_get_timeval(const char *src, struct timeval *tv, struct timeval _default, int *consumed)
get values from config variables.
Definition: main/utils.c:2171
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
static int hashkeys_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int string_toupper2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
static int string_tolower2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
static int hashkeys_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
Utility functions.
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
Definition: strings.h:738
#define ast_strlen_zero(foo)
Definition: strings.h:52
static struct ast_custom_function replace_function
Definition: func_strings.c:854
Custom localtime functions for multiple timezones.
static struct ast_custom_function quote_function
#define MIN(a, b)
Definition: utils.h:226
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1065
#define ast_opt_dont_warn
Definition: options.h:125
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
static int function_eval(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static struct ast_threadstorage tmp_buf
Definition: func_strings.c:46
AST_TEST_DEFINE(test_FIELDNUM)
static int exec_clearhash(struct ast_channel *chan, const char *data)
General Asterisk PBX channel definitions.
static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:911
#define ast_test_status_update(a, b, c...)
Definition: test.h:129
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Definition: channel.h:1283
char * ast_str_append_substr(struct ast_str **buf, ssize_t maxlen, const char *src, size_t maxsrc)
Append a non-NULL terminated substring to the end of a dynamic string.
Definition: strings.h:1014
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
static struct ast_custom_function listfilter_function
Definition: func_strings.c:703
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
static int keypadhash(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static char * app_clearhash
Definition: func_strings.c:993
static struct ast_custom_function toupper_function
int ast_get_encoded_char(const char *stream, char *result, size_t *consumed)
Decode an encoded control or extended ASCII character.
Definition: main/app.c:2927
static struct ast_custom_function csv_quote_function
Core PBX routines and definitions.
char * ast_strptime(const char *s, const char *format, struct ast_tm *tm)
Special version of strptime(3) which places the answer in the common structure ast_tm. Also, unlike strptime(3), ast_strptime() initializes its memory prior to use.
Definition: localtime.c:2550
int ast_autoservice_stop(struct ast_channel *chan)
Stop servicing a channel for us...
Definition: autoservice.c:266
static struct ast_threadstorage result_buf
Definition: func_strings.c:45
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
static int string_toupper(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, struct ast_str **bufstr, ssize_t len)
Definition: func_strings.c:582
char name[0]
Definition: chanvars.h:31
static struct ast_custom_function filter_function
Definition: func_strings.c:785
static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static struct ast_custom_function regex_function
Definition: func_strings.c:985
#define LOG_ERROR
Definition: logger.h:285
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
static int array(struct ast_channel *chan, const char *cmd, char *var, const char *value)
#define AST_TEST_UNREGISTER(cb)
Definition: test.h:128
static int listfilter_read2(struct ast_channel *chan, const char *cmd, char *parse, struct ast_str **buf, ssize_t len)
Definition: func_strings.c:698
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the &#39;nonstandard&#39; argument separation process for an application.
void ast_var_delete(struct ast_var_t *var)
Definition: extconf.c:2473
def info(msg)
static struct ast_custom_function array_function
static int csv_quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
struct sla_ringing_trunk * first
Definition: app_meetme.c:1092
static struct ast_custom_function fieldqty_function
Definition: func_strings.c:497
static int unshift_push(struct ast_channel *chan, const char *cmd, char *data, const char *new_value)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:710
#define ast_channel_unlock(chan)
Definition: channel.h:2946
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
static struct ast_custom_function keypadhash_function
#define ast_free(a)
Definition: astmm.h:182
static int function_fieldnum_str(struct ast_channel *chan, const char *cmd, char *parse, struct ast_str **buf, ssize_t len)
Definition: func_strings.c:570
static struct ast_custom_function hash_function
struct ast_var_t::@249 entries
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
Definition: func_strings.c:948
static int shift_pop(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
#define ast_var_assign(name, value)
Definition: chanvars.h:40
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2524
static struct ast_custom_function pop_function
static int function_fieldnum_helper(struct ast_channel *chan, const char *cmd, char *parse, char *buf, struct ast_str **sbuf, ssize_t len)
Definition: func_strings.c:503
static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
Definition: func_strings.c:790
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition: strings.h:653
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
Definition: strings.h:688
char * strsep(char **str, const char *delims)
struct timeval ast_mktime(struct ast_tm *const tmp, const char *zone)
Timezone-independent version of mktime(3).
Definition: localtime.c:2357
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
void ast_str_update(struct ast_str *buf)
Update the length of the buffer, after using ast_str merely as a buffer.
Definition: strings.h:663
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
static int passthru(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
Definition: ael_main.c:211
static PGresult * result
Definition: cel_pgsql.c:88
static struct ast_custom_function tolower_function
static struct ast_custom_function strptime_function
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
static int function_fieldqty_str(struct ast_channel *chan, const char *cmd, char *parse, struct ast_str **buf, ssize_t len)
Definition: func_strings.c:491
int int32_t
Definition: db.h:60
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
Definition: strings.h:861
static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
Definition: func_strings.c:709
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
static snd_pcm_format_t format
Definition: chan_alsa.c:102
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1508
static struct ast_custom_function strreplace_function
Definition: func_strings.c:943
static int function_eval2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626
#define HASH_PREFIX
Definition: func_strings.c:990
static int unload_module(void)
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620
static char prefix[MAX_PREFIX]
Definition: http.c:141
#define AST_APP_ARG(name)
Define an application argument.
static int hash_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)