2009-09-14 [colin] 3.7.2cvs32
[claws.git] / src / matcher_parser_parse.y
1 %{
2 /*
3  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
4  * Copyright (c) 2001-2007 by Hiroyuki Yamamoto & The Claws Mail Team
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18  * 
19  */
20
21 #include "defs.h"
22
23 #include <glib.h>
24 #include <glib/gi18n.h>
25
26 #include "utils.h"
27 #include "filtering.h"
28 #include "matcher.h"
29 #include "matcher_parser.h"
30 #include "matcher_parser_lex.h"
31 #include "colorlabel.h"
32
33 static gint error = 0;
34 static gint bool_op = 0;
35 static gint match_type = 0;
36 static gchar *header = NULL;
37
38 static MatcherProp *prop;
39
40 static GSList *matchers_list = NULL;
41
42 static gboolean enabled = TRUE;
43 static gchar *name = NULL;
44 static gint account_id = 0;
45 static MatcherList *cond;
46 static GSList *action_list = NULL;
47 static FilteringAction *action = NULL;
48 static gboolean matcher_is_fast = TRUE;
49
50 static FilteringProp *filtering;
51
52 static GSList **prefs_filtering = NULL;
53 static int enable_compatibility = 0;
54
55 enum {
56         MATCHER_PARSE_FILE,
57         MATCHER_PARSE_NO_EOL,
58         MATCHER_PARSE_ENABLED,
59         MATCHER_PARSE_NAME,
60         MATCHER_PARSE_ACCOUNT,
61         MATCHER_PARSE_CONDITION,
62         MATCHER_PARSE_FILTERING_ACTION,
63 };
64
65 static int matcher_parse_op = MATCHER_PARSE_FILE;
66
67
68 /* ******************************************************************** */
69 /* redeclarations to avoid warnings */
70 void matcher_parserrestart(FILE *input_file);
71 void matcher_parser_init(void);
72 void matcher_parser_switch_to_buffer(void * new_buffer);
73 void matcher_parser_delete_buffer(void * b);
74 void matcher_parserpop_buffer_state(void);
75 int matcher_parserlex(void);
76
77 void matcher_parser_start_parsing(FILE *f)
78 {
79         matcher_parserlineno = 1;
80         matcher_parserrestart(f);
81         account_id = 0;
82         matcher_parserparse();
83 }
84
85  
86 void * matcher_parser_scan_string(const char * str);
87  
88 FilteringProp *matcher_parser_get_filtering(gchar *str)
89 {
90         void *bufstate;
91         void *tmp_str = NULL;
92         
93         /* little hack to allow passing rules with no names */
94         if (!strncmp(str, "rulename ", 9))
95                 tmp_str = g_strdup(str);
96         else 
97                 tmp_str = g_strconcat("rulename \"\" ", str, NULL);
98
99         /* bad coding to enable the sub-grammar matching
100            in yacc */
101         matcher_parserlineno = 1;
102         matcher_parse_op = MATCHER_PARSE_NO_EOL;
103         matcher_parserrestart(NULL);
104         matcher_parserpop_buffer_state();
105         matcher_parser_init();
106         bufstate = matcher_parser_scan_string((const char *) tmp_str);
107         matcher_parser_switch_to_buffer(bufstate);
108         if (matcher_parserparse() != 0)
109                 filtering = NULL;
110         matcher_parse_op = MATCHER_PARSE_FILE;
111         matcher_parser_delete_buffer(bufstate);
112         g_free(tmp_str);
113         return filtering;
114 }
115
116 static gboolean check_quote_symetry(gchar *str)
117 {
118         const gchar *walk;
119         int ret = 0;
120         
121         if (str == NULL)
122                 return TRUE; /* heh, that's symetric */
123         if (*str == '\0')
124                 return TRUE;
125         for (walk = str; *walk; walk++) {
126                 if (*walk == '\"') {
127                         if (walk == str         /* first char */
128                         || *(walk - 1) != '\\') /* not escaped */
129                                 ret ++;
130                 }
131         }
132         return !(ret % 2);
133 }
134
135 MatcherList *matcher_parser_get_name(gchar *str)
136 {
137         void *bufstate;
138
139         if (!check_quote_symetry(str)) {
140                 cond = NULL;
141                 return cond;
142         }
143         
144         /* bad coding to enable the sub-grammar matching
145            in yacc */
146         matcher_parserlineno = 1;
147         matcher_parse_op = MATCHER_PARSE_NAME;
148         matcher_parserrestart(NULL);
149         matcher_parserpop_buffer_state();
150         matcher_parser_init();
151         bufstate = matcher_parser_scan_string(str);
152         matcher_parserparse();
153         matcher_parse_op = MATCHER_PARSE_FILE;
154         matcher_parser_delete_buffer(bufstate);
155         return cond;
156 }
157
158 MatcherList *matcher_parser_get_enabled(gchar *str)
159 {
160         void *bufstate;
161
162         if (!check_quote_symetry(str)) {
163                 cond = NULL;
164                 return cond;
165         }
166         
167         /* bad coding to enable the sub-grammar matching
168            in yacc */
169         matcher_parserlineno = 1;
170         matcher_parse_op = MATCHER_PARSE_ENABLED;
171         matcher_parserrestart(NULL);
172         matcher_parserpop_buffer_state();
173         matcher_parser_init();
174         bufstate = matcher_parser_scan_string(str);
175         matcher_parserparse();
176         matcher_parse_op = MATCHER_PARSE_FILE;
177         matcher_parser_delete_buffer(bufstate);
178         return cond;
179 }
180
181 MatcherList *matcher_parser_get_account(gchar *str)
182 {
183         void *bufstate;
184
185         if (!check_quote_symetry(str)) {
186                 cond = NULL;
187                 return cond;
188         }
189         
190         /* bad coding to enable the sub-grammar matching
191            in yacc */
192         matcher_parserlineno = 1;
193         matcher_parse_op = MATCHER_PARSE_ACCOUNT;
194         matcher_parserrestart(NULL);
195         matcher_parserpop_buffer_state();
196         matcher_parser_init();
197         bufstate = matcher_parser_scan_string(str);
198         matcher_parserparse();
199         matcher_parse_op = MATCHER_PARSE_FILE;
200         matcher_parser_delete_buffer(bufstate);
201         return cond;
202 }
203
204 MatcherList *matcher_parser_get_cond(gchar *str, gboolean *is_fast)
205 {
206         void *bufstate;
207
208         if (!check_quote_symetry(str)) {
209                 cond = NULL;
210                 return cond;
211         }
212         
213         matcher_is_fast = TRUE;
214         /* bad coding to enable the sub-grammar matching
215            in yacc */
216         matcher_parserlineno = 1;
217         matcher_parse_op = MATCHER_PARSE_CONDITION;
218         matcher_parserrestart(NULL);
219         matcher_parserpop_buffer_state();
220         matcher_parser_init();
221         bufstate = matcher_parser_scan_string(str);
222         matcher_parserparse();
223         matcher_parse_op = MATCHER_PARSE_FILE;
224         matcher_parser_delete_buffer(bufstate);
225         if (is_fast)
226                 *is_fast = matcher_is_fast;
227         return cond;
228 }
229
230 GSList *matcher_parser_get_action_list(gchar *str)
231 {
232         void *bufstate;
233
234         if (!check_quote_symetry(str)) {
235                 action_list = NULL;
236                 return action_list;
237         }
238         
239         /* bad coding to enable the sub-grammar matching
240            in yacc */
241         matcher_parserlineno = 1;
242         matcher_parse_op = MATCHER_PARSE_FILTERING_ACTION;
243         matcher_parserrestart(NULL);
244         matcher_parserpop_buffer_state();
245         matcher_parser_init();
246         bufstate = matcher_parser_scan_string(str);
247         matcher_parserparse();
248         matcher_parse_op = MATCHER_PARSE_FILE;
249         matcher_parser_delete_buffer(bufstate);
250         return action_list;
251 }
252
253 MatcherProp *matcher_parser_get_prop(gchar *str)
254 {
255         MatcherList *list;
256         MatcherProp *prop;
257
258         matcher_parserlineno = 1;
259         list = matcher_parser_get_cond(str, NULL);
260         if (list == NULL)
261                 return NULL;
262
263         if (list->matchers == NULL)
264                 return NULL;
265
266         if (list->matchers->next != NULL)
267                 return NULL;
268
269         prop = list->matchers->data;
270
271         g_slist_free(list->matchers);
272         g_free(list);
273
274         return prop;
275 }
276
277 void matcher_parsererror(char *str)
278 {
279         GSList *l;
280
281         if (matchers_list) {
282                 for (l = matchers_list; l != NULL; l = g_slist_next(l)) {
283                         matcherprop_free((MatcherProp *)
284                                          l->data);
285                         l->data = NULL;
286                 }
287                 g_slist_free(matchers_list);
288                 matchers_list = NULL;
289         }
290         cond = NULL;
291         g_warning("filtering parsing: %i: %s\n",
292                   matcher_parserlineno, str);
293         error = 1;
294 }
295
296 int matcher_parserwrap(void)
297 {
298         return 1;
299 }
300 %}
301
302 %union {
303         char *str;
304         int value;
305 }
306 %token MATCHER_ALL MATCHER_UNREAD  MATCHER_NOT_UNREAD 
307 %token MATCHER_NEW  MATCHER_NOT_NEW  MATCHER_MARKED
308 %token MATCHER_NOT_MARKED  MATCHER_DELETED  MATCHER_NOT_DELETED
309 %token MATCHER_REPLIED  MATCHER_NOT_REPLIED  MATCHER_FORWARDED
310 %token MATCHER_NOT_FORWARDED  MATCHER_SUBJECT  MATCHER_NOT_SUBJECT
311 %token MATCHER_FROM  MATCHER_NOT_FROM  MATCHER_TO  MATCHER_NOT_TO
312 %token MATCHER_CC  MATCHER_NOT_CC  MATCHER_TO_OR_CC  MATCHER_NOT_TO_AND_NOT_CC
313 %token MATCHER_AGE_GREATER  MATCHER_AGE_LOWER  MATCHER_NEWSGROUPS
314 %token MATCHER_NOT_NEWSGROUPS  MATCHER_INREPLYTO  MATCHER_NOT_INREPLYTO
315 %token MATCHER_REFERENCES  MATCHER_NOT_REFERENCES  MATCHER_SCORE_GREATER
316 %token MATCHER_SCORE_LOWER  MATCHER_HEADER  MATCHER_NOT_HEADER
317 %token MATCHER_HEADERS_PART  MATCHER_NOT_HEADERS_PART  MATCHER_MESSAGE
318 %token MATCHER_NOT_MESSAGE  MATCHER_BODY_PART  MATCHER_NOT_BODY_PART
319 %token MATCHER_TEST  MATCHER_NOT_TEST  MATCHER_MATCHCASE  MATCHER_MATCH
320 %token MATCHER_REGEXPCASE  MATCHER_REGEXP  MATCHER_SCORE  MATCHER_MOVE
321 %token MATCHER_FOUND_IN_ADDRESSBOOK MATCHER_NOT_FOUND_IN_ADDRESSBOOK MATCHER_IN
322 %token MATCHER_COPY  MATCHER_DELETE  MATCHER_MARK  MATCHER_UNMARK
323 %token MATCHER_LOCK MATCHER_UNLOCK
324 %token MATCHER_EXECUTE
325 %token MATCHER_MARK_AS_READ  MATCHER_MARK_AS_UNREAD  MATCHER_FORWARD
326 %token MATCHER_MARK_AS_SPAM MATCHER_MARK_AS_HAM
327 %token MATCHER_FORWARD_AS_ATTACHMENT  MATCHER_EOL
328 %token MATCHER_OR MATCHER_AND  
329 %token MATCHER_COLOR MATCHER_SCORE_EQUAL MATCHER_REDIRECT 
330 %token MATCHER_SIZE_GREATER MATCHER_SIZE_SMALLER MATCHER_SIZE_EQUAL
331 %token MATCHER_LOCKED MATCHER_NOT_LOCKED
332 %token MATCHER_PARTIAL MATCHER_NOT_PARTIAL
333 %token MATCHER_COLORLABEL MATCHER_NOT_COLORLABEL
334 %token MATCHER_IGNORE_THREAD MATCHER_NOT_IGNORE_THREAD
335 %token MATCHER_WATCH_THREAD MATCHER_NOT_WATCH_THREAD
336 %token MATCHER_CHANGE_SCORE MATCHER_SET_SCORE
337 %token MATCHER_ADD_TO_ADDRESSBOOK
338 %token MATCHER_STOP MATCHER_HIDE MATCHER_IGNORE MATCHER_WATCH
339 %token MATCHER_SPAM MATCHER_NOT_SPAM
340 %token MATCHER_HAS_ATTACHMENT MATCHER_HAS_NO_ATTACHMENT
341 %token MATCHER_SIGNED MATCHER_NOT_SIGNED
342 %token MATCHER_TAG MATCHER_NOT_TAG MATCHER_SET_TAG MATCHER_UNSET_TAG
343 %token MATCHER_TAGGED MATCHER_NOT_TAGGED MATCHER_CLEAR_TAGS
344
345 %start file
346
347 %token MATCHER_ENABLED MATCHER_DISABLED
348 %token MATCHER_RULENAME
349 %token MATCHER_ACCOUNT
350 %token <str> MATCHER_STRING
351 %token <str> MATCHER_SECTION
352 %token <str> MATCHER_INTEGER
353
354 %%
355
356 file:
357 {
358         if (matcher_parse_op == MATCHER_PARSE_FILE) {
359                 prefs_filtering = &pre_global_processing;
360         }
361 }
362 file_line_list;
363
364 file_line_list:
365 file_line
366 file_line_list
367 | file_line
368 ;
369
370 file_line:
371 section_notification
372
373 { action_list = NULL; }
374 instruction
375 | error MATCHER_EOL
376 {
377         yyerrok;
378 };
379
380 section_notification:
381 MATCHER_SECTION MATCHER_EOL
382 {
383         gchar *folder = $1;
384         FolderItem *item = NULL;
385
386         if (matcher_parse_op == MATCHER_PARSE_FILE) {
387                 enable_compatibility = 0;
388                 if (!strcmp(folder, "global")) {
389                         /* backward compatibility */
390                         enable_compatibility = 1;
391                 }
392                 else if (!strcmp(folder, "preglobal")) {
393                         prefs_filtering = &pre_global_processing;
394                 }
395                 else if (!strcmp(folder, "postglobal")) {
396                         prefs_filtering = &post_global_processing;
397                 }
398                 else if (!strcmp(folder, "filtering")) {
399                         prefs_filtering = &filtering_rules;
400                 }
401                 else {
402                         item = folder_find_item_from_identifier(folder);
403                         if (item != NULL) {
404                                 prefs_filtering = &item->prefs->processing;
405                         } else {
406                                 prefs_filtering = NULL;
407                         }
408                 }
409         }
410 }
411 ;
412
413 instruction:
414 enabled name account condition filtering MATCHER_EOL
415 | enabled name account condition filtering
416 | enabled name condition filtering MATCHER_EOL
417 | enabled name condition filtering
418 | name condition filtering MATCHER_EOL
419 | name condition filtering
420 {
421         if (matcher_parse_op == MATCHER_PARSE_NO_EOL)
422                 YYACCEPT;
423         else {
424                 matcher_parsererror("parse error [no eol]");
425                 YYERROR;
426         }
427 }
428 | enabled
429 {
430         if (matcher_parse_op == MATCHER_PARSE_ENABLED)
431                 YYACCEPT;
432         else {
433                 matcher_parsererror("parse error [enabled]");
434                 YYERROR;
435         }
436 }
437 | account
438 {
439         if (matcher_parse_op == MATCHER_PARSE_ACCOUNT)
440                 YYACCEPT;
441         else {
442                 matcher_parsererror("parse error [account]");
443                 YYERROR;
444         }
445 }
446 | name
447 {
448         if (matcher_parse_op == MATCHER_PARSE_NAME)
449                 YYACCEPT;
450         else {
451                 matcher_parsererror("parse error [name]");
452                 YYERROR;
453         }
454 }
455 | condition
456 {
457         if (matcher_parse_op == MATCHER_PARSE_CONDITION)
458                 YYACCEPT;
459         else {
460                 matcher_parsererror("parse error [condition]");
461                 YYERROR;
462         }
463 }
464 | filtering_action_list
465 {
466         if (matcher_parse_op == MATCHER_PARSE_FILTERING_ACTION)
467                 YYACCEPT;
468         else {
469                 matcher_parsererror("parse error [filtering action]");
470                 YYERROR;
471         }
472 }
473 | MATCHER_EOL
474 ;
475
476 enabled:
477 MATCHER_ENABLED
478 {
479         enabled = TRUE;
480 }
481 | MATCHER_DISABLED
482 {
483         enabled = FALSE;
484 }
485 ;
486
487 name:
488 MATCHER_RULENAME MATCHER_STRING
489 {
490         name = g_strdup($2);
491 }
492 ;
493
494 account:
495 MATCHER_ACCOUNT MATCHER_INTEGER
496 {
497         account_id = strtol($2, NULL, 10);
498 }
499 ;
500
501 filtering:
502 filtering_action_list
503 {
504         filtering = filteringprop_new(enabled, name, account_id, cond, action_list);
505         enabled = TRUE;
506         account_id = 0;
507         g_free(name);
508         name = NULL;
509         if (enable_compatibility) {
510                 prefs_filtering = &filtering_rules;
511                 if (action_list != NULL) {
512                         FilteringAction * first_action;
513                         
514                         first_action = action_list->data;
515                         
516                         if (first_action->type == MATCHACTION_CHANGE_SCORE)
517                                 prefs_filtering = &pre_global_processing;
518                 }
519         }
520         
521         cond = NULL;
522         action_list = NULL;
523         
524         if ((matcher_parse_op == MATCHER_PARSE_FILE) &&
525             (prefs_filtering != NULL)) {
526                 *prefs_filtering = g_slist_append(*prefs_filtering,
527                                                   filtering);
528                 filtering = NULL;
529         }
530 }
531 ;
532
533 filtering_action_list:
534 filtering_action_b filtering_action_list
535 | filtering_action_b
536 ;
537
538 filtering_action_b:
539 filtering_action
540 {
541         action_list = g_slist_append(action_list, action);
542         action = NULL;
543 }
544 ;
545
546 match_type:
547 MATCHER_MATCHCASE
548 {
549         match_type = MATCHTYPE_MATCHCASE;
550 }
551 | MATCHER_MATCH
552 {
553         match_type = MATCHTYPE_MATCH;
554 }
555 | MATCHER_REGEXPCASE
556 {
557         match_type = MATCHTYPE_REGEXPCASE;
558 }
559 | MATCHER_REGEXP
560 {
561         match_type = MATCHTYPE_REGEXP;
562 }
563 ;
564
565 condition:
566 condition_list
567 {
568         cond = matcherlist_new(matchers_list, (bool_op == MATCHERBOOL_AND));
569         matchers_list = NULL;
570 }
571 ;
572
573 condition_list:
574 condition_list bool_op one_condition
575 {
576         matchers_list = g_slist_append(matchers_list, prop);
577 }
578 | one_condition
579 {
580         matchers_list = NULL;
581         matchers_list = g_slist_append(matchers_list, prop);
582 }
583 ;
584
585 bool_op:
586 MATCHER_AND
587 {
588         bool_op = MATCHERBOOL_AND;
589 }
590 | MATCHER_OR
591 {
592         bool_op = MATCHERBOOL_OR;
593 }
594 ;
595
596 one_condition:
597 MATCHER_ALL
598 {
599         gint criteria = 0;
600
601         criteria = MATCHCRITERIA_ALL;
602         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
603 }
604 | MATCHER_UNREAD
605 {
606         gint criteria = 0;
607
608         criteria = MATCHCRITERIA_UNREAD;
609         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
610 }
611 | MATCHER_NOT_UNREAD 
612 {
613         gint criteria = 0;
614
615         criteria = MATCHCRITERIA_NOT_UNREAD;
616         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
617 }
618 | MATCHER_NEW
619 {
620         gint criteria = 0;
621
622         criteria = MATCHCRITERIA_NEW;
623         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
624 }
625 | MATCHER_NOT_NEW
626 {
627         gint criteria = 0;
628
629         criteria = MATCHCRITERIA_NOT_NEW;
630         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
631 }
632 | MATCHER_MARKED
633 {
634         gint criteria = 0;
635
636         criteria = MATCHCRITERIA_MARKED;
637         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
638 }
639 | MATCHER_NOT_MARKED
640 {
641         gint criteria = 0;
642
643         criteria = MATCHCRITERIA_NOT_MARKED;
644         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
645 }
646 | MATCHER_DELETED
647 {
648         gint criteria = 0;
649
650         criteria = MATCHCRITERIA_DELETED;
651         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
652 }
653 | MATCHER_NOT_DELETED
654 {
655         gint criteria = 0;
656
657         criteria = MATCHCRITERIA_NOT_DELETED;
658         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
659 }
660 | MATCHER_REPLIED
661 {
662         gint criteria = 0;
663
664         criteria = MATCHCRITERIA_REPLIED;
665         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
666 }
667 | MATCHER_NOT_REPLIED
668 {
669         gint criteria = 0;
670
671         criteria = MATCHCRITERIA_NOT_REPLIED;
672         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
673 }
674 | MATCHER_FORWARDED
675 {
676         gint criteria = 0;
677
678         criteria = MATCHCRITERIA_FORWARDED;
679         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
680 }
681 | MATCHER_NOT_FORWARDED
682 {
683         gint criteria = 0;
684
685         criteria = MATCHCRITERIA_NOT_FORWARDED;
686         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
687 }
688 | MATCHER_LOCKED
689 {
690         gint criteria = 0;
691
692         criteria = MATCHCRITERIA_LOCKED;
693         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
694 }
695 | MATCHER_NOT_LOCKED
696 {
697         gint criteria = 0;
698
699         criteria = MATCHCRITERIA_NOT_LOCKED;
700         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
701 }
702 | MATCHER_SPAM
703 {
704         gint criteria = 0;
705
706         criteria = MATCHCRITERIA_SPAM;
707         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
708 }
709 | MATCHER_NOT_SPAM 
710 {
711         gint criteria = 0;
712
713         criteria = MATCHCRITERIA_NOT_SPAM;
714         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
715 }
716 | MATCHER_HAS_ATTACHMENT
717 {
718         gint criteria = 0;
719
720         criteria = MATCHCRITERIA_HAS_ATTACHMENT;
721         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
722 }
723 | MATCHER_HAS_NO_ATTACHMENT
724 {
725         gint criteria = 0;
726
727         criteria = MATCHCRITERIA_HAS_NO_ATTACHMENT;
728         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
729 }
730 | MATCHER_SIGNED
731 {
732         gint criteria = 0;
733
734         criteria = MATCHCRITERIA_SIGNED;
735         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
736 }
737 | MATCHER_NOT_SIGNED
738 {
739         gint criteria = 0;
740
741         criteria = MATCHCRITERIA_NOT_SIGNED;
742         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
743 }
744 | MATCHER_PARTIAL
745 {
746         gint criteria = 0;
747
748         criteria = MATCHCRITERIA_PARTIAL;
749         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
750 }
751 | MATCHER_NOT_PARTIAL
752 {
753         gint criteria = 0;
754
755         criteria = MATCHCRITERIA_NOT_PARTIAL;
756         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
757 }
758 | MATCHER_COLORLABEL MATCHER_INTEGER
759 {
760         gint criteria = 0;
761         gint value = 0;
762
763         criteria = MATCHCRITERIA_COLORLABEL;
764         value = strtol($2, NULL, 10);
765         if (value < 0) value = 0;
766         else if (value > COLORLABELS) value = COLORLABELS;
767         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
768 }
769 | MATCHER_NOT_COLORLABEL MATCHER_INTEGER
770 {
771         gint criteria = 0;
772         gint value = 0;
773
774         criteria = MATCHCRITERIA_NOT_COLORLABEL;
775         value = strtol($2, NULL, 0);
776         if (value < 0) value = 0;
777         else if (value > COLORLABELS) value = COLORLABELS;
778         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
779 }
780 | MATCHER_IGNORE_THREAD
781 {
782         gint criteria = 0;
783
784         criteria = MATCHCRITERIA_IGNORE_THREAD;
785         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
786 }
787 | MATCHER_NOT_IGNORE_THREAD
788 {
789         gint criteria = 0;
790
791         criteria = MATCHCRITERIA_NOT_IGNORE_THREAD;
792         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
793 }
794 | MATCHER_WATCH_THREAD
795 {
796         gint criteria = 0;
797
798         criteria = MATCHCRITERIA_WATCH_THREAD;
799         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
800 }
801 | MATCHER_NOT_WATCH_THREAD
802 {
803         gint criteria = 0;
804
805         criteria = MATCHCRITERIA_NOT_WATCH_THREAD;
806         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
807 }
808 | MATCHER_SUBJECT match_type MATCHER_STRING
809 {
810         gint criteria = 0;
811         gchar *expr = NULL;
812
813         criteria = MATCHCRITERIA_SUBJECT;
814         expr = $3;
815         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
816 }
817 | MATCHER_NOT_SUBJECT match_type MATCHER_STRING
818 {
819         gint criteria = 0;
820         gchar *expr = NULL;
821
822         criteria = MATCHCRITERIA_NOT_SUBJECT;
823         expr = $3;
824         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
825 }
826 | MATCHER_FROM match_type MATCHER_STRING
827 {
828         gint criteria = 0;
829         gchar *expr = NULL;
830
831         criteria = MATCHCRITERIA_FROM;
832         expr = $3;
833         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
834 }
835 | MATCHER_NOT_FROM match_type MATCHER_STRING
836 {
837         gint criteria = 0;
838         gchar *expr = NULL;
839
840         criteria = MATCHCRITERIA_NOT_FROM;
841         expr = $3;
842         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
843 }
844 | MATCHER_TO match_type MATCHER_STRING
845 {
846         gint criteria = 0;
847         gchar *expr = NULL;
848
849         criteria = MATCHCRITERIA_TO;
850         expr = $3;
851         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
852 }
853 | MATCHER_NOT_TO match_type MATCHER_STRING
854 {
855         gint criteria = 0;
856         gchar *expr = NULL;
857
858         criteria = MATCHCRITERIA_NOT_TO;
859         expr = $3;
860         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
861 }
862 | MATCHER_CC match_type MATCHER_STRING
863 {
864         gint criteria = 0;
865         gchar *expr = NULL;
866
867         criteria = MATCHCRITERIA_CC;
868         expr = $3;
869         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
870 }
871 | MATCHER_NOT_CC match_type MATCHER_STRING
872 {
873         gint criteria = 0;
874         gchar *expr = NULL;
875
876         criteria = MATCHCRITERIA_NOT_CC;
877         expr = $3;
878         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
879 }
880 | MATCHER_TO_OR_CC match_type MATCHER_STRING
881 {
882         gint criteria = 0;
883         gchar *expr = NULL;
884
885         criteria = MATCHCRITERIA_TO_OR_CC;
886         expr = $3;
887         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
888 }
889 | MATCHER_NOT_TO_AND_NOT_CC match_type MATCHER_STRING
890 {
891         gint criteria = 0;
892         gchar *expr = NULL;
893
894         criteria = MATCHCRITERIA_NOT_TO_AND_NOT_CC;
895         expr = $3;
896         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
897 }
898 | MATCHER_TAG match_type MATCHER_STRING
899 {
900         gint criteria = 0;
901         gchar *expr = NULL;
902
903         criteria = MATCHCRITERIA_TAG;
904         expr = $3;
905         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
906 }
907 | MATCHER_NOT_TAG match_type MATCHER_STRING
908 {
909         gint criteria = 0;
910         gchar *expr = NULL;
911
912         criteria = MATCHCRITERIA_NOT_TAG;
913         expr = $3;
914         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
915 }
916 | MATCHER_TAGGED
917 {
918         gint criteria = 0;
919
920         criteria = MATCHCRITERIA_TAGGED;
921         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
922 }
923 | MATCHER_NOT_TAGGED
924 {
925         gint criteria = 0;
926
927         criteria = MATCHCRITERIA_NOT_TAGGED;
928         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
929 }
930 | MATCHER_AGE_GREATER MATCHER_INTEGER
931 {
932         gint criteria = 0;
933         gint value = 0;
934
935         criteria = MATCHCRITERIA_AGE_GREATER;
936         value = strtol($2, NULL, 0);
937         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
938 }
939 | MATCHER_AGE_LOWER MATCHER_INTEGER
940 {
941         gint criteria = 0;
942         gint value = 0;
943
944         criteria = MATCHCRITERIA_AGE_LOWER;
945         value = strtol($2, NULL, 0);
946         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
947 }
948 | MATCHER_NEWSGROUPS match_type MATCHER_STRING
949 {
950         gint criteria = 0;
951         gchar *expr = NULL;
952
953         criteria = MATCHCRITERIA_NEWSGROUPS;
954         expr = $3;
955         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
956 }
957 | MATCHER_NOT_NEWSGROUPS match_type MATCHER_STRING
958 {
959         gint criteria = 0;
960         gchar *expr = NULL;
961
962         criteria = MATCHCRITERIA_NOT_NEWSGROUPS;
963         expr = $3;
964         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
965 }
966 | MATCHER_INREPLYTO match_type MATCHER_STRING
967 {
968         gint criteria = 0;
969         gchar *expr = NULL;
970
971         criteria = MATCHCRITERIA_INREPLYTO;
972         expr = $3;
973         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
974 }
975 | MATCHER_NOT_INREPLYTO match_type MATCHER_STRING
976 {
977         gint criteria = 0;
978         gchar *expr = NULL;
979
980         criteria = MATCHCRITERIA_NOT_INREPLYTO;
981         expr = $3;
982         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
983 }
984 | MATCHER_REFERENCES match_type MATCHER_STRING
985 {
986         gint criteria = 0;
987         gchar *expr = NULL;
988
989         criteria = MATCHCRITERIA_REFERENCES;
990         expr = $3;
991         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
992 }
993 | MATCHER_NOT_REFERENCES match_type MATCHER_STRING
994 {
995         gint criteria = 0;
996         gchar *expr = NULL;
997
998         criteria = MATCHCRITERIA_NOT_REFERENCES;
999         expr = $3;
1000         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1001 }
1002 | MATCHER_SCORE_GREATER MATCHER_INTEGER
1003 {
1004         gint criteria = 0;
1005         gint value = 0;
1006
1007         criteria = MATCHCRITERIA_SCORE_GREATER;
1008         value = strtol($2, NULL, 0);
1009         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
1010 }
1011 | MATCHER_SCORE_LOWER MATCHER_INTEGER
1012 {
1013         gint criteria = 0;
1014         gint value = 0;
1015
1016         criteria = MATCHCRITERIA_SCORE_LOWER;
1017         value = strtol($2, NULL, 0);
1018         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
1019 }
1020 | MATCHER_SCORE_EQUAL MATCHER_INTEGER
1021 {
1022         gint criteria = 0;
1023         gint value = 0;
1024
1025         criteria = MATCHCRITERIA_SCORE_EQUAL;
1026         value = strtol($2, NULL, 0);
1027         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
1028 }
1029 | MATCHER_SIZE_GREATER MATCHER_INTEGER 
1030 {
1031         gint criteria = 0;
1032         gint value    = 0;
1033         criteria = MATCHCRITERIA_SIZE_GREATER;
1034         value = strtol($2, NULL, 0);
1035         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
1036 }
1037 | MATCHER_SIZE_SMALLER MATCHER_INTEGER
1038 {
1039         gint criteria = 0;
1040         gint value    = 0;
1041         criteria = MATCHCRITERIA_SIZE_SMALLER;
1042         value = strtol($2, NULL, 0);
1043         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
1044 }
1045 | MATCHER_SIZE_EQUAL MATCHER_INTEGER
1046 {
1047         gint criteria = 0;
1048         gint value    = 0;
1049         criteria = MATCHCRITERIA_SIZE_EQUAL;
1050         value = strtol($2, NULL, 0);
1051         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
1052 }
1053 | MATCHER_HEADER MATCHER_STRING
1054 {
1055         header = g_strdup($2);
1056 } match_type MATCHER_STRING
1057 {
1058         gint criteria = 0;
1059         gchar *expr = NULL;
1060         matcher_is_fast = FALSE;
1061         criteria = MATCHCRITERIA_HEADER;
1062         expr = $2;
1063         prop = matcherprop_new(criteria, header, match_type, expr, 0);
1064         g_free(header);
1065 }
1066 | MATCHER_NOT_HEADER MATCHER_STRING
1067 {
1068         header = g_strdup($2);
1069 } match_type MATCHER_STRING
1070 {
1071         gint criteria = 0;
1072         gchar *expr = NULL;
1073         matcher_is_fast = FALSE;
1074         criteria = MATCHCRITERIA_NOT_HEADER;
1075         expr = $2;
1076         prop = matcherprop_new(criteria, header, match_type, expr, 0);
1077         g_free(header);
1078 }
1079 | MATCHER_HEADERS_PART match_type MATCHER_STRING
1080 {
1081         gint criteria = 0;
1082         gchar *expr = NULL;
1083         matcher_is_fast = FALSE;
1084         criteria = MATCHCRITERIA_HEADERS_PART;
1085         expr = $3;
1086         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1087 }
1088 | MATCHER_NOT_HEADERS_PART match_type MATCHER_STRING
1089 {
1090         gint criteria = 0;
1091         gchar *expr = NULL;
1092         matcher_is_fast = FALSE;
1093         criteria = MATCHCRITERIA_NOT_HEADERS_PART;
1094         expr = $3;
1095         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1096 }
1097 | MATCHER_FOUND_IN_ADDRESSBOOK MATCHER_STRING
1098 {
1099         header = g_strdup($2);
1100 } MATCHER_IN MATCHER_STRING
1101 {
1102         gint criteria = 0;
1103         gchar *expr = NULL;
1104
1105         criteria = MATCHCRITERIA_FOUND_IN_ADDRESSBOOK;
1106         expr = $2;
1107         prop = matcherprop_new(criteria, header, match_type, expr, 0);
1108         g_free(header);
1109 }
1110 | MATCHER_NOT_FOUND_IN_ADDRESSBOOK MATCHER_STRING
1111 {
1112         header = g_strdup($2);
1113 } MATCHER_IN MATCHER_STRING
1114 {
1115         gint criteria = 0;
1116         gchar *expr = NULL;
1117
1118         criteria = MATCHCRITERIA_NOT_FOUND_IN_ADDRESSBOOK;
1119         expr = $2;
1120         prop = matcherprop_new(criteria, header, match_type, expr, 0);
1121         g_free(header);
1122 }
1123 | MATCHER_MESSAGE match_type MATCHER_STRING
1124 {
1125         gint criteria = 0;
1126         gchar *expr = NULL;
1127         matcher_is_fast = FALSE;
1128         criteria = MATCHCRITERIA_MESSAGE;
1129         expr = $3;
1130         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1131 }
1132 | MATCHER_NOT_MESSAGE match_type MATCHER_STRING
1133 {
1134         gint criteria = 0;
1135         gchar *expr = NULL;
1136         matcher_is_fast = FALSE;
1137         criteria = MATCHCRITERIA_NOT_MESSAGE;
1138         expr = $3;
1139         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1140 }
1141 | MATCHER_BODY_PART match_type MATCHER_STRING
1142 {
1143         gint criteria = 0;
1144         gchar *expr = NULL;
1145         matcher_is_fast = FALSE;
1146         criteria = MATCHCRITERIA_BODY_PART;
1147         expr = $3;
1148         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1149 }
1150 | MATCHER_NOT_BODY_PART match_type MATCHER_STRING
1151 {
1152         gint criteria = 0;
1153         gchar *expr = NULL;
1154         matcher_is_fast = FALSE;
1155         criteria = MATCHCRITERIA_NOT_BODY_PART;
1156         expr = $3;
1157         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1158 }
1159 | MATCHER_TEST MATCHER_STRING
1160 {
1161         gint criteria = 0;
1162         gchar *expr = NULL;
1163         matcher_is_fast = FALSE;
1164         criteria = MATCHCRITERIA_TEST;
1165         expr = $2;
1166         prop = matcherprop_new(criteria, NULL, MATCHTYPE_MATCH, expr, 0);
1167 }
1168 | MATCHER_NOT_TEST MATCHER_STRING
1169 {
1170         gint criteria = 0;
1171         gchar *expr = NULL;
1172         matcher_is_fast = FALSE;
1173         criteria = MATCHCRITERIA_NOT_TEST;
1174         expr = $2;
1175         prop = matcherprop_new(criteria, NULL, MATCHTYPE_MATCH, expr, 0);
1176 }
1177 ;
1178
1179 filtering_action:
1180 MATCHER_EXECUTE MATCHER_STRING
1181 {
1182         gchar *cmd = NULL;
1183         gint action_type = 0;
1184
1185         action_type = MATCHACTION_EXECUTE;
1186         cmd = $2;
1187         action = filteringaction_new(action_type, 0, cmd, 0, 0, NULL);
1188 }
1189 | MATCHER_MOVE MATCHER_STRING
1190 {
1191         gchar *destination = NULL;
1192         gint action_type = 0;
1193
1194         action_type = MATCHACTION_MOVE;
1195         destination = $2;
1196         action = filteringaction_new(action_type, 0, destination, 0, 0, NULL);
1197 }
1198 | MATCHER_SET_TAG MATCHER_STRING
1199 {
1200         gchar *destination = NULL;
1201         gint action_type = 0;
1202
1203         action_type = MATCHACTION_SET_TAG;
1204         destination = $2;
1205         action = filteringaction_new(action_type, 0, destination, 0, 0, NULL);
1206 }
1207 | MATCHER_UNSET_TAG MATCHER_STRING
1208 {
1209         gchar *destination = NULL;
1210         gint action_type = 0;
1211
1212         action_type = MATCHACTION_UNSET_TAG;
1213         destination = $2;
1214         action = filteringaction_new(action_type, 0, destination, 0, 0, NULL);
1215 }
1216 | MATCHER_CLEAR_TAGS
1217 {
1218         gint action_type = 0;
1219
1220         action_type = MATCHACTION_CLEAR_TAGS;
1221         action = filteringaction_new(action_type, 0, NULL, 0, 0, NULL);
1222 }
1223 | MATCHER_COPY MATCHER_STRING
1224 {
1225         gchar *destination = NULL;
1226         gint action_type = 0;
1227
1228         action_type = MATCHACTION_COPY;
1229         destination = $2;
1230         action = filteringaction_new(action_type, 0, destination, 0, 0, NULL);
1231 }
1232 | MATCHER_DELETE
1233 {
1234         gint action_type = 0;
1235
1236         action_type = MATCHACTION_DELETE;
1237         action = filteringaction_new(action_type, 0, NULL, 0, 0, NULL);
1238 }
1239 | MATCHER_MARK
1240 {
1241         gint action_type = 0;
1242
1243         action_type = MATCHACTION_MARK;
1244         action = filteringaction_new(action_type, 0, NULL, 0, 0, NULL);
1245 }
1246 | MATCHER_UNMARK
1247 {
1248         gint action_type = 0;
1249
1250         action_type = MATCHACTION_UNMARK;
1251         action = filteringaction_new(action_type, 0, NULL, 0, 0, NULL);
1252 }
1253 | MATCHER_LOCK
1254 {
1255         gint action_type = 0;
1256
1257         action_type = MATCHACTION_LOCK;
1258         action = filteringaction_new(action_type, 0, NULL, 0, 0, NULL);
1259 }
1260 | MATCHER_UNLOCK
1261 {
1262         gint action_type = 0;
1263
1264         action_type = MATCHACTION_UNLOCK;
1265         action = filteringaction_new(action_type, 0, NULL, 0, 0, NULL);
1266 }
1267 | MATCHER_MARK_AS_READ
1268 {
1269         gint action_type = 0;
1270
1271         action_type = MATCHACTION_MARK_AS_READ;
1272         action = filteringaction_new(action_type, 0, NULL, 0, 0, NULL);
1273 }
1274 | MATCHER_MARK_AS_UNREAD
1275 {
1276         gint action_type = 0;
1277
1278         action_type = MATCHACTION_MARK_AS_UNREAD;
1279         action = filteringaction_new(action_type, 0, NULL, 0, 0, NULL);
1280 }
1281 | MATCHER_MARK_AS_SPAM
1282 {
1283         gint action_type = 0;
1284
1285         action_type = MATCHACTION_MARK_AS_SPAM;
1286         action = filteringaction_new(action_type, 0, NULL, 0, 0, NULL);
1287 }
1288 | MATCHER_MARK_AS_HAM
1289 {
1290         gint action_type = 0;
1291
1292         action_type = MATCHACTION_MARK_AS_HAM;
1293         action = filteringaction_new(action_type, 0, NULL, 0, 0, NULL);
1294 }
1295 | MATCHER_FORWARD MATCHER_INTEGER MATCHER_STRING
1296 {
1297         gchar *destination = NULL;
1298         gint action_type = 0;
1299         gint account_id = 0;
1300
1301         action_type = MATCHACTION_FORWARD;
1302         account_id = strtol($2, NULL, 10);
1303         destination = $3;
1304         action = filteringaction_new(action_type,
1305             account_id, destination, 0, 0, NULL);
1306 }
1307 | MATCHER_FORWARD_AS_ATTACHMENT MATCHER_INTEGER MATCHER_STRING
1308 {
1309         gchar *destination = NULL;
1310         gint action_type = 0;
1311         gint account_id = 0;
1312
1313         action_type = MATCHACTION_FORWARD_AS_ATTACHMENT;
1314         account_id = strtol($2, NULL, 10);
1315         destination = $3;
1316         action = filteringaction_new(action_type,
1317             account_id, destination, 0, 0, NULL);
1318 }
1319 | MATCHER_REDIRECT MATCHER_INTEGER MATCHER_STRING
1320 {
1321         gchar *destination = NULL;
1322         gint action_type = 0;
1323         gint account_id = 0;
1324
1325         action_type = MATCHACTION_REDIRECT;
1326         account_id = strtol($2, NULL, 10);
1327         destination = $3;
1328         action = filteringaction_new(action_type,
1329             account_id, destination, 0, 0, NULL);
1330 }
1331 | MATCHER_COLOR MATCHER_INTEGER
1332 {
1333         gint action_type = 0;
1334         gint color = 0;
1335
1336         action_type = MATCHACTION_COLOR;
1337         color = strtol($2, NULL, 10);
1338         action = filteringaction_new(action_type, 0, NULL, color, 0, NULL);
1339 }
1340 | MATCHER_CHANGE_SCORE MATCHER_INTEGER
1341 {
1342         gint score = 0;
1343         
1344         score = strtol($2, NULL, 10);
1345         action = filteringaction_new(MATCHACTION_CHANGE_SCORE, 0,
1346                                      NULL, 0, score, NULL);
1347 }
1348 /* backward compatibility */
1349 | MATCHER_SCORE MATCHER_INTEGER
1350 {
1351         gint score = 0;
1352         
1353         score = strtol($2, NULL, 10);
1354         action = filteringaction_new(MATCHACTION_CHANGE_SCORE, 0,
1355                                      NULL, 0, score, NULL);
1356 }
1357 | MATCHER_SET_SCORE MATCHER_INTEGER
1358 {
1359         gint score = 0;
1360         
1361         score = strtol($2, NULL, 10);
1362         action = filteringaction_new(MATCHACTION_SET_SCORE, 0,
1363                                      NULL, 0, score, NULL);
1364 }
1365 | MATCHER_HIDE
1366 {
1367         action = filteringaction_new(MATCHACTION_HIDE, 0, NULL, 0, 0, NULL);
1368 }
1369 | MATCHER_IGNORE
1370 {
1371         action = filteringaction_new(MATCHACTION_IGNORE, 0, NULL, 0, 0, NULL);
1372 }
1373 | MATCHER_WATCH
1374 {
1375         action = filteringaction_new(MATCHACTION_WATCH, 0, NULL, 0, 0, NULL);
1376 }
1377 | MATCHER_ADD_TO_ADDRESSBOOK MATCHER_STRING
1378 {
1379         header = g_strdup($2);
1380 } MATCHER_STRING
1381 {
1382         gchar *addressbook = NULL;
1383         gint action_type = 0;
1384
1385         action_type = MATCHACTION_ADD_TO_ADDRESSBOOK;
1386         addressbook = $2;
1387         action = filteringaction_new(action_type, 0, addressbook, 0, 0, header);
1388         g_free(header);
1389 }
1390 | MATCHER_STOP
1391 {
1392         action = filteringaction_new(MATCHACTION_STOP, 0, NULL, 0, 0, NULL);
1393 }
1394 ;