23 #include "fileutils.h"
58 #define MAIN_ERR_PREFIX "FILTER: "
61 #define FILTER_PERM (api_posix_mode_t) (API_POSIX_S_IRUSR | API_POSIX_S_IWUSR)
69 #define FILTER_SCORE_MAX INT_MAX
70 #define FILTER_SCORE_MIN INT_MIN
84 SCORE_TYPE_UNKNOWN = 0,
87 SCORE_TYPE_FROM_ERE = 2,
88 SCORE_TYPE_SUBJECT = 3,
89 SCORE_TYPE_SUBJECT_ERE = 4,
90 SCORE_TYPE_MSGID_ERE = 5,
96 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
102 api_posix_regex_t* ere;
103 struct filter_wm* next;
110 const char* group_wildmat;
111 enum filter_rule_type type;
117 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
118 struct filter_wm* wm;
119 api_posix_regex_t* ere;
132 static const char* filter_type_name[] =
146 static enum filter_cs filter_locale = FILTER_CS_ASCII;
147 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
148 static enum filter_cs testgroup_cs;
149 static api_posix_regex_t* testgroup_ere = NULL;
151 static size_t score_len_max = 1000;
152 static struct filter* scores = NULL;
153 static const char scorefile_name[] =
"scorefile";
156 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
179 static void filter_print_ere_error(
int code, api_posix_regex_t* ere)
182 size_t mod_len = strlen(mod_name);
192 # if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI
194 api_posix_setlocale(API_POSIX_LC_MESSAGES,
"POSIX");
196 len = api_posix_regerror(code, ere, buf, 0);
197 if(!len || API_POSIX_SIZE_MAX - mod_len < len)
203 buf = (
char*) api_posix_malloc(mod_len + len);
206 PRINT_ERROR(
"Cannot allocate memory for error message");
210 memcpy(buf, mod_name, mod_len);
211 api_posix_regerror(code, ere, &buf[mod_len], len);
213 api_posix_free((
void*) buf);
216 # if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI
217 api_posix_setlocale(API_POSIX_LC_MESSAGES,
"");
235 static int filter_compile_ere(
enum filter_cs* cs, api_posix_regex_t** ere,
242 const char* p = NULL;
245 if(FILTER_CS_ISO8859_1 == filter_locale)
249 if(NULL == p) { res = -1; }
252 else if(FILTER_CS_UTF_8 != filter_locale)
255 *cs = FILTER_CS_ASCII;
261 PRINT_ERROR(
"ERE cannot be used with current locale");
266 *ere = (api_posix_regex_t*) api_posix_malloc(
sizeof(api_posix_regex_t));
269 PRINT_ERROR(
"Cannot allocate memory for regular expression");
276 if(FILTER_CS_ISO8859_1 == filter_locale) { pat = p; }
277 rv = api_posix_regcomp(*ere, pat,
278 API_POSIX_REG_EXTENDED | API_POSIX_REG_NOSUB);
281 PRINT_ERROR(
"Compiling regular expression failed");
282 filter_print_ere_error(rv, *ere);
283 api_posix_free((
void*) *ere);
288 printf(
"%s: %sCompiling regular expression\n",
294 if(NULL != p &&
string != p) {
enc_free((
void*) p); }
309 static void filter_score_rule_destructor(
struct filter** rule)
311 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
316 if(NULL != rule && NULL != *rule)
318 api_posix_free((
void*) (*rule)->group_wildmat);
319 api_posix_free((
void*) (*rule)->string);
320 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
326 api_posix_regfree(p->ere);
327 api_posix_free((
void*) p->ere);
328 api_posix_free((
void*) p);
332 if(NULL != (*rule)->ere)
334 api_posix_regfree((*rule)->ere);
335 api_posix_free((
void*) (*rule)->ere);
338 api_posix_free((
void*) *rule);
371 static int filter_score_rule_constructor(
struct filter** new_rule,
372 const char* group_wildmat,
373 enum filter_rule_type type,
374 int score,
const char*
string,
378 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
381 struct filter_wm* pat;
383 struct filter_wm* last = NULL;
387 *new_rule = (
struct filter*) api_posix_malloc(
sizeof(
struct filter));
388 if(NULL == *new_rule) { res = -1; }
391 (*new_rule)->group_wildmat = group_wildmat;
392 (*new_rule)->type = type;
393 (*new_rule)->value = score;
394 (*new_rule)->string = string;
395 (*new_rule)->found = 0;
396 (*new_rule)->next = NULL;
397 (*new_rule)->cs = FILTER_CS_UTF_8;
399 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
402 (*new_rule)->wm = NULL;
403 (*new_rule)->ere = NULL;
408 if(strcmp(
"*", (*new_rule)->group_wildmat))
416 pat = (
struct filter_wm*)
417 api_posix_malloc(
sizeof(
struct filter_wm));
418 if(NULL == pat) { res = -1;
break; }
421 pat->negate = wma[i - 1].negate;
422 pat->cs = FILTER_CS_UTF_8;
423 res = filter_compile_ere(&pat->cs, &pat->ere,
427 if(NULL == last) { (*new_rule)->wm = pat; }
428 else { last->next = pat; }
441 switch((*new_rule)->type)
443 case SCORE_TYPE_FROM_ERE:
444 case SCORE_TYPE_SUBJECT_ERE:
445 case SCORE_TYPE_MSGID_ERE:
447 res = filter_compile_ere(&(*new_rule)->cs, &(*new_rule)->ere,
464 (*new_rule)->group_wildmat = NULL;
465 (*new_rule)->string = NULL;
466 filter_score_rule_destructor(new_rule);
485 static int filter_score_add(
int val,
int diff)
493 if(FILTER_SCORE_MAX - val < diff) { val = FILTER_SCORE_MAX; }
494 else { val += diff; }
496 else { val += diff; }
505 if(FILTER_SCORE_MIN - val > diff) { val = FILTER_SCORE_MIN; }
506 else { val += diff; }
508 else { val += diff; }
521 static void filter_add_score_rule(
struct filter* new_rule)
523 struct filter* last_rule = scores;
525 if(NULL == last_rule) { scores = new_rule; }
529 while(NULL != last_rule->next) { last_rule = last_rule->next; }
530 last_rule->next = new_rule;
538 static void filter_delete_score_rules(
void)
540 struct filter* rule = scores;
541 struct filter* next_rule;
545 next_rule = rule->next;
546 filter_score_rule_destructor(&rule);
568 static int filter_decode_rule(
struct filter** rule,
569 const char* line,
size_t len,
int dcre)
574 enum filter_rule_type type;
577 char* group_wildmat = NULL;
587 p = strchr(line, (
int)
':');
595 wm_len = (size_t) (p - line);
596 q = (
char*) api_posix_realloc((
void*) group_wildmat, wm_len + (size_t) 1);
604 strncpy(group_wildmat, line, wm_len);
605 group_wildmat[wm_len] = 0;
606 line += wm_len + (size_t) 1;
612 type = SCORE_TYPE_UNKNOWN;
615 while(SCORE_END_OF_LIST != ++type)
617 p = filter_type_name[type];
619 if(start < len && !strncmp(line, p, start))
622 if(
':' == line[start]) {
break; }
625 if(SCORE_END_OF_LIST == type) { type = SCORE_TYPE_UNKNOWN; }
635 string = (
char*) api_posix_malloc((
size_t) len);
638 PRINT_ERROR(
"Cannot allocate memory for score rule parser");
645 case SCORE_TYPE_FROM:
646 case SCORE_TYPE_FROM_ERE:
647 case SCORE_TYPE_SUBJECT:
648 case SCORE_TYPE_SUBJECT_ERE:
649 case SCORE_TYPE_MSGID_ERE:
650 case SCORE_TYPE_GROUP:
652 rv = sscanf(&line[start],
":%d:%[^\n]", &score,
string);
678 printf(
"=============================\n");
679 printf(
" Groups: %s\n", group_wildmat);
680 printf(
" Type : %s\n", filter_type_name[type]);
681 printf(
" Score : %d\n", score);
682 printf(
" String: %s\n",
string);
684 res = filter_score_rule_constructor(rule, group_wildmat,
685 type, score,
string, dcre);
691 api_posix_free((
void*) group_wildmat);
692 api_posix_free((
void*)
string);
716 static int filter_encode_rule(
char** line,
size_t* len,
struct filter* rule)
718 const char* frt = NULL;
727 case SCORE_TYPE_FROM:
728 case SCORE_TYPE_FROM_ERE:
729 case SCORE_TYPE_SUBJECT:
730 case SCORE_TYPE_SUBJECT_ERE:
731 case SCORE_TYPE_MSGID_ERE:
732 case SCORE_TYPE_GROUP:
734 frt = filter_type_name[rule->type];
735 l += strlen(rule->group_wildmat);
741 l += strlen(rule->string);
744 p = (
char*) api_posix_malloc(l);
747 PRINT_ERROR(
"Cannot allocate memory for score rule");
752 rv = api_posix_snprintf(p, l,
"%s:%s:%d:%s\n", rule->group_wildmat,
753 frt, rule->value, rule->string);
754 if(0 > rv || (
size_t) rv >= l)
757 api_posix_free((
void*) p);
762 api_posix_free((
void*) *line);
789 static int filter_check_rule(
char* line,
size_t len,
struct filter* rule)
792 struct filter* current_rule;
795 if(
'#' != line[0] &&
'\n' != line[0])
798 if(!filter_decode_rule(¤t_rule, line, len, 1))
801 if(current_rule->type == rule->type)
803 if(!strcmp(current_rule->string, rule->string))
810 filter_score_rule_destructor(¤t_rule);
828 static int filter_export_score_rules(FILE* fs, FILE* fs_tmp)
833 api_posix_ssize_t readlen;
845 readlen = api_posix_getline(&line, &len, fs);
848 if(API_POSIX_ENOMEM == api_posix_errno)
850 PRINT_ERROR(
"Cannot assign memory for score file parser");
866 if(0 >= readlen) {
break; }
873 if(!rule->found && !filter_check_rule(line, len, rule))
877 filter_encode_rule(&line, &len, rule);
884 rv = fprintf(fs_tmp,
"%s", line);
885 if(0 > rv) {
break; }
897 rv = filter_encode_rule(&line, &len, rule);
898 if(rv) { res = -1;
break; }
902 rv = fprintf(fs_tmp,
"%s", line);
915 api_posix_free((
void*) line);
928 static int filter_get_pathname(
const char** pathname,
const char* filename)
934 if(NULL != *pathname)
936 rv =
fu_create_path(*pathname, (api_posix_mode_t) API_POSIX_S_IRWXU);
952 api_posix_free((
void*) *pathname);
967 static int filter_group_check(
struct filter* rule,
const char** grouplist)
972 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
973 struct filter_wm* plp = rule->wm;
976 const char* p = NULL;
982 while(NULL != (group = grouplist[i++]))
985 if(!strcmp(
"*", rule->group_wildmat)) { res = 0;
break; }
987 if(!strcmp(rule->group_wildmat, group)) { res = 0;
break; }
988 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
994 if(FILTER_CS_ASCII == plp->cs)
998 else if(FILTER_CS_ISO8859_1 == plp->cs)
1002 if(NULL == p) { rv = -1; }
1004 else {
string = p; }
1006 if(!rv && !api_posix_regexec(plp->ere,
string, 0, NULL, 0))
1011 if(NULL != p && group != p) {
enc_free((
void*) p); }
1016 if(plp->negate) { res = -1; }
1055 const char* scorepathname = NULL;
1056 char* oldscorepathname = NULL;
1058 api_posix_struct_stat state;
1064 api_posix_ssize_t readlen;
1065 struct filter* rule;
1066 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI
1067 const char* loc_ctype;
1070 #if !(CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB)
1071 PRINT_ERROR(
"Regular expression support disabled by configuration");
1075 filter_locale = FILTER_CS_ASCII;
1076 #if !(CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI)
1078 PRINT_ERROR(
"Cannot set locale due to configuration");
1080 printf(
"%s: %sCooked character classification codeset: "
1083 loc_ctype = api_posix_setlocale(API_POSIX_LC_CTYPE,
"");
1084 if(NULL == loc_ctype)
1086 PRINT_ERROR(
"Setting locale for category 'LC_CTYPE' failed");
1091 printf(
"%s: %sCharacter classification locale: %s\n",
1095 printf(
"%s: %sCooked character classification codeset: "
1097 filter_locale = FILTER_CS_UTF_8;
1102 loc_ctype = api_posix_nl_langinfo(CODESET);
1105 if( NULL != strstr(loc_ctype,
"8859-1")
1106 || NULL != strstr(loc_ctype,
"8859_1")
1107 || NULL != strstr(loc_ctype,
"88591") )
1110 if(
'1' == loc_ctype[strlen(loc_ctype) - (
size_t) 1])
1112 printf(
"%s: %sCooked character classification codeset: "
1114 filter_locale = FILTER_CS_ISO8859_1;
1119 PRINT_ERROR(
"Supported codesets: US-ASCII, ISO-8859-1, UTF-8");
1120 PRINT_ERROR(
"(Use \"locale -a\" to find a locale)");
1126 if( !strcmp(loc_ctype,
"POSIX")
1127 || !strcmp(loc_ctype,
"C")
1128 || NULL != strstr(loc_ctype,
"ASCII")
1129 || NULL != strstr(loc_ctype,
"X3.4") )
1131 printf(
"%s: %sCooked character classification codeset: "
1137 PRINT_ERROR(
"Supported codesets: US-ASCII, ISO-8859-1, UTF-8");
1138 PRINT_ERROR(
"(Use \"locale -a\" to find a locale)");
1152 rv = api_posix_snprintf(NULL, 0,
"%d", FILTER_SCORE_MAX);
1155 score_len_max = (size_t) rv;
1156 rv = api_posix_snprintf(NULL, 0,
"%d", FILTER_SCORE_MIN);
1159 if((
size_t) rv > score_len_max) { score_len_max = (size_t) rv; }
1165 PRINT_ERROR(
"Calculation of maximum score string length failed");
1174 printf(
"%s: %sImport external scorerc: %s\n",
1177 rv = api_posix_stat(scorerc, &state);
1178 if(rv) {
PRINT_ERROR(
"Cannot stat scorerc file"); }
1179 else if(API_POSIX_S_ISREG(state.st_mode))
1181 rv = filter_get_pathname(&scorepathname, scorefile_name);
1186 (api_posix_mode_t) 0);
1198 api_posix_malloc(strlen(scorepathname) + (
size_t) 5);
1199 if(NULL == oldscorepathname)
1201 PRINT_ERROR(
"Cannot allocate memory for pathname");
1205 strcpy(oldscorepathname, scorepathname);
1206 strcat(oldscorepathname,
".old");
1207 rv = api_posix_rename(scorepathname, oldscorepathname);
1213 API_POSIX_O_WRONLY | API_POSIX_O_CREAT,
1232 PRINT_ERROR(
"Importing scorerc failed, using local scorefile");
1236 api_posix_free((
void*)
data);
1237 api_posix_free((
void*) oldscorepathname);
1238 api_posix_free((
void*) scorepathname);
1239 scorepathname = NULL;
1242 rv = filter_get_pathname(&scorepathname, scorefile_name);
1245 rv = api_posix_stat(scorepathname, &state);
1247 else if(API_POSIX_S_ISREG(state.st_mode))
1249 rv =
fu_open_file(scorepathname, &fd, API_POSIX_O_RDWR,
1250 (api_posix_mode_t) 0);
1262 printf(
"%s: %sLoad scoring rules from: %s\n",
1268 readlen = api_posix_getline(&line, &len, fs);
1271 if(API_POSIX_ENOMEM == api_posix_errno)
1285 if(0 >= readlen) {
break; }
1289 if(
'#' == line[0] ||
'\n' == line[0]) {
continue; }
1290 rv = filter_decode_rule(&rule, line, (
size_t) readlen,
1292 if(!rv) { filter_add_score_rule(rule); }
1295 api_posix_free((
void*) line);
1302 if(rv) {
PRINT_ERROR(
"Importing rules from score file failed"); }
1305 api_posix_free((
void*) scorepathname);
1307 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
1311 PRINT_ERROR(
"No ERE for test group matching found in config file");
1317 printf(
"%s: %sEnabling test group checking facility\n",
1319 rv = filter_compile_ere(&testgroup_cs, &testgroup_ere,
1322 if(rv) { testgroup_ere = NULL; }
1344 const char* scorepathname = NULL;
1345 char* tmppathname = NULL;
1350 FILE* fs_tmp = NULL;
1353 api_posix_struct_stat state;
1357 rv = filter_get_pathname(&scorepathname, scorefile_name);
1361 rv = api_posix_stat(scorepathname, &state);
1362 if(rv && API_POSIX_ENOENT == api_posix_errno)
1365 API_POSIX_O_WRONLY | API_POSIX_O_CREAT,
FILTER_PERM);
1369 rv = api_posix_stat(scorepathname, &state);
1371 else if(API_POSIX_S_ISREG(state.st_mode))
1373 rv =
fu_open_file(scorepathname, &fd, API_POSIX_O_RDWR,
1374 (api_posix_mode_t) 0);
1384 tmppathname = api_posix_malloc(strlen(scorepathname)
1386 if(NULL == tmppathname)
1388 PRINT_ERROR(
"Cannot allocate memory for pathname");
1392 strcpy(tmppathname, scorepathname);
1393 strcat(tmppathname,
".new");
1394 rv =
fu_open_file(tmppathname, &fd_tmp, API_POSIX_O_WRONLY
1395 | API_POSIX_O_CREAT | API_POSIX_O_TRUNC,
1407 rv = filter_export_score_rules(fs, fs_tmp);
1410 if (!rv) { rv =
fu_sync(fd_tmp, fs_tmp); }
1414 rv = api_posix_rename(tmppathname, scorepathname);
1431 if(rv) {
PRINT_ERROR(
"Exporting rules to score file failed"); }
1433 filter_delete_score_rules();
1436 if(!rv && strlen(scorerc))
1439 rv =
fu_open_file(scorepathname, &fd, API_POSIX_O_RDWR,
1440 (api_posix_mode_t) 0);
1454 printf(
"%s: %sExport to external scorerc: %s\n",
1457 p = api_posix_realloc(tmppathname, strlen(scorerc) + (
size_t) 5);
1460 PRINT_ERROR(
"Cannot allocate memory for pathname");
1465 strcpy(tmppathname, scorerc);
1466 strcat(tmppathname,
".new");
1468 API_POSIX_O_WRONLY | API_POSIX_O_CREAT,
1477 if(rv) { rv =
fu_sync(fd, NULL); }
1480 PRINT_ERROR(
"Writing data to scorerc file failed");
1484 rv = api_posix_rename(tmppathname, scorerc);
1498 PRINT_ERROR(
"Exporting score file data to scorerc failed");
1503 api_posix_free((
void*)
data);
1504 api_posix_free((
void*) tmppathname);
1505 api_posix_free((
void*) scorepathname);
1507 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
1509 if(NULL != testgroup_ere)
1512 api_posix_regfree(testgroup_ere);
1513 api_posix_free((
void*) testgroup_ere);
1514 testgroup_ere = NULL;
1519 filter_locale = FILTER_CS_ASCII;
1538 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
1541 const char* p = NULL;
1545 if(NULL == testgroup_ere)
1547 PRINT_ERROR(
"Test group check failed (ERE not compiled)");
1552 if(FILTER_CS_ASCII == testgroup_cs)
1556 else if(FILTER_CS_ISO8859_1 == testgroup_cs)
1560 if(NULL == p) { rv = -1; }
1562 else {
string = p; }
1566 PRINT_ERROR(
"Test group name cannot be checked with current locale");
1568 else if(!api_posix_regexec(testgroup_ere,
string, 0, NULL, 0))
1576 if(NULL != p && group != p) {
enc_free((
void*) p); }
1646 const char* last_ref =
"";
1688 struct filter* rule = scores;
1691 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
1694 const char* p = NULL;
1711 case SCORE_TYPE_FROM:
1717 case SCORE_TYPE_SUBJECT:
1720 if(!strcmp(rule->string,
data))
1722 res = filter_score_add(res, rule->value);
1728 case SCORE_TYPE_GROUP:
1734 if(!strcmp(rule->string,
data))
1736 res = filter_score_add(res, rule->value);
1743 case SCORE_TYPE_FROM_ERE:
1749 case SCORE_TYPE_SUBJECT_ERE:
1755 case SCORE_TYPE_MSGID_ERE:
1758 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
1759 if(NULL == rule->ere)
1765 PRINT_ERROR(
"Regular expression not compiled (bug)");
1771 if(FILTER_CS_ASCII == rule->cs)
1775 else if(FILTER_CS_ISO8859_1 == rule->cs)
1779 if(NULL == p) { rv = -1; }
1781 else {
string = p; }
1783 if(!rv && !api_posix_regexec(rule->ere,
string, 0, NULL, 0))
1785 res = filter_score_add(res, rule->value);
1818 return(filter_locale);