Wed Jan 8 2020 09:49:47

Asterisk developer's documentation


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