7 #include "procheader.h"
10 #include "matcher_parser.h"
18 typedef struct _MatchParser MatchParser;
20 static MatchParser matchparser_tab[] = {
22 {MATCHCRITERIA_ALL, "all"},
23 {MATCHCRITERIA_UNREAD, "unread"},
24 {MATCHCRITERIA_NOT_UNREAD, "~unread"},
25 {MATCHCRITERIA_NEW, "new"},
26 {MATCHCRITERIA_NOT_NEW, "~new"},
27 {MATCHCRITERIA_MARKED, "marked"},
28 {MATCHCRITERIA_NOT_MARKED, "~marked"},
29 {MATCHCRITERIA_DELETED, "deleted"},
30 {MATCHCRITERIA_NOT_DELETED, "~deleted"},
31 {MATCHCRITERIA_REPLIED, "replied"},
32 {MATCHCRITERIA_NOT_REPLIED, "~replied"},
33 {MATCHCRITERIA_FORWARDED, "forwarded"},
34 {MATCHCRITERIA_NOT_FORWARDED, "~forwarded"},
37 {MATCHCRITERIA_SUBJECT, "subject"},
38 {MATCHCRITERIA_NOT_SUBJECT, "~subject"},
39 {MATCHCRITERIA_FROM, "from"},
40 {MATCHCRITERIA_NOT_FROM, "~from"},
41 {MATCHCRITERIA_TO, "to"},
42 {MATCHCRITERIA_NOT_TO, "~to"},
43 {MATCHCRITERIA_CC, "cc"},
44 {MATCHCRITERIA_NOT_CC, "~cc"},
45 {MATCHCRITERIA_TO_OR_CC, "to_or_cc"},
46 {MATCHCRITERIA_NOT_TO_AND_NOT_CC, "~to_or_cc"},
47 {MATCHCRITERIA_AGE_GREATER, "age_greater"},
48 {MATCHCRITERIA_AGE_LOWER, "age_lower"},
49 {MATCHCRITERIA_NEWSGROUPS, "newsgroups"},
50 {MATCHCRITERIA_NOT_NEWSGROUPS, "~newsgroups"},
51 {MATCHCRITERIA_INREPLYTO, "inreplyto"},
52 {MATCHCRITERIA_NOT_INREPLYTO, "~inreplyto"},
53 {MATCHCRITERIA_REFERENCES, "references"},
54 {MATCHCRITERIA_NOT_REFERENCES, "~references"},
55 {MATCHCRITERIA_SCORE_GREATER, "score_greater"},
56 {MATCHCRITERIA_SCORE_LOWER, "score_lower"},
57 {MATCHCRITERIA_SCORE_EQUAL, "score_equal"},
59 /* content have to be read */
60 {MATCHCRITERIA_HEADER, "header"},
61 {MATCHCRITERIA_NOT_HEADER, "~header"},
62 {MATCHCRITERIA_HEADERS_PART, "headers_part"},
63 {MATCHCRITERIA_NOT_HEADERS_PART, "~headers_part"},
64 {MATCHCRITERIA_MESSAGE, "message"},
65 {MATCHCRITERIA_NOT_MESSAGE, "~message"},
66 {MATCHCRITERIA_BODY_PART, "body_part"},
67 {MATCHCRITERIA_NOT_BODY_PART, "~body_part"},
68 {MATCHCRITERIA_EXECUTE, "execute"},
69 {MATCHCRITERIA_NOT_EXECUTE, "~execute"},
72 {MATCHTYPE_MATCHCASE, "matchcase"},
73 {MATCHTYPE_MATCH, "match"},
74 {MATCHTYPE_REGEXPCASE, "regexpcase"},
75 {MATCHTYPE_REGEXP, "regexp"},
78 {MATCHACTION_SCORE, "score"},
79 {MATCHACTION_MOVE, "move"},
80 {MATCHACTION_COPY, "copy"},
81 {MATCHACTION_DELETE, "delete"},
82 {MATCHACTION_MARK, "mark"},
83 {MATCHACTION_UNMARK, "unmark"},
84 {MATCHACTION_MARK_AS_READ, "mark_as_read"},
85 {MATCHACTION_MARK_AS_UNREAD, "mark_as_unread"},
86 {MATCHACTION_FORWARD, "forward"},
87 {MATCHACTION_FORWARD_AS_ATTACHMENT, "forward_as_attachment"},
88 {MATCHACTION_EXECUTE, "execute"},
89 {MATCHACTION_COLOR, "color"},
90 {MATCHACTION_BOUNCE, "bounce"}
93 /* get_matchparser_tab_str() - used by filtering.c to translate
94 * actions to debug strings */
95 gchar * get_matchparser_tab_str(gint id)
99 for(i = 0 ; i < (int) (sizeof(matchparser_tab) / sizeof(MatchParser)) ;
101 if (matchparser_tab[i].id == id)
102 return matchparser_tab[i].str;
107 /* matcher_unescape_str() - assumes that unescaping frees up room
108 * in the string, so it returns the unescaped string in the
110 gchar *matcher_unescape_str(gchar *str)
112 gchar *tmp = alloca(strlen(str) + 1);
113 register gchar *src = tmp;
114 register gchar *dst = str;
118 for ( ; *src; src++) {
124 *dst++ = '\\'; /* insert backslash */
125 else if (*src == 'n') /* insert control characters */
127 else if (*src == 'r')
129 else if (*src == 't')
131 else if (*src == 'r')
133 else if (*src == 'b')
135 else if (*src == 'f')
137 else if (*src == '\'' || *src == '\"') /* insert \' or \" */
140 /* FIXME: should perhaps escape character... */
150 /* **************** data structure allocation **************** */
152 /* matcherprop_new() - allocates a structure for one condition
154 MatcherProp * matcherprop_new(gint criteria, gchar * header,
155 gint matchtype, gchar * expr,
160 prop = g_new0(MatcherProp, 1);
161 prop->criteria = criteria;
162 if (header != NULL) {
163 prop->header = g_strdup(header);
164 prop->unesc_header = matcher_unescape_str(g_strdup(header));
168 prop->unesc_header = NULL;
171 prop->expr = g_strdup(expr);
172 prop->unesc_expr = matcher_unescape_str(g_strdup(expr));
176 prop->unesc_expr = NULL;
178 prop->matchtype = matchtype;
186 /* matcherprop_free()
188 void matcherprop_free(MatcherProp * prop)
192 if (prop->unesc_expr)
193 g_free(prop->unesc_expr);
195 g_free(prop->header);
196 if (prop->unesc_header)
197 g_free(prop->unesc_header);
198 if (prop->preg != NULL) {
206 /* ************** match ******************************/
209 /* matcherprop_string_match() - finds out if a string matches
210 * with a criterium */
211 static gboolean matcherprop_string_match(MatcherProp * prop, gchar * str)
219 switch(prop->matchtype) {
220 case MATCHTYPE_REGEXPCASE:
221 case MATCHTYPE_REGEXP:
222 if (!prop->preg && (prop->error == 0)) {
223 prop->preg = g_new0(regex_t, 1);
224 /* if regexp then don't use the escaped string */
225 if (regcomp(prop->preg, prop->expr,
226 REG_NOSUB | REG_EXTENDED
227 | ((prop->matchtype == MATCHTYPE_REGEXPCASE)
228 ? REG_ICASE : 0)) != 0) {
233 if (prop->preg == NULL)
236 if (regexec(prop->preg, str, 0, NULL, 0) == 0)
241 case MATCHTYPE_MATCH:
242 return (strstr(str, prop->unesc_expr) != NULL);
244 /* FIXME: put upper in unesc_str */
245 case MATCHTYPE_MATCHCASE:
246 str2 = alloca(strlen(prop->unesc_expr) + 1);
247 strcpy(str2, prop->unesc_expr);
249 str1 = alloca(strlen(str) + 1);
252 return (strstr(str1, str2) != NULL);
259 gboolean matcherprop_match_execute(MatcherProp * prop, MsgInfo * info)
264 file = procmsg_get_message_file(info);
268 cmd = matching_build_command(prop->unesc_expr, info);
272 return (system(cmd) == 0);
275 /* match a message and his headers, hlist can be NULL if you don't
276 want to use headers */
278 gboolean matcherprop_match(MatcherProp * prop, MsgInfo * info)
282 switch(prop->criteria) {
283 case MATCHCRITERIA_ALL:
285 case MATCHCRITERIA_UNREAD:
286 return MSG_IS_UNREAD(info->flags);
287 case MATCHCRITERIA_NOT_UNREAD:
288 return !MSG_IS_UNREAD(info->flags);
289 case MATCHCRITERIA_NEW:
290 return MSG_IS_NEW(info->flags);
291 case MATCHCRITERIA_NOT_NEW:
292 return !MSG_IS_NEW(info->flags);
293 case MATCHCRITERIA_MARKED:
294 return MSG_IS_MARKED(info->flags);
295 case MATCHCRITERIA_NOT_MARKED:
296 return !MSG_IS_MARKED(info->flags);
297 case MATCHCRITERIA_DELETED:
298 return MSG_IS_DELETED(info->flags);
299 case MATCHCRITERIA_NOT_DELETED:
300 return !MSG_IS_DELETED(info->flags);
301 case MATCHCRITERIA_REPLIED:
302 return MSG_IS_REPLIED(info->flags);
303 case MATCHCRITERIA_NOT_REPLIED:
304 return !MSG_IS_REPLIED(info->flags);
305 case MATCHCRITERIA_FORWARDED:
306 return MSG_IS_FORWARDED(info->flags);
307 case MATCHCRITERIA_NOT_FORWARDED:
308 return !MSG_IS_FORWARDED(info->flags);
309 case MATCHCRITERIA_SUBJECT:
310 return matcherprop_string_match(prop, info->subject);
311 case MATCHCRITERIA_NOT_SUBJECT:
312 return !matcherprop_string_match(prop, info->subject);
313 case MATCHCRITERIA_FROM:
314 return matcherprop_string_match(prop, info->from);
315 case MATCHCRITERIA_NOT_FROM:
316 return !matcherprop_string_match(prop, info->from);
317 case MATCHCRITERIA_TO:
318 return matcherprop_string_match(prop, info->to);
319 case MATCHCRITERIA_NOT_TO:
320 return !matcherprop_string_match(prop, info->to);
321 case MATCHCRITERIA_CC:
322 return matcherprop_string_match(prop, info->cc);
323 case MATCHCRITERIA_NOT_CC:
324 return !matcherprop_string_match(prop, info->cc);
325 case MATCHCRITERIA_TO_OR_CC:
326 return matcherprop_string_match(prop, info->to)
327 || matcherprop_string_match(prop, info->cc);
328 case MATCHCRITERIA_NOT_TO_AND_NOT_CC:
329 return !(matcherprop_string_match(prop, info->to)
330 || matcherprop_string_match(prop, info->cc));
331 case MATCHCRITERIA_AGE_GREATER:
333 return ((t - info->date_t) / (60 * 60 * 24)) >= prop->value;
334 case MATCHCRITERIA_AGE_LOWER:
336 return ((t - info->date_t) / (60 * 60 * 24)) <= prop->value;
337 case MATCHCRITERIA_SCORE_GREATER:
338 return info->score >= prop->value;
339 case MATCHCRITERIA_SCORE_LOWER:
340 return info->score <= prop->value;
341 case MATCHCRITERIA_SCORE_EQUAL:
342 return info->score == prop->value;
343 case MATCHCRITERIA_NEWSGROUPS:
344 return matcherprop_string_match(prop, info->newsgroups);
345 case MATCHCRITERIA_NOT_NEWSGROUPS:
346 return !matcherprop_string_match(prop, info->newsgroups);
347 case MATCHCRITERIA_INREPLYTO:
348 return matcherprop_string_match(prop, info->inreplyto);
349 case MATCHCRITERIA_NOT_INREPLYTO:
350 return !matcherprop_string_match(prop, info->inreplyto);
351 case MATCHCRITERIA_REFERENCES:
352 return matcherprop_string_match(prop, info->references);
353 case MATCHCRITERIA_NOT_REFERENCES:
354 return !matcherprop_string_match(prop, info->references);
355 case MATCHCRITERIA_EXECUTE:
356 return matcherprop_match_execute(prop, info);
357 case MATCHCRITERIA_NOT_EXECUTE:
358 return !matcherprop_match_execute(prop, info);
364 /* ********************* MatcherList *************************** */
367 MatcherList * matcherlist_new(GSList * matchers, gboolean bool_and)
371 cond = g_new0(MatcherList, 1);
373 cond->matchers = matchers;
374 cond->bool_and = bool_and;
379 void matcherlist_free(MatcherList * cond)
383 for(l = cond->matchers ; l != NULL ; l = g_slist_next(l)) {
384 matcherprop_free((MatcherProp *) l->data);
393 static void matcherlist_skip_headers(FILE *fp)
397 while (procheader_get_one_field(buf, sizeof(buf), fp, NULL) != -1) {
402 matcherprop_match_one_header
403 returns TRUE if buf matchs the MatchersProp criteria
406 static gboolean matcherprop_match_one_header(MatcherProp * matcher,
412 switch(matcher->criteria) {
413 case MATCHCRITERIA_HEADER:
414 case MATCHCRITERIA_NOT_HEADER:
415 header = procheader_parse_header(buf);
418 if (procheader_headername_equal(header->name,
420 if (matcher->criteria == MATCHCRITERIA_HEADER)
421 result = matcherprop_string_match(matcher, header->body);
423 result = !matcherprop_string_match(matcher, header->body);
424 procheader_header_free(header);
428 procheader_header_free(header);
431 case MATCHCRITERIA_HEADERS_PART:
432 case MATCHCRITERIA_MESSAGE:
433 return matcherprop_string_match(matcher, buf);
434 case MATCHCRITERIA_NOT_MESSAGE:
435 case MATCHCRITERIA_NOT_HEADERS_PART:
436 return !matcherprop_string_match(matcher, buf);
442 matcherprop_criteria_header
443 returns TRUE if the headers must be matched
446 static gboolean matcherprop_criteria_headers(MatcherProp * matcher)
448 switch(matcher->criteria) {
449 case MATCHCRITERIA_HEADER:
450 case MATCHCRITERIA_NOT_HEADER:
451 case MATCHCRITERIA_HEADERS_PART:
452 case MATCHCRITERIA_NOT_HEADERS_PART:
459 static gboolean matcherprop_criteria_message(MatcherProp * matcher)
461 switch(matcher->criteria) {
462 case MATCHCRITERIA_MESSAGE:
463 case MATCHCRITERIA_NOT_MESSAGE:
471 matcherlist_match_one_header
472 returns TRUE if match should stop
475 static gboolean matcherlist_match_one_header(MatcherList * matchers,
480 for(l = matchers->matchers ; l != NULL ; l = g_slist_next(l)) {
481 MatcherProp * matcher = (MatcherProp *) l->data;
483 if (matcherprop_criteria_headers(matcher) ||
484 matcherprop_criteria_message(matcher)) {
485 if (matcherprop_match_one_header(matcher, buf)) {
486 matcher->result = TRUE;
490 if (matcherprop_criteria_headers(matcher)) {
491 if (matcher->result) {
492 if (!matchers->bool_and)
502 matcherlist_match_headers
503 returns TRUE if one of the headers matchs the MatcherList criteria
506 static gboolean matcherlist_match_headers(MatcherList * matchers, FILE * fp)
510 while (procheader_get_one_field(buf, sizeof(buf), fp, NULL) != -1)
511 if (matcherlist_match_one_header(matchers, buf))
518 matcherprop_criteria_body
519 returns TRUE if the body must be matched
522 static gboolean matcherprop_criteria_body(MatcherProp * matcher)
524 switch(matcher->criteria) {
525 case MATCHCRITERIA_BODY_PART:
526 case MATCHCRITERIA_NOT_BODY_PART:
534 matcherprop_match_line
535 returns TRUE if the string matchs the MatcherProp criteria
538 static gboolean matcherprop_match_line(MatcherProp * matcher, gchar * line)
540 switch(matcher->criteria) {
541 case MATCHCRITERIA_BODY_PART:
542 case MATCHCRITERIA_MESSAGE:
543 return matcherprop_string_match(matcher, line);
544 case MATCHCRITERIA_NOT_BODY_PART:
545 case MATCHCRITERIA_NOT_MESSAGE:
546 return !matcherprop_string_match(matcher, line);
552 matcherlist_match_line
553 returns TRUE if the string matchs the MatcherList criteria
556 static gboolean matcherlist_match_line(MatcherList * matchers, gchar * line)
560 for(l = matchers->matchers ; l != NULL ; l = g_slist_next(l)) {
561 MatcherProp * matcher = (MatcherProp *) l->data;
563 if (matcherprop_criteria_body(matcher) ||
564 matcherprop_criteria_message(matcher)) {
565 if (matcherprop_match_line(matcher, line)) {
566 matcher->result = TRUE;
570 if (matcher->result) {
571 if (!matchers->bool_and)
579 matcherlist_match_body
580 returns TRUE if one line of the body matchs the MatcherList criteria
583 static gboolean matcherlist_match_body(MatcherList * matchers, FILE * fp)
587 while (fgets(buf, sizeof(buf), fp) != NULL)
588 if (matcherlist_match_line(matchers, buf))
594 gboolean matcherlist_match_file(MatcherList * matchers, MsgInfo * info,
597 gboolean read_headers;
603 /* file need to be read ? */
605 read_headers = FALSE;
607 for(l = matchers->matchers ; l != NULL ; l = g_slist_next(l)) {
608 MatcherProp * matcher = (MatcherProp *) l->data;
610 if (matcherprop_criteria_headers(matcher))
612 if (matcherprop_criteria_body(matcher))
614 if (matcherprop_criteria_message(matcher)) {
618 matcher->result = FALSE;
621 if (!read_headers && !read_body)
624 file = procmsg_get_message_file(info);
628 if ((fp = fopen(file, "r")) == NULL) {
629 FILE_OP_ERROR(file, "fopen");
634 /* read the headers */
637 if (matcherlist_match_headers(matchers, fp))
641 matcherlist_skip_headers(fp);
646 matcherlist_match_body(matchers, fp);
649 for(l = matchers->matchers ; l != NULL ; l = g_slist_next(l)) {
650 MatcherProp * matcher = (MatcherProp *) l->data;
652 if (matcherprop_criteria_headers(matcher) ||
653 matcherprop_criteria_body(matcher) ||
654 matcherprop_criteria_message(matcher)) {
655 if (matcher->result) {
656 if (!matchers->bool_and) {
662 if (matchers->bool_and) {
677 /* test a list of condition */
679 gboolean matcherlist_match(MatcherList * matchers, MsgInfo * info)
684 if (matchers->bool_and)
689 /* test the cached elements */
691 for(l = matchers->matchers ; l != NULL ; l = g_slist_next(l)) {
692 MatcherProp * matcher = (MatcherProp *) l->data;
694 switch(matcher->criteria) {
695 case MATCHCRITERIA_ALL:
696 case MATCHCRITERIA_UNREAD:
697 case MATCHCRITERIA_NOT_UNREAD:
698 case MATCHCRITERIA_NEW:
699 case MATCHCRITERIA_NOT_NEW:
700 case MATCHCRITERIA_MARKED:
701 case MATCHCRITERIA_NOT_MARKED:
702 case MATCHCRITERIA_DELETED:
703 case MATCHCRITERIA_NOT_DELETED:
704 case MATCHCRITERIA_REPLIED:
705 case MATCHCRITERIA_NOT_REPLIED:
706 case MATCHCRITERIA_FORWARDED:
707 case MATCHCRITERIA_NOT_FORWARDED:
708 case MATCHCRITERIA_SUBJECT:
709 case MATCHCRITERIA_NOT_SUBJECT:
710 case MATCHCRITERIA_FROM:
711 case MATCHCRITERIA_NOT_FROM:
712 case MATCHCRITERIA_TO:
713 case MATCHCRITERIA_NOT_TO:
714 case MATCHCRITERIA_CC:
715 case MATCHCRITERIA_NOT_CC:
716 case MATCHCRITERIA_TO_OR_CC:
717 case MATCHCRITERIA_NOT_TO_AND_NOT_CC:
718 case MATCHCRITERIA_AGE_GREATER:
719 case MATCHCRITERIA_AGE_LOWER:
720 case MATCHCRITERIA_NEWSGROUPS:
721 case MATCHCRITERIA_NOT_NEWSGROUPS:
722 case MATCHCRITERIA_INREPLYTO:
723 case MATCHCRITERIA_NOT_INREPLYTO:
724 case MATCHCRITERIA_REFERENCES:
725 case MATCHCRITERIA_NOT_REFERENCES:
726 case MATCHCRITERIA_SCORE_GREATER:
727 case MATCHCRITERIA_SCORE_LOWER:
728 case MATCHCRITERIA_SCORE_EQUAL:
729 case MATCHCRITERIA_EXECUTE:
730 case MATCHCRITERIA_NOT_EXECUTE:
731 if (matcherprop_match(matcher, info)) {
732 if (!matchers->bool_and) {
737 if (matchers->bool_and) {
744 /* test the condition on the file */
746 if (matcherlist_match_file(matchers, info, result)) {
747 if (!matchers->bool_and)
751 if (matchers->bool_and)
759 gchar * matcherprop_to_string(MatcherProp * matcher)
761 gchar * matcher_str = NULL;
762 gchar * criteria_str;
763 gchar * matchtype_str;
771 for(i = 0 ; i < (int) (sizeof(matchparser_tab) / sizeof(MatchParser)) ;
773 if (matchparser_tab[i].id == matcher->criteria)
774 criteria_str = matchparser_tab[i].str;
776 if (criteria_str == NULL)
779 switch(matcher->criteria) {
780 case MATCHCRITERIA_AGE_GREATER:
781 case MATCHCRITERIA_AGE_LOWER:
782 case MATCHCRITERIA_SCORE_GREATER:
783 case MATCHCRITERIA_SCORE_LOWER:
784 case MATCHCRITERIA_SCORE_EQUAL:
785 return g_strdup_printf("%s %i", criteria_str, matcher->value);
787 case MATCHCRITERIA_ALL:
788 case MATCHCRITERIA_UNREAD:
789 case MATCHCRITERIA_NOT_UNREAD:
790 case MATCHCRITERIA_NEW:
791 case MATCHCRITERIA_NOT_NEW:
792 case MATCHCRITERIA_MARKED:
793 case MATCHCRITERIA_NOT_MARKED:
794 case MATCHCRITERIA_DELETED:
795 case MATCHCRITERIA_NOT_DELETED:
796 case MATCHCRITERIA_REPLIED:
797 case MATCHCRITERIA_NOT_REPLIED:
798 case MATCHCRITERIA_FORWARDED:
799 case MATCHCRITERIA_NOT_FORWARDED:
800 return g_strdup(criteria_str);
803 matchtype_str = NULL;
804 for(i = 0 ; i < (int) (sizeof(matchparser_tab) / sizeof(MatchParser)) ;
806 if (matchparser_tab[i].id == matcher->matchtype)
807 matchtype_str = matchparser_tab[i].str;
810 if (matchtype_str == NULL)
813 switch (matcher->matchtype) {
814 case MATCHTYPE_MATCH:
815 case MATCHTYPE_MATCHCASE:
816 case MATCHTYPE_REGEXP:
817 case MATCHTYPE_REGEXPCASE:
820 g_strdup_printf("%s \"%s\" %s \"%s\"",
821 criteria_str, matcher->header,
822 matchtype_str, matcher->expr);
825 g_strdup_printf("%s %s \"%s\"", criteria_str,
826 matchtype_str, matcher->expr);
833 gchar * matcherlist_to_string(MatcherList * matchers)
841 count = g_slist_length(matchers->matchers);
842 vstr = g_new(gchar *, count + 1);
844 for (l = matchers->matchers, cur_str = vstr ; l != NULL ;
845 l = g_slist_next(l), cur_str ++) {
846 *cur_str = matcherprop_to_string((MatcherProp *) l->data);
847 if (*cur_str == NULL)
852 if (matchers->bool_and)
853 result = g_strjoinv(" & ", vstr);
855 result = g_strjoinv(" | ", vstr);
857 for(cur_str = vstr ; *cur_str != NULL ; cur_str ++)
864 /* matching_build_command() - preferably cmd should be unescaped */
865 gchar * matching_build_command(gchar * cmd, MsgInfo * info)
868 gchar * filename = NULL;
869 gchar * processed_cmd;
873 size = strlen(cmd) + 1;
881 case 's': /* subject */
882 size += strlen(info->subject) - 2;
885 size += strlen(info->from) - 2;
888 size += strlen(info->to) - 2;
891 size += strlen(info->cc) - 2;
894 size += strlen(info->date) - 2;
896 case 'i': /* message-id */
897 size += strlen(info->msgid) - 2;
899 case 'n': /* newsgroups */
900 size += strlen(info->newsgroups) - 2;
902 case 'r': /* references */
903 size += strlen(info->references) - 2;
906 filename = folder_item_fetch_msg(info->folder,
909 if (filename == NULL) {
910 g_warning(_("filename is not set"));
914 size += strlen(filename) - 2;
923 processed_cmd = g_new0(gchar, size);
935 case 's': /* subject */
936 if (info->subject != NULL)
937 strcpy(p, info->subject);
939 strcpy(p, _("(none)"));
943 if (info->from != NULL)
944 strcpy(p, info->from);
946 strcpy(p, _("(none)"));
950 if (info->to != NULL)
953 strcpy(p, _("(none)"));
957 if (info->cc != NULL)
960 strcpy(p, _("(none)"));
964 if (info->date != NULL)
965 strcpy(p, info->date);
967 strcpy(p, _("(none)"));
970 case 'i': /* message-id */
971 if (info->msgid != NULL)
972 strcpy(p, info->msgid);
974 strcpy(p, _("(none)"));
977 case 'n': /* newsgroups */
978 if (info->newsgroups != NULL)
979 strcpy(p, info->newsgroups);
981 strcpy(p, _("(none)"));
984 case 'r': /* references */
985 if (info->references != NULL)
986 strcpy(p, info->references);
988 strcpy(p, _("(none)"));
1011 debug_print("*** exec string \"%s\"\n", processed_cmd);
1012 return processed_cmd;
1015 /* ************************************************************ */
1017 static void prefs_scoring_write(FILE * fp, GSList * prefs_scoring)
1021 for (cur = prefs_scoring; cur != NULL; cur = cur->next) {
1025 prop = (ScoringProp *) cur->data;
1026 scoring_str = scoringprop_to_string(prop);
1027 if (fputs(scoring_str, fp) == EOF ||
1028 fputc('\n', fp) == EOF) {
1029 FILE_OP_ERROR("scoring config", "fputs || fputc");
1030 g_free(scoring_str);
1033 g_free(scoring_str);
1037 static void prefs_filtering_write(FILE * fp, GSList * prefs_scoring)
1041 for (cur = prefs_scoring; cur != NULL; cur = cur->next) {
1042 gchar *filtering_str;
1043 FilteringProp * prop;
1045 prop = (FilteringProp *) cur->data;
1046 filtering_str = filteringprop_to_string(prop);
1048 if (fputs(filtering_str, fp) == EOF ||
1049 fputc('\n', fp) == EOF) {
1050 FILE_OP_ERROR("filtering config", "fputs || fputc");
1051 g_free(filtering_str);
1054 g_free(filtering_str);
1058 static gboolean prefs_matcher_write_func(GNode *node, gpointer data)
1063 GSList * prefs_scoring;
1064 GSList * prefs_filtering;
1068 /* prevent from the warning */
1069 if (item->path == NULL)
1071 id = folder_item_get_identifier(item);
1074 prefs_scoring = item->prefs->scoring;
1075 prefs_filtering = item->prefs->processing;
1079 id = g_strdup("global"); /* because it is g_freed */
1080 prefs_scoring = global_scoring;
1081 prefs_filtering = global_processing;
1084 if (prefs_filtering != NULL || prefs_scoring != NULL) {
1085 fprintf(fp, "[%s]\n", id);
1087 prefs_filtering_write(fp, prefs_filtering);
1088 prefs_scoring_write(fp, prefs_scoring);
1098 static void prefs_matcher_save(FILE * fp)
1102 for (cur = folder_get_list() ; cur != NULL ; cur = g_list_next(cur)) {
1105 folder = (Folder *) cur->data;
1106 g_node_traverse(folder->node, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
1107 prefs_matcher_write_func, fp);
1109 prefs_matcher_write_func(NULL, fp);
1113 void prefs_matcher_write_config(void)
1120 debug_print(_("Writing matcher configuration...\n"));
1122 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
1125 if ((pfile = prefs_write_open(rcpath)) == NULL) {
1126 g_warning(_("failed to write configuration to file\n"));
1132 prefs_matcher_save(pfile->fp);
1136 if (prefs_write_close(pfile) < 0) {
1137 g_warning(_("failed to write configuration to file\n"));
1142 /* ******************************************************************* */
1144 void prefs_matcher_read_config(void)
1149 prefs_scoring_clear();
1150 prefs_filtering_clear();
1152 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, MATCHER_RC, NULL);
1153 f = fopen(rcpath, "r");
1157 matcher_parser_start_parsing(f);
1159 /* previous version compatibily */
1161 printf("reading filtering\n");
1162 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
1163 FILTERING_RC, NULL);
1164 f = fopen(rcpath, "r");
1168 matcher_parser_start_parsing(f);
1169 fclose(matcher_parserin);
1172 printf("reading scoring\n");
1173 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
1175 f = fopen(rcpath, "r");
1179 matcher_parser_start_parsing(f);
1180 fclose(matcher_parserin);