From: Matthias Nick Date: Wed, 30 Sep 2009 20:10:02 +0000 (+0000) Subject: Merged revisions 221368 via svnmerge from X-Git-Tag: 1.6.1.7-rc2~19 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7c411eeb3916dafa881bb0a2249003e8f339bd25;p=thirdparty%2Fasterisk.git Merged revisions 221368 via svnmerge from https://origsvn.digium.com/svn/asterisk/trunk ................ r221368 | mnick | 2009-09-30 14:42:36 -0500 (Wed, 30 Sep 2009) | 23 lines Merged revisions 221153,221157,221303 via svnmerge from https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r221153 | mnick | 2009-09-30 10:37:39 -0500 (Wed, 30 Sep 2009) | 2 lines check bounds - prevents for buffer overflow ........ r221157 | mnick | 2009-09-30 10:41:46 -0500 (Wed, 30 Sep 2009) | 8 lines added a new dialplan function 'CSV_QUOTE' and changed the cdr_custom.sample.conf (closes issue #15471) Reported by: dkerr Patches: csv_quote_14.txt uploaded by mnick (license ) Tested by: mnick ........ r221303 | mnick | 2009-09-30 14:02:00 -0500 (Wed, 30 Sep 2009) | 2 lines changed the prototype definition of csv_quote ........ ................ git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.6.1@221370 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- diff --git a/configs/cdr_custom.conf.sample b/configs/cdr_custom.conf.sample index 8bc2cb34e6..999d9aa8cd 100644 --- a/configs/cdr_custom.conf.sample +++ b/configs/cdr_custom.conf.sample @@ -6,5 +6,6 @@ ; ; ;[mappings] -;Master.csv => "${CDR(clid)}","${CDR(src)}","${CDR(dst)}","${CDR(dcontext)}","${CDR(channel)}","${CDR(dstchannel)}","${CDR(lastapp)}","${CDR(lastdata)}","${CDR(start)}","${CDR(answer)}","${CDR(end)}","${CDR(duration)}","${CDR(billsec)}","${CDR(disposition)}","${CDR(amaflags)}","${CDR(accountcode)}","${CDR(uniqueid)}","${CDR(userfield)}" +;Master.csv => ${CSV_QUOTE(${CDR(clid)})},${CSV_QUOTE(${CDR(src)})},${CSV_QUOTE(${CDR(dst)})},${CSV_QUOTE(${CDR(dcontext)})},${CSV_QUOTE(${CDR(channel)})},${CSV_QUOTE(${CDR(dstchannel)})},${CSV_QUOTE(${CDR(lastapp)})},${CSV_QUOTE(${CDR(lastdata)})},${CSV_QUOTE(${CDR(start)})},${CSV_QUOTE(${CDR(answer)})},${CSV_QUOTE(${CDR(end)})},${CSV_QUOTE(${CDR(duration)})},${CSV_QUOTE(${CDR(billsec)})},${CSV_QUOTE(${CDR(disposition)})},${CSV_QUOTE(${CDR(amaflags)})},${CSV_QUOTE(${CDR(accountcode)})},${CSV_QUOTE(${CDR(uniqueid)})},${CSV_QUOTE(${CDR(userfield)})} +;Simple.csv => ${CSV_QUOTE(${EPOCH})},${CSV_QUOTE(${CDR(src)})},${CSV_QUOTE(${CDR(dst)})} diff --git a/funcs/func_strings.c b/funcs/func_strings.c index 1af4ed05fe..8d931efe63 100644 --- a/funcs/func_strings.c +++ b/funcs/func_strings.c @@ -39,6 +39,326 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/app.h" #include "asterisk/localtime.h" +AST_THREADSTORAGE(result_buf); + +/*** DOCUMENTATION + + + Count the fields with an arbitrary delimiter + + + + + + + The delimiter may be specified as a special or extended ASCII character, by encoding it. The characters + \n, \r, and \t are all recognized as the newline, + carriage return, and tab characters, respectively. Also, octal and hexadecimal specifications are recognized + by the patterns \0nnn and \xHH, respectively. For example, if you wanted + to encode a comma as the delimiter, you could use either \054 or \x2C. + Example: If ${example} contains ex-amp-le, then ${FIELDQTY(example,-)} returns 3. + + + + Remove an item from a list, by name. + + + + + + + Remove value from the list contained in the varname + variable, where the list delimiter is specified by the delim parameter. This is + very useful for removing a single channel name from a list of channels, for example. + + + + + Filter the string to include only the allowed characters + + + + + + + Permits all characters listed in allowed-chars, + filtering all others outs. In addition to literally listing the characters, + you may also use ranges of characters (delimited by a - + Hexadecimal characters started with a \x(i.e. \x20) + Octal characters started with a \0 (i.e. \040) + Also \t,\n and \r are recognized. + If you want the - character it needs to be prefixed with a + \ + + + + + Check string against a regular expression. + + + + + + + Return 1 on regular expression match or 0 otherwise + Please note that the space following the double quotes separating the + regex from the data is optional and if present, is skipped. If a space is + desired at the beginning of the data, then put two spaces there; the second + will not be skipped. + + + + + Clear the keys from a specified hashname. + + + + + + Clears all keys out of the specified hashname. + + + + + Implementation of a dialplan associative array + + + + + + + In two arguments mode, gets and sets values to corresponding keys within + a named associative array. The single-argument mode will only work when assigned + to from a function defined by func_odbc + + + + + Retrieve the keys of the HASH() function. + + + + + + Returns a comma-delimited list of the current keys of the associative array + defined by the HASH() function. Note that if you iterate over the keys of + the result, adding keys during iteration will cause the result of the HASHKEYS() + function to change. + + + + + Hash the letters in string into equivalent keypad numbers. + + + + + + Example: ${KEYPADHASH(Les)} returns "537" + + + + + Allows setting multiple variables at once. + + + + + + + + The comma-delimited list passed as a value to which the function is set will + be interpreted as a set of values to which the comma-delimited list of + variable names in the argument should be set. + Example: Set(ARRAY(var1,var2)=1,2) will set var1 to 1 and var2 to 2 + + + + + Returns the epoch of the arbitrary date/time string structured as described by the format. + + + + + + + + This is useful for converting a date into EPOCH time, + possibly to pass to an application like SayUnixTime or to calculate the difference + between the two date strings + Example: ${STRPTIME(2006-03-01 07:30:35,America/Chicago,%Y-%m-%d %H:%M:%S)} returns 1141219835 + + + + + Returns the current date/time in the specified format. + + + + + + + + STRFTIME supports all of the same formats as the underlying C function + strftime(3). + It also supports the following format: %[n]q - fractions of a second, + with leading zeros. + Example: %3q will give milliseconds and %1q + will give tenths of a second. The default is set at milliseconds (n=3). + The common case is to use it in combination with %S, as in %S.%3q. + + + strftime(3) + + + + + Evaluate stored variables + + + + + + Using EVAL basically causes a string to be evaluated twice. + When a variable or expression is in the dialplan, it will be + evaluated at runtime. However, if the results of the evaluation + is in fact another variable or expression, using EVAL will have it + evaluated a second time. + Example: If the MYVAR contains + OTHERVAR, then the result of ${EVAL( + MYVAR)} in the dialplan will be the + contents of OTHERVAR. Normally just + putting MYVAR in the dialplan the result + would be OTHERVAR. + + + + + Convert string to all uppercase letters. + + + + + + Example: ${TOUPPER(Example)} returns "EXAMPLE" + + + + + Convert string to all lowercase letters. + + + + + + Example: ${TOLOWER(Example)} returns "example" + + + + + Return the length of the string given. + + + + + + Example: ${LEN(example)} returns 7 + + + + + Quotes a given string, escaping embedded quotes as necessary + + + + + + Example: ${QUOTE(ab"c"de)} will return "abcde" + + + + + Quotes a given string for use in a CSV file, escaping embedded quotes as necessary + + + + + + Example: ${CSV_QUOTE("a,b" 123)} will return """a,b"" 123" + + + + + Removes and returns the first item off of a variable containing delimited text + + + + + + + Example: + exten => s,1,Set(array=one,two,three) + exten => s,n,While($["${SET(var=${SHIFT(array)})}" != ""]) + exten => s,n,NoOp(var is ${var}) + exten => s,n,EndWhile + This would iterate over each value in array, left to right, and + would result in NoOp(var is one), NoOp(var is two), and + NoOp(var is three) being executed. + + + + + + Removes and returns the last item off of a variable containing delimited text + + + + + + + Example: + exten => s,1,Set(array=one,two,three) + exten => s,n,While($["${SET(var=${POP(array)})}" != ""]) + exten => s,n,NoOp(var is ${var}) + exten => s,n,EndWhile + This would iterate over each value in array, right to left, and + would result in NoOp(var is three), NoOp(var is two), and + NoOp(var is one) being executed. + + + + + + Appends one or more values to the end of a variable containing delimited text + + + + + + + Example: Set(PUSH(array)=one,two,three) would append one, + two, and three to the end of the values stored in the variable + "array". + + + + + + Inserts one or more values to the beginning of a variable containing delimited text + + + + + + + Example: Set(UNSHIFT(array)=one,two,three) would insert one, + two, and three before the values stored in the variable + "array". + + + + ***/ + static int function_fieldqty(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len) { @@ -580,6 +900,12 @@ static struct ast_custom_function sprintf_function = { static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { char *bufptr = buf, *dataptr = data; + + if (len < 3){ /* at least two for quotes and one for binary zero */ + ast_log(LOG_ERROR, "Not enough buffer"); + return -1; + } + if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "No argument specified!\n"); ast_copy_string(buf, "\"\"", len); @@ -587,7 +913,7 @@ static int quote(struct ast_channel *chan, const char *cmd, char *data, char *bu } *bufptr++ = '"'; - for (; bufptr < buf + len - 1; dataptr++) { + for (; bufptr < buf + len - 3; dataptr++) { if (*dataptr == '\\') { *bufptr++ = '\\'; *bufptr++ = '\\'; @@ -612,9 +938,43 @@ static struct ast_custom_function quote_function = { .read = quote, }; +static int csv_quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) +{ + char *bufptr = buf, *dataptr = data; + + if (len < 3){ /* at least two for quotes and one for binary zero */ + ast_log(LOG_ERROR, "Not enough buffer"); + return -1; + } + + if (ast_strlen_zero(data)) { + ast_log(LOG_WARNING, "No argument specified!\n"); + ast_copy_string(buf,"\"\"",len); + return 0; + } + + *bufptr++ = '"'; + for (; bufptr < buf + len - 3; dataptr++){ + if (*dataptr == '"') { + *bufptr++ = '"'; + *bufptr++ = '"'; + } else if (*dataptr == '\0') { + break; + } else { + *bufptr++ = *dataptr; + } + } + *bufptr++ = '"'; + *bufptr='\0'; + return 0; +} + +static struct ast_custom_function csv_quote_function = { + .name = "CSV_QUOTE", + .read = csv_quote, +}; -static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, - size_t buflen) +static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen) { int length = 0; @@ -849,6 +1209,7 @@ static int unload_module(void) res |= ast_custom_function_unregister(®ex_function); res |= ast_custom_function_unregister(&array_function); res |= ast_custom_function_unregister("e_function); + res |= ast_custom_function_unregister(&csv_quote_function); res |= ast_custom_function_unregister(&len_function); res |= ast_custom_function_unregister(&strftime_function); res |= ast_custom_function_unregister(&strptime_function); @@ -873,6 +1234,7 @@ static int load_module(void) res |= ast_custom_function_register(®ex_function); res |= ast_custom_function_register(&array_function); res |= ast_custom_function_register("e_function); + res |= ast_custom_function_register(&csv_quote_function); res |= ast_custom_function_register(&len_function); res |= ast_custom_function_register(&strftime_function); res |= ast_custom_function_register(&strptime_function);