Wed Apr 6 11:29:45 2011

Asterisk developer's documentation


func_strings.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2005-2006, Digium, Inc.
00005  * Portions Copyright (C) 2005, Tilghman Lesher.  All rights reserved.
00006  * Portions Copyright (C) 2005, Anthony Minessale II
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief String manipulation dialplan functions
00022  *
00023  * \author Tilghman Lesher
00024  * \author Anothony Minessale II 
00025  * \ingroup functions
00026  */
00027 
00028 #include "asterisk.h"
00029 
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 293159 $")
00031 
00032 #include <regex.h>
00033 #include <ctype.h>
00034 
00035 #include "asterisk/module.h"
00036 #include "asterisk/channel.h"
00037 #include "asterisk/pbx.h"
00038 #include "asterisk/utils.h"
00039 #include "asterisk/app.h"
00040 #include "asterisk/localtime.h"
00041 #include "asterisk/test.h"
00042 
00043 AST_THREADSTORAGE(result_buf);
00044 AST_THREADSTORAGE(tmp_buf);
00045 
00046 /*** DOCUMENTATION
00047    <function name="FIELDQTY" language="en_US">
00048       <synopsis>
00049          Count the fields with an arbitrary delimiter
00050       </synopsis>
00051       <syntax>
00052          <parameter name="varname" required="true" />
00053          <parameter name="delim" required="true" />
00054       </syntax>
00055       <description>
00056          <para>The delimiter may be specified as a special or extended ASCII character, by encoding it.  The characters
00057          <literal>\n</literal>, <literal>\r</literal>, and <literal>\t</literal> are all recognized as the newline,
00058          carriage return, and tab characters, respectively.  Also, octal and hexadecimal specifications are recognized
00059          by the patterns <literal>\0nnn</literal> and <literal>\xHH</literal>, respectively.  For example, if you wanted
00060          to encode a comma as the delimiter, you could use either <literal>\054</literal> or <literal>\x2C</literal>.</para>
00061          <para>Example: If ${example} contains <literal>ex-amp-le</literal>, then ${FIELDQTY(example,-)} returns 3.</para>
00062       </description>
00063    </function>
00064    <function name="FIELDNUM" language="en_US">
00065       <synopsis>
00066          Return the 1-based offset of a field in a list
00067       </synopsis>
00068       <syntax>
00069          <parameter name="varname" required="true" />
00070          <parameter name="delim" required="true" />
00071          <parameter name="value" required="true" />
00072       </syntax>
00073       <description>
00074          <para>Search the variable named <replaceable>varname</replaceable> for the string <replaceable>value</replaceable>
00075          delimited by <replaceable>delim</replaceable> and return a 1-based offset as to its location. If not found
00076          or an error occured, return <literal>0</literal>.</para>
00077          <para>The delimiter may be specified as a special or extended ASCII character, by encoding it.  The characters
00078          <literal>\n</literal>, <literal>\r</literal>, and <literal>\t</literal> are all recognized as the newline,
00079          carriage return, and tab characters, respectively.  Also, octal and hexadecimal specifications are recognized
00080          by the patterns <literal>\0nnn</literal> and <literal>\xHH</literal>, respectively.  For example, if you wanted
00081          to encode a comma as the delimiter, you could use either <literal>\054</literal> or <literal>\x2C</literal>.</para>
00082               <para>Example: If ${example} contains <literal>ex-amp-le</literal>, then ${FIELDNUM(example,-,amp)} returns 2.</para>
00083       </description>
00084    </function>
00085    <function name="LISTFILTER" language="en_US">
00086       <synopsis>Remove an item from a list, by name.</synopsis>
00087       <syntax>
00088          <parameter name="varname" required="true" />
00089          <parameter name="delim" required="true" default="," />
00090          <parameter name="value" required="true" />
00091       </syntax>
00092       <description>
00093          <para>Remove <replaceable>value</replaceable> from the list contained in the <replaceable>varname</replaceable>
00094          variable, where the list delimiter is specified by the <replaceable>delim</replaceable> parameter.  This is
00095          very useful for removing a single channel name from a list of channels, for example.</para>
00096       </description>
00097    </function>
00098    <function name="FILTER" language="en_US">
00099       <synopsis>
00100          Filter the string to include only the allowed characters
00101       </synopsis>
00102       <syntax>
00103          <parameter name="allowed-chars" required="true" />
00104          <parameter name="string" required="true" />
00105       </syntax>
00106       <description>
00107          <para>Permits all characters listed in <replaceable>allowed-chars</replaceable>, 
00108          filtering all others outs. In addition to literally listing the characters, 
00109          you may also use ranges of characters (delimited by a <literal>-</literal></para>
00110          <para>Hexadecimal characters started with a <literal>\x</literal>(i.e. \x20)</para>
00111          <para>Octal characters started with a <literal>\0</literal> (i.e. \040)</para>
00112          <para>Also <literal>\t</literal>,<literal>\n</literal> and <literal>\r</literal> are recognized.</para> 
00113          <note><para>If you want the <literal>-</literal> character it needs to be prefixed with a 
00114          <literal></literal></para></note>
00115       </description>
00116    </function>
00117    <function name="REPLACE" language="en_US">
00118       <synopsis>
00119          Replace a set of characters in a given string with another character.
00120       </synopsis>
00121       <syntax>
00122          <parameter name="varname" required="true" />
00123          <parameter name="find-chars" required="true" />
00124          <parameter name="replace-char" required="false" />
00125       </syntax>
00126       <description>
00127          <para>Iterates through a string replacing all the <replaceable>find-chars</replaceable> with
00128          <replaceable>replace-char</replaceable>.  <replaceable>replace-char</replaceable> may be either
00129          empty or contain one character.  If empty, all <replaceable>find-chars</replaceable> will be
00130          deleted from the output.</para>
00131          <note><para>The replacement only occurs in the output.  The original variable is not
00132          altered.</para></note>
00133       </description>
00134    </function>
00135    <function name="PASSTHRU" language="en_US">
00136       <synopsis>
00137          Pass the given argument back as a value.
00138       </synopsis>
00139       <syntax>
00140          <parameter name="string" required="false" />
00141       </syntax>
00142       <description>
00143          <para>Literally returns the given <replaceable>string</replaceable>.  The intent is to permit
00144          other dialplan functions which take a variable name as an argument to be able to take a literal
00145          string, instead.</para>
00146       </description>
00147    </function>
00148    <function name="REGEX" language="en_US">
00149       <synopsis>
00150          Check string against a regular expression.
00151       </synopsis>
00152       <syntax argsep=" ">
00153          <parameter name="&quot;regular expression&quot;" required="true" />
00154          <parameter name="string" required="true" />
00155       </syntax>
00156       <description>
00157          <para>Return <literal>1</literal> on regular expression match or <literal>0</literal> otherwise</para>
00158          <para>Please note that the space following the double quotes separating the 
00159          regex from the data is optional and if present, is skipped. If a space is 
00160          desired at the beginning of the data, then put two spaces there; the second 
00161          will not be skipped.</para>
00162       </description>
00163    </function>
00164    <application name="ClearHash" language="en_US">
00165       <synopsis>
00166          Clear the keys from a specified hashname.
00167       </synopsis>
00168       <syntax>
00169          <parameter name="hashname" required="true" />
00170       </syntax>
00171       <description>
00172          <para>Clears all keys out of the specified <replaceable>hashname</replaceable>.</para>
00173       </description>
00174    </application>
00175    <function name="HASH" language="en_US">
00176       <synopsis>
00177          Implementation of a dialplan associative array
00178       </synopsis>
00179       <syntax>
00180          <parameter name="hashname" required="true" />
00181          <parameter name="hashkey" />
00182       </syntax>
00183       <description>
00184          <para>In two arguments mode, gets and sets values to corresponding keys within
00185          a named associative array. The single-argument mode will only work when assigned
00186          to from a function defined by func_odbc</para>
00187       </description>
00188    </function>
00189    <function name="HASHKEYS" language="en_US">
00190       <synopsis>
00191          Retrieve the keys of the HASH() function.
00192       </synopsis>
00193       <syntax>
00194          <parameter name="hashname" required="true" />
00195       </syntax>
00196       <description>
00197          <para>Returns a comma-delimited list of the current keys of the associative array 
00198          defined by the HASH() function. Note that if you iterate over the keys of 
00199          the result, adding keys during iteration will cause the result of the HASHKEYS()
00200          function to change.</para>
00201       </description>
00202    </function>
00203    <function name="KEYPADHASH" language="en_US">
00204       <synopsis>
00205          Hash the letters in string into equivalent keypad numbers.
00206       </synopsis>
00207       <syntax>
00208          <parameter name="string" required="true" />
00209       </syntax>
00210       <description>
00211          <para>Example: ${KEYPADHASH(Les)} returns "537"</para>
00212       </description>
00213    </function>
00214    <function name="ARRAY" language="en_US">
00215       <synopsis>
00216          Allows setting multiple variables at once.
00217       </synopsis>
00218       <syntax>
00219          <parameter name="var1" required="true" />
00220          <parameter name="var2" required="false" multiple="true" />
00221          <parameter name="varN" required="false" />
00222       </syntax>
00223       <description>
00224          <para>The comma-delimited list passed as a value to which the function is set will 
00225          be interpreted as a set of values to which the comma-delimited list of 
00226          variable names in the argument should be set.</para>
00227          <para>Example: Set(ARRAY(var1,var2)=1,2) will set var1 to 1 and var2 to 2</para>
00228       </description>
00229    </function>
00230    <function name="STRPTIME" language="en_US">
00231       <synopsis>
00232          Returns the epoch of the arbitrary date/time string structured as described by the format.
00233       </synopsis>
00234       <syntax>
00235          <parameter name="datetime" required="true" />
00236          <parameter name="timezone" required="true" />
00237          <parameter name="format" required="true" />
00238       </syntax>
00239       <description>
00240          <para>This is useful for converting a date into <literal>EPOCH</literal> time, 
00241          possibly to pass to an application like SayUnixTime or to calculate the difference
00242          between the two date strings</para>
00243          <para>Example: ${STRPTIME(2006-03-01 07:30:35,America/Chicago,%Y-%m-%d %H:%M:%S)} returns 1141219835</para>
00244       </description>
00245    </function>
00246    <function name="STRFTIME" language="en_US">
00247       <synopsis>
00248          Returns the current date/time in the specified format.
00249       </synopsis>
00250       <syntax>
00251          <parameter name="epoch" />
00252          <parameter name="timezone" />
00253          <parameter name="format" />
00254       </syntax>
00255       <description>
00256          <para>STRFTIME supports all of the same formats as the underlying C function
00257          <emphasis>strftime(3)</emphasis>.
00258          It also supports the following format: <literal>%[n]q</literal> - fractions of a second,
00259          with leading zeros.</para>
00260          <para>Example: <literal>%3q</literal> will give milliseconds and <literal>%1q</literal>
00261          will give tenths of a second. The default is set at milliseconds (n=3).
00262          The common case is to use it in combination with %S, as in <literal>%S.%3q</literal>.</para>
00263       </description>
00264       <see-also>
00265          <ref type="manpage">strftime(3)</ref>
00266       </see-also>
00267    </function>
00268    <function name="EVAL" language="en_US">
00269       <synopsis>
00270          Evaluate stored variables
00271       </synopsis>
00272       <syntax>
00273          <parameter name="variable" required="true" />
00274       </syntax>
00275       <description>
00276          <para>Using EVAL basically causes a string to be evaluated twice.
00277          When a variable or expression is in the dialplan, it will be
00278          evaluated at runtime. However, if the results of the evaluation
00279          is in fact another variable or expression, using EVAL will have it
00280          evaluated a second time.</para>
00281          <para>Example: If the <variable>MYVAR</variable> contains
00282          <variable>OTHERVAR</variable>, then the result of ${EVAL(
00283          <variable>MYVAR</variable>)} in the dialplan will be the
00284          contents of <variable>OTHERVAR</variable>. Normally just
00285          putting <variable>MYVAR</variable> in the dialplan the result
00286          would be <variable>OTHERVAR</variable>.</para>
00287       </description>
00288    </function>
00289    <function name="TOUPPER" language="en_US">
00290       <synopsis>
00291          Convert string to all uppercase letters.
00292       </synopsis>
00293       <syntax>
00294          <parameter name="string" required="true" />
00295       </syntax>
00296       <description>
00297          <para>Example: ${TOUPPER(Example)} returns "EXAMPLE"</para>
00298       </description>
00299    </function>
00300    <function name="TOLOWER" language="en_US">
00301       <synopsis>
00302          Convert string to all lowercase letters.
00303       </synopsis>
00304       <syntax>
00305          <parameter name="string" required="true" />
00306       </syntax>
00307       <description>
00308          <para>Example: ${TOLOWER(Example)} returns "example"</para>
00309       </description>
00310    </function>
00311    <function name="LEN" language="en_US">
00312       <synopsis>
00313          Return the length of the string given.
00314       </synopsis>
00315       <syntax>
00316          <parameter name="string" required="true" />
00317       </syntax>
00318       <description>
00319          <para>Example: ${LEN(example)} returns 7</para>
00320       </description>
00321    </function>
00322    <function name="QUOTE" language="en_US">
00323       <synopsis>
00324          Quotes a given string, escaping embedded quotes as necessary
00325       </synopsis>
00326       <syntax>
00327          <parameter name="string" required="true" />
00328       </syntax>
00329       <description>
00330          <para>Example: ${QUOTE(ab"c"de)} will return "abcde"</para>
00331       </description>
00332    </function>
00333    <function name="CSV_QUOTE" language="en_US">
00334       <synopsis>
00335          Quotes a given string for use in a CSV file, escaping embedded quotes as necessary
00336       </synopsis>
00337       <syntax>
00338          <parameter name="string" required="true" />
00339       </syntax>
00340       <description>
00341          <para>Example: ${CSV_QUOTE("a,b" 123)} will return """a,b"" 123"</para>
00342       </description>
00343    </function>
00344    <function name="SHIFT" language="en_US">
00345       <synopsis>
00346          Removes and returns the first item off of a variable containing delimited text
00347       </synopsis>
00348       <syntax>
00349          <parameter name="varname" required="true" />
00350          <parameter name="delimiter" required="false" default="," />
00351       </syntax>
00352       <description>
00353          <para>Example:</para>
00354          <para>exten => s,1,Set(array=one,two,three)</para>
00355          <para>exten => s,n,While($["${SET(var=${SHIFT(array)})}" != ""])</para>
00356          <para>exten => s,n,NoOp(var is ${var})</para>
00357          <para>exten => s,n,EndWhile</para>
00358          <para>This would iterate over each value in array, left to right, and
00359             would result in NoOp(var is one), NoOp(var is two), and
00360             NoOp(var is three) being executed.
00361          </para>
00362       </description>
00363    </function> 
00364    <function name="POP" language="en_US">
00365       <synopsis>
00366          Removes and returns the last item off of a variable containing delimited text
00367       </synopsis>
00368       <syntax>
00369          <parameter name="varname" required="true" />
00370          <parameter name="delimiter" required="false" default="," />
00371       </syntax>
00372       <description>
00373          <para>Example:</para>
00374          <para>exten => s,1,Set(array=one,two,three)</para>
00375          <para>exten => s,n,While($["${SET(var=${POP(array)})}" != ""])</para>
00376          <para>exten => s,n,NoOp(var is ${var})</para>
00377          <para>exten => s,n,EndWhile</para>
00378          <para>This would iterate over each value in array, right to left, and
00379             would result in NoOp(var is three), NoOp(var is two), and
00380             NoOp(var is one) being executed.
00381          </para>
00382       </description>
00383    </function> 
00384    <function name="PUSH" language="en_US">
00385       <synopsis>
00386          Appends one or more values to the end of a variable containing delimited text
00387       </synopsis>
00388       <syntax>
00389          <parameter name="varname" required="true" />
00390          <parameter name="delimiter" required="false" default="," />
00391       </syntax>
00392       <description>
00393          <para>Example: Set(PUSH(array)=one,two,three) would append one,
00394             two, and three to the end of the values stored in the variable
00395             "array".
00396          </para>
00397       </description>
00398    </function>
00399    <function name="UNSHIFT" language="en_US">
00400       <synopsis>
00401          Inserts one or more values to the beginning of a variable containing delimited text
00402       </synopsis>
00403       <syntax>
00404          <parameter name="varname" required="true" />
00405          <parameter name="delimiter" required="false" default="," />
00406       </syntax>
00407       <description>
00408          <para>Example: Set(UNSHIFT(array)=one,two,three) would insert one,
00409             two, and three before the values stored in the variable
00410             "array".
00411          </para>
00412       </description>
00413    </function>
00414  ***/
00415 
00416 static int function_fieldqty_helper(struct ast_channel *chan, const char *cmd,
00417               char *parse, char *buf, struct ast_str **sbuf, ssize_t len)
00418 {
00419    char *varsubst;
00420    struct ast_str *str = ast_str_thread_get(&result_buf, 16);
00421    int fieldcount = 0;
00422    AST_DECLARE_APP_ARGS(args,
00423               AST_APP_ARG(varname);
00424               AST_APP_ARG(delim);
00425       );
00426    char delim[2] = "";
00427    size_t delim_used;
00428 
00429    if (!str) {
00430       return -1;
00431    }
00432 
00433    AST_STANDARD_APP_ARGS(args, parse);
00434    if (args.delim) {
00435       ast_get_encoded_char(args.delim, delim, &delim_used);
00436 
00437       varsubst = alloca(strlen(args.varname) + 4);
00438 
00439       sprintf(varsubst, "${%s}", args.varname);
00440       ast_str_substitute_variables(&str, 0, chan, varsubst);
00441       if (ast_str_strlen(str) == 0) {
00442          fieldcount = 0;
00443       } else {
00444          char *varval = ast_str_buffer(str);
00445          while (strsep(&varval, delim)) {
00446             fieldcount++;
00447          }
00448       }
00449    } else {
00450       fieldcount = 1;
00451    }
00452    if (sbuf) {
00453       ast_str_set(sbuf, len, "%d", fieldcount);
00454    } else {
00455       snprintf(buf, len, "%d", fieldcount);
00456    }
00457 
00458    return 0;
00459 }
00460 
00461 static int function_fieldqty(struct ast_channel *chan, const char *cmd,
00462               char *parse, char *buf, size_t len)
00463 {
00464    return function_fieldqty_helper(chan, cmd, parse, buf, NULL, len);
00465 }
00466 
00467 static int function_fieldqty_str(struct ast_channel *chan, const char *cmd,
00468              char *parse, struct ast_str **buf, ssize_t len)
00469 {
00470    return function_fieldqty_helper(chan, cmd, parse, NULL, buf, len);
00471 }
00472 
00473 static struct ast_custom_function fieldqty_function = {
00474    .name = "FIELDQTY",
00475    .read = function_fieldqty,
00476    .read2 = function_fieldqty_str,
00477 };
00478 
00479 static int function_fieldnum_helper(struct ast_channel *chan, const char *cmd,
00480             char *parse, char *buf, struct ast_str **sbuf, ssize_t len)
00481 {
00482    char *varsubst, *field;
00483    struct ast_str *str = ast_str_thread_get(&result_buf, 16);
00484    int fieldindex = 0, res = 0;
00485    AST_DECLARE_APP_ARGS(args,
00486       AST_APP_ARG(varname);
00487       AST_APP_ARG(delim);
00488       AST_APP_ARG(field);
00489    );
00490    char delim[2] = "";
00491    size_t delim_used;
00492 
00493    if (!str) {
00494       return -1;
00495    }
00496 
00497    AST_STANDARD_APP_ARGS(args, parse);
00498 
00499    if (args.argc < 3) {
00500       ast_log(LOG_ERROR, "Usage: FIELDNUM(<listname>,<delimiter>,<fieldvalue>)\n");
00501       res = -1;
00502    } else {
00503       varsubst = alloca(strlen(args.varname) + 4);
00504       sprintf(varsubst, "${%s}", args.varname);
00505 
00506       ast_str_substitute_variables(&str, 0, chan, varsubst);
00507 
00508       if (ast_str_strlen(str) == 0 || ast_strlen_zero(args.delim)) {
00509          fieldindex = 0;
00510       } else if (ast_get_encoded_char(args.delim, delim, &delim_used) == -1) {
00511          res = -1;
00512       } else {
00513          char *varval = ast_str_buffer(str);
00514 
00515          while ((field = strsep(&varval, delim)) != NULL) {
00516             fieldindex++;
00517 
00518             if (!strcasecmp(field, args.field)) {
00519                break;
00520             }
00521          }
00522 
00523          if (!field) {
00524             fieldindex = 0;
00525          }
00526 
00527          res = 0;
00528       }
00529    }
00530 
00531    if (sbuf) {
00532       ast_str_set(sbuf, len, "%d", fieldindex);
00533    } else {
00534       snprintf(buf, len, "%d", fieldindex);
00535    }
00536 
00537    return res;
00538 }
00539 
00540 static int function_fieldnum(struct ast_channel *chan, const char *cmd,
00541               char *parse, char *buf, size_t len)
00542 {
00543    return function_fieldnum_helper(chan, cmd, parse, buf, NULL, len);
00544 }
00545 
00546 static int function_fieldnum_str(struct ast_channel *chan, const char *cmd,
00547              char *parse, struct ast_str **buf, ssize_t len)
00548 {
00549    return function_fieldnum_helper(chan, cmd, parse, NULL, buf, len);
00550 }
00551 
00552 static struct ast_custom_function fieldnum_function = {
00553    .name = "FIELDNUM",
00554    .read = function_fieldnum,
00555    .read2 = function_fieldnum_str,
00556 };
00557 
00558 static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, struct ast_str **bufstr, ssize_t len)
00559 {
00560    AST_DECLARE_APP_ARGS(args,
00561       AST_APP_ARG(listname);
00562       AST_APP_ARG(delimiter);
00563       AST_APP_ARG(fieldvalue);
00564    );
00565    const char *ptr;
00566    struct ast_str *orig_list = ast_str_thread_get(&tmp_buf, 16);
00567    const char *begin, *cur, *next;
00568    int dlen, flen, first = 1;
00569    struct ast_str *result, **result_ptr = &result;
00570    char *delim, *varsubst;
00571 
00572    AST_STANDARD_APP_ARGS(args, parse);
00573 
00574    if (buf) {
00575       if (!(result = ast_str_thread_get(&result_buf, 16))) {
00576          return -1;
00577       }
00578    } else {
00579       /* Place the result directly into the output buffer */
00580       result_ptr = bufstr;
00581    }
00582 
00583    if (args.argc < 3) {
00584       ast_log(LOG_ERROR, "Usage: LISTFILTER(<listname>,<delimiter>,<fieldvalue>)\n");
00585       return -1;
00586    }
00587 
00588    varsubst = alloca(strlen(args.listname) + 4);
00589    sprintf(varsubst, "${%s}", args.listname);
00590 
00591    /* If we don't lock the channel, the variable could disappear out from underneath us. */
00592    if (chan) {
00593       ast_channel_lock(chan);
00594    }
00595    ast_str_substitute_variables(&orig_list, 0, chan, varsubst);
00596    if (!ast_str_strlen(orig_list)) {
00597       ast_log(LOG_ERROR, "List variable '%s' not found\n", args.listname);
00598       if (chan) {
00599          ast_channel_unlock(chan);
00600       }
00601       return -1;
00602    }
00603 
00604    /* If the string isn't there, just copy out the string and be done with it. */
00605    if (!(ptr = strstr(ast_str_buffer(orig_list), args.fieldvalue))) {
00606       if (buf) {
00607          ast_copy_string(buf, ast_str_buffer(orig_list), len);
00608       } else {
00609          ast_str_set(result_ptr, len, "%s", ast_str_buffer(orig_list));
00610       }
00611       if (chan) {
00612          ast_channel_unlock(chan);
00613       }
00614       return 0;
00615    }
00616 
00617    dlen = strlen(args.delimiter);
00618    delim = alloca(dlen + 1);
00619    ast_get_encoded_str(args.delimiter, delim, dlen + 1);
00620 
00621    if ((dlen = strlen(delim)) == 0) {
00622       delim = ",";
00623       dlen = 1;
00624    }
00625 
00626    flen = strlen(args.fieldvalue);
00627 
00628    ast_str_reset(*result_ptr);
00629    /* Enough space for any result */
00630    if (len > -1) {
00631       ast_str_make_space(result_ptr, len ? len : ast_str_strlen(orig_list) + 1);
00632    }
00633 
00634    begin = ast_str_buffer(orig_list);
00635    next = strstr(begin, delim);
00636 
00637    do {
00638       /* Find next boundary */
00639       if (next) {
00640          cur = next;
00641          next = strstr(cur + dlen, delim);
00642       } else {
00643          cur = strchr(begin + dlen, '\0');
00644       }
00645 
00646       if (flen == cur - begin && !strncmp(begin, args.fieldvalue, flen)) {
00647          /* Skip field */
00648          begin += flen + dlen;
00649       } else {
00650          /* Copy field to output */
00651          if (!first) {
00652             ast_str_append(result_ptr, len, "%s", delim);
00653          }
00654 
00655          ast_str_append_substr(result_ptr, len, begin, cur - begin);
00656          first = 0;
00657          begin = cur + dlen;
00658       }
00659    } while (*cur != '\0');
00660    if (chan) {
00661       ast_channel_unlock(chan);
00662    }
00663 
00664    if (buf) {
00665       ast_copy_string(buf, ast_str_buffer(result), len);
00666    }
00667 
00668    return 0;
00669 }
00670 
00671 static int listfilter_read(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
00672 {
00673    return listfilter(chan, cmd, parse, buf, NULL, len);
00674 }
00675 
00676 static int listfilter_read2(struct ast_channel *chan, const char *cmd, char *parse, struct ast_str **buf, ssize_t len)
00677 {
00678    return listfilter(chan, cmd, parse, NULL, buf, len);
00679 }
00680 
00681 static struct ast_custom_function listfilter_function = {
00682    .name = "LISTFILTER",
00683    .read = listfilter_read,
00684    .read2 = listfilter_read2,
00685 };
00686 
00687 static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf,
00688         size_t len)
00689 {
00690    AST_DECLARE_APP_ARGS(args,
00691               AST_APP_ARG(allowed);
00692               AST_APP_ARG(string);
00693    );
00694    char *outbuf = buf;
00695    unsigned char ac;
00696    char allowed[256] = "";
00697    size_t allowedlen = 0;
00698    int32_t bitfield[8] = { 0, }; /* 256 bits */
00699 
00700    AST_STANDARD_RAW_ARGS(args, parse);
00701 
00702    if (!args.string) {
00703       ast_log(LOG_ERROR, "Usage: FILTER(<allowed-chars>,<string>)\n");
00704       return -1;
00705    }
00706 
00707    if (args.allowed[0] == '"' && !ast_opt_dont_warn) {
00708       ast_log(LOG_WARNING, "FILTER allowed characters includes the quote (\") character.  This may not be what you want.\n");
00709    }
00710 
00711    /* Expand ranges */
00712    for (; *(args.allowed);) {
00713       char c1 = 0, c2 = 0;
00714       size_t consumed = 0;
00715 
00716       if (ast_get_encoded_char(args.allowed, &c1, &consumed))
00717          return -1;
00718       args.allowed += consumed;
00719 
00720       if (*(args.allowed) == '-') {
00721          if (ast_get_encoded_char(args.allowed + 1, &c2, &consumed))
00722             c2 = c1;
00723          args.allowed += consumed + 1;
00724 
00725          if ((unsigned char) c2 < (unsigned char) c1 && !ast_opt_dont_warn) {
00726             ast_log(LOG_WARNING, "Range wrapping in FILTER(%s,%s).  This may not be what you want.\n", parse, args.string);
00727          }
00728 
00729          /*!\note
00730           * Looks a little strange, until you realize that we can overflow
00731           * the size of a char.
00732           */
00733          for (ac = (unsigned char) c1; ac != (unsigned char) c2; ac++) {
00734             bitfield[ac / 32] |= 1 << (ac % 32);
00735          }
00736          bitfield[ac / 32] |= 1 << (ac % 32);
00737 
00738          ast_debug(4, "c1=%d, c2=%d\n", c1, c2);
00739       } else {
00740          ac = (unsigned char) c1;
00741          ast_debug(4, "c1=%d, consumed=%d, args.allowed=%s\n", c1, (int) consumed, args.allowed - consumed);
00742          bitfield[ac / 32] |= 1 << (ac % 32);
00743       }
00744    }
00745 
00746    for (ac = 1; ac != 0; ac++) {
00747       if (bitfield[ac / 32] & (1 << (ac % 32))) {
00748          allowed[allowedlen++] = ac;
00749       }
00750    }
00751 
00752    ast_debug(1, "Allowed: %s\n", allowed);
00753 
00754    for (; *(args.string) && (buf + len - 1 > outbuf); (args.string)++) {
00755       if (strchr(allowed, *(args.string)))
00756          *outbuf++ = *(args.string);
00757    }
00758    *outbuf = '\0';
00759 
00760    return 0;
00761 }
00762 
00763 static struct ast_custom_function filter_function = {
00764    .name = "FILTER",
00765    .read = filter,
00766 };
00767 
00768 static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
00769 {
00770    AST_DECLARE_APP_ARGS(args,
00771       AST_APP_ARG(varname);
00772       AST_APP_ARG(find);
00773       AST_APP_ARG(replace);
00774    );
00775    char *strptr, *varsubst;
00776    struct ast_str *str = ast_str_thread_get(&result_buf, 16);
00777    char find[256]; /* Only 256 characters possible */
00778    char replace[2] = "";
00779    size_t unused;
00780 
00781    AST_STANDARD_APP_ARGS(args, data);
00782 
00783    if (!str) {
00784       return -1;
00785    }
00786 
00787    if (args.argc < 2) {
00788       ast_log(LOG_ERROR, "Usage: %s(<varname>,<search-chars>[,<replace-char>])\n", cmd);
00789       return -1;
00790    }
00791 
00792    /* Decode escapes */
00793    ast_get_encoded_str(args.find, find, sizeof(find));
00794    ast_get_encoded_char(args.replace, replace, &unused);
00795 
00796    if (ast_strlen_zero(find) || ast_strlen_zero(args.varname)) {
00797       ast_log(LOG_ERROR, "The characters to search for and the variable name must not be empty.\n");
00798       return -1;
00799    }
00800 
00801    varsubst = alloca(strlen(args.varname) + 4);
00802    sprintf(varsubst, "${%s}", args.varname);
00803    ast_str_substitute_variables(&str, 0, chan, varsubst);
00804 
00805    if (!ast_str_strlen(str)) {
00806       /* Blank, nothing to replace */
00807       return -1;
00808    }
00809 
00810    ast_debug(3, "String to search: (%s)\n", ast_str_buffer(str));
00811    ast_debug(3, "Characters to find: (%s)\n", find);
00812    ast_debug(3, "Character to replace with: (%s)\n", replace);
00813 
00814    for (strptr = ast_str_buffer(str); *strptr; strptr++) {
00815       /* buf is already a mutable buffer, so we construct the result
00816        * directly there */
00817       if (strchr(find, *strptr)) {
00818          if (ast_strlen_zero(replace)) {
00819             /* Remove character */
00820             strcpy(strptr, strptr + 1); /* SAFE */
00821             strptr--;
00822          } else {
00823             /* Replace character */
00824             *strptr = *replace;
00825          }
00826       }
00827    }
00828 
00829    ast_str_set(buf, len, "%s", ast_str_buffer(str));
00830    return 0;
00831 }
00832 
00833 static struct ast_custom_function replace_function = {
00834    .name = "REPLACE",
00835    .read2 = replace,
00836 };
00837 
00838 static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf,
00839        size_t len)
00840 {
00841    AST_DECLARE_APP_ARGS(args,
00842               AST_APP_ARG(null);
00843               AST_APP_ARG(reg);
00844               AST_APP_ARG(str);
00845    );
00846    int errcode;
00847    regex_t regexbuf;
00848 
00849    buf[0] = '\0';
00850 
00851    AST_NONSTANDARD_APP_ARGS(args, parse, '"');
00852 
00853    if (args.argc != 3) {
00854       ast_log(LOG_ERROR, "Unexpected arguments: should have been in the form '\"<regex>\" <string>'\n");
00855       return -1;
00856    }
00857    if ((*args.str == ' ') || (*args.str == '\t'))
00858       args.str++;
00859 
00860    ast_debug(1, "FUNCTION REGEX (%s)(%s)\n", args.reg, args.str);
00861 
00862    if ((errcode = regcomp(&regexbuf, args.reg, REG_EXTENDED | REG_NOSUB))) {
00863       regerror(errcode, &regexbuf, buf, len);
00864       ast_log(LOG_WARNING, "Malformed input %s(%s): %s\n", cmd, parse, buf);
00865       return -1;
00866    }
00867    
00868    strcpy(buf, regexec(&regexbuf, args.str, 0, NULL, 0) ? "0" : "1");
00869 
00870    regfree(&regexbuf);
00871 
00872    return 0;
00873 }
00874 
00875 static struct ast_custom_function regex_function = {
00876    .name = "REGEX",
00877    .read = regex,
00878 };
00879 
00880 #define HASH_PREFIX  "~HASH~%s~"
00881 #define HASH_FORMAT  HASH_PREFIX "%s~"
00882 
00883 static char *app_clearhash = "ClearHash";
00884 
00885 /* This function probably should migrate to main/pbx.c, as pbx_builtin_clearvar_prefix() */
00886 static void clearvar_prefix(struct ast_channel *chan, const char *prefix)
00887 {
00888    struct ast_var_t *var;
00889    int len = strlen(prefix);
00890    AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->varshead, var, entries) {
00891       if (strncasecmp(prefix, ast_var_name(var), len) == 0) {
00892          AST_LIST_REMOVE_CURRENT(entries);
00893          ast_free(var);
00894       }
00895    }
00896    AST_LIST_TRAVERSE_SAFE_END
00897 }
00898 
00899 static int exec_clearhash(struct ast_channel *chan, const char *data)
00900 {
00901    char prefix[80];
00902    snprintf(prefix, sizeof(prefix), HASH_PREFIX, data ? (char *)data : "null");
00903    clearvar_prefix(chan, prefix);
00904    return 0;
00905 }
00906 
00907 static int array(struct ast_channel *chan, const char *cmd, char *var,
00908        const char *value)
00909 {
00910    AST_DECLARE_APP_ARGS(arg1,
00911               AST_APP_ARG(var)[100];
00912    );
00913    AST_DECLARE_APP_ARGS(arg2,
00914               AST_APP_ARG(val)[100];
00915    );
00916    char *origvar = "", *value2, varname[256];
00917    int i, ishash = 0;
00918 
00919    value2 = ast_strdupa(value);
00920    if (!var || !value2)
00921       return -1;
00922 
00923    if (!strcmp(cmd, "HASH")) {
00924       const char *var2 = pbx_builtin_getvar_helper(chan, "~ODBCFIELDS~");
00925       origvar = var;
00926       if (var2)
00927          var = ast_strdupa(var2);
00928       else {
00929          if (chan)
00930             ast_autoservice_stop(chan);
00931          return -1;
00932       }
00933       ishash = 1;
00934    }
00935 
00936    /* The functions this will generally be used with are SORT and ODBC_*, which
00937     * both return comma-delimited lists.  However, if somebody uses literal lists,
00938     * their commas will be translated to vertical bars by the load, and I don't
00939     * want them to be surprised by the result.  Hence, we prefer commas as the
00940     * delimiter, but we'll fall back to vertical bars if commas aren't found.
00941     */
00942    ast_debug(1, "array (%s=%s)\n", var, S_OR(value2, ""));
00943    AST_STANDARD_APP_ARGS(arg1, var);
00944 
00945    AST_STANDARD_APP_ARGS(arg2, value2);
00946 
00947    for (i = 0; i < arg1.argc; i++) {
00948       ast_debug(1, "array set value (%s=%s)\n", arg1.var[i],
00949             S_OR(arg2.val[i], ""));
00950       if (i < arg2.argc) {
00951          if (ishash) {
00952             if (origvar[0] == '_') {
00953                if (origvar[1] == '_') {
00954                   snprintf(varname, sizeof(varname), "__" HASH_FORMAT, origvar + 2, arg1.var[i]);
00955                } else {
00956                   snprintf(varname, sizeof(varname), "_" HASH_FORMAT, origvar + 1, arg1.var[i]);
00957                }
00958             } else {
00959                snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
00960             }
00961 
00962             pbx_builtin_setvar_helper(chan, varname, arg2.val[i]);
00963          } else {
00964             pbx_builtin_setvar_helper(chan, arg1.var[i], arg2.val[i]);
00965          }
00966       } else {
00967          /* We could unset the variable, by passing a NULL, but due to
00968           * pushvar semantics, that could create some undesired behavior. */
00969          if (ishash) {
00970             snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
00971             pbx_builtin_setvar_helper(chan, varname, "");
00972          } else {
00973             pbx_builtin_setvar_helper(chan, arg1.var[i], "");
00974          }
00975       }
00976    }
00977 
00978    return 0;
00979 }
00980 
00981 static int hashkeys_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00982 {
00983    struct ast_var_t *newvar;
00984    struct ast_str *prefix = ast_str_alloca(80);
00985 
00986    ast_str_set(&prefix, -1, HASH_PREFIX, data);
00987    memset(buf, 0, len);
00988 
00989    AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) {
00990       if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
00991          /* Copy everything after the prefix */
00992          strncat(buf, ast_var_name(newvar) + ast_str_strlen(prefix), len - strlen(buf) - 1);
00993          /* Trim the trailing ~ */
00994          buf[strlen(buf) - 1] = ',';
00995       }
00996    }
00997    /* Trim the trailing comma */
00998    buf[strlen(buf) - 1] = '\0';
00999    return 0;
01000 }
01001 
01002 static int hashkeys_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
01003 {
01004    struct ast_var_t *newvar;
01005    struct ast_str *prefix = ast_str_alloca(80);
01006    char *tmp;
01007 
01008    ast_str_set(&prefix, -1, HASH_PREFIX, data);
01009 
01010    AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) {
01011       if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
01012          /* Copy everything after the prefix */
01013          ast_str_append(buf, len, "%s", ast_var_name(newvar) + ast_str_strlen(prefix));
01014          /* Trim the trailing ~ */
01015          tmp = ast_str_buffer(*buf);
01016          tmp[ast_str_strlen(*buf) - 1] = ',';
01017       }
01018    }
01019    /* Trim the trailing comma */
01020    tmp = ast_str_buffer(*buf);
01021    tmp[ast_str_strlen(*buf) - 1] = '\0';
01022    return 0;
01023 }
01024 
01025 static int hash_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
01026 {
01027    char varname[256];
01028    AST_DECLARE_APP_ARGS(arg,
01029       AST_APP_ARG(hashname);
01030       AST_APP_ARG(hashkey);
01031    );
01032 
01033    if (!strchr(var, ',')) {
01034       /* Single argument version */
01035       return array(chan, "HASH", var, value);
01036    }
01037 
01038    AST_STANDARD_APP_ARGS(arg, var);
01039    if (arg.hashname[0] == '_') {
01040       if (arg.hashname[1] == '_') {
01041          snprintf(varname, sizeof(varname), "__" HASH_FORMAT, arg.hashname + 2, arg.hashkey);
01042       } else {
01043          snprintf(varname, sizeof(varname), "_" HASH_FORMAT, arg.hashname + 1, arg.hashkey);
01044       }
01045    } else {
01046       snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
01047    }
01048    pbx_builtin_setvar_helper(chan, varname, value);
01049 
01050    return 0;
01051 }
01052 
01053 static int hash_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
01054 {
01055    char varname[256];
01056    const char *varvalue;
01057    AST_DECLARE_APP_ARGS(arg,
01058       AST_APP_ARG(hashname);
01059       AST_APP_ARG(hashkey);
01060    );
01061 
01062    AST_STANDARD_APP_ARGS(arg, data);
01063    if (arg.argc == 2) {
01064       snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
01065       varvalue = pbx_builtin_getvar_helper(chan, varname);
01066       if (varvalue)
01067          ast_copy_string(buf, varvalue, len);
01068       else
01069          *buf = '\0';
01070    } else if (arg.argc == 1) {
01071       char colnames[4096];
01072       int i;
01073       AST_DECLARE_APP_ARGS(arg2,
01074          AST_APP_ARG(col)[100];
01075       );
01076 
01077       /* Get column names, in no particular order */
01078       hashkeys_read(chan, "HASHKEYS", arg.hashname, colnames, sizeof(colnames));
01079       pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames);
01080 
01081       AST_STANDARD_APP_ARGS(arg2, colnames);
01082       *buf = '\0';
01083 
01084       /* Now get the corresponding column values, in exactly the same order */
01085       for (i = 0; i < arg2.argc; i++) {
01086          snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg2.col[i]);
01087          varvalue = pbx_builtin_getvar_helper(chan, varname);
01088          strncat(buf, varvalue, len - strlen(buf) - 1);
01089          strncat(buf, ",", len - strlen(buf) - 1);
01090       }
01091 
01092       /* Strip trailing comma */
01093       buf[strlen(buf) - 1] = '\0';
01094    }
01095 
01096    return 0;
01097 }
01098 
01099 static struct ast_custom_function hash_function = {
01100    .name = "HASH",
01101    .write = hash_write,
01102    .read = hash_read,
01103 };
01104 
01105 static struct ast_custom_function hashkeys_function = {
01106    .name = "HASHKEYS",
01107    .read = hashkeys_read,
01108    .read2 = hashkeys_read2,
01109 };
01110 
01111 static struct ast_custom_function array_function = {
01112    .name = "ARRAY",
01113    .write = array,
01114 };
01115 
01116 static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
01117 {
01118    char *bufptr = buf, *dataptr = data;
01119 
01120    if (len < 3){ /* at least two for quotes and one for binary zero */
01121       ast_log(LOG_ERROR, "Not enough buffer");
01122       return -1;
01123    }
01124 
01125    if (ast_strlen_zero(data)) {
01126       ast_log(LOG_WARNING, "No argument specified!\n");
01127       ast_copy_string(buf, "\"\"", len);
01128       return 0;
01129    }
01130 
01131    *bufptr++ = '"';
01132    for (; bufptr < buf + len - 3; dataptr++) {
01133       if (*dataptr == '\\') {
01134          *bufptr++ = '\\';
01135          *bufptr++ = '\\';
01136       } else if (*dataptr == '"') {
01137          *bufptr++ = '\\';
01138          *bufptr++ = '"';
01139       } else if (*dataptr == '\0') {
01140          break;
01141       } else {
01142          *bufptr++ = *dataptr;
01143       }
01144    }
01145    *bufptr++ = '"';
01146    *bufptr = '\0';
01147    return 0;
01148 }
01149 
01150 static struct ast_custom_function quote_function = {
01151    .name = "QUOTE",
01152    .read = quote,
01153 };
01154 
01155 static int csv_quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
01156 {
01157    char *bufptr = buf, *dataptr = data;
01158 
01159    if (len < 3) { /* at least two for quotes and one for binary zero */
01160       ast_log(LOG_ERROR, "Not enough buffer");
01161       return -1;
01162    }
01163 
01164    if (ast_strlen_zero(data)) {
01165       ast_copy_string(buf, "\"\"", len);
01166       return 0;
01167    }
01168 
01169    *bufptr++ = '"';
01170    for (; bufptr < buf + len - 3; dataptr++){
01171       if (*dataptr == '"') {
01172          *bufptr++ = '"';
01173          *bufptr++ = '"';
01174       } else if (*dataptr == '\0') {
01175          break;
01176       } else {
01177          *bufptr++ = *dataptr;
01178       }
01179    }
01180    *bufptr++ = '"';
01181    *bufptr='\0';
01182    return 0;
01183 }
01184 
01185 static struct ast_custom_function csv_quote_function = {
01186    .name = "CSV_QUOTE",
01187    .read = csv_quote,
01188 };
01189 
01190 static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
01191 {
01192    int length = 0;
01193 
01194    if (data)
01195       length = strlen(data);
01196 
01197    snprintf(buf, buflen, "%d", length);
01198 
01199    return 0;
01200 }
01201 
01202 static struct ast_custom_function len_function = {
01203    .name = "LEN",
01204    .read = len,
01205    .read_max = 12,
01206 };
01207 
01208 static int acf_strftime(struct ast_channel *chan, const char *cmd, char *parse,
01209          char *buf, size_t buflen)
01210 {
01211    AST_DECLARE_APP_ARGS(args,
01212               AST_APP_ARG(epoch);
01213               AST_APP_ARG(timezone);
01214               AST_APP_ARG(format);
01215    );
01216    struct timeval when;
01217    struct ast_tm tm;
01218 
01219    buf[0] = '\0';
01220 
01221    AST_STANDARD_APP_ARGS(args, parse);
01222 
01223    ast_get_timeval(args.epoch, &when, ast_tvnow(), NULL);
01224    ast_localtime(&when, &tm, args.timezone);
01225 
01226    if (!args.format)
01227       args.format = "%c";
01228 
01229    if (ast_strftime(buf, buflen, args.format, &tm) <= 0)
01230       ast_log(LOG_WARNING, "C function strftime() output nothing?!!\n");
01231 
01232    buf[buflen - 1] = '\0';
01233 
01234    return 0;
01235 }
01236 
01237 static struct ast_custom_function strftime_function = {
01238    .name = "STRFTIME",
01239    .read = acf_strftime,
01240 };
01241 
01242 static int acf_strptime(struct ast_channel *chan, const char *cmd, char *data,
01243          char *buf, size_t buflen)
01244 {
01245    AST_DECLARE_APP_ARGS(args,
01246               AST_APP_ARG(timestring);
01247               AST_APP_ARG(timezone);
01248               AST_APP_ARG(format);
01249    );
01250    struct ast_tm tm;
01251 
01252    buf[0] = '\0';
01253 
01254    if (!data) {
01255       ast_log(LOG_ERROR,
01256             "Asterisk function STRPTIME() requires an argument.\n");
01257       return -1;
01258    }
01259 
01260    AST_STANDARD_APP_ARGS(args, data);
01261 
01262    if (ast_strlen_zero(args.format)) {
01263       ast_log(LOG_ERROR,
01264             "No format supplied to STRPTIME(<timestring>,<timezone>,<format>)");
01265       return -1;
01266    }
01267 
01268    if (!ast_strptime(args.timestring, args.format, &tm)) {
01269       ast_log(LOG_WARNING, "STRPTIME() found no time specified within the string\n");
01270    } else {
01271       struct timeval when;
01272       when = ast_mktime(&tm, args.timezone);
01273       snprintf(buf, buflen, "%d", (int) when.tv_sec);
01274    }
01275 
01276    return 0;
01277 }
01278 
01279 static struct ast_custom_function strptime_function = {
01280    .name = "STRPTIME",
01281    .read = acf_strptime,
01282 };
01283 
01284 static int function_eval(struct ast_channel *chan, const char *cmd, char *data,
01285           char *buf, size_t buflen)
01286 {
01287    if (ast_strlen_zero(data)) {
01288       ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
01289       return -1;
01290    }
01291 
01292    pbx_substitute_variables_helper(chan, data, buf, buflen - 1);
01293 
01294    return 0;
01295 }
01296 
01297 static int function_eval2(struct ast_channel *chan, const char *cmd, char *data,
01298           struct ast_str **buf, ssize_t buflen)
01299 {
01300    if (ast_strlen_zero(data)) {
01301       ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
01302       return -1;
01303    }
01304 
01305    ast_str_substitute_variables(buf, buflen, chan, data);
01306 
01307    return 0;
01308 }
01309 
01310 static struct ast_custom_function eval_function = {
01311    .name = "EVAL",
01312    .read = function_eval,
01313    .read2 = function_eval2,
01314 };
01315 
01316 static int keypadhash(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
01317 {
01318    char *bufptr, *dataptr;
01319 
01320    for (bufptr = buf, dataptr = data; bufptr < buf + buflen - 1; dataptr++) {
01321       if (*dataptr == '\0') {
01322          *bufptr++ = '\0';
01323          break;
01324       } else if (*dataptr == '1') {
01325          *bufptr++ = '1';
01326       } else if (strchr("AaBbCc2", *dataptr)) {
01327          *bufptr++ = '2';
01328       } else if (strchr("DdEeFf3", *dataptr)) {
01329          *bufptr++ = '3';
01330       } else if (strchr("GgHhIi4", *dataptr)) {
01331          *bufptr++ = '4';
01332       } else if (strchr("JjKkLl5", *dataptr)) {
01333          *bufptr++ = '5';
01334       } else if (strchr("MmNnOo6", *dataptr)) {
01335          *bufptr++ = '6';
01336       } else if (strchr("PpQqRrSs7", *dataptr)) {
01337          *bufptr++ = '7';
01338       } else if (strchr("TtUuVv8", *dataptr)) {
01339          *bufptr++ = '8';
01340       } else if (strchr("WwXxYyZz9", *dataptr)) {
01341          *bufptr++ = '9';
01342       } else if (*dataptr == '0') {
01343          *bufptr++ = '0';
01344       }
01345    }
01346    buf[buflen - 1] = '\0';
01347 
01348    return 0;
01349 }
01350 
01351 static struct ast_custom_function keypadhash_function = {
01352    .name = "KEYPADHASH",
01353    .read = keypadhash,
01354 };
01355 
01356 static int string_toupper(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
01357 {
01358    char *bufptr = buf, *dataptr = data;
01359 
01360    while ((bufptr < buf + buflen - 1) && (*bufptr++ = toupper(*dataptr++)));
01361 
01362    return 0;
01363 }
01364 
01365 static int string_toupper2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
01366 {
01367    char *bufptr, *dataptr = data;
01368 
01369    if (buflen > -1) {
01370       ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
01371    }
01372    bufptr = ast_str_buffer(*buf);
01373    while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = toupper(*dataptr++)));
01374    ast_str_update(*buf);
01375 
01376    return 0;
01377 }
01378 
01379 static struct ast_custom_function toupper_function = {
01380    .name = "TOUPPER",
01381    .read = string_toupper,
01382    .read2 = string_toupper2,
01383 };
01384 
01385 static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
01386 {
01387    char *bufptr = buf, *dataptr = data;
01388 
01389    while ((bufptr < buf + buflen - 1) && (*bufptr++ = tolower(*dataptr++)));
01390 
01391    return 0;
01392 }
01393 
01394 static int string_tolower2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
01395 {
01396    char *bufptr, *dataptr = data;
01397 
01398    if (buflen > -1) {
01399       ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
01400    }
01401    bufptr = ast_str_buffer(*buf);
01402    while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = tolower(*dataptr++)));
01403    ast_str_update(*buf);
01404 
01405    return 0;
01406 }
01407 
01408 static struct ast_custom_function tolower_function = {
01409    .name = "TOLOWER",
01410    .read = string_tolower,
01411    .read2 = string_tolower2,
01412 };
01413 
01414 static int shift_pop(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
01415 {
01416 #define beginning (cmd[0] == 'S') /* SHIFT */
01417    char *after, delimiter[2] = ",", *varsubst;
01418    size_t unused;
01419    struct ast_str *before = ast_str_thread_get(&result_buf, 16);
01420    char *(*search_func)(const char *s, int c) = (beginning ? strchr : strrchr);
01421    AST_DECLARE_APP_ARGS(args,
01422       AST_APP_ARG(var);
01423       AST_APP_ARG(delimiter);
01424    );
01425 
01426    if (!before) {
01427       return -1;
01428    }
01429 
01430    AST_STANDARD_APP_ARGS(args, data);
01431 
01432    if (ast_strlen_zero(args.var)) {
01433       ast_log(LOG_WARNING, "%s requires a variable name\n", cmd);
01434       return -1;
01435    }
01436 
01437    varsubst = alloca(strlen(args.var) + 4);
01438    sprintf(varsubst, "${%s}", args.var);
01439    ast_str_substitute_variables(&before, 0, chan, varsubst);
01440 
01441    if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
01442       ast_get_encoded_char(args.delimiter, delimiter, &unused);
01443    }
01444 
01445    if (!ast_str_strlen(before)) {
01446       /* Nothing to pop */
01447       return -1;
01448    }
01449 
01450    if (!(after = search_func(ast_str_buffer(before), delimiter[0]))) {
01451       /* Only one entry in array */
01452       ast_str_set(buf, len, "%s", ast_str_buffer(before));
01453       pbx_builtin_setvar_helper(chan, args.var, "");
01454    } else {
01455       *after++ = '\0';
01456       ast_str_set(buf, len, "%s", beginning ? ast_str_buffer(before) : after);
01457       pbx_builtin_setvar_helper(chan, args.var, beginning ? after : ast_str_buffer(before));
01458    }
01459 
01460    return 0;
01461 #undef beginning
01462 }
01463 
01464 static struct ast_custom_function shift_function = {
01465    .name = "SHIFT",
01466    .read2 = shift_pop,
01467 };
01468 
01469 static struct ast_custom_function pop_function = {
01470    .name = "POP",
01471    .read2 = shift_pop,
01472 };
01473 
01474 static int unshift_push(struct ast_channel *chan, const char *cmd, char *data, const char *new_value)
01475 {
01476 #define beginning (cmd[0] == 'U') /* UNSHIFT */
01477    char delimiter[2] = ",", *varsubst;
01478    size_t unused;
01479    struct ast_str *buf, *previous_value;
01480    AST_DECLARE_APP_ARGS(args,
01481       AST_APP_ARG(var);
01482       AST_APP_ARG(delimiter);
01483    );
01484 
01485    if (!(buf = ast_str_thread_get(&result_buf, 16)) ||
01486       !(previous_value = ast_str_thread_get(&tmp_buf, 16))) {
01487       return -1;
01488    }
01489 
01490    AST_STANDARD_APP_ARGS(args, data);
01491 
01492    if (ast_strlen_zero(args.var)) {
01493       ast_log(LOG_WARNING, "%s requires a variable name\n", cmd);
01494       return -1;
01495    }
01496 
01497    if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
01498       ast_get_encoded_char(args.delimiter, delimiter, &unused);
01499    }
01500 
01501    varsubst = alloca(strlen(args.var) + 4);
01502    sprintf(varsubst, "${%s}", args.var);
01503    ast_str_substitute_variables(&previous_value, 0, chan, varsubst);
01504 
01505    if (!ast_str_strlen(previous_value)) {
01506       ast_str_set(&buf, 0, "%s", new_value);
01507    } else {
01508       ast_str_set(&buf, 0, "%s%c%s",
01509          beginning ? new_value : ast_str_buffer(previous_value),
01510          delimiter[0],
01511          beginning ? ast_str_buffer(previous_value) : new_value);
01512    }
01513 
01514    pbx_builtin_setvar_helper(chan, args.var, ast_str_buffer(buf));
01515 
01516    return 0;
01517 #undef beginning
01518 }
01519 
01520 static struct ast_custom_function push_function = {
01521    .name = "PUSH",
01522    .write = unshift_push,
01523 };
01524 
01525 static struct ast_custom_function unshift_function = {
01526    .name = "UNSHIFT",
01527    .write = unshift_push,
01528 };
01529 
01530 static int passthru(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
01531 {
01532    ast_str_set(buf, len, "%s", data);
01533    return 0;
01534 }
01535 
01536 static struct ast_custom_function passthru_function = {
01537    .name = "PASSTHRU",
01538    .read2 = passthru,
01539 };
01540 
01541 #ifdef TEST_FRAMEWORK
01542 AST_TEST_DEFINE(test_FIELDNUM)
01543 {
01544    int i, res = AST_TEST_PASS;
01545    struct ast_channel *chan;
01546    struct ast_str *str;
01547    char expression[256];
01548    struct {
01549       const char *fields;
01550       const char *delim;
01551       const char *field;
01552       const char *expected;
01553    } test_args[] = {
01554       {"abc,def,ghi,jkl", "\\,",     "ghi", "3"},
01555       {"abc def ghi jkl", " ",       "abc", "1"},
01556       {"abc/def/ghi/jkl", "\\\\x2f", "def", "2"},
01557       {"abc$def$ghi$jkl", "",        "ghi", "0"},
01558       {"abc,def,ghi,jkl", "-",       "",    "0"},
01559       {"abc-def-ghi-jkl", "-",       "mno", "0"}
01560    };
01561 
01562    switch (cmd) {
01563    case TEST_INIT:
01564       info->name = "func_FIELDNUM_test";
01565       info->category = "/funcs/func_strings/";
01566       info->summary = "Test FIELDNUM function";
01567       info->description = "Verify FIELDNUM behavior";
01568       return AST_TEST_NOT_RUN;
01569    case TEST_EXECUTE:
01570       break;
01571    }
01572 
01573    if (!(chan = ast_dummy_channel_alloc())) {
01574       ast_test_status_update(test, "Unable to allocate dummy channel\n");
01575       return AST_TEST_FAIL;
01576    }
01577 
01578    if (!(str = ast_str_create(16))) {
01579       ast_test_status_update(test, "Unable to allocate dynamic string buffer\n");
01580       ast_channel_release(chan);
01581       return AST_TEST_FAIL;
01582    }
01583 
01584    for (i = 0; i < ARRAY_LEN(test_args); i++) {
01585       struct ast_var_t *var = ast_var_assign("FIELDS", test_args[i].fields);
01586       AST_LIST_INSERT_HEAD(&chan->varshead, var, entries);
01587 
01588       snprintf(expression, sizeof(expression), "${FIELDNUM(%s,%s,%s)}", var->name, test_args[i].delim, test_args[i].field);
01589       ast_str_substitute_variables(&str, 0, chan, expression);
01590 
01591       AST_LIST_REMOVE(&chan->varshead, var, entries);
01592       ast_var_delete(var);
01593 
01594       if (strcasecmp(ast_str_buffer(str), test_args[i].expected)) {
01595          ast_test_status_update(test, "Evaluation of '%s' returned '%s' instead of the expected value '%s'\n",
01596             expression, ast_str_buffer(str), test_args[i].expected);
01597          res = AST_TEST_FAIL;
01598          break;
01599       }
01600    }
01601 
01602    ast_free(str);
01603    ast_channel_release(chan);
01604 
01605    return res;
01606 }
01607 
01608 AST_TEST_DEFINE(test_FILTER)
01609 {
01610    int i, res = AST_TEST_PASS;
01611    const char *test_strings[][2] = {
01612       {"A-R",            "DAHDI"},
01613       {"A\\-R",          "A"},
01614       {"\\x41-R",        "DAHDI"},
01615       {"0-9A-Ca-c",      "0042133333A12212"},
01616       {"0-9a-cA-C_+\\-", "0042133333A12212"},
01617       {NULL,             NULL},
01618    };
01619 
01620    switch (cmd) {
01621    case TEST_INIT:
01622       info->name = "func_FILTER_test";
01623       info->category = "/funcs/func_strings/";
01624       info->summary = "Test FILTER function";
01625       info->description = "Verify FILTER behavior";
01626       return AST_TEST_NOT_RUN;
01627    case TEST_EXECUTE:
01628       break;
01629    }
01630 
01631    for (i = 0; test_strings[i][0]; i++) {
01632       char tmp[256], tmp2[256] = "";
01633       snprintf(tmp, sizeof(tmp), "${FILTER(%s,0042133333&DAHDI/g1/2212)}", test_strings[i][0]);
01634       pbx_substitute_variables_helper(NULL, tmp, tmp2, sizeof(tmp2) - 1);
01635       if (strcmp(test_strings[i][1], tmp2)) {
01636          ast_test_status_update(test, "Format string '%s' substituted to '%s'.  Expected '%s'.\n", test_strings[i][0], tmp2, test_strings[i][1]);
01637          res = AST_TEST_FAIL;
01638       }
01639    }
01640    return res;
01641 }
01642 #endif
01643 
01644 static int unload_module(void)
01645 {
01646    int res = 0;
01647 
01648    AST_TEST_UNREGISTER(test_FIELDNUM);
01649    AST_TEST_UNREGISTER(test_FILTER);
01650    res |= ast_custom_function_unregister(&fieldqty_function);
01651    res |= ast_custom_function_unregister(&fieldnum_function);
01652    res |= ast_custom_function_unregister(&filter_function);
01653    res |= ast_custom_function_unregister(&replace_function);
01654    res |= ast_custom_function_unregister(&listfilter_function);
01655    res |= ast_custom_function_unregister(&regex_function);
01656    res |= ast_custom_function_unregister(&array_function);
01657    res |= ast_custom_function_unregister(&quote_function);
01658    res |= ast_custom_function_unregister(&csv_quote_function);
01659    res |= ast_custom_function_unregister(&len_function);
01660    res |= ast_custom_function_unregister(&strftime_function);
01661    res |= ast_custom_function_unregister(&strptime_function);
01662    res |= ast_custom_function_unregister(&eval_function);
01663    res |= ast_custom_function_unregister(&keypadhash_function);
01664    res |= ast_custom_function_unregister(&hashkeys_function);
01665    res |= ast_custom_function_unregister(&hash_function);
01666    res |= ast_unregister_application(app_clearhash);
01667    res |= ast_custom_function_unregister(&toupper_function);
01668    res |= ast_custom_function_unregister(&tolower_function);
01669    res |= ast_custom_function_unregister(&shift_function);
01670    res |= ast_custom_function_unregister(&pop_function);
01671    res |= ast_custom_function_unregister(&push_function);
01672    res |= ast_custom_function_unregister(&unshift_function);
01673    res |= ast_custom_function_unregister(&passthru_function);
01674 
01675    return res;
01676 }
01677 
01678 static int load_module(void)
01679 {
01680    int res = 0;
01681 
01682    AST_TEST_REGISTER(test_FIELDNUM);
01683    AST_TEST_REGISTER(test_FILTER);
01684    res |= ast_custom_function_register(&fieldqty_function);
01685    res |= ast_custom_function_register(&fieldnum_function);
01686    res |= ast_custom_function_register(&filter_function);
01687    res |= ast_custom_function_register(&replace_function);
01688    res |= ast_custom_function_register(&listfilter_function);
01689    res |= ast_custom_function_register(&regex_function);
01690    res |= ast_custom_function_register(&array_function);
01691    res |= ast_custom_function_register(&quote_function);
01692    res |= ast_custom_function_register(&csv_quote_function);
01693    res |= ast_custom_function_register(&len_function);
01694    res |= ast_custom_function_register(&strftime_function);
01695    res |= ast_custom_function_register(&strptime_function);
01696    res |= ast_custom_function_register(&eval_function);
01697    res |= ast_custom_function_register(&keypadhash_function);
01698    res |= ast_custom_function_register(&hashkeys_function);
01699    res |= ast_custom_function_register(&hash_function);
01700    res |= ast_register_application_xml(app_clearhash, exec_clearhash);
01701    res |= ast_custom_function_register(&toupper_function);
01702    res |= ast_custom_function_register(&tolower_function);
01703    res |= ast_custom_function_register(&shift_function);
01704    res |= ast_custom_function_register(&pop_function);
01705    res |= ast_custom_function_register(&push_function);
01706    res |= ast_custom_function_register(&unshift_function);
01707    res |= ast_custom_function_register(&passthru_function);
01708 
01709    return res;
01710 }
01711 
01712 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "String handling dialplan functions");

Generated on Wed Apr 6 11:29:45 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7