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