5 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
6 * Copyright (c) 2001-2002 by Hiroyuki Yamamoto & The Sylpheed Claws Team.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29 #include "filtering.h"
32 #include "matcher_parser.h"
33 #include "matcher_parser_lex.h"
36 #define MAX_COLORLABELS (MSG_CLABEL_7 - MSG_CLABEL_NONE)
38 static gint error = 0;
39 static gint bool_op = 0;
40 static gint match_type = 0;
41 static gchar *header = NULL;
43 static MatcherProp *prop;
45 static GSList *matchers_list = NULL;
47 static MatcherList *cond;
48 static gint score = 0;
49 static FilteringAction *action = NULL;
51 static FilteringProp *filtering;
52 static ScoringProp *scoring = NULL;
54 static GSList **prefs_scoring = NULL;
55 static GSList **prefs_filtering = NULL;
57 static int matcher_parser_dialog = 0;
59 /* ******************************************************************** */
61 void matcher_parser_start_parsing(FILE *f)
63 matcher_parserrestart(f);
64 matcher_parserparse();
67 FilteringProp *matcher_parser_get_filtering(gchar *str)
71 /* bad coding to enable the sub-grammar matching
73 matcher_parserlineno = 1;
74 matcher_parser_dialog = 1;
75 matcher_parserrestart(NULL);
76 matcher_parser_init();
77 bufstate = matcher_parser_scan_string(str);
78 matcher_parser_switch_to_buffer(bufstate);
79 if (matcher_parserparse() != 0)
81 matcher_parser_dialog = 0;
82 matcher_parser_delete_buffer(bufstate);
86 ScoringProp *matcher_parser_get_scoring(gchar *str)
90 /* bad coding to enable the sub-grammar matching
92 matcher_parserlineno = 1;
93 matcher_parser_dialog = 1;
94 matcher_parserrestart(NULL);
95 matcher_parser_init();
96 bufstate = matcher_parser_scan_string(str);
97 matcher_parser_switch_to_buffer(bufstate);
98 if (matcher_parserparse() != 0)
100 matcher_parser_dialog = 0;
101 matcher_parser_delete_buffer(bufstate);
105 static gboolean check_quote_symetry(gchar *str)
111 return TRUE; /* heh, that's symetric */
114 for (walk = str; *walk; walk++) {
116 if (walk == str /* first char */
117 || *(walk - 1) != '\\') /* not escaped */
124 MatcherList *matcher_parser_get_cond(gchar *str)
128 if (!check_quote_symetry(str)) {
133 /* bad coding to enable the sub-grammar matching
135 matcher_parserlineno = 1;
136 matcher_parser_dialog = 1;
137 matcher_parserrestart(NULL);
138 matcher_parser_init();
139 bufstate = matcher_parser_scan_string(str);
140 matcher_parserparse();
141 matcher_parser_dialog = 0;
142 matcher_parser_delete_buffer(bufstate);
146 MatcherProp *matcher_parser_get_prop(gchar *str)
151 matcher_parserlineno = 1;
152 list = matcher_parser_get_cond(str);
156 if (list->matchers == NULL)
159 if (list->matchers->next != NULL)
162 prop = list->matchers->data;
164 g_slist_free(list->matchers);
170 void matcher_parsererror(char *str)
175 for (l = matchers_list; l != NULL; l = g_slist_next(l)) {
176 matcherprop_free((MatcherProp *)
180 g_slist_free(matchers_list);
181 matchers_list = NULL;
184 g_warning("scoring / filtering parsing: %i: %s\n",
185 matcher_parserlineno, str);
189 int matcher_parserwrap(void)
200 %token MATCHER_ALL MATCHER_UNREAD MATCHER_NOT_UNREAD
201 %token MATCHER_NEW MATCHER_NOT_NEW MATCHER_MARKED
202 %token MATCHER_NOT_MARKED MATCHER_DELETED MATCHER_NOT_DELETED
203 %token MATCHER_REPLIED MATCHER_NOT_REPLIED MATCHER_FORWARDED
204 %token MATCHER_NOT_FORWARDED MATCHER_SUBJECT MATCHER_NOT_SUBJECT
205 %token MATCHER_FROM MATCHER_NOT_FROM MATCHER_TO MATCHER_NOT_TO
206 %token MATCHER_CC MATCHER_NOT_CC MATCHER_TO_OR_CC MATCHER_NOT_TO_AND_NOT_CC
207 %token MATCHER_AGE_GREATER MATCHER_AGE_LOWER MATCHER_NEWSGROUPS
208 %token MATCHER_NOT_NEWSGROUPS MATCHER_INREPLYTO MATCHER_NOT_INREPLYTO
209 %token MATCHER_REFERENCES MATCHER_NOT_REFERENCES MATCHER_SCORE_GREATER
210 %token MATCHER_SCORE_LOWER MATCHER_HEADER MATCHER_NOT_HEADER
211 %token MATCHER_HEADERS_PART MATCHER_NOT_HEADERS_PART MATCHER_MESSAGE
212 %token MATCHER_NOT_MESSAGE MATCHER_BODY_PART MATCHER_NOT_BODY_PART
213 %token MATCHER_EXECUTE MATCHER_NOT_EXECUTE MATCHER_MATCHCASE MATCHER_MATCH
214 %token MATCHER_REGEXPCASE MATCHER_REGEXP MATCHER_SCORE MATCHER_MOVE
215 %token MATCHER_COPY MATCHER_DELETE MATCHER_MARK MATCHER_UNMARK MATCHER_LOCK MATCHER_UNLOCK
216 %token MATCHER_MARK_AS_READ MATCHER_MARK_AS_UNREAD MATCHER_FORWARD
217 %token MATCHER_FORWARD_AS_ATTACHMENT MATCHER_EOL MATCHER_STRING
218 %token MATCHER_OR MATCHER_AND
219 %token MATCHER_COLOR MATCHER_SCORE_EQUAL MATCHER_REDIRECT
220 %token MATCHER_SIZE_GREATER MATCHER_SIZE_SMALLER MATCHER_SIZE_EQUAL
221 %token MATCHER_LOCKED MATCHER_NOT_LOCKED
222 %token MATCHER_COLORLABEL MATCHER_NOT_COLORLABEL
223 %token MATCHER_IGNORE_THREAD MATCHER_NOT_IGNORE_THREAD
224 %token MATCHER_CHANGE_SCORE
228 %token <str> MATCHER_STRING
229 %token <str> MATCHER_SECTION
230 %token <str> MATCHER_INTEGER
236 if (!matcher_parser_dialog) {
237 prefs_scoring = &global_scoring;
238 prefs_filtering = &global_processing;
257 section_notification:
258 MATCHER_SECTION MATCHER_EOL
261 FolderItem *item = NULL;
263 if (!matcher_parser_dialog) {
264 if (!strcmp(folder, "global")) {
265 prefs_scoring = &global_scoring;
266 prefs_filtering = &global_processing;
268 item = folder_find_item_from_identifier(folder);
270 prefs_scoring = &item->prefs->scoring;
271 prefs_filtering = &item->prefs->processing;
273 prefs_scoring = NULL;
274 prefs_filtering = NULL;
282 condition end_instr_opt
287 filtering_or_scoring end_action
290 if (matcher_parser_dialog)
293 matcher_parsererror("parse error");
303 if (matcher_parser_dialog)
306 matcher_parsererror("parse error");
312 filtering_or_scoring:
315 filtering = filteringprop_new(cond, action);
318 if (!matcher_parser_dialog && (prefs_filtering != NULL)) {
319 *prefs_filtering = g_slist_append(*prefs_filtering,
326 scoring = scoringprop_new(cond, score);
329 if (!matcher_parser_dialog && (prefs_scoring != NULL)) {
330 *prefs_scoring = g_slist_append(*prefs_scoring, scoring);
339 match_type = MATCHTYPE_MATCHCASE;
343 match_type = MATCHTYPE_MATCH;
347 match_type = MATCHTYPE_REGEXPCASE;
351 match_type = MATCHTYPE_REGEXP;
358 cond = matcherlist_new(matchers_list, (bool_op == MATCHERBOOL_AND));
359 matchers_list = NULL;
364 condition_list bool_op one_condition
366 matchers_list = g_slist_append(matchers_list, prop);
370 matchers_list = NULL;
371 matchers_list = g_slist_append(matchers_list, prop);
378 bool_op = MATCHERBOOL_AND;
382 bool_op = MATCHERBOOL_OR;
391 criteria = MATCHCRITERIA_ALL;
392 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, 0);
398 criteria = MATCHCRITERIA_UNREAD;
399 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, 0);
405 criteria = MATCHCRITERIA_NOT_UNREAD;
406 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, 0);
412 criteria = MATCHCRITERIA_NEW;
413 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, 0);
419 criteria = MATCHCRITERIA_NOT_NEW;
420 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, 0);
426 criteria = MATCHCRITERIA_MARKED;
427 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, 0);
433 criteria = MATCHCRITERIA_NOT_MARKED;
434 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, 0);
440 criteria = MATCHCRITERIA_DELETED;
441 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, 0);
443 | MATCHER_NOT_DELETED
447 criteria = MATCHCRITERIA_NOT_DELETED;
448 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, 0);
454 criteria = MATCHCRITERIA_REPLIED;
455 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, 0);
457 | MATCHER_NOT_REPLIED
461 criteria = MATCHCRITERIA_NOT_REPLIED;
462 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, 0);
468 criteria = MATCHCRITERIA_FORWARDED;
469 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, 0);
471 | MATCHER_NOT_FORWARDED
475 criteria = MATCHCRITERIA_NOT_FORWARDED;
476 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, 0);
482 criteria = MATCHCRITERIA_LOCKED;
483 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, 0);
489 criteria = MATCHCRITERIA_NOT_LOCKED;
490 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, 0);
492 | MATCHER_COLORLABEL MATCHER_INTEGER
497 criteria = MATCHCRITERIA_COLORLABEL;
499 if (value < 1) value = 1;
500 else if (value > MAX_COLORLABELS) value = MAX_COLORLABELS;
501 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, value);
503 | MATCHER_NOT_COLORLABEL MATCHER_INTEGER
508 criteria = MATCHCRITERIA_NOT_COLORLABEL;
510 if (value < 1) value = 1;
511 else if (value > MAX_COLORLABELS) value = MAX_COLORLABELS;
512 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, value);
514 | MATCHER_IGNORE_THREAD
518 criteria = MATCHCRITERIA_IGNORE_THREAD;
519 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, 0);
521 | MATCHER_NOT_IGNORE_THREAD
525 criteria = MATCHCRITERIA_NOT_IGNORE_THREAD;
526 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, 0);
528 | MATCHER_SUBJECT match_type MATCHER_STRING
533 criteria = MATCHCRITERIA_SUBJECT;
535 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
537 | MATCHER_NOT_SUBJECT match_type MATCHER_STRING
542 criteria = MATCHCRITERIA_NOT_SUBJECT;
544 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
546 | MATCHER_FROM match_type MATCHER_STRING
551 criteria = MATCHCRITERIA_FROM;
553 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
555 | MATCHER_NOT_FROM match_type MATCHER_STRING
560 criteria = MATCHCRITERIA_NOT_FROM;
562 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
564 | MATCHER_TO match_type MATCHER_STRING
569 criteria = MATCHCRITERIA_TO;
571 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
573 | MATCHER_NOT_TO match_type MATCHER_STRING
578 criteria = MATCHCRITERIA_NOT_TO;
580 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
582 | MATCHER_CC match_type MATCHER_STRING
587 criteria = MATCHCRITERIA_CC;
589 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
591 | MATCHER_NOT_CC match_type MATCHER_STRING
596 criteria = MATCHCRITERIA_NOT_CC;
598 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
600 | MATCHER_TO_OR_CC match_type MATCHER_STRING
605 criteria = MATCHCRITERIA_TO_OR_CC;
607 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
609 | MATCHER_NOT_TO_AND_NOT_CC match_type MATCHER_STRING
614 criteria = MATCHCRITERIA_NOT_TO_AND_NOT_CC;
616 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
618 | MATCHER_AGE_GREATER MATCHER_INTEGER
623 criteria = MATCHCRITERIA_AGE_GREATER;
625 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, value);
627 | MATCHER_AGE_LOWER MATCHER_INTEGER
632 criteria = MATCHCRITERIA_AGE_LOWER;
634 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, value);
636 | MATCHER_NEWSGROUPS match_type MATCHER_STRING
641 criteria = MATCHCRITERIA_NEWSGROUPS;
643 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
645 | MATCHER_NOT_NEWSGROUPS match_type MATCHER_STRING
650 criteria = MATCHCRITERIA_NOT_NEWSGROUPS;
652 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
654 | MATCHER_INREPLYTO match_type MATCHER_STRING
659 criteria = MATCHCRITERIA_INREPLYTO;
661 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
663 | MATCHER_NOT_INREPLYTO match_type MATCHER_STRING
668 criteria = MATCHCRITERIA_NOT_INREPLYTO;
670 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
672 | MATCHER_REFERENCES match_type MATCHER_STRING
677 criteria = MATCHCRITERIA_REFERENCES;
679 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
681 | MATCHER_NOT_REFERENCES match_type MATCHER_STRING
686 criteria = MATCHCRITERIA_NOT_REFERENCES;
688 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
690 | MATCHER_SCORE_GREATER MATCHER_INTEGER
695 criteria = MATCHCRITERIA_SCORE_GREATER;
697 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, value);
699 | MATCHER_SCORE_LOWER MATCHER_INTEGER
704 criteria = MATCHCRITERIA_SCORE_LOWER;
706 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, value);
708 | MATCHER_SCORE_EQUAL MATCHER_INTEGER
713 criteria = MATCHCRITERIA_SCORE_EQUAL;
715 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, value);
717 | MATCHER_SIZE_GREATER MATCHER_INTEGER
721 criteria = MATCHCRITERIA_SIZE_GREATER;
723 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, value);
725 | MATCHER_SIZE_SMALLER MATCHER_INTEGER
729 criteria = MATCHCRITERIA_SIZE_SMALLER;
731 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, value);
733 | MATCHER_SIZE_EQUAL MATCHER_INTEGER
737 criteria = MATCHCRITERIA_SIZE_EQUAL;
739 prop = matcherprop_unquote_new(criteria, NULL, 0, NULL, value);
741 | MATCHER_HEADER MATCHER_STRING
743 header = g_strdup($2);
744 } match_type MATCHER_STRING
749 criteria = MATCHCRITERIA_HEADER;
751 prop = matcherprop_unquote_new(criteria, header, match_type, expr, 0);
754 | MATCHER_NOT_HEADER MATCHER_STRING
756 header = g_strdup($2);
757 } match_type MATCHER_STRING
762 criteria = MATCHCRITERIA_NOT_HEADER;
764 prop = matcherprop_unquote_new(criteria, header, match_type, expr, 0);
767 | MATCHER_HEADERS_PART match_type MATCHER_STRING
772 criteria = MATCHCRITERIA_HEADERS_PART;
774 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
776 | MATCHER_NOT_HEADERS_PART match_type MATCHER_STRING
781 criteria = MATCHCRITERIA_NOT_HEADERS_PART;
783 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
785 | MATCHER_MESSAGE match_type MATCHER_STRING
790 criteria = MATCHCRITERIA_MESSAGE;
792 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
794 | MATCHER_NOT_MESSAGE match_type MATCHER_STRING
799 criteria = MATCHCRITERIA_NOT_MESSAGE;
801 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
803 | MATCHER_BODY_PART match_type MATCHER_STRING
808 criteria = MATCHCRITERIA_BODY_PART;
810 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
812 | MATCHER_NOT_BODY_PART match_type MATCHER_STRING
817 criteria = MATCHCRITERIA_NOT_BODY_PART;
819 prop = matcherprop_unquote_new(criteria, NULL, match_type, expr, 0);
821 | MATCHER_EXECUTE MATCHER_STRING
826 criteria = MATCHCRITERIA_EXECUTE;
828 prop = matcherprop_unquote_new(criteria, NULL, 0, expr, 0);
830 | MATCHER_NOT_EXECUTE MATCHER_STRING
835 criteria = MATCHCRITERIA_NOT_EXECUTE;
837 prop = matcherprop_unquote_new(criteria, NULL, 0, expr, 0);
842 MATCHER_EXECUTE MATCHER_STRING
845 gint action_type = 0;
847 action_type = MATCHACTION_EXECUTE;
849 action = filteringaction_new(action_type, 0, cmd, 0);
851 | MATCHER_MOVE MATCHER_STRING
853 gchar *destination = NULL;
854 gint action_type = 0;
856 action_type = MATCHACTION_MOVE;
858 action = filteringaction_new(action_type, 0, destination, 0);
860 | MATCHER_COPY MATCHER_STRING
862 gchar *destination = NULL;
863 gint action_type = 0;
865 action_type = MATCHACTION_COPY;
867 action = filteringaction_new(action_type, 0, destination, 0);
871 gint action_type = 0;
873 action_type = MATCHACTION_DELETE;
874 action = filteringaction_new(action_type, 0, NULL, 0);
878 gint action_type = 0;
880 action_type = MATCHACTION_MARK;
881 action = filteringaction_new(action_type, 0, NULL, 0);
885 gint action_type = 0;
887 action_type = MATCHACTION_UNMARK;
888 action = filteringaction_new(action_type, 0, NULL, 0);
892 gint action_type = 0;
894 action_type = MATCHACTION_LOCK;
895 action = filteringaction_new(action_type, 0, NULL, 0);
899 gint action_type = 0;
901 action_type = MATCHACTION_UNLOCK;
902 action = filteringaction_new(action_type, 0, NULL, 0);
904 | MATCHER_MARK_AS_READ
906 gint action_type = 0;
908 action_type = MATCHACTION_MARK_AS_READ;
909 action = filteringaction_new(action_type, 0, NULL, 0);
911 | MATCHER_MARK_AS_UNREAD
913 gint action_type = 0;
915 action_type = MATCHACTION_MARK_AS_UNREAD;
916 action = filteringaction_new(action_type, 0, NULL, 0);
918 | MATCHER_FORWARD MATCHER_INTEGER MATCHER_STRING
920 gchar *destination = NULL;
921 gint action_type = 0;
924 action_type = MATCHACTION_FORWARD;
925 account_id = atoi($2);
927 action = filteringaction_new(action_type, account_id, destination, 0);
929 | MATCHER_FORWARD_AS_ATTACHMENT MATCHER_INTEGER MATCHER_STRING
931 gchar *destination = NULL;
932 gint action_type = 0;
935 action_type = MATCHACTION_FORWARD_AS_ATTACHMENT;
936 account_id = atoi($2);
938 action = filteringaction_new(action_type, account_id, destination, 0);
940 | MATCHER_REDIRECT MATCHER_INTEGER MATCHER_STRING
942 gchar *destination = NULL;
943 gint action_type = 0;
946 action_type = MATCHACTION_REDIRECT;
947 account_id = atoi($2);
949 action = filteringaction_new(action_type, account_id, destination, 0);
951 | MATCHER_COLOR MATCHER_INTEGER
953 gint action_type = 0;
956 action_type = MATCHACTION_COLOR;
958 action = filteringaction_new(action_type, 0, NULL, color);
960 | MATCHER_CHANGE_SCORE MATCHER_STRING
962 gint action_type = MATCHACTION_CHANGE_SCORE;
963 char *last_tok = NULL;
964 const gchar *first_tok;
966 int change_type; /* -1 == decrement, 0 == assign, 1 == increment */
968 #define is_number(x) ( ((x) == '+') || ((x) == '-') || (isdigit((x))) )
970 for (first_tok = $2; *first_tok && !is_number(*first_tok); first_tok++)
974 chscore = strtol(first_tok, &last_tok, 10);
975 if (last_tok == first_tok || *last_tok == 0)
977 change_type = *first_tok == '+' ? 1 : *first_tok == '-' ? -1 : 0;
978 action = filteringaction_new(MATCHACTION_CHANGE_SCORE, change_type,
984 MATCHER_SCORE MATCHER_INTEGER