23 #include "fileutils.h"
58 #define MAIN_ERR_PREFIX "FILTER: "
61 #define FILTER_PERM (posix_mode_t) (POSIX_S_IRUSR | 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
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;
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 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, posix_regex_t* ere)
182 size_t mod_len = strlen(mod_name);
192 # if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI
194 posix_setlocale(POSIX_LC_MESSAGES,
"POSIX");
196 len = posix_regerror(code, ere, buf, 0);
197 if(!len || POSIX_SIZE_MAX - mod_len < len)
203 buf = (
char*) posix_malloc(mod_len + len);
206 PRINT_ERROR(
"Cannot allocate memory for error message");
210 memcpy(buf, mod_name, mod_len);
211 posix_regerror(code, ere, &buf[mod_len], len);
213 posix_free((
void*) buf);
216 # if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI
217 posix_setlocale(POSIX_LC_MESSAGES,
"");
235 static int filter_compile_ere(
enum filter_cs* cs, 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 = (posix_regex_t*) posix_malloc(
sizeof(posix_regex_t));
269 PRINT_ERROR(
"Cannot allocate memory for regular expression");
276 if(FILTER_CS_ISO8859_1 == filter_locale) { pat = p; }
277 rv = posix_regcomp(*ere, pat, POSIX_REG_EXTENDED | POSIX_REG_NOSUB);
280 PRINT_ERROR(
"Compiling regular expression failed");
281 filter_print_ere_error(rv, *ere);
282 posix_free((
void*) *ere);
287 printf(
"%s: %sCompiling regular expression\n",
293 if(NULL != p &&
string != p) {
enc_free((
void*) p); }
308 static void filter_score_rule_destructor(
struct filter** rule)
310 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
315 if(NULL != rule && NULL != *rule)
317 posix_free((
void*) (*rule)->group_wildmat);
318 posix_free((
void*) (*rule)->string);
319 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
325 posix_regfree(p->ere);
326 posix_free((
void*) p->ere);
327 posix_free((
void*) p);
331 if(NULL != (*rule)->ere)
333 posix_regfree((*rule)->ere);
334 posix_free((
void*) (*rule)->ere);
337 posix_free((
void*) *rule);
370 static int filter_score_rule_constructor(
struct filter** new_rule,
371 const char* group_wildmat,
372 enum filter_rule_type type,
373 int score,
const char*
string,
377 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
380 struct filter_wm* pat;
382 struct filter_wm* last = NULL;
386 *new_rule = (
struct filter*) posix_malloc(
sizeof(
struct filter));
387 if(NULL == *new_rule) { res = -1; }
390 (*new_rule)->group_wildmat = group_wildmat;
391 (*new_rule)->type = type;
392 (*new_rule)->value = score;
393 (*new_rule)->string = string;
394 (*new_rule)->found = 0;
395 (*new_rule)->next = NULL;
396 (*new_rule)->cs = FILTER_CS_UTF_8;
398 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
401 (*new_rule)->wm = NULL;
402 (*new_rule)->ere = NULL;
407 if(strcmp(
"*", (*new_rule)->group_wildmat))
415 pat = (
struct filter_wm*)
416 posix_malloc(
sizeof(
struct filter_wm));
417 if(NULL == pat) { res = -1;
break; }
420 pat->negate = wma[i - 1].negate;
421 pat->cs = FILTER_CS_UTF_8;
422 res = filter_compile_ere(&pat->cs, &pat->ere,
426 if(NULL == last) { (*new_rule)->wm = pat; }
427 else { last->next = pat; }
440 switch((*new_rule)->type)
442 case SCORE_TYPE_FROM_ERE:
443 case SCORE_TYPE_SUBJECT_ERE:
444 case SCORE_TYPE_MSGID_ERE:
446 res = filter_compile_ere(&(*new_rule)->cs, &(*new_rule)->ere,
463 (*new_rule)->group_wildmat = NULL;
464 (*new_rule)->string = NULL;
465 filter_score_rule_destructor(new_rule);
484 static int filter_score_add(
int val,
int diff)
492 if(FILTER_SCORE_MAX - val < diff) { val = FILTER_SCORE_MAX; }
493 else { val += diff; }
495 else { val += diff; }
504 if(FILTER_SCORE_MIN - val > diff) { val = FILTER_SCORE_MIN; }
505 else { val += diff; }
507 else { val += diff; }
520 static void filter_add_score_rule(
struct filter* new_rule)
522 struct filter* last_rule = scores;
524 if(NULL == last_rule) { scores = new_rule; }
528 while(NULL != last_rule->next) { last_rule = last_rule->next; }
529 last_rule->next = new_rule;
537 static void filter_delete_score_rules(
void)
539 struct filter* rule = scores;
540 struct filter* next_rule;
544 next_rule = rule->next;
545 filter_score_rule_destructor(&rule);
567 static int filter_decode_rule(
struct filter** rule,
568 const char* line,
size_t len,
int dcre)
573 enum filter_rule_type type;
576 char* group_wildmat = NULL;
586 p = strchr(line, (
int)
':');
594 wm_len = (size_t) (p - line);
595 q = (
char*) posix_realloc((
void*) group_wildmat, wm_len + (size_t) 1);
603 strncpy(group_wildmat, line, wm_len);
604 group_wildmat[wm_len] = 0;
605 line += wm_len + (size_t) 1;
611 type = SCORE_TYPE_UNKNOWN;
614 while(SCORE_END_OF_LIST != ++type)
616 p = filter_type_name[type];
618 if(start < len && !strncmp(line, p, start))
621 if(
':' == line[start]) {
break; }
624 if(SCORE_END_OF_LIST == type) { type = SCORE_TYPE_UNKNOWN; }
634 string = (
char*) posix_malloc((
size_t) len);
637 PRINT_ERROR(
"Cannot allocate memory for score rule parser");
644 case SCORE_TYPE_FROM:
645 case SCORE_TYPE_FROM_ERE:
646 case SCORE_TYPE_SUBJECT:
647 case SCORE_TYPE_SUBJECT_ERE:
648 case SCORE_TYPE_MSGID_ERE:
649 case SCORE_TYPE_GROUP:
651 rv = sscanf(&line[start],
":%d:%[^\n]", &score,
string);
677 printf(
"=============================\n");
678 printf(
" Groups: %s\n", group_wildmat);
679 printf(
" Type : %s\n", filter_type_name[type]);
680 printf(
" Score : %d\n", score);
681 printf(
" String: %s\n",
string);
683 res = filter_score_rule_constructor(rule, group_wildmat,
684 type, score,
string, dcre);
690 posix_free((
void*) group_wildmat);
691 posix_free((
void*)
string);
715 static int filter_encode_rule(
char** line,
size_t* len,
struct filter* rule)
717 const char* frt = NULL;
726 case SCORE_TYPE_FROM:
727 case SCORE_TYPE_FROM_ERE:
728 case SCORE_TYPE_SUBJECT:
729 case SCORE_TYPE_SUBJECT_ERE:
730 case SCORE_TYPE_MSGID_ERE:
731 case SCORE_TYPE_GROUP:
733 frt = filter_type_name[rule->type];
734 l += strlen(rule->group_wildmat);
740 l += strlen(rule->string);
743 p = (
char*) posix_malloc(l);
746 PRINT_ERROR(
"Cannot allocate memory for score rule");
751 rv = posix_snprintf(p, l,
"%s:%s:%d:%s\n", rule->group_wildmat,
752 frt, rule->value, rule->string);
753 if(0 > rv || (
size_t) rv >= l)
756 posix_free((
void*) p);
761 posix_free((
void*) *line);
788 static int filter_check_rule(
char* line,
size_t len,
struct filter* rule)
791 struct filter* current_rule;
797 if(!filter_decode_rule(¤t_rule, line, len, 1))
800 if(current_rule->type == rule->type)
802 if(!strcmp(current_rule->string, rule->string))
809 filter_score_rule_destructor(¤t_rule);
827 static int filter_export_score_rules(FILE* fs, FILE* fs_tmp)
832 posix_ssize_t readlen;
844 readlen = posix_getline(&line, &len, fs);
847 if(POSIX_ENOMEM == posix_errno)
849 PRINT_ERROR(
"Cannot assign memory for score file parser");
865 if(0 >= readlen) {
break; }
872 if(!rule->found && !filter_check_rule(line, len, rule))
876 filter_encode_rule(&line, &len, rule);
883 rv = fprintf(fs_tmp,
"%s", line);
884 if(0 > rv) {
break; }
896 rv = filter_encode_rule(&line, &len, rule);
897 if(rv) { res = -1;
break; }
901 rv = fprintf(fs_tmp,
"%s", line);
914 posix_free((
void*) line);
927 static int filter_get_pathname(
const char** pathname,
const char* filename)
933 if(NULL != *pathname)
951 posix_free((
void*) *pathname);
966 static int filter_group_check(
struct filter* rule,
const char** grouplist)
971 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
972 struct filter_wm* plp = rule->wm;
975 const char* p = NULL;
981 while(NULL != (group = grouplist[i++]))
984 if(!strcmp(
"*", rule->group_wildmat)) { res = 0;
break; }
986 if(!strcmp(rule->group_wildmat, group)) { res = 0;
break; }
987 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
993 if(FILTER_CS_ASCII == plp->cs)
997 else if(FILTER_CS_ISO8859_1 == plp->cs)
1001 if(NULL == p) { rv = -1; }
1003 else {
string = p; }
1005 if(!rv && !posix_regexec(plp->ere,
string, 0, NULL, 0)) { res = 0; }
1007 if(NULL != p && group != p) {
enc_free((
void*) p); }
1012 if(plp->negate) { res = -1; }
1051 const char* scorepathname = NULL;
1052 char* oldscorepathname = NULL;
1054 struct_posix_stat state;
1060 posix_ssize_t readlen;
1061 struct filter* rule;
1062 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI
1063 const char* loc_ctype;
1066 #if !(CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB)
1067 PRINT_ERROR(
"Regular expression support disabled by configuration");
1071 filter_locale = FILTER_CS_ASCII;
1072 #if !(CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI)
1074 PRINT_ERROR(
"Cannot set locale due to configuration");
1076 printf(
"%s: %sCooked character classification codeset: "
1079 loc_ctype = posix_setlocale(POSIX_LC_CTYPE,
"");
1080 if(NULL == loc_ctype)
1082 PRINT_ERROR(
"Setting locale for category 'LC_CTYPE' failed");
1087 printf(
"%s: %sCharacter classification locale: %s\n",
1091 printf(
"%s: %sCooked character classification codeset: "
1093 filter_locale = FILTER_CS_UTF_8;
1098 loc_ctype = posix_nl_langinfo(CODESET);
1101 if( NULL != strstr(loc_ctype,
"8859-1")
1102 || NULL != strstr(loc_ctype,
"8859_1")
1103 || NULL != strstr(loc_ctype,
"88591") )
1106 if(
'1' == loc_ctype[strlen(loc_ctype) - (
size_t) 1])
1108 printf(
"%s: %sCooked character classification codeset: "
1110 filter_locale = FILTER_CS_ISO8859_1;
1115 PRINT_ERROR(
"Supported codesets: US-ASCII, ISO-8859-1, UTF-8");
1116 PRINT_ERROR(
"(Use \"locale -a\" to find a locale)");
1122 if( !strcmp(loc_ctype,
"POSIX")
1123 || !strcmp(loc_ctype,
"C")
1124 || NULL != strstr(loc_ctype,
"ASCII")
1125 || NULL != strstr(loc_ctype,
"X3.4") )
1127 printf(
"%s: %sCooked character classification codeset: "
1133 PRINT_ERROR(
"Supported codesets: US-ASCII, ISO-8859-1, UTF-8");
1134 PRINT_ERROR(
"(Use \"locale -a\" to find a locale)");
1148 rv = posix_snprintf(NULL, 0,
"%d", FILTER_SCORE_MAX);
1151 score_len_max = (size_t) rv;
1152 rv = posix_snprintf(NULL, 0,
"%d", FILTER_SCORE_MIN);
1155 if((
size_t) rv > score_len_max) { score_len_max = (size_t) rv; }
1161 PRINT_ERROR(
"Calculation of maximum score string length failed");
1170 printf(
"%s: %sImport external scorerc: %s\n",
1173 rv = posix_stat(scorerc, &state);
1174 if(rv) {
PRINT_ERROR(
"Cannot stat scorerc file"); }
1175 else if(POSIX_S_ISREG(state.st_mode))
1177 rv = filter_get_pathname(&scorepathname, scorefile_name);
1181 rv =
fu_open_file(scorerc, &fd, POSIX_O_RDWR, (posix_mode_t) 0);
1193 posix_malloc(strlen(scorepathname) + (
size_t) 5);
1194 if(NULL == oldscorepathname)
1196 PRINT_ERROR(
"Cannot allocate memory for pathname");
1200 strcpy(oldscorepathname, scorepathname);
1201 strcat(oldscorepathname,
".old");
1202 rv = posix_rename(scorepathname, oldscorepathname);
1208 POSIX_O_WRONLY | POSIX_O_CREAT,
1227 PRINT_ERROR(
"Importing scorerc failed, using local scorefile");
1231 posix_free((
void*)
data);
1232 posix_free((
void*) oldscorepathname);
1233 posix_free((
void*) scorepathname);
1234 scorepathname = NULL;
1237 rv = filter_get_pathname(&scorepathname, scorefile_name);
1240 rv = posix_stat(scorepathname, &state);
1242 else if(POSIX_S_ISREG(state.st_mode))
1244 rv =
fu_open_file(scorepathname, &fd, POSIX_O_RDWR, (posix_mode_t) 0);
1256 printf(
"%s: %sLoad scoring rules from: %s\n",
1262 readlen = posix_getline(&line, &len, fs);
1265 if(POSIX_ENOMEM == posix_errno)
1279 if(0 >= readlen) {
break; }
1283 if(
'#' == line[0]) {
continue; }
1284 rv = filter_decode_rule(&rule, line, (
size_t) readlen,
1286 if(!rv) { filter_add_score_rule(rule); }
1289 posix_free((
void*) line);
1296 if(rv) {
PRINT_ERROR(
"Importing rules from score file failed"); }
1299 posix_free((
void*) scorepathname);
1301 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
1305 PRINT_ERROR(
"No ERE for test group matching found in config file");
1311 printf(
"%s: %sEnabling test group checking facility\n",
1313 rv = filter_compile_ere(&testgroup_cs, &testgroup_ere,
1316 if(rv) { testgroup_ere = NULL; }
1338 const char* scorepathname = NULL;
1339 char* tmppathname = NULL;
1344 FILE* fs_tmp = NULL;
1347 struct_posix_stat state;
1351 rv = filter_get_pathname(&scorepathname, scorefile_name);
1355 rv = posix_stat(scorepathname, &state);
1356 if(rv && POSIX_ENOENT == posix_errno)
1363 rv = posix_stat(scorepathname, &state);
1365 else if(POSIX_S_ISREG(state.st_mode))
1367 rv =
fu_open_file(scorepathname, &fd, POSIX_O_RDWR, (posix_mode_t) 0);
1377 tmppathname = posix_malloc(strlen(scorepathname)
1379 if(NULL == tmppathname)
1381 PRINT_ERROR(
"Cannot allocate memory for pathname");
1385 strcpy(tmppathname, scorepathname);
1386 strcat(tmppathname,
".new");
1388 | POSIX_O_CREAT | POSIX_O_TRUNC,
1400 rv = filter_export_score_rules(fs, fs_tmp);
1403 if (!rv) { rv =
fu_sync(fd_tmp, fs_tmp); }
1407 rv = posix_rename(tmppathname, scorepathname);
1424 if(rv) {
PRINT_ERROR(
"Exporting rules to score file failed"); }
1426 filter_delete_score_rules();
1429 if(!rv && strlen(scorerc))
1447 printf(
"%s: %sExport to external scorerc: %s\n",
1450 p = posix_realloc(tmppathname, strlen(scorerc) + (
size_t) 5);
1453 PRINT_ERROR(
"Cannot allocate memory for pathname");
1458 strcpy(tmppathname, scorerc);
1459 strcat(tmppathname,
".new");
1469 if(rv) { rv =
fu_sync(fd, NULL); }
1472 PRINT_ERROR(
"Writing data to scorerc file failed");
1476 rv = posix_rename(tmppathname, scorerc);
1490 PRINT_ERROR(
"Exporting score file data to scorerc failed");
1495 posix_free((
void*)
data);
1496 posix_free((
void*) tmppathname);
1497 posix_free((
void*) scorepathname);
1499 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
1501 if(NULL != testgroup_ere)
1504 posix_regfree(testgroup_ere);
1505 posix_free((
void*) testgroup_ere);
1506 testgroup_ere = NULL;
1511 filter_locale = FILTER_CS_ASCII;
1530 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
1533 const char* p = NULL;
1537 if(NULL == testgroup_ere)
1539 PRINT_ERROR(
"Test group check failed (ERE not compiled)");
1544 if(FILTER_CS_ASCII == testgroup_cs)
1548 else if(FILTER_CS_ISO8859_1 == testgroup_cs)
1552 if(NULL == p) { rv = -1; }
1554 else {
string = p; }
1558 PRINT_ERROR(
"Test group name cannot be checked with current locale");
1560 else if(!posix_regexec(testgroup_ere,
string, 0, NULL, 0))
1568 if(NULL != p && group != p) {
enc_free((
void*) p); }
1638 const char* last_ref =
"";
1680 struct filter* rule = scores;
1683 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
1686 const char* p = NULL;
1703 case SCORE_TYPE_FROM:
1708 case SCORE_TYPE_SUBJECT:
1711 if(!strcmp(rule->string,
data))
1713 res = filter_score_add(res, rule->value);
1719 case SCORE_TYPE_GROUP:
1725 if(!strcmp(rule->string,
data))
1727 res = filter_score_add(res, rule->value);
1734 case SCORE_TYPE_FROM_ERE:
1739 case SCORE_TYPE_SUBJECT_ERE:
1744 case SCORE_TYPE_MSGID_ERE:
1747 #if CFG_USE_POSIX_API >= 200112 || CFG_USE_XSI || CFG_USE_CLB
1748 if(NULL == rule->ere)
1754 PRINT_ERROR(
"Regular expression not compiled (bug)");
1760 if(FILTER_CS_ASCII == rule->cs)
1764 else if(FILTER_CS_ISO8859_1 == rule->cs)
1768 if(NULL == p) { rv = -1; }
1770 else {
string = p; }
1772 if(!rv && !posix_regexec(rule->ere,
string, 0, NULL, 0))
1774 res = filter_score_add(res, rule->value);
1807 return(filter_locale);