00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "asterisk.h"
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 221964 $")
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
00042 static int function_fieldqty(struct ast_channel *chan, const char *cmd,
00043 char *parse, char *buf, size_t len)
00044 {
00045 char *varsubst, varval[8192], *varval2 = varval;
00046 int fieldcount = 0;
00047 AST_DECLARE_APP_ARGS(args,
00048 AST_APP_ARG(varname);
00049 AST_APP_ARG(delim);
00050 );
00051 char delim[2] = "";
00052 size_t delim_used;
00053
00054 AST_STANDARD_APP_ARGS(args, parse);
00055 if (args.delim) {
00056 ast_get_encoded_char(args.delim, delim, &delim_used);
00057
00058 varsubst = alloca(strlen(args.varname) + 4);
00059
00060 sprintf(varsubst, "${%s}", args.varname);
00061 pbx_substitute_variables_helper(chan, varsubst, varval, sizeof(varval) - 1);
00062 if (ast_strlen_zero(varval2))
00063 fieldcount = 0;
00064 else {
00065 while (strsep(&varval2, delim))
00066 fieldcount++;
00067 }
00068 } else {
00069 fieldcount = 1;
00070 }
00071 snprintf(buf, len, "%d", fieldcount);
00072
00073 return 0;
00074 }
00075
00076 static struct ast_custom_function fieldqty_function = {
00077 .name = "FIELDQTY",
00078 .synopsis = "Count the fields, with an arbitrary delimiter",
00079 .syntax = "FIELDQTY(<varname>,<delim>)",
00080 .read = function_fieldqty,
00081 };
00082
00083 static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf,
00084 size_t len)
00085 {
00086 AST_DECLARE_APP_ARGS(args,
00087 AST_APP_ARG(allowed);
00088 AST_APP_ARG(string);
00089 );
00090 char *outbuf = buf, ac;
00091 char allowed[256] = "";
00092 size_t allowedlen = 0;
00093
00094 AST_STANDARD_APP_ARGS(args, parse);
00095
00096 if (!args.string) {
00097 ast_log(LOG_ERROR, "Usage: FILTER(<allowed-chars>,<string>)\n");
00098 return -1;
00099 }
00100
00101
00102 for (; *(args.allowed) && allowedlen < sizeof(allowed); ) {
00103 char c1 = 0, c2 = 0;
00104 size_t consumed = 0;
00105
00106 if (ast_get_encoded_char(args.allowed, &c1, &consumed))
00107 return -1;
00108 args.allowed += consumed;
00109
00110 if (*(args.allowed) == '-') {
00111 if (ast_get_encoded_char(args.allowed + 1, &c2, &consumed))
00112 c2 = -1;
00113 args.allowed += consumed + 1;
00114
00115
00116
00117
00118
00119 for (ac = c1; ac != c2 && allowedlen < sizeof(allowed) - 1; ac++)
00120 allowed[allowedlen++] = ac;
00121 allowed[allowedlen++] = ac;
00122
00123 ast_debug(4, "c1=%d, c2=%d\n", c1, c2);
00124
00125
00126 (args.allowed)--;
00127 } else
00128 allowed[allowedlen++] = c1;
00129 }
00130
00131 ast_debug(1, "Allowed: %s\n", allowed);
00132
00133 for (; *(args.string) && (buf + len - 1 > outbuf); (args.string)++) {
00134 if (strchr(allowed, *(args.string)))
00135 *outbuf++ = *(args.string);
00136 }
00137 *outbuf = '\0';
00138
00139 return 0;
00140 }
00141
00142 static struct ast_custom_function filter_function = {
00143 .name = "FILTER",
00144 .synopsis = "Filter the string to include only the allowed characters",
00145 .syntax = "FILTER(<allowed-chars>,<string>)",
00146 .read = filter,
00147 .desc =
00148 "Permits all characters listed in <allowed-chars>, filtering all others out.\n"
00149 "In addition to literally listing the characters, you may also use ranges of\n"
00150 "characters (delimited by a '-'), as well as hexadecimal characters started\n"
00151 "with a \\x (i.e. \\x20) and octal characters started with \\0 (i.e. \\040).\n"
00152 "Also, \\t, \\n, and \\r are recognized. If you want a literal '-' character,\n"
00153 "simply prefix it with a '\\'\n",
00154 };
00155
00156 static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf,
00157 size_t len)
00158 {
00159 AST_DECLARE_APP_ARGS(args,
00160 AST_APP_ARG(null);
00161 AST_APP_ARG(reg);
00162 AST_APP_ARG(str);
00163 );
00164 int errcode;
00165 regex_t regexbuf;
00166
00167 buf[0] = '\0';
00168
00169 AST_NONSTANDARD_APP_ARGS(args, parse, '"');
00170
00171 if (args.argc != 3) {
00172 ast_log(LOG_ERROR, "Unexpected arguments: should have been in the form '\"<regex>\" <string>'\n");
00173 return -1;
00174 }
00175 if ((*args.str == ' ') || (*args.str == '\t'))
00176 args.str++;
00177
00178 ast_debug(1, "FUNCTION REGEX (%s)(%s)\n", args.reg, args.str);
00179
00180 if ((errcode = regcomp(®exbuf, args.reg, REG_EXTENDED | REG_NOSUB))) {
00181 regerror(errcode, ®exbuf, buf, len);
00182 ast_log(LOG_WARNING, "Malformed input %s(%s): %s\n", cmd, parse, buf);
00183 return -1;
00184 }
00185
00186 strcpy(buf, regexec(®exbuf, args.str, 0, NULL, 0) ? "0" : "1");
00187
00188 regfree(®exbuf);
00189
00190 return 0;
00191 }
00192
00193 static struct ast_custom_function regex_function = {
00194 .name = "REGEX",
00195 .synopsis = "Regular Expression",
00196 .desc =
00197 "Returns 1 if data matches regular expression, or 0 otherwise.\n"
00198 "Please note that the space following the double quotes separating the regex from the data\n"
00199 "is optional and if present, is skipped. If a space is desired at the beginning of the data,\n"
00200 "then put two spaces there; the second will not be skipped.\n",
00201 .syntax = "REGEX(\"<regular expression>\" <data>)",
00202 .read = regex,
00203 };
00204
00205 #define HASH_PREFIX "~HASH~%s~"
00206 #define HASH_FORMAT HASH_PREFIX "%s~"
00207
00208 static char *app_clearhash = "ClearHash";
00209 static char *syn_clearhash = "Clear the keys from a specified hashname";
00210 static char *desc_clearhash =
00211 "ClearHash(<hashname>)\n"
00212 " Clears all keys out of the specified hashname\n";
00213
00214
00215 static void clearvar_prefix(struct ast_channel *chan, const char *prefix)
00216 {
00217 struct ast_var_t *var;
00218 int len = strlen(prefix);
00219 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->varshead, var, entries) {
00220 if (strncasecmp(prefix, ast_var_name(var), len) == 0) {
00221 AST_LIST_REMOVE_CURRENT(entries);
00222 ast_free(var);
00223 }
00224 }
00225 AST_LIST_TRAVERSE_SAFE_END
00226 }
00227
00228 static int exec_clearhash(struct ast_channel *chan, void *data)
00229 {
00230 char prefix[80];
00231 snprintf(prefix, sizeof(prefix), HASH_PREFIX, data ? (char *)data : "null");
00232 clearvar_prefix(chan, prefix);
00233 return 0;
00234 }
00235
00236 static int array(struct ast_channel *chan, const char *cmd, char *var,
00237 const char *value)
00238 {
00239 AST_DECLARE_APP_ARGS(arg1,
00240 AST_APP_ARG(var)[100];
00241 );
00242 AST_DECLARE_APP_ARGS(arg2,
00243 AST_APP_ARG(val)[100];
00244 );
00245 char *origvar = "", *value2, varname[256];
00246 int i, ishash = 0;
00247
00248 value2 = ast_strdupa(value);
00249 if (!var || !value2)
00250 return -1;
00251
00252 if (!strcmp(cmd, "HASH")) {
00253 const char *var2 = pbx_builtin_getvar_helper(chan, "~ODBCFIELDS~");
00254 origvar = var;
00255 if (var2)
00256 var = ast_strdupa(var2);
00257 else {
00258 if (chan)
00259 ast_autoservice_stop(chan);
00260 return -1;
00261 }
00262 ishash = 1;
00263 }
00264
00265
00266
00267
00268
00269
00270
00271 ast_debug(1, "array (%s=%s)\n", var, value2);
00272 AST_STANDARD_APP_ARGS(arg1, var);
00273
00274 AST_STANDARD_APP_ARGS(arg2, value2);
00275
00276 for (i = 0; i < arg1.argc; i++) {
00277 ast_debug(1, "array set value (%s=%s)\n", arg1.var[i],
00278 arg2.val[i]);
00279 if (i < arg2.argc) {
00280 if (ishash) {
00281 snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
00282 pbx_builtin_setvar_helper(chan, varname, arg2.val[i]);
00283 } else {
00284 pbx_builtin_setvar_helper(chan, arg1.var[i], arg2.val[i]);
00285 }
00286 } else {
00287
00288
00289 if (ishash) {
00290 snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
00291 pbx_builtin_setvar_helper(chan, varname, "");
00292 } else {
00293 pbx_builtin_setvar_helper(chan, arg1.var[i], "");
00294 }
00295 }
00296 }
00297
00298 return 0;
00299 }
00300
00301 static int hashkeys_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00302 {
00303 struct ast_var_t *newvar;
00304 int plen;
00305 char prefix[80];
00306 snprintf(prefix, sizeof(prefix), HASH_PREFIX, data);
00307 plen = strlen(prefix);
00308
00309 memset(buf, 0, len);
00310 AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) {
00311 if (strncasecmp(prefix, ast_var_name(newvar), plen) == 0) {
00312
00313 strncat(buf, ast_var_name(newvar) + plen, len - strlen(buf) - 1);
00314
00315 buf[strlen(buf) - 1] = ',';
00316 }
00317 }
00318
00319 buf[strlen(buf) - 1] = '\0';
00320 return 0;
00321 }
00322
00323 static int hash_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
00324 {
00325 char varname[256];
00326 AST_DECLARE_APP_ARGS(arg,
00327 AST_APP_ARG(hashname);
00328 AST_APP_ARG(hashkey);
00329 );
00330
00331 if (!strchr(var, ',')) {
00332
00333 return array(chan, "HASH", var, value);
00334 }
00335
00336 AST_STANDARD_APP_ARGS(arg, var);
00337 snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
00338 pbx_builtin_setvar_helper(chan, varname, value);
00339
00340 return 0;
00341 }
00342
00343 static int hash_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00344 {
00345 char varname[256];
00346 const char *varvalue;
00347 AST_DECLARE_APP_ARGS(arg,
00348 AST_APP_ARG(hashname);
00349 AST_APP_ARG(hashkey);
00350 );
00351
00352 AST_STANDARD_APP_ARGS(arg, data);
00353 if (arg.argc == 2) {
00354 snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
00355 varvalue = pbx_builtin_getvar_helper(chan, varname);
00356 if (varvalue)
00357 ast_copy_string(buf, varvalue, len);
00358 else
00359 *buf = '\0';
00360 } else if (arg.argc == 1) {
00361 char colnames[4096];
00362 int i;
00363 AST_DECLARE_APP_ARGS(arg2,
00364 AST_APP_ARG(col)[100];
00365 );
00366
00367
00368 hashkeys_read(chan, "HASHKEYS", arg.hashname, colnames, sizeof(colnames));
00369 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames);
00370
00371 AST_STANDARD_APP_ARGS(arg2, colnames);
00372 *buf = '\0';
00373
00374
00375 for (i = 0; i < arg2.argc; i++) {
00376 snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg2.col[i]);
00377 varvalue = pbx_builtin_getvar_helper(chan, varname);
00378 strncat(buf, varvalue, len - strlen(buf) - 1);
00379 strncat(buf, ",", len - strlen(buf) - 1);
00380 }
00381
00382
00383 buf[strlen(buf) - 1] = '\0';
00384 }
00385
00386 return 0;
00387 }
00388
00389 static struct ast_custom_function hash_function = {
00390 .name = "HASH",
00391 .synopsis = "Implementation of a dialplan associative array",
00392 .syntax = "HASH(hashname[,hashkey])",
00393 .write = hash_write,
00394 .read = hash_read,
00395 .desc =
00396 "In two argument mode, gets and sets values to corresponding keys within a named\n"
00397 "associative array. The single-argument mode will only work when assigned to from\n"
00398 "a function defined by func_odbc.so.\n",
00399 };
00400
00401 static struct ast_custom_function hashkeys_function = {
00402 .name = "HASHKEYS",
00403 .synopsis = "Retrieve the keys of a HASH()",
00404 .syntax = "HASHKEYS(<hashname>)",
00405 .read = hashkeys_read,
00406 .desc =
00407 "Returns a comma-delimited list of the current keys of an associative array\n"
00408 "defined by the HASH() function. Note that if you iterate over the keys of\n"
00409 "the result, adding keys during iteration will cause the result of the HASHKEYS\n"
00410 "function to change.\n",
00411 };
00412
00413 static struct ast_custom_function array_function = {
00414 .name = "ARRAY",
00415 .synopsis = "Allows setting multiple variables at once",
00416 .syntax = "ARRAY(var1[,var2[...][,varN]])",
00417 .write = array,
00418 .desc =
00419 "The comma-separated list passed as a value to which the function is set will\n"
00420 "be interpreted as a set of values to which the comma-separated list of\n"
00421 "variable names in the argument should be set.\n"
00422 "Hence, Set(ARRAY(var1,var2)=1,2) will set var1 to 1 and var2 to 2.\n",
00423 };
00424
00425 static int acf_sprintf(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00426 {
00427 #define SPRINTF_FLAG 0
00428 #define SPRINTF_WIDTH 1
00429 #define SPRINTF_PRECISION 2
00430 #define SPRINTF_LENGTH 3
00431 #define SPRINTF_CONVERSION 4
00432 int i, state = -1, argcount = 0;
00433 char *formatstart = NULL, *bufptr = buf;
00434 char formatbuf[256] = "";
00435 int tmpi;
00436 double tmpd;
00437 AST_DECLARE_APP_ARGS(arg,
00438 AST_APP_ARG(format);
00439 AST_APP_ARG(var)[100];
00440 );
00441
00442 AST_STANDARD_APP_ARGS(arg, data);
00443
00444
00445 for (i = 0; arg.format[i]; i++) {
00446 switch (state) {
00447 case SPRINTF_FLAG:
00448 if (strchr("#0- +'I", arg.format[i]))
00449 break;
00450 state = SPRINTF_WIDTH;
00451 case SPRINTF_WIDTH:
00452 if (arg.format[i] >= '0' && arg.format[i] <= '9')
00453 break;
00454
00455
00456 if (arg.format[i] == '.') {
00457 state = SPRINTF_PRECISION;
00458 } else {
00459 state = SPRINTF_LENGTH;
00460 i--;
00461 }
00462 break;
00463 case SPRINTF_PRECISION:
00464 if (arg.format[i] >= '0' && arg.format[i] <= '9')
00465 break;
00466 state = SPRINTF_LENGTH;
00467 case SPRINTF_LENGTH:
00468 if (strchr("hl", arg.format[i])) {
00469 if (arg.format[i + 1] == arg.format[i])
00470 i++;
00471 state = SPRINTF_CONVERSION;
00472 break;
00473 } else if (strchr("Lqjzt", arg.format[i])) {
00474 state = SPRINTF_CONVERSION;
00475 break;
00476 }
00477 state = SPRINTF_CONVERSION;
00478 case SPRINTF_CONVERSION:
00479 if (strchr("diouxXc", arg.format[i])) {
00480
00481
00482
00483 ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
00484 formatbuf[&arg.format[i] - formatstart + 1] = '\0';
00485
00486
00487 if (arg.var[argcount]) {
00488 if (sscanf(arg.var[argcount++], "%30d", &tmpi) != 1) {
00489 ast_log(LOG_ERROR, "Argument '%s' is not an integer number for format '%s'\n", arg.var[argcount - 1], formatbuf);
00490 goto sprintf_fail;
00491 }
00492 } else {
00493 ast_log(LOG_ERROR, "SPRINTF() has more format specifiers than arguments!\n");
00494 goto sprintf_fail;
00495 }
00496
00497
00498 snprintf(bufptr, buf + len - bufptr, formatbuf, tmpi);
00499
00500
00501 bufptr = strchr(buf, '\0');
00502 } else if (strchr("eEfFgGaA", arg.format[i])) {
00503
00504
00505
00506 ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
00507 formatbuf[&arg.format[i] - formatstart + 1] = '\0';
00508
00509
00510 if (arg.var[argcount]) {
00511 if (sscanf(arg.var[argcount++], "%30lf", &tmpd) != 1) {
00512 ast_log(LOG_ERROR, "Argument '%s' is not a floating point number for format '%s'\n", arg.var[argcount - 1], formatbuf);
00513 goto sprintf_fail;
00514 }
00515 } else {
00516 ast_log(LOG_ERROR, "SPRINTF() has more format specifiers than arguments!\n");
00517 goto sprintf_fail;
00518 }
00519
00520
00521 snprintf(bufptr, buf + len - bufptr, formatbuf, tmpd);
00522
00523
00524 bufptr = strchr(buf, '\0');
00525 } else if (arg.format[i] == 's') {
00526
00527
00528
00529 ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
00530 formatbuf[&arg.format[i] - formatstart + 1] = '\0';
00531
00532
00533 snprintf(bufptr, buf + len - bufptr, formatbuf, arg.var[argcount++]);
00534
00535
00536 bufptr = strchr(buf, '\0');
00537 } else if (arg.format[i] == '%') {
00538
00539 *bufptr++ = arg.format[i];
00540 } else {
00541
00542
00543
00544 ast_copy_string(formatbuf, formatstart, sizeof(formatbuf));
00545 formatbuf[&arg.format[i] - formatstart + 1] = '\0';
00546
00547 ast_log(LOG_ERROR, "Format type not supported: '%s' with argument '%s'\n", formatbuf, arg.var[argcount++]);
00548 goto sprintf_fail;
00549 }
00550 state = -1;
00551 break;
00552 default:
00553 if (arg.format[i] == '%') {
00554 state = SPRINTF_FLAG;
00555 formatstart = &arg.format[i];
00556 break;
00557 } else {
00558
00559 *bufptr++ = arg.format[i];
00560 }
00561 }
00562 }
00563 *bufptr = '\0';
00564 return 0;
00565 sprintf_fail:
00566 return -1;
00567 }
00568
00569 static struct ast_custom_function sprintf_function = {
00570 .name = "SPRINTF",
00571 .synopsis = "Format a variable according to a format string",
00572 .syntax = "SPRINTF(<format>,<arg1>[,...<argN>])",
00573 .read = acf_sprintf,
00574 .desc =
00575 "Parses the format string specified and returns a string matching that format.\n"
00576 "Supports most options supported by sprintf(3). Returns a shortened string if\n"
00577 "a format specifier is not recognized.\n",
00578 };
00579
00580 static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00581 {
00582 char *bufptr = buf, *dataptr = data;
00583
00584 if (len < 3){
00585 ast_log(LOG_ERROR, "Not enough buffer");
00586 return -1;
00587 }
00588
00589 if (ast_strlen_zero(data)) {
00590 ast_log(LOG_WARNING, "No argument specified!\n");
00591 ast_copy_string(buf, "\"\"", len);
00592 return 0;
00593 }
00594
00595 *bufptr++ = '"';
00596 for (; bufptr < buf + len - 3; dataptr++) {
00597 if (*dataptr == '\\') {
00598 *bufptr++ = '\\';
00599 *bufptr++ = '\\';
00600 } else if (*dataptr == '"') {
00601 *bufptr++ = '\\';
00602 *bufptr++ = '"';
00603 } else if (*dataptr == '\0') {
00604 break;
00605 } else {
00606 *bufptr++ = *dataptr;
00607 }
00608 }
00609 *bufptr++ = '"';
00610 *bufptr = '\0';
00611 return 0;
00612 }
00613
00614 static struct ast_custom_function quote_function = {
00615 .name = "QUOTE",
00616 .synopsis = "Quotes a given string, escaping embedded quotes as necessary",
00617 .syntax = "QUOTE(<string>)",
00618 .read = quote,
00619 };
00620
00621 static int csv_quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00622 {
00623 char *bufptr = buf, *dataptr = data;
00624
00625 if (len < 3){
00626 ast_log(LOG_ERROR, "Not enough buffer");
00627 return -1;
00628 }
00629
00630 if (ast_strlen_zero(data)) {
00631 ast_log(LOG_WARNING, "No argument specified!\n");
00632 ast_copy_string(buf,"\"\"",len);
00633 return 0;
00634 }
00635
00636 *bufptr++ = '"';
00637 for (; bufptr < buf + len - 3; dataptr++){
00638 if (*dataptr == '"') {
00639 *bufptr++ = '"';
00640 *bufptr++ = '"';
00641 } else if (*dataptr == '\0') {
00642 break;
00643 } else {
00644 *bufptr++ = *dataptr;
00645 }
00646 }
00647 *bufptr++ = '"';
00648 *bufptr='\0';
00649 return 0;
00650 }
00651
00652 static struct ast_custom_function csv_quote_function = {
00653 .name = "CSV_QUOTE",
00654 .read = csv_quote,
00655 };
00656
00657 static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
00658 {
00659 int length = 0;
00660
00661 if (data)
00662 length = strlen(data);
00663
00664 snprintf(buf, buflen, "%d", length);
00665
00666 return 0;
00667 }
00668
00669 static struct ast_custom_function len_function = {
00670 .name = "LEN",
00671 .synopsis = "Returns the length of the argument given",
00672 .syntax = "LEN(<string>)",
00673 .read = len,
00674 };
00675
00676 static int acf_strftime(struct ast_channel *chan, const char *cmd, char *parse,
00677 char *buf, size_t buflen)
00678 {
00679 AST_DECLARE_APP_ARGS(args,
00680 AST_APP_ARG(epoch);
00681 AST_APP_ARG(timezone);
00682 AST_APP_ARG(format);
00683 );
00684 struct timeval when;
00685 struct ast_tm tm;
00686
00687 buf[0] = '\0';
00688
00689 AST_STANDARD_APP_ARGS(args, parse);
00690
00691 ast_get_timeval(args.epoch, &when, ast_tvnow(), NULL);
00692 ast_localtime(&when, &tm, args.timezone);
00693
00694 if (!args.format)
00695 args.format = "%c";
00696
00697 if (ast_strftime(buf, buflen, args.format, &tm) <= 0)
00698 ast_log(LOG_WARNING, "C function strftime() output nothing?!!\n");
00699
00700 buf[buflen - 1] = '\0';
00701
00702 return 0;
00703 }
00704
00705 static struct ast_custom_function strftime_function = {
00706 .name = "STRFTIME",
00707 .synopsis = "Returns the current date/time in a specified format.",
00708 .syntax = "STRFTIME([<epoch>][,[timezone][,format]])",
00709 .desc =
00710 "STRFTIME sports all of the same formats as the underlying C function\n"
00711 "strftime(3) - see the man page for details. It also supports the\n"
00712 "following format:\n"
00713 " %[n]q - fractions of a second, with leading zeroes. For example, %3q will\n"
00714 " give milliseconds and %1q will give tenths of a second. The default\n"
00715 " is to output milliseconds (n=3). The common case is to use it in\n"
00716 " combination with %S, as in \"%S.%3q\".\n",
00717 .read = acf_strftime,
00718 };
00719
00720 static int acf_strptime(struct ast_channel *chan, const char *cmd, char *data,
00721 char *buf, size_t buflen)
00722 {
00723 AST_DECLARE_APP_ARGS(args,
00724 AST_APP_ARG(timestring);
00725 AST_APP_ARG(timezone);
00726 AST_APP_ARG(format);
00727 );
00728 union {
00729 struct ast_tm atm;
00730 struct tm time;
00731 } t = { { 0, }, };
00732
00733 buf[0] = '\0';
00734
00735 if (!data) {
00736 ast_log(LOG_ERROR,
00737 "Asterisk function STRPTIME() requires an argument.\n");
00738 return -1;
00739 }
00740
00741 AST_STANDARD_APP_ARGS(args, data);
00742
00743 if (ast_strlen_zero(args.format)) {
00744 ast_log(LOG_ERROR,
00745 "No format supplied to STRPTIME(<timestring>,<timezone>,<format>)");
00746 return -1;
00747 }
00748
00749 if (!strptime(args.timestring, args.format, &t.time)) {
00750 ast_log(LOG_WARNING, "C function strptime() output nothing?!!\n");
00751 } else {
00752 struct timeval when;
00753
00754 t.atm.tm_isdst = -1;
00755 when = ast_mktime(&t.atm, args.timezone);
00756 snprintf(buf, buflen, "%d", (int) when.tv_sec);
00757 }
00758
00759 return 0;
00760 }
00761
00762 static struct ast_custom_function strptime_function = {
00763 .name = "STRPTIME",
00764 .synopsis =
00765 "Returns the epoch of the arbitrary date/time string structured as described in the format.",
00766 .syntax = "STRPTIME(<datetime>,<timezone>,<format>)",
00767 .desc =
00768 "This is useful for converting a date into an EPOCH time, possibly to pass to\n"
00769 "an application like SayUnixTime or to calculate the difference between two\n"
00770 "date strings.\n"
00771 "\n"
00772 "Example:\n"
00773 " ${STRPTIME(2006-03-01 07:30:35,America/Chicago,%Y-%m-%d %H:%M:%S)} returns 1141219835\n",
00774 .read = acf_strptime,
00775 };
00776
00777 static int function_eval(struct ast_channel *chan, const char *cmd, char *data,
00778 char *buf, size_t buflen)
00779 {
00780 if (ast_strlen_zero(data)) {
00781 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
00782 return -1;
00783 }
00784
00785 pbx_substitute_variables_helper(chan, data, buf, buflen - 1);
00786
00787 return 0;
00788 }
00789
00790 static struct ast_custom_function eval_function = {
00791 .name = "EVAL",
00792 .synopsis = "Evaluate stored variables.",
00793 .syntax = "EVAL(<variable>)",
00794 .desc = "Using EVAL basically causes a string to be evaluated twice.\n"
00795 "When a variable or expression is in the dialplan, it will be\n"
00796 "evaluated at runtime. However, if the result of the evaluation\n"
00797 "is in fact a variable or expression, using EVAL will have it\n"
00798 "evaluated a second time. For example, if the variable ${MYVAR}\n"
00799 "contains \"${OTHERVAR}\", then the result of putting ${EVAL(${MYVAR})}\n"
00800 "in the dialplan will be the contents of the variable, OTHERVAR.\n"
00801 "Normally, by just putting ${MYVAR} in the dialplan, you would be\n"
00802 "left with \"${OTHERVAR}\".\n",
00803 .read = function_eval,
00804 };
00805
00806 static int keypadhash(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
00807 {
00808 char *bufptr, *dataptr;
00809
00810 for (bufptr = buf, dataptr = data; bufptr < buf + buflen - 1; dataptr++) {
00811 if (*dataptr == '\0') {
00812 *bufptr++ = '\0';
00813 break;
00814 } else if (*dataptr == '1') {
00815 *bufptr++ = '1';
00816 } else if (strchr("AaBbCc2", *dataptr)) {
00817 *bufptr++ = '2';
00818 } else if (strchr("DdEeFf3", *dataptr)) {
00819 *bufptr++ = '3';
00820 } else if (strchr("GgHhIi4", *dataptr)) {
00821 *bufptr++ = '4';
00822 } else if (strchr("JjKkLl5", *dataptr)) {
00823 *bufptr++ = '5';
00824 } else if (strchr("MmNnOo6", *dataptr)) {
00825 *bufptr++ = '6';
00826 } else if (strchr("PpQqRrSs7", *dataptr)) {
00827 *bufptr++ = '7';
00828 } else if (strchr("TtUuVv8", *dataptr)) {
00829 *bufptr++ = '8';
00830 } else if (strchr("WwXxYyZz9", *dataptr)) {
00831 *bufptr++ = '9';
00832 } else if (*dataptr == '0') {
00833 *bufptr++ = '0';
00834 }
00835 }
00836 buf[buflen - 1] = '\0';
00837
00838 return 0;
00839 }
00840
00841 static struct ast_custom_function keypadhash_function = {
00842 .name = "KEYPADHASH",
00843 .synopsis = "Hash the letters in the string into the equivalent keypad numbers.",
00844 .syntax = "KEYPADHASH(<string>)",
00845 .read = keypadhash,
00846 .desc = "Example: ${KEYPADHASH(Les)} returns \"537\"\n",
00847 };
00848
00849 static int string_toupper(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
00850 {
00851 char *bufptr = buf, *dataptr = data;
00852
00853 while ((bufptr < buf + buflen - 1) && (*bufptr++ = toupper(*dataptr++)));
00854
00855 return 0;
00856 }
00857
00858 static struct ast_custom_function toupper_function = {
00859 .name = "TOUPPER",
00860 .synopsis = "Convert the string to upper case.",
00861 .syntax = "TOUPPER(<string>)",
00862 .read = string_toupper,
00863 .desc = "Example: ${TOUPPER(Example)} returns \"EXAMPLE\"\n",
00864 };
00865
00866 static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
00867 {
00868 char *bufptr = buf, *dataptr = data;
00869
00870 while ((bufptr < buf + buflen - 1) && (*bufptr++ = tolower(*dataptr++)));
00871
00872 return 0;
00873 }
00874
00875 static struct ast_custom_function tolower_function = {
00876 .name = "TOLOWER",
00877 .synopsis = "Convert the string to lower case.",
00878 .syntax = "TOLOWER(<string>)",
00879 .read = string_tolower,
00880 .desc = "Example: ${TOLOWER(Example)} returns \"example\"\n",
00881 };
00882
00883 static int unload_module(void)
00884 {
00885 int res = 0;
00886
00887 res |= ast_custom_function_unregister(&fieldqty_function);
00888 res |= ast_custom_function_unregister(&filter_function);
00889 res |= ast_custom_function_unregister(®ex_function);
00890 res |= ast_custom_function_unregister(&array_function);
00891 res |= ast_custom_function_unregister("e_function);
00892 res |= ast_custom_function_unregister(&csv_quote_function);
00893 res |= ast_custom_function_unregister(&len_function);
00894 res |= ast_custom_function_unregister(&strftime_function);
00895 res |= ast_custom_function_unregister(&strptime_function);
00896 res |= ast_custom_function_unregister(&eval_function);
00897 res |= ast_custom_function_unregister(&keypadhash_function);
00898 res |= ast_custom_function_unregister(&sprintf_function);
00899 res |= ast_custom_function_unregister(&hashkeys_function);
00900 res |= ast_custom_function_unregister(&hash_function);
00901 res |= ast_unregister_application(app_clearhash);
00902 res |= ast_custom_function_unregister(&toupper_function);
00903 res |= ast_custom_function_unregister(&tolower_function);
00904
00905 return res;
00906 }
00907
00908 static int load_module(void)
00909 {
00910 int res = 0;
00911
00912 res |= ast_custom_function_register(&fieldqty_function);
00913 res |= ast_custom_function_register(&filter_function);
00914 res |= ast_custom_function_register(®ex_function);
00915 res |= ast_custom_function_register(&array_function);
00916 res |= ast_custom_function_register("e_function);
00917 res |= ast_custom_function_register(&csv_quote_function);
00918 res |= ast_custom_function_register(&len_function);
00919 res |= ast_custom_function_register(&strftime_function);
00920 res |= ast_custom_function_register(&strptime_function);
00921 res |= ast_custom_function_register(&eval_function);
00922 res |= ast_custom_function_register(&keypadhash_function);
00923 res |= ast_custom_function_register(&sprintf_function);
00924 res |= ast_custom_function_register(&hashkeys_function);
00925 res |= ast_custom_function_register(&hash_function);
00926 res |= ast_register_application(app_clearhash, exec_clearhash, syn_clearhash, desc_clearhash);
00927 res |= ast_custom_function_register(&toupper_function);
00928 res |= ast_custom_function_register(&tolower_function);
00929
00930 return res;
00931 }
00932
00933 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "String handling dialplan functions");