diff options
Diffstat (limited to 'funcs')
-rw-r--r-- | funcs/func_aes.c | 78 | ||||
-rw-r--r-- | funcs/func_base64.c | 50 | ||||
-rw-r--r-- | funcs/func_blacklist.c | 17 | ||||
-rw-r--r-- | funcs/func_callerid.c | 2 | ||||
-rw-r--r-- | funcs/func_curl.c | 110 | ||||
-rw-r--r-- | funcs/func_cut.c | 70 | ||||
-rw-r--r-- | funcs/func_db.c | 1 | ||||
-rw-r--r-- | funcs/func_dialplan.c | 1 | ||||
-rw-r--r-- | funcs/func_env.c | 3 | ||||
-rw-r--r-- | funcs/func_extstate.c | 1 | ||||
-rw-r--r-- | funcs/func_groupcount.c | 2 | ||||
-rw-r--r-- | funcs/func_lock.c | 3 | ||||
-rw-r--r-- | funcs/func_logic.c | 45 | ||||
-rw-r--r-- | funcs/func_md5.c | 1 | ||||
-rw-r--r-- | funcs/func_module.c | 1 | ||||
-rw-r--r-- | funcs/func_rand.c | 1 | ||||
-rw-r--r-- | funcs/func_sha1.c | 1 | ||||
-rw-r--r-- | funcs/func_speex.c | 6 | ||||
-rw-r--r-- | funcs/func_strings.c | 163 | ||||
-rw-r--r-- | funcs/func_sysinfo.c | 1 | ||||
-rw-r--r-- | funcs/func_timeout.c | 1 | ||||
-rw-r--r-- | funcs/func_vmcount.c | 1 |
22 files changed, 449 insertions, 110 deletions
diff --git a/funcs/func_aes.c b/funcs/func_aes.c index 87319fa77..770ce3ae7 100644 --- a/funcs/func_aes.c +++ b/funcs/func_aes.c @@ -31,6 +31,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/pbx.h" #include "asterisk/app.h" #include "asterisk/aes.h" +#include "asterisk/strings.h" #define AES_BLOCK_SIZE 16 @@ -71,15 +72,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") static int aes_helper(struct ast_channel *chan, const char *cmd, char *data, - char *buf, size_t len) + char *buf, struct ast_str **str, ssize_t maxlen) { unsigned char curblock[AES_BLOCK_SIZE] = { 0, }; - char *tmp; + char *tmp = NULL; char *tmpP; int data_len, encrypt; + int keylen, len, tmplen, elen = 0; ast_aes_encrypt_key ecx; /* AES 128 Encryption context */ ast_aes_decrypt_key dcx; - AST_DECLARE_APP_ARGS(args, AST_APP_ARG(key); AST_APP_ARG(data); @@ -92,22 +93,37 @@ static int aes_helper(struct ast_channel *chan, const char *cmd, char *data, return -1; } - if (strlen(args.key) != AES_BLOCK_SIZE) { /* key must be of 16 characters in length, 128 bits */ - ast_log(LOG_WARNING, "Syntax: %s(<key>,<data>) - <key> parameter must be exactly 16 characters!\n", cmd); + if ((keylen = strlen(args.key)) != AES_BLOCK_SIZE) { /* key must be of 16 characters in length, 128 bits */ + ast_log(LOG_WARNING, "Syntax: %s(<key>,<data>) - <key> parameter must be exactly 16 characters%s!\n", cmd, keylen < 16 ? " - padding" : ""); return -1; } - ast_aes_encrypt_key((unsigned char *) args.key, &ecx); /* encryption: plaintext -> encryptedtext -> base64 */ - ast_aes_decrypt_key((unsigned char *) args.key, &dcx); /* decryption: base64 -> encryptedtext -> plaintext */ - tmp = ast_calloc(1, len); /* requires a tmp buffer for the base64 decode */ - tmpP = tmp; + if (buf) { + len = maxlen; + } else if (maxlen == -1) { + len = ast_str_size(*str); + } else if (maxlen > 0) { + len = maxlen; + } else { + len = INT_MAX; + } + ast_debug(3, "len=%d\n", len); + encrypt = strcmp("AES_DECRYPT", cmd); /* -1 if encrypting, 0 if decrypting */ + /* Round up the buffer to an even multiple of 16, plus 1 */ + tmplen = (strlen(args.data) / 16 + 1) * 16 + 1; + tmp = ast_calloc(1, tmplen); + tmpP = tmp; if (encrypt) { /* if decrypting first decode src to base64 */ - ast_copy_string(tmp, args.data, len); + /* encryption: plaintext -> encryptedtext -> base64 */ + ast_aes_encrypt_key((unsigned char *) args.key, &ecx); + strcpy(tmp, args.data); data_len = strlen(tmp); } else { - data_len = ast_base64decode((unsigned char *) tmp, args.data, len); + /* decryption: base64 -> encryptedtext -> plaintext */ + ast_aes_decrypt_key((unsigned char *) args.key, &dcx); + data_len = ast_base64decode((unsigned char *) tmp, args.data, tmplen); } if (data_len >= len) { /* make sure to not go over buffer len */ @@ -116,8 +132,11 @@ static int aes_helper(struct ast_channel *chan, const char *cmd, char *data, } while (data_len > 0) { + /* Tricky operation. We first copy the data into curblock, then + * the data is encrypted or decrypted and put back into the original + * buffer. */ memset(curblock, 0, AES_BLOCK_SIZE); - memcpy(curblock, tmpP, (data_len < AES_BLOCK_SIZE) ? data_len : AES_BLOCK_SIZE); + memcpy(curblock, tmpP, AES_BLOCK_SIZE); if (encrypt) { ast_aes_encrypt(curblock, (unsigned char *) tmpP, &ecx); } else { @@ -125,26 +144,53 @@ static int aes_helper(struct ast_channel *chan, const char *cmd, char *data, } tmpP += AES_BLOCK_SIZE; data_len -= AES_BLOCK_SIZE; + elen += AES_BLOCK_SIZE; } if (encrypt) { /* if encrypting encode result to base64 */ - ast_base64encode(buf, (unsigned char *) tmp, strlen(tmp), len); + if (buf) { + ast_base64encode(buf, (unsigned char *) tmp, elen, len); + } else { + if (maxlen >= 0) { + ast_str_make_space(str, maxlen ? maxlen : elen * 4 / 3 + 2); + } + ast_base64encode(ast_str_buffer(*str), (unsigned char *) tmp, elen, ast_str_size(*str)); + ast_str_update(*str); + } } else { - memcpy(buf, tmp, len); + if (buf) { + memcpy(buf, tmp, len); + } else { + ast_str_set(str, maxlen, "%s", tmp); + } } ast_free(tmp); return 0; } +static int aes_buf_helper(struct ast_channel *chan, const char *cmd, char *data, + char *buf, size_t maxlen) +{ + return aes_helper(chan, cmd, data, buf, NULL, maxlen); +} + +static int aes_str_helper(struct ast_channel *chan, const char *cmd, char *data, + struct ast_str **buf, ssize_t maxlen) +{ + return aes_helper(chan, cmd, data, NULL, buf, maxlen); +} + static struct ast_custom_function aes_encrypt_function = { .name = "AES_ENCRYPT", - .read = aes_helper, + .read = aes_buf_helper, + .read2 = aes_str_helper, }; static struct ast_custom_function aes_decrypt_function = { .name = "AES_DECRYPT", - .read = aes_helper, + .read = aes_buf_helper, + .read2 = aes_str_helper, }; static int unload_module(void) diff --git a/funcs/func_base64.c b/funcs/func_base64.c index 28805b943..a68cf9bda 100644 --- a/funcs/func_base64.c +++ b/funcs/func_base64.c @@ -29,6 +29,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/module.h" #include "asterisk/pbx.h" /* function register/unregister */ #include "asterisk/utils.h" +#include "asterisk/strings.h" /*** DOCUMENTATION <function name="BASE64_ENCODE" language="en_US"> @@ -59,40 +60,61 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") </function> ***/ -static int base64_encode(struct ast_channel *chan, const char *cmd, char *data, - char *buf, size_t len) +static int base64_helper(struct ast_channel *chan, const char *cmd, char *data, + char *buf, struct ast_str **str, ssize_t len) { if (ast_strlen_zero(data)) { - ast_log(LOG_WARNING, "Syntax: BASE64_ENCODE(<data>) - missing argument!\n"); + ast_log(LOG_WARNING, "Syntax: %s(<data>) - missing argument!\n", cmd); return -1; } - ast_base64encode(buf, (unsigned char *) data, strlen(data), len); + if (cmd[7] == 'E') { + if (buf) { + ast_base64encode(buf, (unsigned char *) data, strlen(data), len); + } else { + if (len >= 0) { + ast_str_make_space(str, len ? len : ast_str_strlen(*str) + strlen(data) * 4 / 3 + 2); + } + ast_base64encode(ast_str_buffer(*str) + ast_str_strlen(*str), (unsigned char *) data, strlen(data), ast_str_size(*str) - ast_str_strlen(*str)); + ast_str_update(*str); + } + } else { + if (buf) { + ast_base64decode((unsigned char *) buf, data, len); + } else { + if (len >= 0) { + ast_str_make_space(str, len ? len : ast_str_strlen(*str) + strlen(data) * 3 / 4 + 2); + } + ast_base64decode((unsigned char *) ast_str_buffer(*str) + ast_str_strlen(*str), data, ast_str_size(*str) - ast_str_strlen(*str)); + ast_str_update(*str); + } + } return 0; } -static int base64_decode(struct ast_channel *chan, const char *cmd, char *data, +static int base64_buf_helper(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { - if (ast_strlen_zero(data)) { - ast_log(LOG_WARNING, "Syntax: BASE64_DECODE(<base_64 string>) - missing argument!\n"); - return -1; - } - - ast_base64decode((unsigned char *) buf, data, len); + return base64_helper(chan, cmd, data, buf, NULL, len); +} - return 0; +static int base64_str_helper(struct ast_channel *chan, const char *cmd, char *data, + struct ast_str **buf, ssize_t len) +{ + return base64_helper(chan, cmd, data, NULL, buf, len); } static struct ast_custom_function base64_encode_function = { .name = "BASE64_ENCODE", - .read = base64_encode, + .read = base64_buf_helper, + .read2 = base64_str_helper, }; static struct ast_custom_function base64_decode_function = { .name = "BASE64_DECODE", - .read = base64_decode, + .read = base64_buf_helper, + .read2 = base64_str_helper, }; static int unload_module(void) diff --git a/funcs/func_blacklist.c b/funcs/func_blacklist.c index 304ba9bdf..a765242d4 100644 --- a/funcs/func_blacklist.c +++ b/funcs/func_blacklist.c @@ -70,9 +70,26 @@ static int blacklist_read(struct ast_channel *chan, const char *cmd, char *data, return 0; } +static int blacklist_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len) +{ + /* 2 bytes is a single integer, plus terminating null */ + if (ast_str_size(*str) - ast_str_strlen(*str) < 2) { + if (len > ast_str_size(*str) || len == 0) { + ast_str_make_space(str, len ? len : ast_str_strlen(*str) + 2); + } + } + if (ast_str_size(*str) - ast_str_strlen(*str) >= 2) { + int res = blacklist_read(chan, cmd, data, ast_str_buffer(*str) + ast_str_strlen(*str), 2); + ast_str_update(*str); + return res; + } + return -1; +} + static struct ast_custom_function blacklist_function = { .name = "BLACKLIST", .read = blacklist_read, + .read2 = blacklist_read2, }; static int unload_module(void) diff --git a/funcs/func_callerid.c b/funcs/func_callerid.c index 8bce770a2..3968e9438 100644 --- a/funcs/func_callerid.c +++ b/funcs/func_callerid.c @@ -274,12 +274,14 @@ static int callerid_write(struct ast_channel *chan, const char *cmd, char *data, static struct ast_custom_function callerid_function = { .name = "CALLERID", .read = callerid_read, + .read_max = 256, .write = callerid_write, }; static struct ast_custom_function callerpres_function = { .name = "CALLERPRES", .read = callerpres_read, + .read_max = 50, .write = callerpres_write, }; diff --git a/funcs/func_curl.c b/funcs/func_curl.c index d4f34b850..b7918836d 100644 --- a/funcs/func_curl.c +++ b/funcs/func_curl.c @@ -276,7 +276,7 @@ yuck: return 0; } -static int acf_curlopt_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) +static int acf_curlopt_helper(struct ast_channel *chan, const char *cmd, char *data, char *buf, struct ast_str **bufstr, ssize_t len) { struct ast_datastore *store; struct global_curl_info *list[2] = { &global_curl_info, NULL }; @@ -303,38 +303,78 @@ static int acf_curlopt_read(struct ast_channel *chan, const char *cmd, char *dat AST_LIST_TRAVERSE(list[i], cur, list) { if (cur->key == key) { if (ot == OT_BOOLEAN || ot == OT_INTEGER) { - snprintf(buf, len, "%ld", (long)cur->value); + if (buf) { + snprintf(buf, len, "%ld", (long) cur->value); + } else { + ast_str_set(bufstr, len, "%ld", (long) cur->value); + } } else if (ot == OT_INTEGER_MS) { - if ((long)cur->value % 1000 == 0) { - snprintf(buf, len, "%ld", (long)cur->value / 1000); + if ((long) cur->value % 1000 == 0) { + if (buf) { + snprintf(buf, len, "%ld", (long)cur->value / 1000); + } else { + ast_str_set(bufstr, len, "%ld", (long) cur->value / 1000); + } } else { - snprintf(buf, len, "%.3f", (double)((long)cur->value) / 1000.0); + if (buf) { + snprintf(buf, len, "%.3f", (double) ((long) cur->value) / 1000.0); + } else { + ast_str_set(bufstr, len, "%.3f", (double) ((long) cur->value) / 1000.0); + } } } else if (ot == OT_STRING) { ast_debug(1, "Found entry %p, with key %d and value %p\n", cur, cur->key, cur->value); - ast_copy_string(buf, cur->value, len); + if (buf) { + ast_copy_string(buf, cur->value, len); + } else { + ast_str_set(bufstr, 0, "%s", (char *) cur->value); + } } else if (key == CURLOPT_PROXYTYPE) { if (0) { #if CURLVERSION_ATLEAST(7,15,2) } else if ((long)cur->value == CURLPROXY_SOCKS4) { - ast_copy_string(buf, "socks4", len); + if (buf) { + ast_copy_string(buf, "socks4", len); + } else { + ast_str_set(bufstr, 0, "socks4"); + } #endif #if CURLVERSION_ATLEAST(7,18,0) } else if ((long)cur->value == CURLPROXY_SOCKS4A) { - ast_copy_string(buf, "socks4a", len); + if (buf) { + ast_copy_string(buf, "socks4a", len); + } else { + ast_str_set(bufstr, 0, "socks4a"); + } #endif } else if ((long)cur->value == CURLPROXY_SOCKS5) { - ast_copy_string(buf, "socks5", len); + if (buf) { + ast_copy_string(buf, "socks5", len); + } else { + ast_str_set(bufstr, 0, "socks5"); + } #if CURLVERSION_ATLEAST(7,18,0) } else if ((long)cur->value == CURLPROXY_SOCKS5_HOSTNAME) { - ast_copy_string(buf, "socks5hostname", len); + if (buf) { + ast_copy_string(buf, "socks5hostname", len); + } else { + ast_str_set(bufstr, 0, "socks5hostname"); + } #endif #if CURLVERSION_ATLEAST(7,10,0) } else if ((long)cur->value == CURLPROXY_HTTP) { - ast_copy_string(buf, "http", len); + if (buf) { + ast_copy_string(buf, "http", len); + } else { + ast_str_set(bufstr, 0, "http"); + } #endif } else { - ast_copy_string(buf, "unknown", len); + if (buf) { + ast_copy_string(buf, "unknown", len); + } else { + ast_str_set(bufstr, 0, "unknown"); + } } } break; @@ -349,6 +389,16 @@ static int acf_curlopt_read(struct ast_channel *chan, const char *cmd, char *dat return cur ? 0 : -1; } +static int acf_curlopt_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) +{ + return acf_curlopt_helper(chan, cmd, data, buf, NULL, len); +} + +static int acf_curlopt_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len) +{ + return acf_curlopt_helper(chan, cmd, data, NULL, buf, len); +} + static size_t WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) { register int realsize = size * nmemb; @@ -391,7 +441,7 @@ static void curl_instance_cleanup(void *data) AST_THREADSTORAGE_CUSTOM(curl_instance, curl_instance_init, curl_instance_cleanup); -static int acf_curl_exec(struct ast_channel *chan, const char *cmd, char *info, char *buf, size_t len) +static int acf_curl_helper(struct ast_channel *chan, const char *cmd, char *info, char *buf, struct ast_str **input_str, ssize_t len) { struct ast_str *str = ast_str_create(16); int ret = -1; @@ -405,15 +455,17 @@ static int acf_curl_exec(struct ast_channel *chan, const char *cmd, char *info, int hashcompat = 0; AST_LIST_HEAD(global_curl_info, curl_settings) *list = NULL; - *buf = '\0'; - + if (buf) { + *buf = '\0'; + } + if (ast_strlen_zero(info)) { ast_log(LOG_WARNING, "CURL requires an argument (URL)\n"); ast_free(str); return -1; } - AST_STANDARD_APP_ARGS(args, info); + AST_STANDARD_APP_ARGS(args, info); if (chan) { ast_autoservice_start(chan); @@ -483,11 +535,19 @@ static int acf_curl_exec(struct ast_channel *chan, const char *cmd, char *info, rowcount++; } pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", ast_str_buffer(fields)); - ast_copy_string(buf, ast_str_buffer(values), len); + if (buf) { + ast_copy_string(buf, ast_str_buffer(values), len); + } else { + ast_str_set(input_str, len, "%s", ast_str_buffer(values)); + } ast_free(fields); ast_free(values); } else { - ast_copy_string(buf, ast_str_buffer(str), len); + if (buf) { + ast_copy_string(buf, ast_str_buffer(str), len); + } else { + ast_str_set(input_str, len, "%s", ast_str_buffer(str)); + } } ret = 0; } @@ -495,10 +555,20 @@ static int acf_curl_exec(struct ast_channel *chan, const char *cmd, char *info, if (chan) ast_autoservice_stop(chan); - + return ret; } +static int acf_curl_exec(struct ast_channel *chan, const char *cmd, char *info, char *buf, size_t len) +{ + return acf_curl_helper(chan, cmd, info, buf, NULL, len); +} + +static int acf_curl2_exec(struct ast_channel *chan, const char *cmd, char *info, struct ast_str **buf, ssize_t len) +{ + return acf_curl_helper(chan, cmd, info, NULL, buf, len); +} + struct ast_custom_function acf_curl = { .name = "CURL", .synopsis = "Retrieves the contents of a URL", @@ -507,6 +577,7 @@ struct ast_custom_function acf_curl = { " url - URL to retrieve\n" " post-data - Optional data to send as a POST (GET is default action)\n", .read = acf_curl_exec, + .read2 = acf_curl2_exec, }; struct ast_custom_function acf_curlopt = { @@ -532,6 +603,7 @@ struct ast_custom_function acf_curlopt = { " hashcompat - Result data will be compatible for use with HASH()\n" "", .read = acf_curlopt_read, + .read2 = acf_curlopt_read2, .write = acf_curlopt_write, }; diff --git a/funcs/func_cut.c b/funcs/func_cut.c index 3a3c2f309..437ebf621 100644 --- a/funcs/func_cut.c +++ b/funcs/func_cut.c @@ -77,9 +77,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") </function> ***/ -/* Maximum length of any variable */ -#define MAXRESULT 1024 - struct sortable_keys { char *key; float value; @@ -151,7 +148,7 @@ static int sort_internal(struct ast_channel *chan, char *data, char *buffer, siz return 0; } -static int cut_internal(struct ast_channel *chan, char *data, char *buffer, size_t buflen) +static int cut_internal(struct ast_channel *chan, char *data, struct ast_str **buf, ssize_t buflen) { char *parse; size_t delim_consumed; @@ -160,8 +157,7 @@ static int cut_internal(struct ast_channel *chan, char *data, char *buffer, size AST_APP_ARG(delimiter); AST_APP_ARG(field); ); - - *buffer = '\0'; + struct ast_str *str = ast_str_create(16); parse = ast_strdupa(data); @@ -169,31 +165,30 @@ static int cut_internal(struct ast_channel *chan, char *data, char *buffer, size /* Check and parse arguments */ if (args.argc < 3) { + ast_free(str); return ERROR_NOARG; } else { - char d, ds[2] = ""; + char ds[2] = ""; char *tmp = alloca(strlen(args.varname) + 4); - char varvalue[MAXRESULT], *tmp2=varvalue; if (tmp) { snprintf(tmp, strlen(args.varname) + 4, "${%s}", args.varname); } else { + ast_free(str); return ERROR_NOMEM; } if (ast_get_encoded_char(args.delimiter, ds, &delim_consumed)) ast_copy_string(ds, "-", sizeof(ds)); - /* String form of the delimiter, for use with strsep(3) */ - d = *ds; - - pbx_substitute_variables_helper(chan, tmp, tmp2, MAXRESULT - 1); + ast_str_substitute_variables(&str, 0, chan, tmp); - if (tmp2) { + if (ast_str_strlen(str)) { int curfieldnum = 1; + char *tmp2 = ast_str_buffer(str); while (tmp2 != NULL && args.field != NULL) { char *nextgroup = strsep(&(args.field), "&"); - int num1 = 0, num2 = MAXRESULT; + int num1 = 0, num2 = INT_MAX; char trashchar; if (sscanf(nextgroup, "%d-%d", &num1, &num2) == 2) { @@ -203,18 +198,19 @@ static int cut_internal(struct ast_channel *chan, char *data, char *buffer, size num1 = 0; } else if ((sscanf(nextgroup, "%d%c", &num1, &trashchar) == 2) && (trashchar == '-')) { /* range with start */ - num2 = MAXRESULT; + num2 = INT_MAX; } else if (sscanf(nextgroup, "%d", &num1) == 1) { /* single number */ num2 = num1; } else { + ast_free(str); return ERROR_USAGE; } /* Get to start, if any */ if (num1 > 0) { - while (tmp2 != (char *)NULL + 1 && curfieldnum < num1) { - tmp2 = strchr(tmp2, d) + 1; + while (tmp2 != NULL && curfieldnum < num1) { + tmp2 = strchr(tmp2 + 1, ds[0]); curfieldnum++; } } @@ -223,25 +219,16 @@ static int cut_internal(struct ast_channel *chan, char *data, char *buffer, size if ((num1 > 0) && (curfieldnum > num1)) ast_log(LOG_WARNING, "We're already past the field you wanted?\n"); - /* Re-null tmp2 if we added 1 to NULL */ - if (tmp2 == (char *)NULL + 1) - tmp2 = NULL; - /* Output fields until we either run out of fields or num2 is reached */ while (tmp2 != NULL && curfieldnum <= num2) { char *tmp3 = strsep(&tmp2, ds); - int curlen = strlen(buffer); - - if (curlen) - snprintf(buffer + curlen, buflen - curlen, "%c%s", d, tmp3); - else - snprintf(buffer, buflen, "%s", tmp3); - + ast_str_append(buf, buflen, "%s%s", ast_str_strlen(*buf) ? ds : "", tmp3); curfieldnum++; } } } } + ast_free(str); return 0; } @@ -269,6 +256,32 @@ static int acf_sort_exec(struct ast_channel *chan, const char *cmd, char *data, static int acf_cut_exec(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { int ret = -1; + struct ast_str *str = ast_str_create(16); + + switch (cut_internal(chan, data, &str, len)) { + case ERROR_NOARG: + ast_log(LOG_ERROR, "Syntax: CUT(<varname>,<char-delim>,<range-spec>) - missing argument!\n"); + break; + case ERROR_NOMEM: + ast_log(LOG_ERROR, "Out of memory\n"); + break; + case ERROR_USAGE: + ast_log(LOG_ERROR, "Usage: CUT(<varname>,<char-delim>,<range-spec>)\n"); + break; + case 0: + ret = 0; + ast_copy_string(buf, ast_str_buffer(str), len); + break; + default: + ast_log(LOG_ERROR, "Unknown internal error\n"); + } + ast_free(str); + return ret; +} + +static int acf_cut_exec2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len) +{ + int ret = -1; switch (cut_internal(chan, data, buf, len)) { case ERROR_NOARG: @@ -298,6 +311,7 @@ struct ast_custom_function acf_sort = { struct ast_custom_function acf_cut = { .name = "CUT", .read = acf_cut_exec, + .read2 = acf_cut_exec2, }; static int unload_module(void) diff --git a/funcs/func_db.c b/funcs/func_db.c index 5fa753f6d..736fb0d75 100644 --- a/funcs/func_db.c +++ b/funcs/func_db.c @@ -201,6 +201,7 @@ static int function_db_exists(struct ast_channel *chan, const char *cmd, static struct ast_custom_function db_exists_function = { .name = "DB_EXISTS", .read = function_db_exists, + .read_max = 2, }; static int function_db_delete(struct ast_channel *chan, const char *cmd, diff --git a/funcs/func_dialplan.c b/funcs/func_dialplan.c index 0e371d2c8..1968a8b66 100644 --- a/funcs/func_dialplan.c +++ b/funcs/func_dialplan.c @@ -105,6 +105,7 @@ static int isexten_function_read(struct ast_channel *chan, const char *cmd, char static struct ast_custom_function isexten_function = { .name = "DIALPLAN_EXISTS", .read = isexten_function_read, + .read_max = 2, }; static int unload_module(void) diff --git a/funcs/func_env.c b/funcs/func_env.c index 707e96a12..70a87776b 100644 --- a/funcs/func_env.c +++ b/funcs/func_env.c @@ -230,7 +230,8 @@ static struct ast_custom_function env_function = { static struct ast_custom_function stat_function = { .name = "STAT", - .read = stat_read + .read = stat_read, + .read_max = 12, }; static struct ast_custom_function file_function = { diff --git a/funcs/func_extstate.c b/funcs/func_extstate.c index 7f2288560..d3c7ba4b7 100644 --- a/funcs/func_extstate.c +++ b/funcs/func_extstate.c @@ -122,6 +122,7 @@ static int extstate_read(struct ast_channel *chan, const char *cmd, char *data, static struct ast_custom_function extstate_function = { .name = "EXTENSION_STATE", .read = extstate_read, + .read_max = 12, }; static int unload_module(void) diff --git a/funcs/func_groupcount.c b/funcs/func_groupcount.c index ecb927467..81c4c97c9 100644 --- a/funcs/func_groupcount.c +++ b/funcs/func_groupcount.c @@ -134,6 +134,7 @@ static int group_count_function_read(struct ast_channel *chan, const char *cmd, static struct ast_custom_function group_count_function = { .name = "GROUP_COUNT", .read = group_count_function_read, + .read_max = 12, }; static int group_match_count_function_read(struct ast_channel *chan, @@ -159,6 +160,7 @@ static int group_match_count_function_read(struct ast_channel *chan, static struct ast_custom_function group_match_count_function = { .name = "GROUP_MATCH_COUNT", .read = group_match_count_function_read, + .read_max = 12, .write = NULL, }; diff --git a/funcs/func_lock.c b/funcs/func_lock.c index d6df6d0ef..de8377a9c 100644 --- a/funcs/func_lock.c +++ b/funcs/func_lock.c @@ -324,16 +324,19 @@ static int trylock_read(struct ast_channel *chan, const char *cmd, char *data, c static struct ast_custom_function lock_function = { .name = "LOCK", .read = lock_read, + .read_max = 2, }; static struct ast_custom_function trylock_function = { .name = "TRYLOCK", .read = trylock_read, + .read_max = 2, }; static struct ast_custom_function unlock_function = { .name = "UNLOCK", .read = unlock_read, + .read_max = 2, }; static int unload_module(void) diff --git a/funcs/func_logic.c b/funcs/func_logic.c index 6ec3a0847..27734ed78 100644 --- a/funcs/func_logic.c +++ b/funcs/func_logic.c @@ -223,25 +223,40 @@ static int set(struct ast_channel *chan, const char *cmd, char *data, char *buf, return 0; } -static int acf_import(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) +static int set2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len) +{ + if (len > -1) { + ast_str_make_space(str, len == 0 ? strlen(data) : len); + } + return set(chan, cmd, data, ast_str_buffer(*str), ast_str_size(*str)); +} + +static int import_helper(struct ast_channel *chan, const char *cmd, char *data, char *buf, struct ast_str **str, ssize_t len) { AST_DECLARE_APP_ARGS(args, AST_APP_ARG(channel); AST_APP_ARG(varname); ); AST_STANDARD_APP_ARGS(args, data); - - buf[0] = '\0'; + if (buf) { + *buf = '\0'; + } if (!ast_strlen_zero(args.varname)) { struct ast_channel *chan2; if ((chan2 = ast_channel_get_by_name(args.channel))) { char *s = alloca(strlen(args.varname) + 4); - sprintf(s, "${%s}", args.varname); - ast_channel_lock(chan2); - pbx_substitute_variables_helper(chan2, s, buf, len); - ast_channel_unlock(chan2); + if (s) { + sprintf(s, "${%s}", args.varname); + ast_channel_lock(chan2); + if (buf) { + pbx_substitute_variables_helper(chan2, s, buf, len); + } else { + ast_str_substitute_variables(str, len, chan2, s); + } + ast_channel_unlock(chan2); + } chan2 = ast_channel_unref(chan2); } } @@ -249,19 +264,32 @@ static int acf_import(struct ast_channel *chan, const char *cmd, char *data, cha return 0; } +static int import_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) +{ + return import_helper(chan, cmd, data, buf, NULL, len); +} + +static int import_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **str, ssize_t len) +{ + return import_helper(chan, cmd, data, NULL, str, len); +} + static struct ast_custom_function isnull_function = { .name = "ISNULL", .read = isnull, + .read_max = 2, }; static struct ast_custom_function set_function = { .name = "SET", .read = set, + .read2 = set2, }; static struct ast_custom_function exists_function = { .name = "EXISTS", .read = exists, + .read_max = 2, }; static struct ast_custom_function if_function = { @@ -276,7 +304,8 @@ static struct ast_custom_function if_time_function = { static struct ast_custom_function import_function = { .name = "IMPORT", - .read = acf_import, + .read = import_read, + .read2 = import_read2, }; static int unload_module(void) diff --git a/funcs/func_md5.c b/funcs/func_md5.c index 23b35489a..7c61d9f8c 100644 --- a/funcs/func_md5.c +++ b/funcs/func_md5.c @@ -64,6 +64,7 @@ static int md5(struct ast_channel *chan, const char *cmd, char *data, static struct ast_custom_function md5_function = { .name = "MD5", .read = md5, + .read_max = 33, }; static int unload_module(void) diff --git a/funcs/func_module.c b/funcs/func_module.c index a7cf73164..44ec08e4d 100644 --- a/funcs/func_module.c +++ b/funcs/func_module.c @@ -65,6 +65,7 @@ static int ifmodule_read(struct ast_channel *chan, const char *cmd, char *data, static struct ast_custom_function ifmodule_function = { .name = "IFMODULE", .read = ifmodule_read, + .read_max = 2, }; diff --git a/funcs/func_rand.c b/funcs/func_rand.c index 079723686..c49e63a44 100644 --- a/funcs/func_rand.c +++ b/funcs/func_rand.c @@ -87,6 +87,7 @@ static int acf_rand_exec(struct ast_channel *chan, const char *cmd, static struct ast_custom_function acf_rand = { .name = "RAND", .read = acf_rand_exec, + .read_max = 12, }; static int unload_module(void) diff --git a/funcs/func_sha1.c b/funcs/func_sha1.c index 973bc5c07..985e11a38 100644 --- a/funcs/func_sha1.c +++ b/funcs/func_sha1.c @@ -74,6 +74,7 @@ static int sha1(struct ast_channel *chan, const char *cmd, char *data, static struct ast_custom_function sha1_function = { .name = "SHA1", .read = sha1, + .read_max = 42, }; static int unload_module(void) diff --git a/funcs/func_speex.c b/funcs/func_speex.c index a3a5345ed..edfa3579b 100644 --- a/funcs/func_speex.c +++ b/funcs/func_speex.c @@ -337,13 +337,15 @@ static int speex_read(struct ast_channel *chan, const char *cmd, char *data, cha static struct ast_custom_function agc_function = { .name = "AGC", .write = speex_write, - .read = speex_read + .read = speex_read, + .read_max = 22, }; static struct ast_custom_function denoise_function = { .name = "DENOISE", .write = speex_write, - .read = speex_read + .read = speex_read, + .read_max = 22, }; static int unload_module(void) diff --git a/funcs/func_strings.c b/funcs/func_strings.c index 35211ab85..a2ba285d4 100644 --- a/funcs/func_strings.c +++ b/funcs/func_strings.c @@ -343,10 +343,11 @@ AST_THREADSTORAGE(result_buf); </function> ***/ -static int function_fieldqty(struct ast_channel *chan, const char *cmd, - char *parse, char *buf, size_t len) +static int function_fieldqty_helper(struct ast_channel *chan, const char *cmd, + char *parse, char *buf, struct ast_str **sbuf, ssize_t len) { - char *varsubst, varval[8192], *varval2 = varval; + char *varsubst; + struct ast_str *str = ast_str_create(16); int fieldcount = 0; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(varname); @@ -355,6 +356,10 @@ static int function_fieldqty(struct ast_channel *chan, const char *cmd, char delim[2] = ""; size_t delim_used; + if (!str) { + return -1; + } + AST_STANDARD_APP_ARGS(args, parse); if (args.delim) { ast_get_encoded_char(args.delim, delim, &delim_used); @@ -362,27 +367,47 @@ static int function_fieldqty(struct ast_channel *chan, const char *cmd, varsubst = alloca(strlen(args.varname) + 4); sprintf(varsubst, "${%s}", args.varname); - pbx_substitute_variables_helper(chan, varsubst, varval, sizeof(varval) - 1); - if (ast_strlen_zero(varval2)) + ast_str_substitute_variables(&str, 0, chan, varsubst); + if (ast_str_strlen(str) == 0) { fieldcount = 0; - else { - while (strsep(&varval2, delim)) + } else { + char *varval = ast_str_buffer(str); + while (strsep(&varval, delim)) { fieldcount++; + } } } else { fieldcount = 1; } - snprintf(buf, len, "%d", fieldcount); + if (sbuf) { + ast_str_set(sbuf, len, "%d", fieldcount); + } else { + snprintf(buf, len, "%d", fieldcount); + } + ast_free(str); return 0; } +static int function_fieldqty(struct ast_channel *chan, const char *cmd, + char *parse, char *buf, size_t len) +{ + return function_fieldqty_helper(chan, cmd, parse, buf, NULL, len); +} + +static int function_fieldqty_str(struct ast_channel *chan, const char *cmd, + char *parse, struct ast_str **buf, ssize_t len) +{ + return function_fieldqty_helper(chan, cmd, parse, NULL, buf, len); +} + static struct ast_custom_function fieldqty_function = { .name = "FIELDQTY", .read = function_fieldqty, + .read2 = function_fieldqty_str, }; -static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len) +static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, struct ast_str **bufstr, ssize_t len) { AST_DECLARE_APP_ARGS(args, AST_APP_ARG(listname); @@ -392,11 +417,18 @@ static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, ch const char *orig_list, *ptr; const char *begin, *cur, *next; int dlen, flen, first = 1; - struct ast_str *result = ast_str_thread_get(&result_buf, 16); + struct ast_str *result, **result_ptr = &result; char *delim; AST_STANDARD_APP_ARGS(args, parse); + if (buf) { + result = ast_str_thread_get(&result_buf, 16); + } else { + /* Place the result directly into the output buffer */ + result_ptr = bufstr; + } + if (args.argc < 3) { ast_log(LOG_ERROR, "Usage: LISTFILTER(<listname>,<delimiter>,<fieldvalue>)\n"); return -1; @@ -416,7 +448,11 @@ static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, ch /* If the string isn't there, just copy out the string and be done with it. */ if (!(ptr = strstr(orig_list, args.fieldvalue))) { - ast_copy_string(buf, orig_list, len); + if (buf) { + ast_copy_string(buf, orig_list, len); + } else { + ast_str_set(result_ptr, len, "%s", orig_list); + } if (chan) { ast_channel_unlock(chan); } @@ -436,7 +472,9 @@ static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, ch ast_str_reset(result); /* Enough space for any result */ - ast_str_make_space(&result, strlen(orig_list) + 1); + if (len > -1) { + ast_str_make_space(result_ptr, len ? len : strlen(orig_list) + 1); + } begin = orig_list; next = strstr(begin, delim); @@ -456,10 +494,10 @@ static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, ch } else { /* Copy field to output */ if (!first) { - ast_str_append(&result, 0, "%s", delim); + ast_str_append(result_ptr, len, "%s", delim); } - ast_str_append_substr(&result, 0, begin, cur - begin + 1); + ast_str_append_substr(result_ptr, len, begin, cur - begin + 1); first = 0; begin = cur + dlen; } @@ -468,14 +506,27 @@ static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, ch ast_channel_unlock(chan); } - ast_copy_string(buf, ast_str_buffer(result), len); + if (buf) { + ast_copy_string(buf, ast_str_buffer(result), len); + } return 0; } +static int listfilter_read(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len) +{ + return listfilter(chan, cmd, parse, buf, NULL, len); +} + +static int listfilter_read2(struct ast_channel *chan, const char *cmd, char *parse, struct ast_str **buf, ssize_t len) +{ + return listfilter(chan, cmd, parse, NULL, buf, len); +} + static struct ast_custom_function listfilter_function = { .name = "LISTFILTER", - .read = listfilter, + .read = listfilter_read, + .read2 = listfilter_read2, }; static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, @@ -679,16 +730,15 @@ static int array(struct ast_channel *chan, const char *cmd, char *var, static int hashkeys_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len) { struct ast_var_t *newvar; - int plen; - char prefix[80]; - snprintf(prefix, sizeof(prefix), HASH_PREFIX, data); - plen = strlen(prefix); + struct ast_str *prefix = ast_str_alloca(80); + ast_str_set(&prefix, -1, HASH_PREFIX, data); memset(buf, 0, len); + AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) { - if (strncasecmp(prefix, ast_var_name(newvar), plen) == 0) { + if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) { /* Copy everything after the prefix */ - strncat(buf, ast_var_name(newvar) + plen, len - strlen(buf) - 1); + strncat(buf, ast_var_name(newvar) + ast_str_strlen(prefix), len - strlen(buf) - 1); /* Trim the trailing ~ */ buf[strlen(buf) - 1] = ','; } @@ -698,6 +748,29 @@ static int hashkeys_read(struct ast_channel *chan, const char *cmd, char *data, return 0; } +static int hashkeys_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len) +{ + struct ast_var_t *newvar; + struct ast_str *prefix = ast_str_alloca(80); + char *tmp; + + ast_str_set(&prefix, -1, HASH_PREFIX, data); + + AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) { + if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) { + /* Copy everything after the prefix */ + ast_str_append(buf, len, "%s", ast_var_name(newvar) + ast_str_strlen(prefix)); + /* Trim the trailing ~ */ + tmp = ast_str_buffer(*buf); + tmp[ast_str_strlen(*buf) - 1] = ','; + } + } + /* Trim the trailing comma */ + tmp = ast_str_buffer(*buf); + tmp[ast_str_strlen(*buf) - 1] = '\0'; + return 0; +} + static int hash_write(struct ast_channel *chan, const char *cmd, char *var, const char *value) { char varname[256]; @@ -773,6 +846,7 @@ static struct ast_custom_function hash_function = { static struct ast_custom_function hashkeys_function = { .name = "HASHKEYS", .read = hashkeys_read, + .read2 = hashkeys_read2, }; static struct ast_custom_function array_function = { @@ -824,6 +898,7 @@ static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, static struct ast_custom_function len_function = { .name = "LEN", .read = len, + .read_max = 12, }; static int acf_strftime(struct ast_channel *chan, const char *cmd, char *parse, @@ -915,9 +990,23 @@ static int function_eval(struct ast_channel *chan, const char *cmd, char *data, return 0; } +static int function_eval2(struct ast_channel *chan, const char *cmd, char *data, + struct ast_str **buf, ssize_t buflen) +{ + if (ast_strlen_zero(data)) { + ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n"); + return -1; + } + + ast_str_substitute_variables(buf, buflen, chan, data); + + return 0; +} + static struct ast_custom_function eval_function = { .name = "EVAL", .read = function_eval, + .read2 = function_eval2, }; static int keypadhash(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen) @@ -969,9 +1058,24 @@ static int string_toupper(struct ast_channel *chan, const char *cmd, char *data, return 0; } +static int string_toupper2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen) +{ + char *bufptr, *dataptr = data; + + if (buflen > -1) { + ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1); + } + bufptr = ast_str_buffer(*buf); + while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = toupper(*dataptr++))); + ast_str_update(*buf); + + return 0; +} + static struct ast_custom_function toupper_function = { .name = "TOUPPER", .read = string_toupper, + .read2 = string_toupper2, }; static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen) @@ -983,9 +1087,24 @@ static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, return 0; } +static int string_tolower2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen) +{ + char *bufptr, *dataptr = data; + + if (buflen > -1) { + ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1); + } + bufptr = ast_str_buffer(*buf); + while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = tolower(*dataptr++))); + ast_str_update(*buf); + + return 0; +} + static struct ast_custom_function tolower_function = { .name = "TOLOWER", .read = string_tolower, + .read2 = string_tolower2, }; static int array_remove(struct ast_channel *chan, const char *cmd, char *var, char *buf, size_t len, int beginning) diff --git a/funcs/func_sysinfo.c b/funcs/func_sysinfo.c index 16e9632d5..8fdfda3f1 100644 --- a/funcs/func_sysinfo.c +++ b/funcs/func_sysinfo.c @@ -86,6 +86,7 @@ static struct ast_custom_function sysinfo_function = { .synopsis = "Returns system information specified by parameter.", .syntax = "SYSINFO(<parameter>)", .read = sysinfo_helper, + .read_max = 22, .desc = "Returns information from a given parameter\n" " Options:\n" diff --git a/funcs/func_timeout.c b/funcs/func_timeout.c index 2b3a000b4..caa562834 100644 --- a/funcs/func_timeout.c +++ b/funcs/func_timeout.c @@ -191,6 +191,7 @@ static int timeout_write(struct ast_channel *chan, const char *cmd, char *data, static struct ast_custom_function timeout_function = { .name = "TIMEOUT", .read = timeout_read, + .read_max = 22, .write = timeout_write, }; diff --git a/funcs/func_vmcount.c b/funcs/func_vmcount.c index f79669b6d..550070891 100644 --- a/funcs/func_vmcount.c +++ b/funcs/func_vmcount.c @@ -97,6 +97,7 @@ static int acf_vmcount_exec(struct ast_channel *chan, const char *cmd, char *arg struct ast_custom_function acf_vmcount = { .name = "VMCOUNT", .read = acf_vmcount_exec, + .read_max = 12, }; static int unload_module(void) |