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: 404951 $")
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 struct ast_str *str = ast_str_thread_get(&result_buf, 16);
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 ast_str_set(&prefix, -1, HASH_PREFIX, data);
00994 memset(buf, 0, len);
00995
00996 AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) {
00997 if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
00998
00999 strncat(buf, ast_var_name(newvar) + ast_str_strlen(prefix), len - strlen(buf) - 1);
01000
01001 buf[strlen(buf) - 1] = ',';
01002 }
01003 }
01004
01005 buf[strlen(buf) - 1] = '\0';
01006 return 0;
01007 }
01008
01009 static int hashkeys_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
01010 {
01011 struct ast_var_t *newvar;
01012 struct ast_str *prefix = ast_str_alloca(80);
01013 char *tmp;
01014
01015 ast_str_set(&prefix, -1, HASH_PREFIX, data);
01016
01017 AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) {
01018 if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
01019
01020 ast_str_append(buf, len, "%s", ast_var_name(newvar) + ast_str_strlen(prefix));
01021
01022 tmp = ast_str_buffer(*buf);
01023 tmp[ast_str_strlen(*buf) - 1] = ',';
01024 }
01025 }
01026
01027 tmp = ast_str_buffer(*buf);
01028 tmp[ast_str_strlen(*buf) - 1] = '\0';
01029 return 0;
01030 }
01031
01032 static int hash_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
01033 {
01034 char varname[256];
01035 AST_DECLARE_APP_ARGS(arg,
01036 AST_APP_ARG(hashname);
01037 AST_APP_ARG(hashkey);
01038 );
01039
01040 if (!strchr(var, ',')) {
01041
01042 return array(chan, "HASH", var, value);
01043 }
01044
01045 AST_STANDARD_APP_ARGS(arg, var);
01046 if (arg.hashname[0] == '_') {
01047 if (arg.hashname[1] == '_') {
01048 snprintf(varname, sizeof(varname), "__" HASH_FORMAT, arg.hashname + 2, arg.hashkey);
01049 } else {
01050 snprintf(varname, sizeof(varname), "_" HASH_FORMAT, arg.hashname + 1, arg.hashkey);
01051 }
01052 } else {
01053 snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
01054 }
01055 pbx_builtin_setvar_helper(chan, varname, value);
01056
01057 return 0;
01058 }
01059
01060 static int hash_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
01061 {
01062 char varname[256];
01063 const char *varvalue;
01064 AST_DECLARE_APP_ARGS(arg,
01065 AST_APP_ARG(hashname);
01066 AST_APP_ARG(hashkey);
01067 );
01068
01069 AST_STANDARD_APP_ARGS(arg, data);
01070 if (arg.argc == 2) {
01071 snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
01072 varvalue = pbx_builtin_getvar_helper(chan, varname);
01073 if (varvalue)
01074 ast_copy_string(buf, varvalue, len);
01075 else
01076 *buf = '\0';
01077 } else if (arg.argc == 1) {
01078 char colnames[4096];
01079 int i;
01080 AST_DECLARE_APP_ARGS(arg2,
01081 AST_APP_ARG(col)[100];
01082 );
01083
01084
01085 hashkeys_read(chan, "HASHKEYS", arg.hashname, colnames, sizeof(colnames));
01086 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames);
01087
01088 AST_STANDARD_APP_ARGS(arg2, colnames);
01089 *buf = '\0';
01090
01091
01092 for (i = 0; i < arg2.argc; i++) {
01093 snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg2.col[i]);
01094 varvalue = pbx_builtin_getvar_helper(chan, varname);
01095 strncat(buf, varvalue, len - strlen(buf) - 1);
01096 strncat(buf, ",", len - strlen(buf) - 1);
01097 }
01098
01099
01100 buf[strlen(buf) - 1] = '\0';
01101 }
01102
01103 return 0;
01104 }
01105
01106 static struct ast_custom_function hash_function = {
01107 .name = "HASH",
01108 .write = hash_write,
01109 .read = hash_read,
01110 };
01111
01112 static struct ast_custom_function hashkeys_function = {
01113 .name = "HASHKEYS",
01114 .read = hashkeys_read,
01115 .read2 = hashkeys_read2,
01116 };
01117
01118 static struct ast_custom_function array_function = {
01119 .name = "ARRAY",
01120 .write = array,
01121 };
01122
01123 static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
01124 {
01125 char *bufptr = buf, *dataptr = data;
01126
01127 if (len < 3){
01128 ast_log(LOG_ERROR, "Not enough buffer\n");
01129 return -1;
01130 }
01131
01132 if (ast_strlen_zero(data)) {
01133 ast_log(LOG_WARNING, "No argument specified!\n");
01134 ast_copy_string(buf, "\"\"", len);
01135 return 0;
01136 }
01137
01138 *bufptr++ = '"';
01139 for (; bufptr < buf + len - 3; dataptr++) {
01140 if (*dataptr == '\\') {
01141 *bufptr++ = '\\';
01142 *bufptr++ = '\\';
01143 } else if (*dataptr == '"') {
01144 *bufptr++ = '\\';
01145 *bufptr++ = '"';
01146 } else if (*dataptr == '\0') {
01147 break;
01148 } else {
01149 *bufptr++ = *dataptr;
01150 }
01151 }
01152 *bufptr++ = '"';
01153 *bufptr = '\0';
01154 return 0;
01155 }
01156
01157 static struct ast_custom_function quote_function = {
01158 .name = "QUOTE",
01159 .read = quote,
01160 };
01161
01162 static int csv_quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
01163 {
01164 char *bufptr = buf, *dataptr = data;
01165
01166 if (len < 3) {
01167 ast_log(LOG_ERROR, "Not enough buffer\n");
01168 return -1;
01169 }
01170
01171 if (ast_strlen_zero(data)) {
01172 ast_copy_string(buf, "\"\"", len);
01173 return 0;
01174 }
01175
01176 *bufptr++ = '"';
01177 for (; bufptr < buf + len - 3; dataptr++){
01178 if (*dataptr == '"') {
01179 *bufptr++ = '"';
01180 *bufptr++ = '"';
01181 } else if (*dataptr == '\0') {
01182 break;
01183 } else {
01184 *bufptr++ = *dataptr;
01185 }
01186 }
01187 *bufptr++ = '"';
01188 *bufptr='\0';
01189 return 0;
01190 }
01191
01192 static struct ast_custom_function csv_quote_function = {
01193 .name = "CSV_QUOTE",
01194 .read = csv_quote,
01195 };
01196
01197 static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
01198 {
01199 int length = 0;
01200
01201 if (data)
01202 length = strlen(data);
01203
01204 snprintf(buf, buflen, "%d", length);
01205
01206 return 0;
01207 }
01208
01209 static struct ast_custom_function len_function = {
01210 .name = "LEN",
01211 .read = len,
01212 .read_max = 12,
01213 };
01214
01215 static int acf_strftime(struct ast_channel *chan, const char *cmd, char *parse,
01216 char *buf, size_t buflen)
01217 {
01218 AST_DECLARE_APP_ARGS(args,
01219 AST_APP_ARG(epoch);
01220 AST_APP_ARG(timezone);
01221 AST_APP_ARG(format);
01222 );
01223 struct timeval when;
01224 struct ast_tm tm;
01225
01226 buf[0] = '\0';
01227
01228 AST_STANDARD_APP_ARGS(args, parse);
01229
01230 ast_get_timeval(args.epoch, &when, ast_tvnow(), NULL);
01231 ast_localtime(&when, &tm, args.timezone);
01232
01233 if (!args.format)
01234 args.format = "%c";
01235
01236 if (ast_strftime(buf, buflen, args.format, &tm) <= 0)
01237 ast_log(LOG_WARNING, "C function strftime() output nothing?!!\n");
01238
01239 buf[buflen - 1] = '\0';
01240
01241 return 0;
01242 }
01243
01244 static struct ast_custom_function strftime_function = {
01245 .name = "STRFTIME",
01246 .read = acf_strftime,
01247 };
01248
01249 static int acf_strptime(struct ast_channel *chan, const char *cmd, char *data,
01250 char *buf, size_t buflen)
01251 {
01252 AST_DECLARE_APP_ARGS(args,
01253 AST_APP_ARG(timestring);
01254 AST_APP_ARG(timezone);
01255 AST_APP_ARG(format);
01256 );
01257 struct ast_tm tm;
01258
01259 buf[0] = '\0';
01260
01261 if (!data) {
01262 ast_log(LOG_ERROR,
01263 "Asterisk function STRPTIME() requires an argument.\n");
01264 return -1;
01265 }
01266
01267 AST_STANDARD_APP_ARGS(args, data);
01268
01269 if (ast_strlen_zero(args.format)) {
01270 ast_log(LOG_ERROR,
01271 "No format supplied to STRPTIME(<timestring>,<timezone>,<format>)");
01272 return -1;
01273 }
01274
01275 if (!ast_strptime(args.timestring, args.format, &tm)) {
01276 ast_log(LOG_WARNING, "STRPTIME() found no time specified within the string\n");
01277 } else {
01278 struct timeval when;
01279 when = ast_mktime(&tm, args.timezone);
01280 snprintf(buf, buflen, "%d", (int) when.tv_sec);
01281 }
01282
01283 return 0;
01284 }
01285
01286 static struct ast_custom_function strptime_function = {
01287 .name = "STRPTIME",
01288 .read = acf_strptime,
01289 };
01290
01291 static int function_eval(struct ast_channel *chan, const char *cmd, char *data,
01292 char *buf, size_t buflen)
01293 {
01294 if (ast_strlen_zero(data)) {
01295 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
01296 return -1;
01297 }
01298
01299 pbx_substitute_variables_helper(chan, data, buf, buflen - 1);
01300
01301 return 0;
01302 }
01303
01304 static int function_eval2(struct ast_channel *chan, const char *cmd, char *data,
01305 struct ast_str **buf, ssize_t buflen)
01306 {
01307 if (ast_strlen_zero(data)) {
01308 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
01309 return -1;
01310 }
01311
01312 ast_str_substitute_variables(buf, buflen, chan, data);
01313
01314 return 0;
01315 }
01316
01317 static struct ast_custom_function eval_function = {
01318 .name = "EVAL",
01319 .read = function_eval,
01320 .read2 = function_eval2,
01321 };
01322
01323 static int keypadhash(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
01324 {
01325 char *bufptr, *dataptr;
01326
01327 for (bufptr = buf, dataptr = data; bufptr < buf + buflen - 1; dataptr++) {
01328 if (*dataptr == '\0') {
01329 *bufptr++ = '\0';
01330 break;
01331 } else if (*dataptr == '1') {
01332 *bufptr++ = '1';
01333 } else if (strchr("AaBbCc2", *dataptr)) {
01334 *bufptr++ = '2';
01335 } else if (strchr("DdEeFf3", *dataptr)) {
01336 *bufptr++ = '3';
01337 } else if (strchr("GgHhIi4", *dataptr)) {
01338 *bufptr++ = '4';
01339 } else if (strchr("JjKkLl5", *dataptr)) {
01340 *bufptr++ = '5';
01341 } else if (strchr("MmNnOo6", *dataptr)) {
01342 *bufptr++ = '6';
01343 } else if (strchr("PpQqRrSs7", *dataptr)) {
01344 *bufptr++ = '7';
01345 } else if (strchr("TtUuVv8", *dataptr)) {
01346 *bufptr++ = '8';
01347 } else if (strchr("WwXxYyZz9", *dataptr)) {
01348 *bufptr++ = '9';
01349 } else if (*dataptr == '0') {
01350 *bufptr++ = '0';
01351 }
01352 }
01353 buf[buflen - 1] = '\0';
01354
01355 return 0;
01356 }
01357
01358 static struct ast_custom_function keypadhash_function = {
01359 .name = "KEYPADHASH",
01360 .read = keypadhash,
01361 };
01362
01363 static int string_toupper(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
01364 {
01365 char *bufptr = buf, *dataptr = data;
01366
01367 while ((bufptr < buf + buflen - 1) && (*bufptr++ = toupper(*dataptr++)));
01368
01369 return 0;
01370 }
01371
01372 static int string_toupper2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
01373 {
01374 char *bufptr, *dataptr = data;
01375
01376 if (buflen > -1) {
01377 ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
01378 }
01379 bufptr = ast_str_buffer(*buf);
01380 while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = toupper(*dataptr++)));
01381 ast_str_update(*buf);
01382
01383 return 0;
01384 }
01385
01386 static struct ast_custom_function toupper_function = {
01387 .name = "TOUPPER",
01388 .read = string_toupper,
01389 .read2 = string_toupper2,
01390 };
01391
01392 static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
01393 {
01394 char *bufptr = buf, *dataptr = data;
01395
01396 while ((bufptr < buf + buflen - 1) && (*bufptr++ = tolower(*dataptr++)));
01397
01398 return 0;
01399 }
01400
01401 static int string_tolower2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
01402 {
01403 char *bufptr, *dataptr = data;
01404
01405 if (buflen > -1) {
01406 ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
01407 }
01408 bufptr = ast_str_buffer(*buf);
01409 while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = tolower(*dataptr++)));
01410 ast_str_update(*buf);
01411
01412 return 0;
01413 }
01414
01415 static struct ast_custom_function tolower_function = {
01416 .name = "TOLOWER",
01417 .read = string_tolower,
01418 .read2 = string_tolower2,
01419 };
01420
01421 static int shift_pop(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
01422 {
01423 #define beginning (cmd[0] == 'S')
01424 char *after, delimiter[2] = ",", *varsubst;
01425 size_t unused;
01426 struct ast_str *before = ast_str_thread_get(&result_buf, 16);
01427 char *(*search_func)(const char *s, int c) = (beginning ? strchr : strrchr);
01428 AST_DECLARE_APP_ARGS(args,
01429 AST_APP_ARG(var);
01430 AST_APP_ARG(delimiter);
01431 );
01432
01433 if (!before) {
01434 return -1;
01435 }
01436
01437 AST_STANDARD_APP_ARGS(args, data);
01438
01439 if (ast_strlen_zero(args.var)) {
01440 ast_log(LOG_WARNING, "%s requires a variable name\n", cmd);
01441 return -1;
01442 }
01443
01444 varsubst = ast_alloca(strlen(args.var) + 4);
01445 sprintf(varsubst, "${%s}", args.var);
01446 ast_str_substitute_variables(&before, 0, chan, varsubst);
01447
01448 if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
01449 ast_get_encoded_char(args.delimiter, delimiter, &unused);
01450 }
01451
01452 if (!ast_str_strlen(before)) {
01453
01454 return -1;
01455 }
01456
01457 if (!(after = search_func(ast_str_buffer(before), delimiter[0]))) {
01458
01459 ast_str_set(buf, len, "%s", ast_str_buffer(before));
01460 pbx_builtin_setvar_helper(chan, args.var, "");
01461 } else {
01462 *after++ = '\0';
01463 ast_str_set(buf, len, "%s", beginning ? ast_str_buffer(before) : after);
01464 pbx_builtin_setvar_helper(chan, args.var, beginning ? after : ast_str_buffer(before));
01465 }
01466
01467 return 0;
01468 #undef beginning
01469 }
01470
01471 static struct ast_custom_function shift_function = {
01472 .name = "SHIFT",
01473 .read2 = shift_pop,
01474 };
01475
01476 static struct ast_custom_function pop_function = {
01477 .name = "POP",
01478 .read2 = shift_pop,
01479 };
01480
01481 static int unshift_push(struct ast_channel *chan, const char *cmd, char *data, const char *new_value)
01482 {
01483 #define beginning (cmd[0] == 'U')
01484 char delimiter[2] = ",", *varsubst;
01485 size_t unused;
01486 struct ast_str *buf, *previous_value;
01487 AST_DECLARE_APP_ARGS(args,
01488 AST_APP_ARG(var);
01489 AST_APP_ARG(delimiter);
01490 );
01491
01492 if (!(buf = ast_str_thread_get(&result_buf, 16)) ||
01493 !(previous_value = ast_str_thread_get(&tmp_buf, 16))) {
01494 return -1;
01495 }
01496
01497 AST_STANDARD_APP_ARGS(args, data);
01498
01499 if (ast_strlen_zero(args.var)) {
01500 ast_log(LOG_WARNING, "%s requires a variable name\n", cmd);
01501 return -1;
01502 }
01503
01504 if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
01505 ast_get_encoded_char(args.delimiter, delimiter, &unused);
01506 }
01507
01508 varsubst = ast_alloca(strlen(args.var) + 4);
01509 sprintf(varsubst, "${%s}", args.var);
01510 ast_str_substitute_variables(&previous_value, 0, chan, varsubst);
01511
01512 if (!ast_str_strlen(previous_value)) {
01513 ast_str_set(&buf, 0, "%s", new_value);
01514 } else {
01515 ast_str_set(&buf, 0, "%s%c%s",
01516 beginning ? new_value : ast_str_buffer(previous_value),
01517 delimiter[0],
01518 beginning ? ast_str_buffer(previous_value) : new_value);
01519 }
01520
01521 pbx_builtin_setvar_helper(chan, args.var, ast_str_buffer(buf));
01522
01523 return 0;
01524 #undef beginning
01525 }
01526
01527 static struct ast_custom_function push_function = {
01528 .name = "PUSH",
01529 .write = unshift_push,
01530 };
01531
01532 static struct ast_custom_function unshift_function = {
01533 .name = "UNSHIFT",
01534 .write = unshift_push,
01535 };
01536
01537 static int passthru(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
01538 {
01539 ast_str_set(buf, len, "%s", data);
01540 return 0;
01541 }
01542
01543 static struct ast_custom_function passthru_function = {
01544 .name = "PASSTHRU",
01545 .read2 = passthru,
01546 };
01547
01548 #ifdef TEST_FRAMEWORK
01549 AST_TEST_DEFINE(test_FIELDNUM)
01550 {
01551 int i, res = AST_TEST_PASS;
01552 struct ast_channel *chan;
01553 struct ast_str *str;
01554 char expression[256];
01555 struct {
01556 const char *fields;
01557 const char *delim;
01558 const char *field;
01559 const char *expected;
01560 } test_args[] = {
01561 {"abc,def,ghi,jkl", "\\,", "ghi", "3"},
01562 {"abc def ghi jkl", " ", "abc", "1"},
01563 {"abc/def/ghi/jkl", "\\\\x2f", "def", "2"},
01564 {"abc$def$ghi$jkl", "", "ghi", "0"},
01565 {"abc,def,ghi,jkl", "-", "", "0"},
01566 {"abc-def-ghi-jkl", "-", "mno", "0"}
01567 };
01568
01569 switch (cmd) {
01570 case TEST_INIT:
01571 info->name = "func_FIELDNUM_test";
01572 info->category = "/funcs/func_strings/";
01573 info->summary = "Test FIELDNUM function";
01574 info->description = "Verify FIELDNUM behavior";
01575 return AST_TEST_NOT_RUN;
01576 case TEST_EXECUTE:
01577 break;
01578 }
01579
01580 if (!(chan = ast_dummy_channel_alloc())) {
01581 ast_test_status_update(test, "Unable to allocate dummy channel\n");
01582 return AST_TEST_FAIL;
01583 }
01584
01585 if (!(str = ast_str_create(16))) {
01586 ast_test_status_update(test, "Unable to allocate dynamic string buffer\n");
01587 ast_channel_release(chan);
01588 return AST_TEST_FAIL;
01589 }
01590
01591 for (i = 0; i < ARRAY_LEN(test_args); i++) {
01592 struct ast_var_t *var = ast_var_assign("FIELDS", test_args[i].fields);
01593 if (!var) {
01594 ast_test_status_update(test, "Out of memory\n");
01595 res = AST_TEST_FAIL;
01596 break;
01597 }
01598
01599 AST_LIST_INSERT_HEAD(&chan->varshead, var, entries);
01600
01601 snprintf(expression, sizeof(expression), "${FIELDNUM(%s,%s,%s)}", var->name, test_args[i].delim, test_args[i].field);
01602 ast_str_substitute_variables(&str, 0, chan, expression);
01603
01604 AST_LIST_REMOVE(&chan->varshead, var, entries);
01605 ast_var_delete(var);
01606
01607 if (strcasecmp(ast_str_buffer(str), test_args[i].expected)) {
01608 ast_test_status_update(test, "Evaluation of '%s' returned '%s' instead of the expected value '%s'\n",
01609 expression, ast_str_buffer(str), test_args[i].expected);
01610 res = AST_TEST_FAIL;
01611 break;
01612 }
01613 }
01614
01615 ast_free(str);
01616 ast_channel_release(chan);
01617
01618 return res;
01619 }
01620
01621 AST_TEST_DEFINE(test_REPLACE)
01622 {
01623 int i, res = AST_TEST_PASS;
01624 struct ast_channel *chan;
01625 struct ast_str *str;
01626 char expression[256];
01627 struct {
01628 const char *test_string;
01629 const char *find_chars;
01630 const char *replace_char;
01631 const char *expected;
01632 } test_args[] = {
01633 {"abc,def", "\\,", "-", "abc-def"},
01634 {"abc,abc", "bc", "a", "aaa,aaa"},
01635 {"abc,def", "x", "?", "abc,def"},
01636 {"abc,def", "\\,", "", "abcdef"}
01637 };
01638
01639 switch (cmd) {
01640 case TEST_INIT:
01641 info->name = "func_REPLACE_test";
01642 info->category = "/funcs/func_strings/";
01643 info->summary = "Test REPLACE function";
01644 info->description = "Verify REPLACE behavior";
01645 return AST_TEST_NOT_RUN;
01646 case TEST_EXECUTE:
01647 break;
01648 }
01649
01650 if (!(chan = ast_dummy_channel_alloc())) {
01651 ast_test_status_update(test, "Unable to allocate dummy channel\n");
01652 return AST_TEST_FAIL;
01653 }
01654
01655 if (!(str = ast_str_create(16))) {
01656 ast_test_status_update(test, "Unable to allocate dynamic string buffer\n");
01657 ast_channel_release(chan);
01658 return AST_TEST_FAIL;
01659 }
01660
01661 for (i = 0; i < ARRAY_LEN(test_args); i++) {
01662 struct ast_var_t *var = ast_var_assign("TEST_STRING", test_args[i].test_string);
01663 if (!var) {
01664 ast_test_status_update(test, "Out of memory\n");
01665 res = AST_TEST_FAIL;
01666 break;
01667 }
01668
01669 AST_LIST_INSERT_HEAD(&chan->varshead, var, entries);
01670
01671 snprintf(expression, sizeof(expression), "${REPLACE(%s,%s,%s)}", var->name, test_args[i].find_chars, test_args[i].replace_char);
01672 ast_str_substitute_variables(&str, 0, chan, expression);
01673
01674 AST_LIST_REMOVE(&chan->varshead, var, entries);
01675 ast_var_delete(var);
01676
01677 if (strcasecmp(ast_str_buffer(str), test_args[i].expected)) {
01678 ast_test_status_update(test, "Evaluation of '%s' returned '%s' instead of the expected value '%s'\n",
01679 expression, ast_str_buffer(str), test_args[i].expected);
01680 res = AST_TEST_FAIL;
01681 break;
01682 }
01683 }
01684
01685 ast_free(str);
01686 ast_channel_release(chan);
01687
01688 return res;
01689 }
01690
01691 AST_TEST_DEFINE(test_FILTER)
01692 {
01693 int i, res = AST_TEST_PASS;
01694 const char *test_strings[][2] = {
01695 {"A-R", "DAHDI"},
01696 {"A\\-R", "A"},
01697 {"\\x41-R", "DAHDI"},
01698 {"0-9A-Ca-c", "0042133333A12212"},
01699 {"0-9a-cA-C_+\\-", "0042133333A12212"},
01700 {NULL, NULL},
01701 };
01702
01703 switch (cmd) {
01704 case TEST_INIT:
01705 info->name = "func_FILTER_test";
01706 info->category = "/funcs/func_strings/";
01707 info->summary = "Test FILTER function";
01708 info->description = "Verify FILTER behavior";
01709 return AST_TEST_NOT_RUN;
01710 case TEST_EXECUTE:
01711 break;
01712 }
01713
01714 for (i = 0; test_strings[i][0]; i++) {
01715 char tmp[256], tmp2[256] = "";
01716 snprintf(tmp, sizeof(tmp), "${FILTER(%s,0042133333&DAHDI/g1/2212)}", test_strings[i][0]);
01717 pbx_substitute_variables_helper(NULL, tmp, tmp2, sizeof(tmp2) - 1);
01718 if (strcmp(test_strings[i][1], tmp2)) {
01719 ast_test_status_update(test, "Format string '%s' substituted to '%s'. Expected '%s'.\n", test_strings[i][0], tmp2, test_strings[i][1]);
01720 res = AST_TEST_FAIL;
01721 }
01722 }
01723 return res;
01724 }
01725 #endif
01726
01727 static int unload_module(void)
01728 {
01729 int res = 0;
01730
01731 AST_TEST_UNREGISTER(test_FIELDNUM);
01732 AST_TEST_UNREGISTER(test_REPLACE);
01733 AST_TEST_UNREGISTER(test_FILTER);
01734 res |= ast_custom_function_unregister(&fieldqty_function);
01735 res |= ast_custom_function_unregister(&fieldnum_function);
01736 res |= ast_custom_function_unregister(&filter_function);
01737 res |= ast_custom_function_unregister(&replace_function);
01738 res |= ast_custom_function_unregister(&listfilter_function);
01739 res |= ast_custom_function_unregister(®ex_function);
01740 res |= ast_custom_function_unregister(&array_function);
01741 res |= ast_custom_function_unregister("e_function);
01742 res |= ast_custom_function_unregister(&csv_quote_function);
01743 res |= ast_custom_function_unregister(&len_function);
01744 res |= ast_custom_function_unregister(&strftime_function);
01745 res |= ast_custom_function_unregister(&strptime_function);
01746 res |= ast_custom_function_unregister(&eval_function);
01747 res |= ast_custom_function_unregister(&keypadhash_function);
01748 res |= ast_custom_function_unregister(&hashkeys_function);
01749 res |= ast_custom_function_unregister(&hash_function);
01750 res |= ast_unregister_application(app_clearhash);
01751 res |= ast_custom_function_unregister(&toupper_function);
01752 res |= ast_custom_function_unregister(&tolower_function);
01753 res |= ast_custom_function_unregister(&shift_function);
01754 res |= ast_custom_function_unregister(&pop_function);
01755 res |= ast_custom_function_unregister(&push_function);
01756 res |= ast_custom_function_unregister(&unshift_function);
01757 res |= ast_custom_function_unregister(&passthru_function);
01758
01759 return res;
01760 }
01761
01762 static int load_module(void)
01763 {
01764 int res = 0;
01765
01766 AST_TEST_REGISTER(test_FIELDNUM);
01767 AST_TEST_REGISTER(test_REPLACE);
01768 AST_TEST_REGISTER(test_FILTER);
01769 res |= ast_custom_function_register(&fieldqty_function);
01770 res |= ast_custom_function_register(&fieldnum_function);
01771 res |= ast_custom_function_register(&filter_function);
01772 res |= ast_custom_function_register(&replace_function);
01773 res |= ast_custom_function_register(&listfilter_function);
01774 res |= ast_custom_function_register(®ex_function);
01775 res |= ast_custom_function_register(&array_function);
01776 res |= ast_custom_function_register("e_function);
01777 res |= ast_custom_function_register(&csv_quote_function);
01778 res |= ast_custom_function_register(&len_function);
01779 res |= ast_custom_function_register(&strftime_function);
01780 res |= ast_custom_function_register(&strptime_function);
01781 res |= ast_custom_function_register(&eval_function);
01782 res |= ast_custom_function_register(&keypadhash_function);
01783 res |= ast_custom_function_register(&hashkeys_function);
01784 res |= ast_custom_function_register(&hash_function);
01785 res |= ast_register_application_xml(app_clearhash, exec_clearhash);
01786 res |= ast_custom_function_register(&toupper_function);
01787 res |= ast_custom_function_register(&tolower_function);
01788 res |= ast_custom_function_register(&shift_function);
01789 res |= ast_custom_function_register(&pop_function);
01790 res |= ast_custom_function_register(&push_function);
01791 res |= ast_custom_function_register(&unshift_function);
01792 res |= ast_custom_function_register(&passthru_function);
01793
01794 return res;
01795 }
01796
01797 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "String handling dialplan functions");