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: 172707 $")
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++], "%d", &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++], "%lf", &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 *bufptr++ = '"';
00584 for (; bufptr < buf + len - 1; dataptr++) {
00585 if (*dataptr == '\\') {
00586 *bufptr++ = '\\';
00587 *bufptr++ = '\\';
00588 } else if (*dataptr == '"') {
00589 *bufptr++ = '\\';
00590 *bufptr++ = '"';
00591 } else if (*dataptr == '\0') {
00592 break;
00593 } else {
00594 *bufptr++ = *dataptr;
00595 }
00596 }
00597 *bufptr++ = '"';
00598 *bufptr = '\0';
00599 return 0;
00600 }
00601
00602 static struct ast_custom_function quote_function = {
00603 .name = "QUOTE",
00604 .synopsis = "Quotes a given string, escaping embedded quotes as necessary",
00605 .syntax = "QUOTE(<string>)",
00606 .read = quote,
00607 };
00608
00609
00610 static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf,
00611 size_t len)
00612 {
00613 int length = 0;
00614
00615 if (data)
00616 length = strlen(data);
00617
00618 snprintf(buf, len, "%d", length);
00619
00620 return 0;
00621 }
00622
00623 static struct ast_custom_function len_function = {
00624 .name = "LEN",
00625 .synopsis = "Returns the length of the argument given",
00626 .syntax = "LEN(<string>)",
00627 .read = len,
00628 };
00629
00630 static int acf_strftime(struct ast_channel *chan, const char *cmd, char *parse,
00631 char *buf, size_t len)
00632 {
00633 AST_DECLARE_APP_ARGS(args,
00634 AST_APP_ARG(epoch);
00635 AST_APP_ARG(timezone);
00636 AST_APP_ARG(format);
00637 );
00638 struct timeval tv;
00639 struct ast_tm tm;
00640
00641 buf[0] = '\0';
00642
00643 AST_STANDARD_APP_ARGS(args, parse);
00644
00645 ast_get_timeval(args.epoch, &tv, ast_tvnow(), NULL);
00646 ast_localtime(&tv, &tm, args.timezone);
00647
00648 if (!args.format)
00649 args.format = "%c";
00650
00651 if (ast_strftime(buf, len, args.format, &tm) <= 0)
00652 ast_log(LOG_WARNING, "C function strftime() output nothing?!!\n");
00653
00654 buf[len - 1] = '\0';
00655
00656 return 0;
00657 }
00658
00659 static struct ast_custom_function strftime_function = {
00660 .name = "STRFTIME",
00661 .synopsis = "Returns the current date/time in a specified format.",
00662 .syntax = "STRFTIME([<epoch>][,[timezone][,format]])",
00663 .desc =
00664 "STRFTIME sports all of the same formats as the underlying C function\n"
00665 "strftime(3) - see the man page for details. It also supports the\n"
00666 "following format:\n"
00667 " %[n]q - fractions of a second, with leading zeroes. For example, %3q will\n"
00668 " give milliseconds and %1q will give tenths of a second. The default\n"
00669 " is to output milliseconds (n=3). The common case is to use it in\n"
00670 " combination with %S, as in \"%S.%3q\".\n",
00671 .read = acf_strftime,
00672 };
00673
00674 static int acf_strptime(struct ast_channel *chan, const char *cmd, char *data,
00675 char *buf, size_t len)
00676 {
00677 AST_DECLARE_APP_ARGS(args,
00678 AST_APP_ARG(timestring);
00679 AST_APP_ARG(timezone);
00680 AST_APP_ARG(format);
00681 );
00682 union {
00683 struct ast_tm atm;
00684 struct tm time;
00685 } t = { { 0, }, };
00686
00687 buf[0] = '\0';
00688
00689 if (!data) {
00690 ast_log(LOG_ERROR,
00691 "Asterisk function STRPTIME() requires an argument.\n");
00692 return -1;
00693 }
00694
00695 AST_STANDARD_APP_ARGS(args, data);
00696
00697 if (ast_strlen_zero(args.format)) {
00698 ast_log(LOG_ERROR,
00699 "No format supplied to STRPTIME(<timestring>,<timezone>,<format>)");
00700 return -1;
00701 }
00702
00703 if (!strptime(args.timestring, args.format, &t.time)) {
00704 ast_log(LOG_WARNING, "C function strptime() output nothing?!!\n");
00705 } else {
00706 struct timeval tv;
00707
00708 t.atm.tm_isdst = -1;
00709 tv = ast_mktime(&t.atm, args.timezone);
00710 snprintf(buf, len, "%d", (int) tv.tv_sec);
00711 }
00712
00713 return 0;
00714 }
00715
00716 static struct ast_custom_function strptime_function = {
00717 .name = "STRPTIME",
00718 .synopsis =
00719 "Returns the epoch of the arbitrary date/time string structured as described in the format.",
00720 .syntax = "STRPTIME(<datetime>,<timezone>,<format>)",
00721 .desc =
00722 "This is useful for converting a date into an EPOCH time, possibly to pass to\n"
00723 "an application like SayUnixTime or to calculate the difference between two\n"
00724 "date strings.\n"
00725 "\n"
00726 "Example:\n"
00727 " ${STRPTIME(2006-03-01 07:30:35,America/Chicago,%Y-%m-%d %H:%M:%S)} returns 1141219835\n",
00728 .read = acf_strptime,
00729 };
00730
00731 static int function_eval(struct ast_channel *chan, const char *cmd, char *data,
00732 char *buf, size_t len)
00733 {
00734 if (ast_strlen_zero(data)) {
00735 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
00736 return -1;
00737 }
00738
00739 pbx_substitute_variables_helper(chan, data, buf, len - 1);
00740
00741 return 0;
00742 }
00743
00744 static struct ast_custom_function eval_function = {
00745 .name = "EVAL",
00746 .synopsis = "Evaluate stored variables.",
00747 .syntax = "EVAL(<variable>)",
00748 .desc = "Using EVAL basically causes a string to be evaluated twice.\n"
00749 "When a variable or expression is in the dialplan, it will be\n"
00750 "evaluated at runtime. However, if the result of the evaluation\n"
00751 "is in fact a variable or expression, using EVAL will have it\n"
00752 "evaluated a second time. For example, if the variable ${MYVAR}\n"
00753 "contains \"${OTHERVAR}\", then the result of putting ${EVAL(${MYVAR})}\n"
00754 "in the dialplan will be the contents of the variable, OTHERVAR.\n"
00755 "Normally, by just putting ${MYVAR} in the dialplan, you would be\n"
00756 "left with \"${OTHERVAR}\".\n",
00757 .read = function_eval,
00758 };
00759
00760 static int keypadhash(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00761 {
00762 char *bufptr, *dataptr;
00763
00764 for (bufptr = buf, dataptr = data; bufptr < buf + len - 1; dataptr++) {
00765 if (*dataptr == '\0') {
00766 *bufptr++ = '\0';
00767 break;
00768 } else if (*dataptr == '1') {
00769 *bufptr++ = '1';
00770 } else if (strchr("AaBbCc2", *dataptr)) {
00771 *bufptr++ = '2';
00772 } else if (strchr("DdEeFf3", *dataptr)) {
00773 *bufptr++ = '3';
00774 } else if (strchr("GgHhIi4", *dataptr)) {
00775 *bufptr++ = '4';
00776 } else if (strchr("JjKkLl5", *dataptr)) {
00777 *bufptr++ = '5';
00778 } else if (strchr("MmNnOo6", *dataptr)) {
00779 *bufptr++ = '6';
00780 } else if (strchr("PpQqRrSs7", *dataptr)) {
00781 *bufptr++ = '7';
00782 } else if (strchr("TtUuVv8", *dataptr)) {
00783 *bufptr++ = '8';
00784 } else if (strchr("WwXxYyZz9", *dataptr)) {
00785 *bufptr++ = '9';
00786 } else if (*dataptr == '0') {
00787 *bufptr++ = '0';
00788 }
00789 }
00790 buf[len - 1] = '\0';
00791
00792 return 0;
00793 }
00794
00795 static struct ast_custom_function keypadhash_function = {
00796 .name = "KEYPADHASH",
00797 .synopsis = "Hash the letters in the string into the equivalent keypad numbers.",
00798 .syntax = "KEYPADHASH(<string>)",
00799 .read = keypadhash,
00800 .desc = "Example: ${KEYPADHASH(Les)} returns \"537\"\n",
00801 };
00802
00803 static int string_toupper(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00804 {
00805 char *bufptr = buf, *dataptr = data;
00806
00807 while ((bufptr < buf + len - 1) && (*bufptr++ = toupper(*dataptr++)));
00808
00809 return 0;
00810 }
00811
00812 static struct ast_custom_function toupper_function = {
00813 .name = "TOUPPER",
00814 .synopsis = "Convert the string to upper case.",
00815 .syntax = "TOUPPER(<string>)",
00816 .read = string_toupper,
00817 .desc = "Example: ${TOUPPER(Example)} returns \"EXAMPLE\"\n",
00818 };
00819
00820 static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00821 {
00822 char *bufptr = buf, *dataptr = data;
00823
00824 while ((bufptr < buf + len - 1) && (*bufptr++ = tolower(*dataptr++)));
00825
00826 return 0;
00827 }
00828
00829 static struct ast_custom_function tolower_function = {
00830 .name = "TOLOWER",
00831 .synopsis = "Convert the string to lower case.",
00832 .syntax = "TOLOWER(<string>)",
00833 .read = string_tolower,
00834 .desc = "Example: ${TOLOWER(Example)} returns \"example\"\n",
00835 };
00836
00837 static int unload_module(void)
00838 {
00839 int res = 0;
00840
00841 res |= ast_custom_function_unregister(&fieldqty_function);
00842 res |= ast_custom_function_unregister(&filter_function);
00843 res |= ast_custom_function_unregister(®ex_function);
00844 res |= ast_custom_function_unregister(&array_function);
00845 res |= ast_custom_function_unregister("e_function);
00846 res |= ast_custom_function_unregister(&len_function);
00847 res |= ast_custom_function_unregister(&strftime_function);
00848 res |= ast_custom_function_unregister(&strptime_function);
00849 res |= ast_custom_function_unregister(&eval_function);
00850 res |= ast_custom_function_unregister(&keypadhash_function);
00851 res |= ast_custom_function_unregister(&sprintf_function);
00852 res |= ast_custom_function_unregister(&hashkeys_function);
00853 res |= ast_custom_function_unregister(&hash_function);
00854 res |= ast_unregister_application(app_clearhash);
00855 res |= ast_custom_function_unregister(&toupper_function);
00856 res |= ast_custom_function_unregister(&tolower_function);
00857
00858 return res;
00859 }
00860
00861 static int load_module(void)
00862 {
00863 int res = 0;
00864
00865 res |= ast_custom_function_register(&fieldqty_function);
00866 res |= ast_custom_function_register(&filter_function);
00867 res |= ast_custom_function_register(®ex_function);
00868 res |= ast_custom_function_register(&array_function);
00869 res |= ast_custom_function_register("e_function);
00870 res |= ast_custom_function_register(&len_function);
00871 res |= ast_custom_function_register(&strftime_function);
00872 res |= ast_custom_function_register(&strptime_function);
00873 res |= ast_custom_function_register(&eval_function);
00874 res |= ast_custom_function_register(&keypadhash_function);
00875 res |= ast_custom_function_register(&sprintf_function);
00876 res |= ast_custom_function_register(&hashkeys_function);
00877 res |= ast_custom_function_register(&hash_function);
00878 res |= ast_register_application(app_clearhash, exec_clearhash, syn_clearhash, desc_clearhash);
00879 res |= ast_custom_function_register(&toupper_function);
00880 res |= ast_custom_function_register(&tolower_function);
00881
00882 return res;
00883 }
00884
00885 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "String handling dialplan functions");