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