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
00029
00030
00031
00032 #include "asterisk.h"
00033
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 416500 $")
00035
00036 #include <regex.h>
00037 #include <ctype.h>
00038
00039 #include "asterisk/module.h"
00040 #include "asterisk/channel.h"
00041 #include "asterisk/pbx.h"
00042 #include "asterisk/utils.h"
00043 #include "asterisk/app.h"
00044 #include "asterisk/localtime.h"
00045 #include "asterisk/test.h"
00046
00047 AST_THREADSTORAGE(result_buf);
00048 AST_THREADSTORAGE(tmp_buf);
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424 static int function_fieldqty_helper(struct ast_channel *chan, const char *cmd,
00425 char *parse, char *buf, struct ast_str **sbuf, ssize_t len)
00426 {
00427 char *varsubst;
00428 struct ast_str *str = ast_str_thread_get(&result_buf, 16);
00429 int fieldcount = 0;
00430 AST_DECLARE_APP_ARGS(args,
00431 AST_APP_ARG(varname);
00432 AST_APP_ARG(delim);
00433 );
00434 char delim[2] = "";
00435 size_t delim_used;
00436
00437 if (!str) {
00438 return -1;
00439 }
00440
00441 AST_STANDARD_APP_ARGS(args, parse);
00442 if (args.delim) {
00443 ast_get_encoded_char(args.delim, delim, &delim_used);
00444
00445 varsubst = ast_alloca(strlen(args.varname) + 4);
00446
00447 sprintf(varsubst, "${%s}", args.varname);
00448 ast_str_substitute_variables(&str, 0, chan, varsubst);
00449 if (ast_str_strlen(str) == 0) {
00450 fieldcount = 0;
00451 } else {
00452 char *varval = ast_str_buffer(str);
00453 while (strsep(&varval, delim)) {
00454 fieldcount++;
00455 }
00456 }
00457 } else {
00458 fieldcount = 1;
00459 }
00460 if (sbuf) {
00461 ast_str_set(sbuf, len, "%d", fieldcount);
00462 } else {
00463 snprintf(buf, len, "%d", fieldcount);
00464 }
00465
00466 return 0;
00467 }
00468
00469 static int function_fieldqty(struct ast_channel *chan, const char *cmd,
00470 char *parse, char *buf, size_t len)
00471 {
00472 return function_fieldqty_helper(chan, cmd, parse, buf, NULL, len);
00473 }
00474
00475 static int function_fieldqty_str(struct ast_channel *chan, const char *cmd,
00476 char *parse, struct ast_str **buf, ssize_t len)
00477 {
00478 return function_fieldqty_helper(chan, cmd, parse, NULL, buf, len);
00479 }
00480
00481 static struct ast_custom_function fieldqty_function = {
00482 .name = "FIELDQTY",
00483 .read = function_fieldqty,
00484 .read2 = function_fieldqty_str,
00485 };
00486
00487 static int function_fieldnum_helper(struct ast_channel *chan, const char *cmd,
00488 char *parse, char *buf, struct ast_str **sbuf, ssize_t len)
00489 {
00490 char *varsubst, *field;
00491 struct ast_str *str = ast_str_thread_get(&result_buf, 16);
00492 int fieldindex = 0, res = 0;
00493 AST_DECLARE_APP_ARGS(args,
00494 AST_APP_ARG(varname);
00495 AST_APP_ARG(delim);
00496 AST_APP_ARG(field);
00497 );
00498 char delim[2] = "";
00499 size_t delim_used;
00500
00501 if (!str) {
00502 return -1;
00503 }
00504
00505 AST_STANDARD_APP_ARGS(args, parse);
00506
00507 if (args.argc < 3) {
00508 ast_log(LOG_ERROR, "Usage: FIELDNUM(<listname>,<delimiter>,<fieldvalue>)\n");
00509 res = -1;
00510 } else {
00511 varsubst = ast_alloca(strlen(args.varname) + 4);
00512 sprintf(varsubst, "${%s}", args.varname);
00513
00514 ast_str_substitute_variables(&str, 0, chan, varsubst);
00515
00516 if (ast_str_strlen(str) == 0 || ast_strlen_zero(args.delim)) {
00517 fieldindex = 0;
00518 } else if (ast_get_encoded_char(args.delim, delim, &delim_used) == -1) {
00519 res = -1;
00520 } else {
00521 char *varval = ast_str_buffer(str);
00522
00523 while ((field = strsep(&varval, delim)) != NULL) {
00524 fieldindex++;
00525
00526 if (!strcasecmp(field, args.field)) {
00527 break;
00528 }
00529 }
00530
00531 if (!field) {
00532 fieldindex = 0;
00533 }
00534
00535 res = 0;
00536 }
00537 }
00538
00539 if (sbuf) {
00540 ast_str_set(sbuf, len, "%d", fieldindex);
00541 } else {
00542 snprintf(buf, len, "%d", fieldindex);
00543 }
00544
00545 return res;
00546 }
00547
00548 static int function_fieldnum(struct ast_channel *chan, const char *cmd,
00549 char *parse, char *buf, size_t len)
00550 {
00551 return function_fieldnum_helper(chan, cmd, parse, buf, NULL, len);
00552 }
00553
00554 static int function_fieldnum_str(struct ast_channel *chan, const char *cmd,
00555 char *parse, struct ast_str **buf, ssize_t len)
00556 {
00557 return function_fieldnum_helper(chan, cmd, parse, NULL, buf, len);
00558 }
00559
00560 static struct ast_custom_function fieldnum_function = {
00561 .name = "FIELDNUM",
00562 .read = function_fieldnum,
00563 .read2 = function_fieldnum_str,
00564 };
00565
00566 static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, struct ast_str **bufstr, ssize_t len)
00567 {
00568 AST_DECLARE_APP_ARGS(args,
00569 AST_APP_ARG(listname);
00570 AST_APP_ARG(delimiter);
00571 AST_APP_ARG(fieldvalue);
00572 );
00573 struct ast_str *orig_list = ast_str_thread_get(&tmp_buf, 16);
00574 const char *begin, *cur, *next;
00575 int dlen, flen, first = 1;
00576 struct ast_str *result, **result_ptr = &result;
00577 char *delim, *varsubst;
00578
00579 AST_STANDARD_APP_ARGS(args, parse);
00580
00581 if (buf) {
00582 if (!(result = ast_str_thread_get(&result_buf, 16))) {
00583 return -1;
00584 }
00585 } else {
00586
00587 result_ptr = bufstr;
00588 }
00589
00590 if (args.argc < 3) {
00591 ast_log(LOG_ERROR, "Usage: LISTFILTER(<listname>,<delimiter>,<fieldvalue>)\n");
00592 return -1;
00593 }
00594
00595 varsubst = ast_alloca(strlen(args.listname) + 4);
00596 sprintf(varsubst, "${%s}", args.listname);
00597
00598
00599 if (chan) {
00600 ast_channel_lock(chan);
00601 }
00602 ast_str_substitute_variables(&orig_list, 0, chan, varsubst);
00603 if (!ast_str_strlen(orig_list)) {
00604 ast_log(LOG_ERROR, "List variable '%s' not found\n", args.listname);
00605 if (chan) {
00606 ast_channel_unlock(chan);
00607 }
00608 return -1;
00609 }
00610
00611
00612 if (!strstr(ast_str_buffer(orig_list), args.fieldvalue)) {
00613 if (buf) {
00614 ast_copy_string(buf, ast_str_buffer(orig_list), len);
00615 } else {
00616 ast_str_set(result_ptr, len, "%s", ast_str_buffer(orig_list));
00617 }
00618 if (chan) {
00619 ast_channel_unlock(chan);
00620 }
00621 return 0;
00622 }
00623
00624 dlen = strlen(args.delimiter);
00625 delim = ast_alloca(dlen + 1);
00626 ast_get_encoded_str(args.delimiter, delim, dlen + 1);
00627
00628 if ((dlen = strlen(delim)) == 0) {
00629 delim = ",";
00630 dlen = 1;
00631 }
00632
00633 flen = strlen(args.fieldvalue);
00634
00635 ast_str_reset(*result_ptr);
00636
00637 if (len > -1) {
00638 ast_str_make_space(result_ptr, len ? len : ast_str_strlen(orig_list) + 1);
00639 }
00640
00641 begin = ast_str_buffer(orig_list);
00642 next = strstr(begin, delim);
00643
00644 do {
00645
00646 if (next) {
00647 cur = next;
00648 next = strstr(cur + dlen, delim);
00649 } else {
00650 cur = strchr(begin + dlen, '\0');
00651 }
00652
00653 if (flen == cur - begin && !strncmp(begin, args.fieldvalue, flen)) {
00654
00655 begin += flen + dlen;
00656 } else {
00657
00658 if (!first) {
00659 ast_str_append(result_ptr, len, "%s", delim);
00660 }
00661
00662 ast_str_append_substr(result_ptr, len, begin, cur - begin);
00663 first = 0;
00664 begin = cur + dlen;
00665 }
00666 } while (*cur != '\0');
00667 if (chan) {
00668 ast_channel_unlock(chan);
00669 }
00670
00671 if (buf) {
00672 ast_copy_string(buf, ast_str_buffer(result), len);
00673 }
00674
00675 return 0;
00676 }
00677
00678 static int listfilter_read(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
00679 {
00680 return listfilter(chan, cmd, parse, buf, NULL, len);
00681 }
00682
00683 static int listfilter_read2(struct ast_channel *chan, const char *cmd, char *parse, struct ast_str **buf, ssize_t len)
00684 {
00685 return listfilter(chan, cmd, parse, NULL, buf, len);
00686 }
00687
00688 static struct ast_custom_function listfilter_function = {
00689 .name = "LISTFILTER",
00690 .read = listfilter_read,
00691 .read2 = listfilter_read2,
00692 };
00693
00694 static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf,
00695 size_t len)
00696 {
00697 AST_DECLARE_APP_ARGS(args,
00698 AST_APP_ARG(allowed);
00699 AST_APP_ARG(string);
00700 );
00701 char *outbuf = buf;
00702 unsigned char ac;
00703 char allowed[256] = "";
00704 size_t allowedlen = 0;
00705 int32_t bitfield[8] = { 0, };
00706
00707 AST_STANDARD_RAW_ARGS(args, parse);
00708
00709 if (!args.string) {
00710 ast_log(LOG_ERROR, "Usage: FILTER(<allowed-chars>,<string>)\n");
00711 return -1;
00712 }
00713
00714 if (args.allowed[0] == '"' && !ast_opt_dont_warn) {
00715 ast_log(LOG_WARNING, "FILTER allowed characters includes the quote (\") character. This may not be what you want.\n");
00716 }
00717
00718
00719 for (; *(args.allowed);) {
00720 char c1 = 0, c2 = 0;
00721 size_t consumed = 0;
00722
00723 if (ast_get_encoded_char(args.allowed, &c1, &consumed))
00724 return -1;
00725 args.allowed += consumed;
00726
00727 if (*(args.allowed) == '-') {
00728 if (ast_get_encoded_char(args.allowed + 1, &c2, &consumed))
00729 c2 = c1;
00730 args.allowed += consumed + 1;
00731
00732 if ((unsigned char) c2 < (unsigned char) c1 && !ast_opt_dont_warn) {
00733 ast_log(LOG_WARNING, "Range wrapping in FILTER(%s,%s). This may not be what you want.\n", parse, args.string);
00734 }
00735
00736
00737
00738
00739
00740 for (ac = (unsigned char) c1; ac != (unsigned char) c2; ac++) {
00741 bitfield[ac / 32] |= 1 << (ac % 32);
00742 }
00743 bitfield[ac / 32] |= 1 << (ac % 32);
00744
00745 ast_debug(4, "c1=%d, c2=%d\n", c1, c2);
00746 } else {
00747 ac = (unsigned char) c1;
00748 ast_debug(4, "c1=%d, consumed=%d, args.allowed=%s\n", c1, (int) consumed, args.allowed - consumed);
00749 bitfield[ac / 32] |= 1 << (ac % 32);
00750 }
00751 }
00752
00753 for (ac = 1; ac != 0; ac++) {
00754 if (bitfield[ac / 32] & (1 << (ac % 32))) {
00755 allowed[allowedlen++] = ac;
00756 }
00757 }
00758
00759 ast_debug(1, "Allowed: %s\n", allowed);
00760
00761 for (; *(args.string) && (buf + len - 1 > outbuf); (args.string)++) {
00762 if (strchr(allowed, *(args.string)))
00763 *outbuf++ = *(args.string);
00764 }
00765 *outbuf = '\0';
00766
00767 return 0;
00768 }
00769
00770 static struct ast_custom_function filter_function = {
00771 .name = "FILTER",
00772 .read = filter,
00773 };
00774
00775 static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
00776 {
00777 AST_DECLARE_APP_ARGS(args,
00778 AST_APP_ARG(varname);
00779 AST_APP_ARG(find);
00780 AST_APP_ARG(replace);
00781 );
00782 char *strptr, *varsubst;
00783 RAII_VAR(struct ast_str *, str, ast_str_create(16), ast_free);
00784 char find[256];
00785 char replace[2] = "";
00786 size_t unused;
00787
00788 AST_STANDARD_APP_ARGS(args, data);
00789
00790 if (!str) {
00791 return -1;
00792 }
00793
00794 if (args.argc < 2) {
00795 ast_log(LOG_ERROR, "Usage: %s(<varname>,<search-chars>[,<replace-char>])\n", cmd);
00796 return -1;
00797 }
00798
00799
00800 ast_get_encoded_str(args.find, find, sizeof(find));
00801 ast_get_encoded_char(args.replace, replace, &unused);
00802
00803 if (ast_strlen_zero(find) || ast_strlen_zero(args.varname)) {
00804 ast_log(LOG_ERROR, "The characters to search for and the variable name must not be empty.\n");
00805 return -1;
00806 }
00807
00808 varsubst = ast_alloca(strlen(args.varname) + 4);
00809 sprintf(varsubst, "${%s}", args.varname);
00810 ast_str_substitute_variables(&str, 0, chan, varsubst);
00811
00812 if (!ast_str_strlen(str)) {
00813
00814 return -1;
00815 }
00816
00817 ast_debug(3, "String to search: (%s)\n", ast_str_buffer(str));
00818 ast_debug(3, "Characters to find: (%s)\n", find);
00819 ast_debug(3, "Character to replace with: (%s)\n", replace);
00820
00821 for (strptr = ast_str_buffer(str); *strptr; strptr++) {
00822
00823
00824 if (strchr(find, *strptr)) {
00825 if (ast_strlen_zero(replace)) {
00826 memmove(strptr, strptr + 1, strlen(strptr + 1) + 1);
00827 strptr--;
00828 } else {
00829
00830 *strptr = *replace;
00831 }
00832 }
00833 }
00834
00835 ast_str_set(buf, len, "%s", ast_str_buffer(str));
00836 return 0;
00837 }
00838
00839 static struct ast_custom_function replace_function = {
00840 .name = "REPLACE",
00841 .read2 = replace,
00842 };
00843
00844 static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf,
00845 size_t len)
00846 {
00847 AST_DECLARE_APP_ARGS(args,
00848 AST_APP_ARG(null);
00849 AST_APP_ARG(reg);
00850 AST_APP_ARG(str);
00851 );
00852 int errcode;
00853 regex_t regexbuf;
00854
00855 buf[0] = '\0';
00856
00857 AST_NONSTANDARD_APP_ARGS(args, parse, '"');
00858
00859 if (args.argc != 3) {
00860 ast_log(LOG_ERROR, "Unexpected arguments: should have been in the form '\"<regex>\" <string>'\n");
00861 return -1;
00862 }
00863 if ((*args.str == ' ') || (*args.str == '\t'))
00864 args.str++;
00865
00866 ast_debug(1, "FUNCTION REGEX (%s)(%s)\n", args.reg, args.str);
00867
00868 if ((errcode = regcomp(®exbuf, args.reg, REG_EXTENDED | REG_NOSUB))) {
00869 regerror(errcode, ®exbuf, buf, len);
00870 ast_log(LOG_WARNING, "Malformed input %s(%s): %s\n", cmd, parse, buf);
00871 return -1;
00872 }
00873
00874 strcpy(buf, regexec(®exbuf, args.str, 0, NULL, 0) ? "0" : "1");
00875
00876 regfree(®exbuf);
00877
00878 return 0;
00879 }
00880
00881 static struct ast_custom_function regex_function = {
00882 .name = "REGEX",
00883 .read = regex,
00884 };
00885
00886 #define HASH_PREFIX "~HASH~%s~"
00887 #define HASH_FORMAT HASH_PREFIX "%s~"
00888
00889 static char *app_clearhash = "ClearHash";
00890
00891
00892 static void clearvar_prefix(struct ast_channel *chan, const char *prefix)
00893 {
00894 struct ast_var_t *var;
00895 int len = strlen(prefix);
00896 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->varshead, var, entries) {
00897 if (strncasecmp(prefix, ast_var_name(var), len) == 0) {
00898 AST_LIST_REMOVE_CURRENT(entries);
00899 ast_free(var);
00900 }
00901 }
00902 AST_LIST_TRAVERSE_SAFE_END
00903 }
00904
00905 static int exec_clearhash(struct ast_channel *chan, const char *data)
00906 {
00907 char prefix[80];
00908 snprintf(prefix, sizeof(prefix), HASH_PREFIX, data ? (char *)data : "null");
00909 clearvar_prefix(chan, prefix);
00910 return 0;
00911 }
00912
00913 static int array(struct ast_channel *chan, const char *cmd, char *var,
00914 const char *value)
00915 {
00916 AST_DECLARE_APP_ARGS(arg1,
00917 AST_APP_ARG(var)[100];
00918 );
00919 AST_DECLARE_APP_ARGS(arg2,
00920 AST_APP_ARG(val)[100];
00921 );
00922 char *origvar = "", *value2, varname[256];
00923 int i, ishash = 0;
00924
00925 if (!var) {
00926 return -1;
00927 }
00928 value2 = ast_strdupa(value);
00929
00930 if (!strcmp(cmd, "HASH")) {
00931 const char *var2 = pbx_builtin_getvar_helper(chan, "~ODBCFIELDS~");
00932 origvar = var;
00933 if (var2)
00934 var = ast_strdupa(var2);
00935 else {
00936 if (chan)
00937 ast_autoservice_stop(chan);
00938 return -1;
00939 }
00940 ishash = 1;
00941 }
00942
00943
00944
00945
00946
00947
00948
00949 ast_debug(1, "array (%s=%s)\n", var, S_OR(value2, ""));
00950 AST_STANDARD_APP_ARGS(arg1, var);
00951
00952 AST_STANDARD_APP_ARGS(arg2, value2);
00953
00954 for (i = 0; i < arg1.argc; i++) {
00955 ast_debug(1, "array set value (%s=%s)\n", arg1.var[i],
00956 S_OR(arg2.val[i], ""));
00957 if (i < arg2.argc) {
00958 if (ishash) {
00959 if (origvar[0] == '_') {
00960 if (origvar[1] == '_') {
00961 snprintf(varname, sizeof(varname), "__" HASH_FORMAT, origvar + 2, arg1.var[i]);
00962 } else {
00963 snprintf(varname, sizeof(varname), "_" HASH_FORMAT, origvar + 1, arg1.var[i]);
00964 }
00965 } else {
00966 snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
00967 }
00968
00969 pbx_builtin_setvar_helper(chan, varname, arg2.val[i]);
00970 } else {
00971 pbx_builtin_setvar_helper(chan, arg1.var[i], arg2.val[i]);
00972 }
00973 } else {
00974
00975
00976 if (ishash) {
00977 snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
00978 pbx_builtin_setvar_helper(chan, varname, "");
00979 } else {
00980 pbx_builtin_setvar_helper(chan, arg1.var[i], "");
00981 }
00982 }
00983 }
00984
00985 return 0;
00986 }
00987
00988 static int hashkeys_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
00989 {
00990 struct ast_var_t *newvar;
00991 struct ast_str *prefix = ast_str_alloca(80);
00992
00993 if (!chan) {
00994 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
00995 return -1;
00996 }
00997
00998 ast_str_set(&prefix, -1, HASH_PREFIX, data);
00999 memset(buf, 0, len);
01000
01001 AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) {
01002 if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
01003
01004 strncat(buf, ast_var_name(newvar) + ast_str_strlen(prefix), len - strlen(buf) - 1);
01005
01006 buf[strlen(buf) - 1] = ',';
01007 }
01008 }
01009
01010 buf[strlen(buf) - 1] = '\0';
01011 return 0;
01012 }
01013
01014 static int hashkeys_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
01015 {
01016 struct ast_var_t *newvar;
01017 struct ast_str *prefix = ast_str_alloca(80);
01018 char *tmp;
01019
01020 if (!chan) {
01021 ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
01022 return -1;
01023 }
01024
01025 ast_str_set(&prefix, -1, HASH_PREFIX, data);
01026
01027 AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) {
01028 if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
01029
01030 ast_str_append(buf, len, "%s", ast_var_name(newvar) + ast_str_strlen(prefix));
01031
01032 tmp = ast_str_buffer(*buf);
01033 tmp[ast_str_strlen(*buf) - 1] = ',';
01034 }
01035 }
01036
01037 tmp = ast_str_buffer(*buf);
01038 tmp[ast_str_strlen(*buf) - 1] = '\0';
01039 return 0;
01040 }
01041
01042 static int hash_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
01043 {
01044 char varname[256];
01045 AST_DECLARE_APP_ARGS(arg,
01046 AST_APP_ARG(hashname);
01047 AST_APP_ARG(hashkey);
01048 );
01049
01050 if (!strchr(var, ',')) {
01051
01052 return array(chan, "HASH", var, value);
01053 }
01054
01055 AST_STANDARD_APP_ARGS(arg, var);
01056 if (arg.hashname[0] == '_') {
01057 if (arg.hashname[1] == '_') {
01058 snprintf(varname, sizeof(varname), "__" HASH_FORMAT, arg.hashname + 2, arg.hashkey);
01059 } else {
01060 snprintf(varname, sizeof(varname), "_" HASH_FORMAT, arg.hashname + 1, arg.hashkey);
01061 }
01062 } else {
01063 snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
01064 }
01065 pbx_builtin_setvar_helper(chan, varname, value);
01066
01067 return 0;
01068 }
01069
01070 static int hash_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
01071 {
01072 char varname[256];
01073 const char *varvalue;
01074 AST_DECLARE_APP_ARGS(arg,
01075 AST_APP_ARG(hashname);
01076 AST_APP_ARG(hashkey);
01077 );
01078
01079 AST_STANDARD_APP_ARGS(arg, data);
01080 if (arg.argc == 2) {
01081 snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
01082 varvalue = pbx_builtin_getvar_helper(chan, varname);
01083 if (varvalue)
01084 ast_copy_string(buf, varvalue, len);
01085 else
01086 *buf = '\0';
01087 } else if (arg.argc == 1) {
01088 char colnames[4096];
01089 int i;
01090 AST_DECLARE_APP_ARGS(arg2,
01091 AST_APP_ARG(col)[100];
01092 );
01093
01094 if (!chan) {
01095 ast_log(LOG_WARNING, "No channel and only 1 parameter was provided to %s function.\n", cmd);
01096 return -1;
01097 }
01098
01099
01100 hashkeys_read(chan, "HASHKEYS", arg.hashname, colnames, sizeof(colnames));
01101 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames);
01102
01103 AST_STANDARD_APP_ARGS(arg2, colnames);
01104 *buf = '\0';
01105
01106
01107 for (i = 0; i < arg2.argc; i++) {
01108 snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg2.col[i]);
01109 varvalue = pbx_builtin_getvar_helper(chan, varname);
01110 strncat(buf, varvalue, len - strlen(buf) - 1);
01111 strncat(buf, ",", len - strlen(buf) - 1);
01112 }
01113
01114
01115 buf[strlen(buf) - 1] = '\0';
01116 }
01117
01118 return 0;
01119 }
01120
01121 static struct ast_custom_function hash_function = {
01122 .name = "HASH",
01123 .write = hash_write,
01124 .read = hash_read,
01125 };
01126
01127 static struct ast_custom_function hashkeys_function = {
01128 .name = "HASHKEYS",
01129 .read = hashkeys_read,
01130 .read2 = hashkeys_read2,
01131 };
01132
01133 static struct ast_custom_function array_function = {
01134 .name = "ARRAY",
01135 .write = array,
01136 };
01137
01138 static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
01139 {
01140 char *bufptr = buf, *dataptr = data;
01141
01142 if (len < 3){
01143 ast_log(LOG_ERROR, "Not enough buffer\n");
01144 return -1;
01145 }
01146
01147 if (ast_strlen_zero(data)) {
01148 ast_log(LOG_WARNING, "No argument specified!\n");
01149 ast_copy_string(buf, "\"\"", len);
01150 return 0;
01151 }
01152
01153 *bufptr++ = '"';
01154 for (; bufptr < buf + len - 3; dataptr++) {
01155 if (*dataptr == '\\') {
01156 *bufptr++ = '\\';
01157 *bufptr++ = '\\';
01158 } else if (*dataptr == '"') {
01159 *bufptr++ = '\\';
01160 *bufptr++ = '"';
01161 } else if (*dataptr == '\0') {
01162 break;
01163 } else {
01164 *bufptr++ = *dataptr;
01165 }
01166 }
01167 *bufptr++ = '"';
01168 *bufptr = '\0';
01169 return 0;
01170 }
01171
01172 static struct ast_custom_function quote_function = {
01173 .name = "QUOTE",
01174 .read = quote,
01175 };
01176
01177 static int csv_quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
01178 {
01179 char *bufptr = buf, *dataptr = data;
01180
01181 if (len < 3) {
01182 ast_log(LOG_ERROR, "Not enough buffer\n");
01183 return -1;
01184 }
01185
01186 if (ast_strlen_zero(data)) {
01187 ast_copy_string(buf, "\"\"", len);
01188 return 0;
01189 }
01190
01191 *bufptr++ = '"';
01192 for (; bufptr < buf + len - 3; dataptr++){
01193 if (*dataptr == '"') {
01194 *bufptr++ = '"';
01195 *bufptr++ = '"';
01196 } else if (*dataptr == '\0') {
01197 break;
01198 } else {
01199 *bufptr++ = *dataptr;
01200 }
01201 }
01202 *bufptr++ = '"';
01203 *bufptr='\0';
01204 return 0;
01205 }
01206
01207 static struct ast_custom_function csv_quote_function = {
01208 .name = "CSV_QUOTE",
01209 .read = csv_quote,
01210 };
01211
01212 static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
01213 {
01214 int length = 0;
01215
01216 if (data)
01217 length = strlen(data);
01218
01219 snprintf(buf, buflen, "%d", length);
01220
01221 return 0;
01222 }
01223
01224 static struct ast_custom_function len_function = {
01225 .name = "LEN",
01226 .read = len,
01227 .read_max = 12,
01228 };
01229
01230 static int acf_strftime(struct ast_channel *chan, const char *cmd, char *parse,
01231 char *buf, size_t buflen)
01232 {
01233 AST_DECLARE_APP_ARGS(args,
01234 AST_APP_ARG(epoch);
01235 AST_APP_ARG(timezone);
01236 AST_APP_ARG(format);
01237 );
01238 struct timeval when;
01239 struct ast_tm tm;
01240
01241 buf[0] = '\0';
01242
01243 AST_STANDARD_APP_ARGS(args, parse);
01244
01245 ast_get_timeval(args.epoch, &when, ast_tvnow(), NULL);
01246 ast_localtime(&when, &tm, args.timezone);
01247
01248 if (!args.format)
01249 args.format = "%c";
01250
01251 if (ast_strftime(buf, buflen, args.format, &tm) <= 0)
01252 ast_log(LOG_WARNING, "C function strftime() output nothing?!!\n");
01253
01254 buf[buflen - 1] = '\0';
01255
01256 return 0;
01257 }
01258
01259 static struct ast_custom_function strftime_function = {
01260 .name = "STRFTIME",
01261 .read = acf_strftime,
01262 };
01263
01264 static int acf_strptime(struct ast_channel *chan, const char *cmd, char *data,
01265 char *buf, size_t buflen)
01266 {
01267 AST_DECLARE_APP_ARGS(args,
01268 AST_APP_ARG(timestring);
01269 AST_APP_ARG(timezone);
01270 AST_APP_ARG(format);
01271 );
01272 struct ast_tm tm;
01273
01274 buf[0] = '\0';
01275
01276 if (!data) {
01277 ast_log(LOG_ERROR,
01278 "Asterisk function STRPTIME() requires an argument.\n");
01279 return -1;
01280 }
01281
01282 AST_STANDARD_APP_ARGS(args, data);
01283
01284 if (ast_strlen_zero(args.format)) {
01285 ast_log(LOG_ERROR,
01286 "No format supplied to STRPTIME(<timestring>,<timezone>,<format>)");
01287 return -1;
01288 }
01289
01290 if (!ast_strptime(args.timestring, args.format, &tm)) {
01291 ast_log(LOG_WARNING, "STRPTIME() found no time specified within the string\n");
01292 } else {
01293 struct timeval when;
01294 when = ast_mktime(&tm, args.timezone);
01295 snprintf(buf, buflen, "%d", (int) when.tv_sec);
01296 }
01297
01298 return 0;
01299 }
01300
01301 static struct ast_custom_function strptime_function = {
01302 .name = "STRPTIME",
01303 .read = acf_strptime,
01304 };
01305
01306 static int function_eval(struct ast_channel *chan, const char *cmd, char *data,
01307 char *buf, size_t buflen)
01308 {
01309 if (ast_strlen_zero(data)) {
01310 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
01311 return -1;
01312 }
01313
01314 pbx_substitute_variables_helper(chan, data, buf, buflen - 1);
01315
01316 return 0;
01317 }
01318
01319 static int function_eval2(struct ast_channel *chan, const char *cmd, char *data,
01320 struct ast_str **buf, ssize_t buflen)
01321 {
01322 if (ast_strlen_zero(data)) {
01323 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
01324 return -1;
01325 }
01326
01327 ast_str_substitute_variables(buf, buflen, chan, data);
01328
01329 return 0;
01330 }
01331
01332 static struct ast_custom_function eval_function = {
01333 .name = "EVAL",
01334 .read = function_eval,
01335 .read2 = function_eval2,
01336 };
01337
01338 static int keypadhash(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
01339 {
01340 char *bufptr, *dataptr;
01341
01342 for (bufptr = buf, dataptr = data; bufptr < buf + buflen - 1; dataptr++) {
01343 if (*dataptr == '\0') {
01344 *bufptr++ = '\0';
01345 break;
01346 } else if (*dataptr == '1') {
01347 *bufptr++ = '1';
01348 } else if (strchr("AaBbCc2", *dataptr)) {
01349 *bufptr++ = '2';
01350 } else if (strchr("DdEeFf3", *dataptr)) {
01351 *bufptr++ = '3';
01352 } else if (strchr("GgHhIi4", *dataptr)) {
01353 *bufptr++ = '4';
01354 } else if (strchr("JjKkLl5", *dataptr)) {
01355 *bufptr++ = '5';
01356 } else if (strchr("MmNnOo6", *dataptr)) {
01357 *bufptr++ = '6';
01358 } else if (strchr("PpQqRrSs7", *dataptr)) {
01359 *bufptr++ = '7';
01360 } else if (strchr("TtUuVv8", *dataptr)) {
01361 *bufptr++ = '8';
01362 } else if (strchr("WwXxYyZz9", *dataptr)) {
01363 *bufptr++ = '9';
01364 } else if (*dataptr == '0') {
01365 *bufptr++ = '0';
01366 }
01367 }
01368 buf[buflen - 1] = '\0';
01369
01370 return 0;
01371 }
01372
01373 static struct ast_custom_function keypadhash_function = {
01374 .name = "KEYPADHASH",
01375 .read = keypadhash,
01376 };
01377
01378 static int string_toupper(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
01379 {
01380 char *bufptr = buf, *dataptr = data;
01381
01382 while ((bufptr < buf + buflen - 1) && (*bufptr++ = toupper(*dataptr++)));
01383
01384 return 0;
01385 }
01386
01387 static int string_toupper2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
01388 {
01389 char *bufptr, *dataptr = data;
01390
01391 if (buflen > -1) {
01392 ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
01393 }
01394 bufptr = ast_str_buffer(*buf);
01395 while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = toupper(*dataptr++)));
01396 ast_str_update(*buf);
01397
01398 return 0;
01399 }
01400
01401 static struct ast_custom_function toupper_function = {
01402 .name = "TOUPPER",
01403 .read = string_toupper,
01404 .read2 = string_toupper2,
01405 };
01406
01407 static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
01408 {
01409 char *bufptr = buf, *dataptr = data;
01410
01411 while ((bufptr < buf + buflen - 1) && (*bufptr++ = tolower(*dataptr++)));
01412
01413 return 0;
01414 }
01415
01416 static int string_tolower2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
01417 {
01418 char *bufptr, *dataptr = data;
01419
01420 if (buflen > -1) {
01421 ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
01422 }
01423 bufptr = ast_str_buffer(*buf);
01424 while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = tolower(*dataptr++)));
01425 ast_str_update(*buf);
01426
01427 return 0;
01428 }
01429
01430 static struct ast_custom_function tolower_function = {
01431 .name = "TOLOWER",
01432 .read = string_tolower,
01433 .read2 = string_tolower2,
01434 };
01435
01436 static int shift_pop(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
01437 {
01438 #define beginning (cmd[0] == 'S')
01439 char *after, delimiter[2] = ",", *varsubst;
01440 size_t unused;
01441 struct ast_str *before = ast_str_thread_get(&result_buf, 16);
01442 char *(*search_func)(const char *s, int c) = (beginning ? strchr : strrchr);
01443 AST_DECLARE_APP_ARGS(args,
01444 AST_APP_ARG(var);
01445 AST_APP_ARG(delimiter);
01446 );
01447
01448 if (!before) {
01449 return -1;
01450 }
01451
01452 AST_STANDARD_APP_ARGS(args, data);
01453
01454 if (ast_strlen_zero(args.var)) {
01455 ast_log(LOG_WARNING, "%s requires a variable name\n", cmd);
01456 return -1;
01457 }
01458
01459 varsubst = ast_alloca(strlen(args.var) + 4);
01460 sprintf(varsubst, "${%s}", args.var);
01461 ast_str_substitute_variables(&before, 0, chan, varsubst);
01462
01463 if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
01464 ast_get_encoded_char(args.delimiter, delimiter, &unused);
01465 }
01466
01467 if (!ast_str_strlen(before)) {
01468
01469 return -1;
01470 }
01471
01472 if (!(after = search_func(ast_str_buffer(before), delimiter[0]))) {
01473
01474 ast_str_set(buf, len, "%s", ast_str_buffer(before));
01475 pbx_builtin_setvar_helper(chan, args.var, "");
01476 } else {
01477 *after++ = '\0';
01478 ast_str_set(buf, len, "%s", beginning ? ast_str_buffer(before) : after);
01479 pbx_builtin_setvar_helper(chan, args.var, beginning ? after : ast_str_buffer(before));
01480 }
01481
01482 return 0;
01483 #undef beginning
01484 }
01485
01486 static struct ast_custom_function shift_function = {
01487 .name = "SHIFT",
01488 .read2 = shift_pop,
01489 };
01490
01491 static struct ast_custom_function pop_function = {
01492 .name = "POP",
01493 .read2 = shift_pop,
01494 };
01495
01496 static int unshift_push(struct ast_channel *chan, const char *cmd, char *data, const char *new_value)
01497 {
01498 #define beginning (cmd[0] == 'U')
01499 char delimiter[2] = ",", *varsubst;
01500 size_t unused;
01501 struct ast_str *buf, *previous_value;
01502 AST_DECLARE_APP_ARGS(args,
01503 AST_APP_ARG(var);
01504 AST_APP_ARG(delimiter);
01505 );
01506 const char *stripped_var;
01507
01508 if (!(buf = ast_str_thread_get(&result_buf, 16)) ||
01509 !(previous_value = ast_str_thread_get(&tmp_buf, 16))) {
01510 return -1;
01511 }
01512
01513 AST_STANDARD_APP_ARGS(args, data);
01514
01515 if (ast_strlen_zero(args.var)) {
01516 ast_log(LOG_WARNING, "%s requires a variable name\n", cmd);
01517 return -1;
01518 }
01519
01520 if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
01521 ast_get_encoded_char(args.delimiter, delimiter, &unused);
01522 }
01523
01524
01525
01526
01527
01528
01529
01530 stripped_var = args.var + MIN(strspn(args.var, "_"), 2);
01531 varsubst = ast_alloca(strlen(stripped_var) + 4);
01532 sprintf(varsubst, "${%s}", stripped_var);
01533 ast_str_substitute_variables(&previous_value, 0, chan, varsubst);
01534
01535 if (!ast_str_strlen(previous_value)) {
01536 ast_str_set(&buf, 0, "%s", new_value);
01537 } else {
01538 ast_str_set(&buf, 0, "%s%c%s",
01539 beginning ? new_value : ast_str_buffer(previous_value),
01540 delimiter[0],
01541 beginning ? ast_str_buffer(previous_value) : new_value);
01542 }
01543
01544 pbx_builtin_setvar_helper(chan, args.var, ast_str_buffer(buf));
01545
01546 return 0;
01547 #undef beginning
01548 }
01549
01550 static struct ast_custom_function push_function = {
01551 .name = "PUSH",
01552 .write = unshift_push,
01553 };
01554
01555 static struct ast_custom_function unshift_function = {
01556 .name = "UNSHIFT",
01557 .write = unshift_push,
01558 };
01559
01560 static int passthru(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
01561 {
01562 ast_str_set(buf, len, "%s", data);
01563 return 0;
01564 }
01565
01566 static struct ast_custom_function passthru_function = {
01567 .name = "PASSTHRU",
01568 .read2 = passthru,
01569 };
01570
01571 #ifdef TEST_FRAMEWORK
01572 AST_TEST_DEFINE(test_FIELDNUM)
01573 {
01574 int i, res = AST_TEST_PASS;
01575 struct ast_channel *chan;
01576 struct ast_str *str;
01577 char expression[256];
01578 struct {
01579 const char *fields;
01580 const char *delim;
01581 const char *field;
01582 const char *expected;
01583 } test_args[] = {
01584 {"abc,def,ghi,jkl", "\\,", "ghi", "3"},
01585 {"abc def ghi jkl", " ", "abc", "1"},
01586 {"abc/def/ghi/jkl", "\\\\x2f", "def", "2"},
01587 {"abc$def$ghi$jkl", "", "ghi", "0"},
01588 {"abc,def,ghi,jkl", "-", "", "0"},
01589 {"abc-def-ghi-jkl", "-", "mno", "0"}
01590 };
01591
01592 switch (cmd) {
01593 case TEST_INIT:
01594 info->name = "func_FIELDNUM_test";
01595 info->category = "/funcs/func_strings/";
01596 info->summary = "Test FIELDNUM function";
01597 info->description = "Verify FIELDNUM behavior";
01598 return AST_TEST_NOT_RUN;
01599 case TEST_EXECUTE:
01600 break;
01601 }
01602
01603 if (!(chan = ast_dummy_channel_alloc())) {
01604 ast_test_status_update(test, "Unable to allocate dummy channel\n");
01605 return AST_TEST_FAIL;
01606 }
01607
01608 if (!(str = ast_str_create(16))) {
01609 ast_test_status_update(test, "Unable to allocate dynamic string buffer\n");
01610 ast_channel_release(chan);
01611 return AST_TEST_FAIL;
01612 }
01613
01614 for (i = 0; i < ARRAY_LEN(test_args); i++) {
01615 struct ast_var_t *var = ast_var_assign("FIELDS", test_args[i].fields);
01616 if (!var) {
01617 ast_test_status_update(test, "Out of memory\n");
01618 res = AST_TEST_FAIL;
01619 break;
01620 }
01621
01622 AST_LIST_INSERT_HEAD(&chan->varshead, var, entries);
01623
01624 snprintf(expression, sizeof(expression), "${FIELDNUM(%s,%s,%s)}", var->name, test_args[i].delim, test_args[i].field);
01625 ast_str_substitute_variables(&str, 0, chan, expression);
01626
01627 AST_LIST_REMOVE(&chan->varshead, var, entries);
01628 ast_var_delete(var);
01629
01630 if (strcasecmp(ast_str_buffer(str), test_args[i].expected)) {
01631 ast_test_status_update(test, "Evaluation of '%s' returned '%s' instead of the expected value '%s'\n",
01632 expression, ast_str_buffer(str), test_args[i].expected);
01633 res = AST_TEST_FAIL;
01634 break;
01635 }
01636 }
01637
01638 ast_free(str);
01639 ast_channel_release(chan);
01640
01641 return res;
01642 }
01643
01644 AST_TEST_DEFINE(test_REPLACE)
01645 {
01646 int i, res = AST_TEST_PASS;
01647 struct ast_channel *chan;
01648 struct ast_str *str;
01649 char expression[256];
01650 struct {
01651 const char *test_string;
01652 const char *find_chars;
01653 const char *replace_char;
01654 const char *expected;
01655 } test_args[] = {
01656 {"abc,def", "\\,", "-", "abc-def"},
01657 {"abc,abc", "bc", "a", "aaa,aaa"},
01658 {"abc,def", "x", "?", "abc,def"},
01659 {"abc,def", "\\,", "", "abcdef"}
01660 };
01661
01662 switch (cmd) {
01663 case TEST_INIT:
01664 info->name = "func_REPLACE_test";
01665 info->category = "/funcs/func_strings/";
01666 info->summary = "Test REPLACE function";
01667 info->description = "Verify REPLACE behavior";
01668 return AST_TEST_NOT_RUN;
01669 case TEST_EXECUTE:
01670 break;
01671 }
01672
01673 if (!(chan = ast_dummy_channel_alloc())) {
01674 ast_test_status_update(test, "Unable to allocate dummy channel\n");
01675 return AST_TEST_FAIL;
01676 }
01677
01678 if (!(str = ast_str_create(16))) {
01679 ast_test_status_update(test, "Unable to allocate dynamic string buffer\n");
01680 ast_channel_release(chan);
01681 return AST_TEST_FAIL;
01682 }
01683
01684 for (i = 0; i < ARRAY_LEN(test_args); i++) {
01685 struct ast_var_t *var = ast_var_assign("TEST_STRING", test_args[i].test_string);
01686 if (!var) {
01687 ast_test_status_update(test, "Out of memory\n");
01688 res = AST_TEST_FAIL;
01689 break;
01690 }
01691
01692 AST_LIST_INSERT_HEAD(&chan->varshead, var, entries);
01693
01694 snprintf(expression, sizeof(expression), "${REPLACE(%s,%s,%s)}", var->name, test_args[i].find_chars, test_args[i].replace_char);
01695 ast_str_substitute_variables(&str, 0, chan, expression);
01696
01697 AST_LIST_REMOVE(&chan->varshead, var, entries);
01698 ast_var_delete(var);
01699
01700 if (strcasecmp(ast_str_buffer(str), test_args[i].expected)) {
01701 ast_test_status_update(test, "Evaluation of '%s' returned '%s' instead of the expected value '%s'\n",
01702 expression, ast_str_buffer(str), test_args[i].expected);
01703 res = AST_TEST_FAIL;
01704 break;
01705 }
01706 }
01707
01708 ast_free(str);
01709 ast_channel_release(chan);
01710
01711 return res;
01712 }
01713
01714 AST_TEST_DEFINE(test_FILTER)
01715 {
01716 int i, res = AST_TEST_PASS;
01717 const char *test_strings[][2] = {
01718 {"A-R", "DAHDI"},
01719 {"A\\-R", "A"},
01720 {"\\x41-R", "DAHDI"},
01721 {"0-9A-Ca-c", "0042133333A12212"},
01722 {"0-9a-cA-C_+\\-", "0042133333A12212"},
01723 {NULL, NULL},
01724 };
01725
01726 switch (cmd) {
01727 case TEST_INIT:
01728 info->name = "func_FILTER_test";
01729 info->category = "/funcs/func_strings/";
01730 info->summary = "Test FILTER function";
01731 info->description = "Verify FILTER behavior";
01732 return AST_TEST_NOT_RUN;
01733 case TEST_EXECUTE:
01734 break;
01735 }
01736
01737 for (i = 0; test_strings[i][0]; i++) {
01738 char tmp[256], tmp2[256] = "";
01739 snprintf(tmp, sizeof(tmp), "${FILTER(%s,0042133333&DAHDI/g1/2212)}", test_strings[i][0]);
01740 pbx_substitute_variables_helper(NULL, tmp, tmp2, sizeof(tmp2) - 1);
01741 if (strcmp(test_strings[i][1], tmp2)) {
01742 ast_test_status_update(test, "Format string '%s' substituted to '%s'. Expected '%s'.\n", test_strings[i][0], tmp2, test_strings[i][1]);
01743 res = AST_TEST_FAIL;
01744 }
01745 }
01746 return res;
01747 }
01748 #endif
01749
01750 static int unload_module(void)
01751 {
01752 int res = 0;
01753
01754 AST_TEST_UNREGISTER(test_FIELDNUM);
01755 AST_TEST_UNREGISTER(test_REPLACE);
01756 AST_TEST_UNREGISTER(test_FILTER);
01757 res |= ast_custom_function_unregister(&fieldqty_function);
01758 res |= ast_custom_function_unregister(&fieldnum_function);
01759 res |= ast_custom_function_unregister(&filter_function);
01760 res |= ast_custom_function_unregister(&replace_function);
01761 res |= ast_custom_function_unregister(&listfilter_function);
01762 res |= ast_custom_function_unregister(®ex_function);
01763 res |= ast_custom_function_unregister(&array_function);
01764 res |= ast_custom_function_unregister("e_function);
01765 res |= ast_custom_function_unregister(&csv_quote_function);
01766 res |= ast_custom_function_unregister(&len_function);
01767 res |= ast_custom_function_unregister(&strftime_function);
01768 res |= ast_custom_function_unregister(&strptime_function);
01769 res |= ast_custom_function_unregister(&eval_function);
01770 res |= ast_custom_function_unregister(&keypadhash_function);
01771 res |= ast_custom_function_unregister(&hashkeys_function);
01772 res |= ast_custom_function_unregister(&hash_function);
01773 res |= ast_unregister_application(app_clearhash);
01774 res |= ast_custom_function_unregister(&toupper_function);
01775 res |= ast_custom_function_unregister(&tolower_function);
01776 res |= ast_custom_function_unregister(&shift_function);
01777 res |= ast_custom_function_unregister(&pop_function);
01778 res |= ast_custom_function_unregister(&push_function);
01779 res |= ast_custom_function_unregister(&unshift_function);
01780 res |= ast_custom_function_unregister(&passthru_function);
01781
01782 return res;
01783 }
01784
01785 static int load_module(void)
01786 {
01787 int res = 0;
01788
01789 AST_TEST_REGISTER(test_FIELDNUM);
01790 AST_TEST_REGISTER(test_REPLACE);
01791 AST_TEST_REGISTER(test_FILTER);
01792 res |= ast_custom_function_register(&fieldqty_function);
01793 res |= ast_custom_function_register(&fieldnum_function);
01794 res |= ast_custom_function_register(&filter_function);
01795 res |= ast_custom_function_register(&replace_function);
01796 res |= ast_custom_function_register(&listfilter_function);
01797 res |= ast_custom_function_register(®ex_function);
01798 res |= ast_custom_function_register(&array_function);
01799 res |= ast_custom_function_register("e_function);
01800 res |= ast_custom_function_register(&csv_quote_function);
01801 res |= ast_custom_function_register(&len_function);
01802 res |= ast_custom_function_register(&strftime_function);
01803 res |= ast_custom_function_register(&strptime_function);
01804 res |= ast_custom_function_register(&eval_function);
01805 res |= ast_custom_function_register(&keypadhash_function);
01806 res |= ast_custom_function_register(&hashkeys_function);
01807 res |= ast_custom_function_register(&hash_function);
01808 res |= ast_register_application_xml(app_clearhash, exec_clearhash);
01809 res |= ast_custom_function_register(&toupper_function);
01810 res |= ast_custom_function_register(&tolower_function);
01811 res |= ast_custom_function_register(&shift_function);
01812 res |= ast_custom_function_register(&pop_function);
01813 res |= ast_custom_function_register(&push_function);
01814 res |= ast_custom_function_register(&unshift_function);
01815 res |= ast_custom_function_register(&passthru_function);
01816
01817 return res;
01818 }
01819
01820 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "String handling dialplan functions");