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: 354429 $")
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
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438 static int function_fieldqty_helper(struct ast_channel *chan, const char *cmd,
00439 char *parse, char *buf, struct ast_str **sbuf, ssize_t len)
00440 {
00441 char *varsubst;
00442 struct ast_str *str = ast_str_thread_get(&result_buf, 16);
00443 int fieldcount = 0;
00444 AST_DECLARE_APP_ARGS(args,
00445 AST_APP_ARG(varname);
00446 AST_APP_ARG(delim);
00447 );
00448 char delim[2] = "";
00449 size_t delim_used;
00450
00451 if (!str) {
00452 return -1;
00453 }
00454
00455 AST_STANDARD_APP_ARGS(args, parse);
00456 if (args.delim) {
00457 ast_get_encoded_char(args.delim, delim, &delim_used);
00458
00459 varsubst = alloca(strlen(args.varname) + 4);
00460
00461 sprintf(varsubst, "${%s}", args.varname);
00462 ast_str_substitute_variables(&str, 0, chan, varsubst);
00463 if (ast_str_strlen(str) == 0) {
00464 fieldcount = 0;
00465 } else {
00466 char *varval = ast_str_buffer(str);
00467 while (strsep(&varval, delim)) {
00468 fieldcount++;
00469 }
00470 }
00471 } else {
00472 fieldcount = 1;
00473 }
00474 if (sbuf) {
00475 ast_str_set(sbuf, len, "%d", fieldcount);
00476 } else {
00477 snprintf(buf, len, "%d", fieldcount);
00478 }
00479
00480 return 0;
00481 }
00482
00483 static int function_fieldqty(struct ast_channel *chan, const char *cmd,
00484 char *parse, char *buf, size_t len)
00485 {
00486 return function_fieldqty_helper(chan, cmd, parse, buf, NULL, len);
00487 }
00488
00489 static int function_fieldqty_str(struct ast_channel *chan, const char *cmd,
00490 char *parse, struct ast_str **buf, ssize_t len)
00491 {
00492 return function_fieldqty_helper(chan, cmd, parse, NULL, buf, len);
00493 }
00494
00495 static struct ast_custom_function fieldqty_function = {
00496 .name = "FIELDQTY",
00497 .read = function_fieldqty,
00498 .read2 = function_fieldqty_str,
00499 };
00500
00501 static int function_fieldnum_helper(struct ast_channel *chan, const char *cmd,
00502 char *parse, char *buf, struct ast_str **sbuf, ssize_t len)
00503 {
00504 char *varsubst, *field;
00505 struct ast_str *str = ast_str_thread_get(&result_buf, 16);
00506 int fieldindex = 0, res = 0;
00507 AST_DECLARE_APP_ARGS(args,
00508 AST_APP_ARG(varname);
00509 AST_APP_ARG(delim);
00510 AST_APP_ARG(field);
00511 );
00512 char delim[2] = "";
00513 size_t delim_used;
00514
00515 if (!str) {
00516 return -1;
00517 }
00518
00519 AST_STANDARD_APP_ARGS(args, parse);
00520
00521 if (args.argc < 3) {
00522 ast_log(LOG_ERROR, "Usage: FIELDNUM(<listname>,<delimiter>,<fieldvalue>)\n");
00523 res = -1;
00524 } else {
00525 varsubst = alloca(strlen(args.varname) + 4);
00526 sprintf(varsubst, "${%s}", args.varname);
00527
00528 ast_str_substitute_variables(&str, 0, chan, varsubst);
00529
00530 if (ast_str_strlen(str) == 0 || ast_strlen_zero(args.delim)) {
00531 fieldindex = 0;
00532 } else if (ast_get_encoded_char(args.delim, delim, &delim_used) == -1) {
00533 res = -1;
00534 } else {
00535 char *varval = ast_str_buffer(str);
00536
00537 while ((field = strsep(&varval, delim)) != NULL) {
00538 fieldindex++;
00539
00540 if (!strcasecmp(field, args.field)) {
00541 break;
00542 }
00543 }
00544
00545 if (!field) {
00546 fieldindex = 0;
00547 }
00548
00549 res = 0;
00550 }
00551 }
00552
00553 if (sbuf) {
00554 ast_str_set(sbuf, len, "%d", fieldindex);
00555 } else {
00556 snprintf(buf, len, "%d", fieldindex);
00557 }
00558
00559 return res;
00560 }
00561
00562 static int function_fieldnum(struct ast_channel *chan, const char *cmd,
00563 char *parse, char *buf, size_t len)
00564 {
00565 return function_fieldnum_helper(chan, cmd, parse, buf, NULL, len);
00566 }
00567
00568 static int function_fieldnum_str(struct ast_channel *chan, const char *cmd,
00569 char *parse, struct ast_str **buf, ssize_t len)
00570 {
00571 return function_fieldnum_helper(chan, cmd, parse, NULL, buf, len);
00572 }
00573
00574 static struct ast_custom_function fieldnum_function = {
00575 .name = "FIELDNUM",
00576 .read = function_fieldnum,
00577 .read2 = function_fieldnum_str,
00578 };
00579
00580 static int listfilter(struct ast_channel *chan, const char *cmd, char *parse, char *buf, struct ast_str **bufstr, ssize_t len)
00581 {
00582 AST_DECLARE_APP_ARGS(args,
00583 AST_APP_ARG(listname);
00584 AST_APP_ARG(delimiter);
00585 AST_APP_ARG(fieldvalue);
00586 );
00587 struct ast_str *orig_list = ast_str_thread_get(&tmp_buf, 16);
00588 const char *begin, *cur, *next;
00589 int dlen, flen, first = 1;
00590 struct ast_str *result, **result_ptr = &result;
00591 char *delim, *varsubst;
00592
00593 AST_STANDARD_APP_ARGS(args, parse);
00594
00595 if (buf) {
00596 if (!(result = ast_str_thread_get(&result_buf, 16))) {
00597 return -1;
00598 }
00599 } else {
00600
00601 result_ptr = bufstr;
00602 }
00603
00604 if (args.argc < 3) {
00605 ast_log(LOG_ERROR, "Usage: LISTFILTER(<listname>,<delimiter>,<fieldvalue>)\n");
00606 return -1;
00607 }
00608
00609 varsubst = alloca(strlen(args.listname) + 4);
00610 sprintf(varsubst, "${%s}", args.listname);
00611
00612
00613 if (chan) {
00614 ast_channel_lock(chan);
00615 }
00616 ast_str_substitute_variables(&orig_list, 0, chan, varsubst);
00617 if (!ast_str_strlen(orig_list)) {
00618 ast_log(LOG_ERROR, "List variable '%s' not found\n", args.listname);
00619 if (chan) {
00620 ast_channel_unlock(chan);
00621 }
00622 return -1;
00623 }
00624
00625
00626 if (!strstr(ast_str_buffer(orig_list), args.fieldvalue)) {
00627 if (buf) {
00628 ast_copy_string(buf, ast_str_buffer(orig_list), len);
00629 } else {
00630 ast_str_set(result_ptr, len, "%s", ast_str_buffer(orig_list));
00631 }
00632 if (chan) {
00633 ast_channel_unlock(chan);
00634 }
00635 return 0;
00636 }
00637
00638 dlen = strlen(args.delimiter);
00639 delim = alloca(dlen + 1);
00640 ast_get_encoded_str(args.delimiter, delim, dlen + 1);
00641
00642 if ((dlen = strlen(delim)) == 0) {
00643 delim = ",";
00644 dlen = 1;
00645 }
00646
00647 flen = strlen(args.fieldvalue);
00648
00649 ast_str_reset(*result_ptr);
00650
00651 if (len > -1) {
00652 ast_str_make_space(result_ptr, len ? len : ast_str_strlen(orig_list) + 1);
00653 }
00654
00655 begin = ast_str_buffer(orig_list);
00656 next = strstr(begin, delim);
00657
00658 do {
00659
00660 if (next) {
00661 cur = next;
00662 next = strstr(cur + dlen, delim);
00663 } else {
00664 cur = strchr(begin + dlen, '\0');
00665 }
00666
00667 if (flen == cur - begin && !strncmp(begin, args.fieldvalue, flen)) {
00668
00669 begin += flen + dlen;
00670 } else {
00671
00672 if (!first) {
00673 ast_str_append(result_ptr, len, "%s", delim);
00674 }
00675
00676 ast_str_append_substr(result_ptr, len, begin, cur - begin);
00677 first = 0;
00678 begin = cur + dlen;
00679 }
00680 } while (*cur != '\0');
00681 if (chan) {
00682 ast_channel_unlock(chan);
00683 }
00684
00685 if (buf) {
00686 ast_copy_string(buf, ast_str_buffer(result), len);
00687 }
00688
00689 return 0;
00690 }
00691
00692 static int listfilter_read(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
00693 {
00694 return listfilter(chan, cmd, parse, buf, NULL, len);
00695 }
00696
00697 static int listfilter_read2(struct ast_channel *chan, const char *cmd, char *parse, struct ast_str **buf, ssize_t len)
00698 {
00699 return listfilter(chan, cmd, parse, NULL, buf, len);
00700 }
00701
00702 static struct ast_custom_function listfilter_function = {
00703 .name = "LISTFILTER",
00704 .read = listfilter_read,
00705 .read2 = listfilter_read2,
00706 };
00707
00708 static int filter(struct ast_channel *chan, const char *cmd, char *parse, char *buf,
00709 size_t len)
00710 {
00711 AST_DECLARE_APP_ARGS(args,
00712 AST_APP_ARG(allowed);
00713 AST_APP_ARG(string);
00714 );
00715 char *outbuf = buf;
00716 unsigned char ac;
00717 char allowed[256] = "";
00718 size_t allowedlen = 0;
00719 int32_t bitfield[8] = { 0, };
00720
00721 AST_STANDARD_RAW_ARGS(args, parse);
00722
00723 if (!args.string) {
00724 ast_log(LOG_ERROR, "Usage: FILTER(<allowed-chars>,<string>)\n");
00725 return -1;
00726 }
00727
00728 if (args.allowed[0] == '"' && !ast_opt_dont_warn) {
00729 ast_log(LOG_WARNING, "FILTER allowed characters includes the quote (\") character. This may not be what you want.\n");
00730 }
00731
00732
00733 for (; *(args.allowed);) {
00734 char c1 = 0, c2 = 0;
00735 size_t consumed = 0;
00736
00737 if (ast_get_encoded_char(args.allowed, &c1, &consumed))
00738 return -1;
00739 args.allowed += consumed;
00740
00741 if (*(args.allowed) == '-') {
00742 if (ast_get_encoded_char(args.allowed + 1, &c2, &consumed))
00743 c2 = c1;
00744 args.allowed += consumed + 1;
00745
00746 if ((unsigned char) c2 < (unsigned char) c1 && !ast_opt_dont_warn) {
00747 ast_log(LOG_WARNING, "Range wrapping in FILTER(%s,%s). This may not be what you want.\n", parse, args.string);
00748 }
00749
00750
00751
00752
00753
00754 for (ac = (unsigned char) c1; ac != (unsigned char) c2; ac++) {
00755 bitfield[ac / 32] |= 1 << (ac % 32);
00756 }
00757 bitfield[ac / 32] |= 1 << (ac % 32);
00758
00759 ast_debug(4, "c1=%d, c2=%d\n", c1, c2);
00760 } else {
00761 ac = (unsigned char) c1;
00762 ast_debug(4, "c1=%d, consumed=%d, args.allowed=%s\n", c1, (int) consumed, args.allowed - consumed);
00763 bitfield[ac / 32] |= 1 << (ac % 32);
00764 }
00765 }
00766
00767 for (ac = 1; ac != 0; ac++) {
00768 if (bitfield[ac / 32] & (1 << (ac % 32))) {
00769 allowed[allowedlen++] = ac;
00770 }
00771 }
00772
00773 ast_debug(1, "Allowed: %s\n", allowed);
00774
00775 for (; *(args.string) && (buf + len - 1 > outbuf); (args.string)++) {
00776 if (strchr(allowed, *(args.string)))
00777 *outbuf++ = *(args.string);
00778 }
00779 *outbuf = '\0';
00780
00781 return 0;
00782 }
00783
00784 static struct ast_custom_function filter_function = {
00785 .name = "FILTER",
00786 .read = filter,
00787 };
00788
00789 static int replace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
00790 {
00791 AST_DECLARE_APP_ARGS(args,
00792 AST_APP_ARG(varname);
00793 AST_APP_ARG(find);
00794 AST_APP_ARG(replace);
00795 );
00796 char *strptr, *varsubst;
00797 struct ast_str *str = ast_str_thread_get(&result_buf, 16);
00798 char find[256];
00799 char replace[2] = "";
00800 size_t unused;
00801
00802 AST_STANDARD_APP_ARGS(args, data);
00803
00804 if (!str) {
00805 return -1;
00806 }
00807
00808 if (args.argc < 2) {
00809 ast_log(LOG_ERROR, "Usage: %s(<varname>,<search-chars>[,<replace-char>])\n", cmd);
00810 return -1;
00811 }
00812
00813
00814 ast_get_encoded_str(args.find, find, sizeof(find));
00815 ast_get_encoded_char(args.replace, replace, &unused);
00816
00817 if (ast_strlen_zero(find) || ast_strlen_zero(args.varname)) {
00818 ast_log(LOG_ERROR, "The characters to search for and the variable name must not be empty.\n");
00819 return -1;
00820 }
00821
00822 varsubst = alloca(strlen(args.varname) + 4);
00823 sprintf(varsubst, "${%s}", args.varname);
00824 ast_str_substitute_variables(&str, 0, chan, varsubst);
00825
00826 if (!ast_str_strlen(str)) {
00827
00828 return -1;
00829 }
00830
00831 ast_debug(3, "String to search: (%s)\n", ast_str_buffer(str));
00832 ast_debug(3, "Characters to find: (%s)\n", find);
00833 ast_debug(3, "Character to replace with: (%s)\n", replace);
00834
00835 for (strptr = ast_str_buffer(str); *strptr; strptr++) {
00836
00837
00838 if (strchr(find, *strptr)) {
00839 if (ast_strlen_zero(replace)) {
00840
00841 strcpy(strptr, strptr + 1);
00842 strptr--;
00843 } else {
00844
00845 *strptr = *replace;
00846 }
00847 }
00848 }
00849
00850 ast_str_set(buf, len, "%s", ast_str_buffer(str));
00851 return 0;
00852 }
00853
00854 static struct ast_custom_function replace_function = {
00855 .name = "REPLACE",
00856 .read2 = replace,
00857 };
00858
00859 static int strreplace(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
00860 {
00861 char *varsubstr;
00862 char *start;
00863 char *end;
00864 int find_size;
00865 unsigned max_matches;
00866 unsigned count;
00867 struct ast_str *str = ast_str_thread_get(&result_buf, 16);
00868
00869 AST_DECLARE_APP_ARGS(args,
00870 AST_APP_ARG(varname);
00871 AST_APP_ARG(find_string);
00872 AST_APP_ARG(replace_string);
00873 AST_APP_ARG(max_replacements);
00874 AST_APP_ARG(other);
00875 );
00876
00877
00878 ast_str_reset(*buf);
00879
00880 if (!str) {
00881
00882 return -1;
00883 }
00884
00885
00886 AST_STANDARD_APP_ARGS(args, data);
00887
00888 if (args.argc < 2) {
00889
00890 ast_log(LOG_ERROR,
00891 "Usage: %s(<varname>,<find-string>[,<replace-string>,[<max-replacements>]])\n",
00892 cmd);
00893 return -1;
00894 }
00895
00896
00897 if (ast_strlen_zero(args.varname)) {
00898 return -1;
00899 }
00900
00901
00902 if (ast_strlen_zero(args.find_string)) {
00903 ast_log(LOG_ERROR, "No <find-string> specified\n");
00904 return -1;
00905 }
00906 find_size = strlen(args.find_string);
00907
00908
00909 varsubstr = alloca(strlen(args.varname) + 4);
00910 sprintf(varsubstr, "${%s}", args.varname);
00911 ast_str_substitute_variables(&str, 0, chan, varsubstr);
00912
00913
00914 if (!args.max_replacements
00915 || (max_matches = atoi(args.max_replacements)) <= 0) {
00916
00917 max_matches = -1;
00918 }
00919
00920
00921 start = ast_str_buffer(str);
00922 for (count = 0; count < max_matches; ++count) {
00923 end = strstr(start, args.find_string);
00924 if (!end) {
00925
00926 break;
00927 }
00928
00929
00930 *end = '\0';
00931 ast_str_append(buf, len, "%s", start);
00932 if (args.replace_string) {
00933
00934 ast_str_append(buf, len, "%s", args.replace_string);
00935 }
00936 start = end + find_size;
00937 }
00938 ast_str_append(buf, len, "%s", start);
00939
00940 return 0;
00941 }
00942
00943 static struct ast_custom_function strreplace_function = {
00944 .name = "STRREPLACE",
00945 .read2 = strreplace,
00946 };
00947
00948 static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf,
00949 size_t len)
00950 {
00951 AST_DECLARE_APP_ARGS(args,
00952 AST_APP_ARG(null);
00953 AST_APP_ARG(reg);
00954 AST_APP_ARG(str);
00955 );
00956 int errcode;
00957 regex_t regexbuf;
00958
00959 buf[0] = '\0';
00960
00961 AST_NONSTANDARD_APP_ARGS(args, parse, '"');
00962
00963 if (args.argc != 3) {
00964 ast_log(LOG_ERROR, "Unexpected arguments: should have been in the form '\"<regex>\" <string>'\n");
00965 return -1;
00966 }
00967 if ((*args.str == ' ') || (*args.str == '\t'))
00968 args.str++;
00969
00970 ast_debug(1, "FUNCTION REGEX (%s)(%s)\n", args.reg, args.str);
00971
00972 if ((errcode = regcomp(®exbuf, args.reg, REG_EXTENDED | REG_NOSUB))) {
00973 regerror(errcode, ®exbuf, buf, len);
00974 ast_log(LOG_WARNING, "Malformed input %s(%s): %s\n", cmd, parse, buf);
00975 return -1;
00976 }
00977
00978 strcpy(buf, regexec(®exbuf, args.str, 0, NULL, 0) ? "0" : "1");
00979
00980 regfree(®exbuf);
00981
00982 return 0;
00983 }
00984
00985 static struct ast_custom_function regex_function = {
00986 .name = "REGEX",
00987 .read = regex,
00988 };
00989
00990 #define HASH_PREFIX "~HASH~%s~"
00991 #define HASH_FORMAT HASH_PREFIX "%s~"
00992
00993 static char *app_clearhash = "ClearHash";
00994
00995
00996 static void clearvar_prefix(struct ast_channel *chan, const char *prefix)
00997 {
00998 struct ast_var_t *var;
00999 int len = strlen(prefix);
01000 AST_LIST_TRAVERSE_SAFE_BEGIN(&chan->varshead, var, entries) {
01001 if (strncasecmp(prefix, ast_var_name(var), len) == 0) {
01002 AST_LIST_REMOVE_CURRENT(entries);
01003 ast_free(var);
01004 }
01005 }
01006 AST_LIST_TRAVERSE_SAFE_END
01007 }
01008
01009 static int exec_clearhash(struct ast_channel *chan, const char *data)
01010 {
01011 char prefix[80];
01012 snprintf(prefix, sizeof(prefix), HASH_PREFIX, data ? (char *)data : "null");
01013 clearvar_prefix(chan, prefix);
01014 return 0;
01015 }
01016
01017 static int array(struct ast_channel *chan, const char *cmd, char *var,
01018 const char *value)
01019 {
01020 AST_DECLARE_APP_ARGS(arg1,
01021 AST_APP_ARG(var)[100];
01022 );
01023 AST_DECLARE_APP_ARGS(arg2,
01024 AST_APP_ARG(val)[100];
01025 );
01026 char *origvar = "", *value2, varname[256];
01027 int i, ishash = 0;
01028
01029 value2 = ast_strdupa(value);
01030 if (!var || !value2)
01031 return -1;
01032
01033 if (!strcmp(cmd, "HASH")) {
01034 const char *var2 = pbx_builtin_getvar_helper(chan, "~ODBCFIELDS~");
01035 origvar = var;
01036 if (var2)
01037 var = ast_strdupa(var2);
01038 else {
01039 if (chan)
01040 ast_autoservice_stop(chan);
01041 return -1;
01042 }
01043 ishash = 1;
01044 }
01045
01046
01047
01048
01049
01050
01051
01052 ast_debug(1, "array (%s=%s)\n", var, S_OR(value2, ""));
01053 AST_STANDARD_APP_ARGS(arg1, var);
01054
01055 AST_STANDARD_APP_ARGS(arg2, value2);
01056
01057 for (i = 0; i < arg1.argc; i++) {
01058 ast_debug(1, "array set value (%s=%s)\n", arg1.var[i],
01059 S_OR(arg2.val[i], ""));
01060 if (i < arg2.argc) {
01061 if (ishash) {
01062 if (origvar[0] == '_') {
01063 if (origvar[1] == '_') {
01064 snprintf(varname, sizeof(varname), "__" HASH_FORMAT, origvar + 2, arg1.var[i]);
01065 } else {
01066 snprintf(varname, sizeof(varname), "_" HASH_FORMAT, origvar + 1, arg1.var[i]);
01067 }
01068 } else {
01069 snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
01070 }
01071
01072 pbx_builtin_setvar_helper(chan, varname, arg2.val[i]);
01073 } else {
01074 pbx_builtin_setvar_helper(chan, arg1.var[i], arg2.val[i]);
01075 }
01076 } else {
01077
01078
01079 if (ishash) {
01080 snprintf(varname, sizeof(varname), HASH_FORMAT, origvar, arg1.var[i]);
01081 pbx_builtin_setvar_helper(chan, varname, "");
01082 } else {
01083 pbx_builtin_setvar_helper(chan, arg1.var[i], "");
01084 }
01085 }
01086 }
01087
01088 return 0;
01089 }
01090
01091 static int hashkeys_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
01092 {
01093 struct ast_var_t *newvar;
01094 struct ast_str *prefix = ast_str_alloca(80);
01095
01096 ast_str_set(&prefix, -1, HASH_PREFIX, data);
01097 memset(buf, 0, len);
01098
01099 AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) {
01100 if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
01101
01102 strncat(buf, ast_var_name(newvar) + ast_str_strlen(prefix), len - strlen(buf) - 1);
01103
01104 buf[strlen(buf) - 1] = ',';
01105 }
01106 }
01107
01108 buf[strlen(buf) - 1] = '\0';
01109 return 0;
01110 }
01111
01112 static int hashkeys_read2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
01113 {
01114 struct ast_var_t *newvar;
01115 struct ast_str *prefix = ast_str_alloca(80);
01116 char *tmp;
01117
01118 ast_str_set(&prefix, -1, HASH_PREFIX, data);
01119
01120 AST_LIST_TRAVERSE(&chan->varshead, newvar, entries) {
01121 if (strncasecmp(ast_str_buffer(prefix), ast_var_name(newvar), ast_str_strlen(prefix)) == 0) {
01122
01123 ast_str_append(buf, len, "%s", ast_var_name(newvar) + ast_str_strlen(prefix));
01124
01125 tmp = ast_str_buffer(*buf);
01126 tmp[ast_str_strlen(*buf) - 1] = ',';
01127 }
01128 }
01129
01130 tmp = ast_str_buffer(*buf);
01131 tmp[ast_str_strlen(*buf) - 1] = '\0';
01132 return 0;
01133 }
01134
01135 static int hash_write(struct ast_channel *chan, const char *cmd, char *var, const char *value)
01136 {
01137 char varname[256];
01138 AST_DECLARE_APP_ARGS(arg,
01139 AST_APP_ARG(hashname);
01140 AST_APP_ARG(hashkey);
01141 );
01142
01143 if (!strchr(var, ',')) {
01144
01145 return array(chan, "HASH", var, value);
01146 }
01147
01148 AST_STANDARD_APP_ARGS(arg, var);
01149 if (arg.hashname[0] == '_') {
01150 if (arg.hashname[1] == '_') {
01151 snprintf(varname, sizeof(varname), "__" HASH_FORMAT, arg.hashname + 2, arg.hashkey);
01152 } else {
01153 snprintf(varname, sizeof(varname), "_" HASH_FORMAT, arg.hashname + 1, arg.hashkey);
01154 }
01155 } else {
01156 snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
01157 }
01158 pbx_builtin_setvar_helper(chan, varname, value);
01159
01160 return 0;
01161 }
01162
01163 static int hash_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
01164 {
01165 char varname[256];
01166 const char *varvalue;
01167 AST_DECLARE_APP_ARGS(arg,
01168 AST_APP_ARG(hashname);
01169 AST_APP_ARG(hashkey);
01170 );
01171
01172 AST_STANDARD_APP_ARGS(arg, data);
01173 if (arg.argc == 2) {
01174 snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg.hashkey);
01175 varvalue = pbx_builtin_getvar_helper(chan, varname);
01176 if (varvalue)
01177 ast_copy_string(buf, varvalue, len);
01178 else
01179 *buf = '\0';
01180 } else if (arg.argc == 1) {
01181 char colnames[4096];
01182 int i;
01183 AST_DECLARE_APP_ARGS(arg2,
01184 AST_APP_ARG(col)[100];
01185 );
01186
01187
01188 hashkeys_read(chan, "HASHKEYS", arg.hashname, colnames, sizeof(colnames));
01189 pbx_builtin_setvar_helper(chan, "~ODBCFIELDS~", colnames);
01190
01191 AST_STANDARD_APP_ARGS(arg2, colnames);
01192 *buf = '\0';
01193
01194
01195 for (i = 0; i < arg2.argc; i++) {
01196 snprintf(varname, sizeof(varname), HASH_FORMAT, arg.hashname, arg2.col[i]);
01197 varvalue = pbx_builtin_getvar_helper(chan, varname);
01198 strncat(buf, varvalue, len - strlen(buf) - 1);
01199 strncat(buf, ",", len - strlen(buf) - 1);
01200 }
01201
01202
01203 buf[strlen(buf) - 1] = '\0';
01204 }
01205
01206 return 0;
01207 }
01208
01209 static struct ast_custom_function hash_function = {
01210 .name = "HASH",
01211 .write = hash_write,
01212 .read = hash_read,
01213 };
01214
01215 static struct ast_custom_function hashkeys_function = {
01216 .name = "HASHKEYS",
01217 .read = hashkeys_read,
01218 .read2 = hashkeys_read2,
01219 };
01220
01221 static struct ast_custom_function array_function = {
01222 .name = "ARRAY",
01223 .write = array,
01224 };
01225
01226 static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
01227 {
01228 char *bufptr = buf, *dataptr = data;
01229
01230 if (len < 3){
01231 ast_log(LOG_ERROR, "Not enough buffer");
01232 return -1;
01233 }
01234
01235 if (ast_strlen_zero(data)) {
01236 ast_log(LOG_WARNING, "No argument specified!\n");
01237 ast_copy_string(buf, "\"\"", len);
01238 return 0;
01239 }
01240
01241 *bufptr++ = '"';
01242 for (; bufptr < buf + len - 3; dataptr++) {
01243 if (*dataptr == '\\') {
01244 *bufptr++ = '\\';
01245 *bufptr++ = '\\';
01246 } else if (*dataptr == '"') {
01247 *bufptr++ = '\\';
01248 *bufptr++ = '"';
01249 } else if (*dataptr == '\0') {
01250 break;
01251 } else {
01252 *bufptr++ = *dataptr;
01253 }
01254 }
01255 *bufptr++ = '"';
01256 *bufptr = '\0';
01257 return 0;
01258 }
01259
01260 static struct ast_custom_function quote_function = {
01261 .name = "QUOTE",
01262 .read = quote,
01263 };
01264
01265 static int csv_quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
01266 {
01267 char *bufptr = buf, *dataptr = data;
01268
01269 if (len < 3) {
01270 ast_log(LOG_ERROR, "Not enough buffer");
01271 return -1;
01272 }
01273
01274 if (ast_strlen_zero(data)) {
01275 ast_copy_string(buf, "\"\"", len);
01276 return 0;
01277 }
01278
01279 *bufptr++ = '"';
01280 for (; bufptr < buf + len - 3; dataptr++){
01281 if (*dataptr == '"') {
01282 *bufptr++ = '"';
01283 *bufptr++ = '"';
01284 } else if (*dataptr == '\0') {
01285 break;
01286 } else {
01287 *bufptr++ = *dataptr;
01288 }
01289 }
01290 *bufptr++ = '"';
01291 *bufptr='\0';
01292 return 0;
01293 }
01294
01295 static struct ast_custom_function csv_quote_function = {
01296 .name = "CSV_QUOTE",
01297 .read = csv_quote,
01298 };
01299
01300 static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
01301 {
01302 int length = 0;
01303
01304 if (data)
01305 length = strlen(data);
01306
01307 snprintf(buf, buflen, "%d", length);
01308
01309 return 0;
01310 }
01311
01312 static struct ast_custom_function len_function = {
01313 .name = "LEN",
01314 .read = len,
01315 .read_max = 12,
01316 };
01317
01318 static int acf_strftime(struct ast_channel *chan, const char *cmd, char *parse,
01319 char *buf, size_t buflen)
01320 {
01321 AST_DECLARE_APP_ARGS(args,
01322 AST_APP_ARG(epoch);
01323 AST_APP_ARG(timezone);
01324 AST_APP_ARG(format);
01325 );
01326 struct timeval when;
01327 struct ast_tm tm;
01328
01329 buf[0] = '\0';
01330
01331 AST_STANDARD_APP_ARGS(args, parse);
01332
01333 ast_get_timeval(args.epoch, &when, ast_tvnow(), NULL);
01334 ast_localtime(&when, &tm, args.timezone);
01335
01336 if (!args.format)
01337 args.format = "%c";
01338
01339 if (ast_strftime(buf, buflen, args.format, &tm) <= 0)
01340 ast_log(LOG_WARNING, "C function strftime() output nothing?!!\n");
01341
01342 buf[buflen - 1] = '\0';
01343
01344 return 0;
01345 }
01346
01347 static struct ast_custom_function strftime_function = {
01348 .name = "STRFTIME",
01349 .read = acf_strftime,
01350 };
01351
01352 static int acf_strptime(struct ast_channel *chan, const char *cmd, char *data,
01353 char *buf, size_t buflen)
01354 {
01355 AST_DECLARE_APP_ARGS(args,
01356 AST_APP_ARG(timestring);
01357 AST_APP_ARG(timezone);
01358 AST_APP_ARG(format);
01359 );
01360 struct ast_tm tm;
01361
01362 buf[0] = '\0';
01363
01364 if (!data) {
01365 ast_log(LOG_ERROR,
01366 "Asterisk function STRPTIME() requires an argument.\n");
01367 return -1;
01368 }
01369
01370 AST_STANDARD_APP_ARGS(args, data);
01371
01372 if (ast_strlen_zero(args.format)) {
01373 ast_log(LOG_ERROR,
01374 "No format supplied to STRPTIME(<timestring>,<timezone>,<format>)");
01375 return -1;
01376 }
01377
01378 if (!ast_strptime(args.timestring, args.format, &tm)) {
01379 ast_log(LOG_WARNING, "STRPTIME() found no time specified within the string\n");
01380 } else {
01381 struct timeval when;
01382 when = ast_mktime(&tm, args.timezone);
01383 snprintf(buf, buflen, "%d", (int) when.tv_sec);
01384 }
01385
01386 return 0;
01387 }
01388
01389 static struct ast_custom_function strptime_function = {
01390 .name = "STRPTIME",
01391 .read = acf_strptime,
01392 };
01393
01394 static int function_eval(struct ast_channel *chan, const char *cmd, char *data,
01395 char *buf, size_t buflen)
01396 {
01397 if (ast_strlen_zero(data)) {
01398 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
01399 return -1;
01400 }
01401
01402 pbx_substitute_variables_helper(chan, data, buf, buflen - 1);
01403
01404 return 0;
01405 }
01406
01407 static int function_eval2(struct ast_channel *chan, const char *cmd, char *data,
01408 struct ast_str **buf, ssize_t buflen)
01409 {
01410 if (ast_strlen_zero(data)) {
01411 ast_log(LOG_WARNING, "EVAL requires an argument: EVAL(<string>)\n");
01412 return -1;
01413 }
01414
01415 ast_str_substitute_variables(buf, buflen, chan, data);
01416
01417 return 0;
01418 }
01419
01420 static struct ast_custom_function eval_function = {
01421 .name = "EVAL",
01422 .read = function_eval,
01423 .read2 = function_eval2,
01424 };
01425
01426 static int keypadhash(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
01427 {
01428 char *bufptr, *dataptr;
01429
01430 for (bufptr = buf, dataptr = data; bufptr < buf + buflen - 1; dataptr++) {
01431 if (*dataptr == '\0') {
01432 *bufptr++ = '\0';
01433 break;
01434 } else if (*dataptr == '1') {
01435 *bufptr++ = '1';
01436 } else if (strchr("AaBbCc2", *dataptr)) {
01437 *bufptr++ = '2';
01438 } else if (strchr("DdEeFf3", *dataptr)) {
01439 *bufptr++ = '3';
01440 } else if (strchr("GgHhIi4", *dataptr)) {
01441 *bufptr++ = '4';
01442 } else if (strchr("JjKkLl5", *dataptr)) {
01443 *bufptr++ = '5';
01444 } else if (strchr("MmNnOo6", *dataptr)) {
01445 *bufptr++ = '6';
01446 } else if (strchr("PpQqRrSs7", *dataptr)) {
01447 *bufptr++ = '7';
01448 } else if (strchr("TtUuVv8", *dataptr)) {
01449 *bufptr++ = '8';
01450 } else if (strchr("WwXxYyZz9", *dataptr)) {
01451 *bufptr++ = '9';
01452 } else if (*dataptr == '0') {
01453 *bufptr++ = '0';
01454 }
01455 }
01456 buf[buflen - 1] = '\0';
01457
01458 return 0;
01459 }
01460
01461 static struct ast_custom_function keypadhash_function = {
01462 .name = "KEYPADHASH",
01463 .read = keypadhash,
01464 };
01465
01466 static int string_toupper(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
01467 {
01468 char *bufptr = buf, *dataptr = data;
01469
01470 while ((bufptr < buf + buflen - 1) && (*bufptr++ = toupper(*dataptr++)));
01471
01472 return 0;
01473 }
01474
01475 static int string_toupper2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
01476 {
01477 char *bufptr, *dataptr = data;
01478
01479 if (buflen > -1) {
01480 ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
01481 }
01482 bufptr = ast_str_buffer(*buf);
01483 while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = toupper(*dataptr++)));
01484 ast_str_update(*buf);
01485
01486 return 0;
01487 }
01488
01489 static struct ast_custom_function toupper_function = {
01490 .name = "TOUPPER",
01491 .read = string_toupper,
01492 .read2 = string_toupper2,
01493 };
01494
01495 static int string_tolower(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
01496 {
01497 char *bufptr = buf, *dataptr = data;
01498
01499 while ((bufptr < buf + buflen - 1) && (*bufptr++ = tolower(*dataptr++)));
01500
01501 return 0;
01502 }
01503
01504 static int string_tolower2(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t buflen)
01505 {
01506 char *bufptr, *dataptr = data;
01507
01508 if (buflen > -1) {
01509 ast_str_make_space(buf, buflen > 0 ? buflen : strlen(data) + 1);
01510 }
01511 bufptr = ast_str_buffer(*buf);
01512 while ((bufptr < ast_str_buffer(*buf) + ast_str_size(*buf) - 1) && (*bufptr++ = tolower(*dataptr++)));
01513 ast_str_update(*buf);
01514
01515 return 0;
01516 }
01517
01518 static struct ast_custom_function tolower_function = {
01519 .name = "TOLOWER",
01520 .read = string_tolower,
01521 .read2 = string_tolower2,
01522 };
01523
01524 static int shift_pop(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
01525 {
01526 #define beginning (cmd[0] == 'S')
01527 char *after, delimiter[2] = ",", *varsubst;
01528 size_t unused;
01529 struct ast_str *before = ast_str_thread_get(&result_buf, 16);
01530 char *(*search_func)(const char *s, int c) = (beginning ? strchr : strrchr);
01531 AST_DECLARE_APP_ARGS(args,
01532 AST_APP_ARG(var);
01533 AST_APP_ARG(delimiter);
01534 );
01535
01536 if (!before) {
01537 return -1;
01538 }
01539
01540 AST_STANDARD_APP_ARGS(args, data);
01541
01542 if (ast_strlen_zero(args.var)) {
01543 ast_log(LOG_WARNING, "%s requires a variable name\n", cmd);
01544 return -1;
01545 }
01546
01547 varsubst = alloca(strlen(args.var) + 4);
01548 sprintf(varsubst, "${%s}", args.var);
01549 ast_str_substitute_variables(&before, 0, chan, varsubst);
01550
01551 if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
01552 ast_get_encoded_char(args.delimiter, delimiter, &unused);
01553 }
01554
01555 if (!ast_str_strlen(before)) {
01556
01557 return -1;
01558 }
01559
01560 if (!(after = search_func(ast_str_buffer(before), delimiter[0]))) {
01561
01562 ast_str_set(buf, len, "%s", ast_str_buffer(before));
01563 pbx_builtin_setvar_helper(chan, args.var, "");
01564 } else {
01565 *after++ = '\0';
01566 ast_str_set(buf, len, "%s", beginning ? ast_str_buffer(before) : after);
01567 pbx_builtin_setvar_helper(chan, args.var, beginning ? after : ast_str_buffer(before));
01568 }
01569
01570 return 0;
01571 #undef beginning
01572 }
01573
01574 static struct ast_custom_function shift_function = {
01575 .name = "SHIFT",
01576 .read2 = shift_pop,
01577 };
01578
01579 static struct ast_custom_function pop_function = {
01580 .name = "POP",
01581 .read2 = shift_pop,
01582 };
01583
01584 static int unshift_push(struct ast_channel *chan, const char *cmd, char *data, const char *new_value)
01585 {
01586 #define beginning (cmd[0] == 'U')
01587 char delimiter[2] = ",", *varsubst;
01588 size_t unused;
01589 struct ast_str *buf, *previous_value;
01590 AST_DECLARE_APP_ARGS(args,
01591 AST_APP_ARG(var);
01592 AST_APP_ARG(delimiter);
01593 );
01594
01595 if (!(buf = ast_str_thread_get(&result_buf, 16)) ||
01596 !(previous_value = ast_str_thread_get(&tmp_buf, 16))) {
01597 return -1;
01598 }
01599
01600 AST_STANDARD_APP_ARGS(args, data);
01601
01602 if (ast_strlen_zero(args.var)) {
01603 ast_log(LOG_WARNING, "%s requires a variable name\n", cmd);
01604 return -1;
01605 }
01606
01607 if (args.argc > 1 && !ast_strlen_zero(args.delimiter)) {
01608 ast_get_encoded_char(args.delimiter, delimiter, &unused);
01609 }
01610
01611 varsubst = alloca(strlen(args.var) + 4);
01612 sprintf(varsubst, "${%s}", args.var);
01613 ast_str_substitute_variables(&previous_value, 0, chan, varsubst);
01614
01615 if (!ast_str_strlen(previous_value)) {
01616 ast_str_set(&buf, 0, "%s", new_value);
01617 } else {
01618 ast_str_set(&buf, 0, "%s%c%s",
01619 beginning ? new_value : ast_str_buffer(previous_value),
01620 delimiter[0],
01621 beginning ? ast_str_buffer(previous_value) : new_value);
01622 }
01623
01624 pbx_builtin_setvar_helper(chan, args.var, ast_str_buffer(buf));
01625
01626 return 0;
01627 #undef beginning
01628 }
01629
01630 static struct ast_custom_function push_function = {
01631 .name = "PUSH",
01632 .write = unshift_push,
01633 };
01634
01635 static struct ast_custom_function unshift_function = {
01636 .name = "UNSHIFT",
01637 .write = unshift_push,
01638 };
01639
01640 static int passthru(struct ast_channel *chan, const char *cmd, char *data, struct ast_str **buf, ssize_t len)
01641 {
01642 ast_str_set(buf, len, "%s", data);
01643 return 0;
01644 }
01645
01646 static struct ast_custom_function passthru_function = {
01647 .name = "PASSTHRU",
01648 .read2 = passthru,
01649 };
01650
01651 #ifdef TEST_FRAMEWORK
01652 AST_TEST_DEFINE(test_FIELDNUM)
01653 {
01654 int i, res = AST_TEST_PASS;
01655 struct ast_channel *chan;
01656 struct ast_str *str;
01657 char expression[256];
01658 struct {
01659 const char *fields;
01660 const char *delim;
01661 const char *field;
01662 const char *expected;
01663 } test_args[] = {
01664 {"abc,def,ghi,jkl", "\\,", "ghi", "3"},
01665 {"abc def ghi jkl", " ", "abc", "1"},
01666 {"abc/def/ghi/jkl", "\\\\x2f", "def", "2"},
01667 {"abc$def$ghi$jkl", "", "ghi", "0"},
01668 {"abc,def,ghi,jkl", "-", "", "0"},
01669 {"abc-def-ghi-jkl", "-", "mno", "0"}
01670 };
01671
01672 switch (cmd) {
01673 case TEST_INIT:
01674 info->name = "func_FIELDNUM_test";
01675 info->category = "/funcs/func_strings/";
01676 info->summary = "Test FIELDNUM function";
01677 info->description = "Verify FIELDNUM behavior";
01678 return AST_TEST_NOT_RUN;
01679 case TEST_EXECUTE:
01680 break;
01681 }
01682
01683 if (!(chan = ast_dummy_channel_alloc())) {
01684 ast_test_status_update(test, "Unable to allocate dummy channel\n");
01685 return AST_TEST_FAIL;
01686 }
01687
01688 if (!(str = ast_str_create(16))) {
01689 ast_test_status_update(test, "Unable to allocate dynamic string buffer\n");
01690 ast_channel_release(chan);
01691 return AST_TEST_FAIL;
01692 }
01693
01694 for (i = 0; i < ARRAY_LEN(test_args); i++) {
01695 struct ast_var_t *var = ast_var_assign("FIELDS", test_args[i].fields);
01696 AST_LIST_INSERT_HEAD(&chan->varshead, var, entries);
01697
01698 snprintf(expression, sizeof(expression), "${FIELDNUM(%s,%s,%s)}", var->name, test_args[i].delim, test_args[i].field);
01699 ast_str_substitute_variables(&str, 0, chan, expression);
01700
01701 AST_LIST_REMOVE(&chan->varshead, var, entries);
01702 ast_var_delete(var);
01703
01704 if (strcasecmp(ast_str_buffer(str), test_args[i].expected)) {
01705 ast_test_status_update(test, "Evaluation of '%s' returned '%s' instead of the expected value '%s'\n",
01706 expression, ast_str_buffer(str), test_args[i].expected);
01707 res = AST_TEST_FAIL;
01708 break;
01709 }
01710 }
01711
01712 ast_free(str);
01713 ast_channel_release(chan);
01714
01715 return res;
01716 }
01717
01718 AST_TEST_DEFINE(test_FILTER)
01719 {
01720 int i, res = AST_TEST_PASS;
01721 const char *test_strings[][2] = {
01722 {"A-R", "DAHDI"},
01723 {"A\\-R", "A"},
01724 {"\\x41-R", "DAHDI"},
01725 {"0-9A-Ca-c", "0042133333A12212"},
01726 {"0-9a-cA-C_+\\-", "0042133333A12212"},
01727 {NULL, NULL},
01728 };
01729
01730 switch (cmd) {
01731 case TEST_INIT:
01732 info->name = "func_FILTER_test";
01733 info->category = "/funcs/func_strings/";
01734 info->summary = "Test FILTER function";
01735 info->description = "Verify FILTER behavior";
01736 return AST_TEST_NOT_RUN;
01737 case TEST_EXECUTE:
01738 break;
01739 }
01740
01741 for (i = 0; test_strings[i][0]; i++) {
01742 char tmp[256], tmp2[256] = "";
01743 snprintf(tmp, sizeof(tmp), "${FILTER(%s,0042133333&DAHDI/g1/2212)}", test_strings[i][0]);
01744 pbx_substitute_variables_helper(NULL, tmp, tmp2, sizeof(tmp2) - 1);
01745 if (strcmp(test_strings[i][1], tmp2)) {
01746 ast_test_status_update(test, "Format string '%s' substituted to '%s'. Expected '%s'.\n", test_strings[i][0], tmp2, test_strings[i][1]);
01747 res = AST_TEST_FAIL;
01748 }
01749 }
01750 return res;
01751 }
01752
01753 AST_TEST_DEFINE(test_STRREPLACE)
01754 {
01755 int i, res = AST_TEST_PASS;
01756 struct ast_channel *chan;
01757 struct ast_str *str;
01758
01759 const char *test_strings[][5] = {
01760 {"Weasels have eaten my telephone system", "have eaten my", "are eating our", "", "Weasels are eating our telephone system"},
01761 {"Did you know twenty plus two is twenty-two?", "twenty", "thirty", NULL, "Did you know thirty plus two is thirty-two?"},
01762 {"foofoofoofoofoofoofoo", "foofoo", "bar", NULL, "barbarbarfoo"},
01763 {"My pet dog once ate a dog who sat on a dog while eating a corndog.", "dog", "cat", "3", "My pet cat once ate a cat who sat on a cat while eating a corndog."},
01764 {"One and one and one is three", "and", "plus", "1", "One plus one and one is three"},
01765 {"", "fhqwagads", "spelunker", NULL, ""},
01766 {"Part of this string is missing.", "missing", NULL, NULL, "Part of this string is ."},
01767 {"'Accidentally' left off a bunch of stuff.", NULL, NULL, NULL, ""},
01768 {"This test will also error.", "", "", "", ""},
01769 {"This is an \"escape character\" test.", "\\\"escape character\\\"", "evil", NULL, "This is an evil test."}
01770 };
01771
01772 switch (cmd) {
01773 case TEST_INIT:
01774 info->name = "func_STRREPLACE_test";
01775 info->category = "/funcs/func_strings/";
01776 info->summary = "Test STRREPLACE function";
01777 info->description = "Verify STRREPLACE behavior";
01778 return AST_TEST_NOT_RUN;
01779 case TEST_EXECUTE:
01780 break;
01781 }
01782
01783 if (!(chan = ast_dummy_channel_alloc())) {
01784 ast_test_status_update(test, "Unable to allocate dummy channel\n");
01785 return AST_TEST_FAIL;
01786 }
01787
01788 if (!(str = ast_str_create(64))) {
01789 ast_test_status_update(test, "Unable to allocate dynamic string buffer\n");
01790 ast_channel_release(chan);
01791 return AST_TEST_FAIL;
01792 }
01793
01794 for (i = 0; i < ARRAY_LEN(test_strings); i++) {
01795 char tmp[512], tmp2[512] = "";
01796
01797 struct ast_var_t *var = ast_var_assign("test_string", test_strings[i][0]);
01798 AST_LIST_INSERT_HEAD(&chan->varshead, var, entries);
01799
01800 if (test_strings[i][3]) {
01801 snprintf(tmp, sizeof(tmp), "${STRREPLACE(%s,%s,%s,%s)}", "test_string", test_strings[i][1], test_strings[i][2], test_strings[i][3]);
01802 } else if (test_strings[i][2]) {
01803 snprintf(tmp, sizeof(tmp), "${STRREPLACE(%s,%s,%s)}", "test_string", test_strings[i][1], test_strings[i][2]);
01804 } else if (test_strings[i][1]) {
01805 snprintf(tmp, sizeof(tmp), "${STRREPLACE(%s,%s)}", "test_string", test_strings[i][1]);
01806 } else {
01807 snprintf(tmp, sizeof(tmp), "${STRREPLACE(%s)}", "test_string");
01808 }
01809 ast_str_substitute_variables(&str, 0, chan, tmp);
01810 if (strcmp(test_strings[i][4], ast_str_buffer(str))) {
01811 ast_test_status_update(test, "Format string '%s' substituted to '%s'. Expected '%s'.\n", test_strings[i][0], tmp2, test_strings[i][4]);
01812 res = AST_TEST_FAIL;
01813 }
01814 }
01815
01816 ast_free(str);
01817 ast_channel_release(chan);
01818
01819 return res;
01820 }
01821 #endif
01822
01823 static int unload_module(void)
01824 {
01825 int res = 0;
01826
01827 AST_TEST_UNREGISTER(test_FIELDNUM);
01828 AST_TEST_UNREGISTER(test_FILTER);
01829 AST_TEST_UNREGISTER(test_STRREPLACE);
01830 res |= ast_custom_function_unregister(&fieldqty_function);
01831 res |= ast_custom_function_unregister(&fieldnum_function);
01832 res |= ast_custom_function_unregister(&filter_function);
01833 res |= ast_custom_function_unregister(&replace_function);
01834 res |= ast_custom_function_unregister(&strreplace_function);
01835 res |= ast_custom_function_unregister(&listfilter_function);
01836 res |= ast_custom_function_unregister(®ex_function);
01837 res |= ast_custom_function_unregister(&array_function);
01838 res |= ast_custom_function_unregister("e_function);
01839 res |= ast_custom_function_unregister(&csv_quote_function);
01840 res |= ast_custom_function_unregister(&len_function);
01841 res |= ast_custom_function_unregister(&strftime_function);
01842 res |= ast_custom_function_unregister(&strptime_function);
01843 res |= ast_custom_function_unregister(&eval_function);
01844 res |= ast_custom_function_unregister(&keypadhash_function);
01845 res |= ast_custom_function_unregister(&hashkeys_function);
01846 res |= ast_custom_function_unregister(&hash_function);
01847 res |= ast_unregister_application(app_clearhash);
01848 res |= ast_custom_function_unregister(&toupper_function);
01849 res |= ast_custom_function_unregister(&tolower_function);
01850 res |= ast_custom_function_unregister(&shift_function);
01851 res |= ast_custom_function_unregister(&pop_function);
01852 res |= ast_custom_function_unregister(&push_function);
01853 res |= ast_custom_function_unregister(&unshift_function);
01854 res |= ast_custom_function_unregister(&passthru_function);
01855
01856 return res;
01857 }
01858
01859 static int load_module(void)
01860 {
01861 int res = 0;
01862
01863 AST_TEST_REGISTER(test_FIELDNUM);
01864 AST_TEST_REGISTER(test_FILTER);
01865 AST_TEST_REGISTER(test_STRREPLACE);
01866 res |= ast_custom_function_register(&fieldqty_function);
01867 res |= ast_custom_function_register(&fieldnum_function);
01868 res |= ast_custom_function_register(&filter_function);
01869 res |= ast_custom_function_register(&replace_function);
01870 res |= ast_custom_function_register(&strreplace_function);
01871 res |= ast_custom_function_register(&listfilter_function);
01872 res |= ast_custom_function_register(®ex_function);
01873 res |= ast_custom_function_register(&array_function);
01874 res |= ast_custom_function_register("e_function);
01875 res |= ast_custom_function_register(&csv_quote_function);
01876 res |= ast_custom_function_register(&len_function);
01877 res |= ast_custom_function_register(&strftime_function);
01878 res |= ast_custom_function_register(&strptime_function);
01879 res |= ast_custom_function_register(&eval_function);
01880 res |= ast_custom_function_register(&keypadhash_function);
01881 res |= ast_custom_function_register(&hashkeys_function);
01882 res |= ast_custom_function_register(&hash_function);
01883 res |= ast_register_application_xml(app_clearhash, exec_clearhash);
01884 res |= ast_custom_function_register(&toupper_function);
01885 res |= ast_custom_function_register(&tolower_function);
01886 res |= ast_custom_function_register(&shift_function);
01887 res |= ast_custom_function_register(&pop_function);
01888 res |= ast_custom_function_register(&push_function);
01889 res |= ast_custom_function_register(&unshift_function);
01890 res |= ast_custom_function_register(&passthru_function);
01891
01892 return res;
01893 }
01894
01895 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "String handling dialplan functions");