2007-07-27 [paul] 2.10.0cvs74
[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_TAG MATCHER_NOT_TAG MATCHER_SET_TAG MATCHER_UNSET_TAG
341 %token MATCHER_TAGGED MATCHER_NOT_TAGGED MATCHER_CLEAR_TAGS
342
343 %start file
344
345 %token MATCHER_ENABLED MATCHER_DISABLED
346 %token MATCHER_RULENAME
347 %token MATCHER_ACCOUNT
348 %token <str> MATCHER_STRING
349 %token <str> MATCHER_SECTION
350 %token <str> MATCHER_INTEGER
351
352 %%
353
354 file:
355 {
356         if (matcher_parse_op == MATCHER_PARSE_FILE) {
357                 prefs_filtering = &pre_global_processing;
358         }
359 }
360 file_line_list;
361
362 file_line_list:
363 file_line
364 file_line_list
365 | file_line
366 ;
367
368 file_line:
369 section_notification
370
371 { action_list = NULL; }
372 instruction
373 | error MATCHER_EOL
374 {
375         yyerrok;
376 };
377
378 section_notification:
379 MATCHER_SECTION MATCHER_EOL
380 {
381         gchar *folder = $1;
382         FolderItem *item = NULL;
383
384         if (matcher_parse_op == MATCHER_PARSE_FILE) {
385                 enable_compatibility = 0;
386                 if (!strcmp(folder, "global")) {
387                         /* backward compatibility */
388                         enable_compatibility = 1;
389                 }
390                 else if (!strcmp(folder, "preglobal")) {
391                         prefs_filtering = &pre_global_processing;
392                 }
393                 else if (!strcmp(folder, "postglobal")) {
394                         prefs_filtering = &post_global_processing;
395                 }
396                 else if (!strcmp(folder, "filtering")) {
397                         prefs_filtering = &filtering_rules;
398                 }
399                 else {
400                         item = folder_find_item_from_identifier(folder);
401                         if (item != NULL) {
402                                 prefs_filtering = &item->prefs->processing;
403                         } else {
404                                 prefs_filtering = NULL;
405                         }
406                 }
407         }
408 }
409 ;
410
411 instruction:
412 enabled name account condition filtering MATCHER_EOL
413 | enabled name account condition filtering
414 | enabled name condition filtering MATCHER_EOL
415 | enabled name condition filtering
416 | name condition filtering MATCHER_EOL
417 | name condition filtering
418 {
419         if (matcher_parse_op == MATCHER_PARSE_NO_EOL)
420                 YYACCEPT;
421         else {
422                 matcher_parsererror("parse error [no eol]");
423                 YYERROR;
424         }
425 }
426 | enabled
427 {
428         if (matcher_parse_op == MATCHER_PARSE_ENABLED)
429                 YYACCEPT;
430         else {
431                 matcher_parsererror("parse error [enabled]");
432                 YYERROR;
433         }
434 }
435 | account
436 {
437         if (matcher_parse_op == MATCHER_PARSE_ACCOUNT)
438                 YYACCEPT;
439         else {
440                 matcher_parsererror("parse error [account]");
441                 YYERROR;
442         }
443 }
444 | name
445 {
446         if (matcher_parse_op == MATCHER_PARSE_NAME)
447                 YYACCEPT;
448         else {
449                 matcher_parsererror("parse error [name]");
450                 YYERROR;
451         }
452 }
453 | condition
454 {
455         if (matcher_parse_op == MATCHER_PARSE_CONDITION)
456                 YYACCEPT;
457         else {
458                 matcher_parsererror("parse error [condition]");
459                 YYERROR;
460         }
461 }
462 | filtering_action_list
463 {
464         if (matcher_parse_op == MATCHER_PARSE_FILTERING_ACTION)
465                 YYACCEPT;
466         else {
467                 matcher_parsererror("parse error [filtering action]");
468                 YYERROR;
469         }
470 }
471 | MATCHER_EOL
472 ;
473
474 enabled:
475 MATCHER_ENABLED
476 {
477         enabled = TRUE;
478 }
479 | MATCHER_DISABLED
480 {
481         enabled = FALSE;
482 }
483 ;
484
485 name:
486 MATCHER_RULENAME MATCHER_STRING
487 {
488         name = g_strdup($2);
489 }
490 ;
491
492 account:
493 MATCHER_ACCOUNT MATCHER_INTEGER
494 {
495         account_id = strtol($2, NULL, 10);
496 }
497 ;
498
499 filtering:
500 filtering_action_list
501 {
502         filtering = filteringprop_new(enabled, name, account_id, cond, action_list);
503         enabled = TRUE;
504         account_id = 0;
505         g_free(name);
506         name = NULL;
507         if (enable_compatibility) {
508                 prefs_filtering = &filtering_rules;
509                 if (action_list != NULL) {
510                         FilteringAction * first_action;
511                         
512                         first_action = action_list->data;
513                         
514                         if (first_action->type == MATCHACTION_CHANGE_SCORE)
515                                 prefs_filtering = &pre_global_processing;
516                 }
517         }
518         
519         cond = NULL;
520         action_list = NULL;
521         
522         if ((matcher_parse_op == MATCHER_PARSE_FILE) &&
523             (prefs_filtering != NULL)) {
524                 *prefs_filtering = g_slist_append(*prefs_filtering,
525                                                   filtering);
526                 filtering = NULL;
527         }
528 }
529 ;
530
531 filtering_action_list:
532 filtering_action_b filtering_action_list
533 | filtering_action_b
534 ;
535
536 filtering_action_b:
537 filtering_action
538 {
539         action_list = g_slist_append(action_list, action);
540         action = NULL;
541 }
542 ;
543
544 match_type:
545 MATCHER_MATCHCASE
546 {
547         match_type = MATCHTYPE_MATCHCASE;
548 }
549 | MATCHER_MATCH
550 {
551         match_type = MATCHTYPE_MATCH;
552 }
553 | MATCHER_REGEXPCASE
554 {
555         match_type = MATCHTYPE_REGEXPCASE;
556 }
557 | MATCHER_REGEXP
558 {
559         match_type = MATCHTYPE_REGEXP;
560 }
561 ;
562
563 condition:
564 condition_list
565 {
566         cond = matcherlist_new(matchers_list, (bool_op == MATCHERBOOL_AND));
567         matchers_list = NULL;
568 }
569 ;
570
571 condition_list:
572 condition_list bool_op one_condition
573 {
574         matchers_list = g_slist_append(matchers_list, prop);
575 }
576 | one_condition
577 {
578         matchers_list = NULL;
579         matchers_list = g_slist_append(matchers_list, prop);
580 }
581 ;
582
583 bool_op:
584 MATCHER_AND
585 {
586         bool_op = MATCHERBOOL_AND;
587 }
588 | MATCHER_OR
589 {
590         bool_op = MATCHERBOOL_OR;
591 }
592 ;
593
594 one_condition:
595 MATCHER_ALL
596 {
597         gint criteria = 0;
598
599         criteria = MATCHCRITERIA_ALL;
600         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
601 }
602 | MATCHER_UNREAD
603 {
604         gint criteria = 0;
605
606         criteria = MATCHCRITERIA_UNREAD;
607         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
608 }
609 | MATCHER_NOT_UNREAD 
610 {
611         gint criteria = 0;
612
613         criteria = MATCHCRITERIA_NOT_UNREAD;
614         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
615 }
616 | MATCHER_NEW
617 {
618         gint criteria = 0;
619
620         criteria = MATCHCRITERIA_NEW;
621         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
622 }
623 | MATCHER_NOT_NEW
624 {
625         gint criteria = 0;
626
627         criteria = MATCHCRITERIA_NOT_NEW;
628         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
629 }
630 | MATCHER_MARKED
631 {
632         gint criteria = 0;
633
634         criteria = MATCHCRITERIA_MARKED;
635         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
636 }
637 | MATCHER_NOT_MARKED
638 {
639         gint criteria = 0;
640
641         criteria = MATCHCRITERIA_NOT_MARKED;
642         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
643 }
644 | MATCHER_DELETED
645 {
646         gint criteria = 0;
647
648         criteria = MATCHCRITERIA_DELETED;
649         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
650 }
651 | MATCHER_NOT_DELETED
652 {
653         gint criteria = 0;
654
655         criteria = MATCHCRITERIA_NOT_DELETED;
656         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
657 }
658 | MATCHER_REPLIED
659 {
660         gint criteria = 0;
661
662         criteria = MATCHCRITERIA_REPLIED;
663         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
664 }
665 | MATCHER_NOT_REPLIED
666 {
667         gint criteria = 0;
668
669         criteria = MATCHCRITERIA_NOT_REPLIED;
670         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
671 }
672 | MATCHER_FORWARDED
673 {
674         gint criteria = 0;
675
676         criteria = MATCHCRITERIA_FORWARDED;
677         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
678 }
679 | MATCHER_NOT_FORWARDED
680 {
681         gint criteria = 0;
682
683         criteria = MATCHCRITERIA_NOT_FORWARDED;
684         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
685 }
686 | MATCHER_LOCKED
687 {
688         gint criteria = 0;
689
690         criteria = MATCHCRITERIA_LOCKED;
691         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
692 }
693 | MATCHER_NOT_LOCKED
694 {
695         gint criteria = 0;
696
697         criteria = MATCHCRITERIA_NOT_LOCKED;
698         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
699 }
700 | MATCHER_SPAM
701 {
702         gint criteria = 0;
703
704         criteria = MATCHCRITERIA_SPAM;
705         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
706 }
707 | MATCHER_NOT_SPAM 
708 {
709         gint criteria = 0;
710
711         criteria = MATCHCRITERIA_NOT_SPAM;
712         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
713 }
714 | MATCHER_PARTIAL
715 {
716         gint criteria = 0;
717
718         criteria = MATCHCRITERIA_PARTIAL;
719         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
720 }
721 | MATCHER_NOT_PARTIAL
722 {
723         gint criteria = 0;
724
725         criteria = MATCHCRITERIA_NOT_PARTIAL;
726         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
727 }
728 | MATCHER_COLORLABEL MATCHER_INTEGER
729 {
730         gint criteria = 0;
731         gint value = 0;
732
733         criteria = MATCHCRITERIA_COLORLABEL;
734         value = strtol($2, NULL, 10);
735         if (value < 0) value = 0;
736         else if (value > COLORLABELS) value = COLORLABELS;
737         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
738 }
739 | MATCHER_NOT_COLORLABEL MATCHER_INTEGER
740 {
741         gint criteria = 0;
742         gint value = 0;
743
744         criteria = MATCHCRITERIA_NOT_COLORLABEL;
745         value = strtol($2, NULL, 0);
746         if (value < 0) value = 0;
747         else if (value > COLORLABELS) value = COLORLABELS;
748         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
749 }
750 | MATCHER_IGNORE_THREAD
751 {
752         gint criteria = 0;
753
754         criteria = MATCHCRITERIA_IGNORE_THREAD;
755         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
756 }
757 | MATCHER_NOT_IGNORE_THREAD
758 {
759         gint criteria = 0;
760
761         criteria = MATCHCRITERIA_NOT_IGNORE_THREAD;
762         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
763 }
764 | MATCHER_WATCH_THREAD
765 {
766         gint criteria = 0;
767
768         criteria = MATCHCRITERIA_WATCH_THREAD;
769         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
770 }
771 | MATCHER_NOT_WATCH_THREAD
772 {
773         gint criteria = 0;
774
775         criteria = MATCHCRITERIA_NOT_WATCH_THREAD;
776         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
777 }
778 | MATCHER_SUBJECT match_type MATCHER_STRING
779 {
780         gint criteria = 0;
781         gchar *expr = NULL;
782
783         criteria = MATCHCRITERIA_SUBJECT;
784         expr = $3;
785         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
786 }
787 | MATCHER_NOT_SUBJECT match_type MATCHER_STRING
788 {
789         gint criteria = 0;
790         gchar *expr = NULL;
791
792         criteria = MATCHCRITERIA_NOT_SUBJECT;
793         expr = $3;
794         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
795 }
796 | MATCHER_FROM match_type MATCHER_STRING
797 {
798         gint criteria = 0;
799         gchar *expr = NULL;
800
801         criteria = MATCHCRITERIA_FROM;
802         expr = $3;
803         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
804 }
805 | MATCHER_NOT_FROM match_type MATCHER_STRING
806 {
807         gint criteria = 0;
808         gchar *expr = NULL;
809
810         criteria = MATCHCRITERIA_NOT_FROM;
811         expr = $3;
812         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
813 }
814 | MATCHER_TO match_type MATCHER_STRING
815 {
816         gint criteria = 0;
817         gchar *expr = NULL;
818
819         criteria = MATCHCRITERIA_TO;
820         expr = $3;
821         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
822 }
823 | MATCHER_NOT_TO match_type MATCHER_STRING
824 {
825         gint criteria = 0;
826         gchar *expr = NULL;
827
828         criteria = MATCHCRITERIA_NOT_TO;
829         expr = $3;
830         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
831 }
832 | MATCHER_CC match_type MATCHER_STRING
833 {
834         gint criteria = 0;
835         gchar *expr = NULL;
836
837         criteria = MATCHCRITERIA_CC;
838         expr = $3;
839         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
840 }
841 | MATCHER_NOT_CC match_type MATCHER_STRING
842 {
843         gint criteria = 0;
844         gchar *expr = NULL;
845
846         criteria = MATCHCRITERIA_NOT_CC;
847         expr = $3;
848         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
849 }
850 | MATCHER_TO_OR_CC match_type MATCHER_STRING
851 {
852         gint criteria = 0;
853         gchar *expr = NULL;
854
855         criteria = MATCHCRITERIA_TO_OR_CC;
856         expr = $3;
857         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
858 }
859 | MATCHER_NOT_TO_AND_NOT_CC match_type MATCHER_STRING
860 {
861         gint criteria = 0;
862         gchar *expr = NULL;
863
864         criteria = MATCHCRITERIA_NOT_TO_AND_NOT_CC;
865         expr = $3;
866         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
867 }
868 | MATCHER_TAG match_type MATCHER_STRING
869 {
870         gint criteria = 0;
871         gchar *expr = NULL;
872
873         criteria = MATCHCRITERIA_TAG;
874         expr = $3;
875         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
876 }
877 | MATCHER_NOT_TAG match_type MATCHER_STRING
878 {
879         gint criteria = 0;
880         gchar *expr = NULL;
881
882         criteria = MATCHCRITERIA_NOT_TAG;
883         expr = $3;
884         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
885 }
886 | MATCHER_TAGGED
887 {
888         gint criteria = 0;
889
890         criteria = MATCHCRITERIA_TAGGED;
891         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
892 }
893 | MATCHER_NOT_TAGGED
894 {
895         gint criteria = 0;
896
897         criteria = MATCHCRITERIA_NOT_TAGGED;
898         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
899 }
900 | MATCHER_AGE_GREATER MATCHER_INTEGER
901 {
902         gint criteria = 0;
903         gint value = 0;
904
905         criteria = MATCHCRITERIA_AGE_GREATER;
906         value = strtol($2, NULL, 0);
907         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
908 }
909 | MATCHER_AGE_LOWER MATCHER_INTEGER
910 {
911         gint criteria = 0;
912         gint value = 0;
913
914         criteria = MATCHCRITERIA_AGE_LOWER;
915         value = strtol($2, NULL, 0);
916         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
917 }
918 | MATCHER_NEWSGROUPS match_type MATCHER_STRING
919 {
920         gint criteria = 0;
921         gchar *expr = NULL;
922
923         criteria = MATCHCRITERIA_NEWSGROUPS;
924         expr = $3;
925         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
926 }
927 | MATCHER_NOT_NEWSGROUPS match_type MATCHER_STRING
928 {
929         gint criteria = 0;
930         gchar *expr = NULL;
931
932         criteria = MATCHCRITERIA_NOT_NEWSGROUPS;
933         expr = $3;
934         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
935 }
936 | MATCHER_INREPLYTO match_type MATCHER_STRING
937 {
938         gint criteria = 0;
939         gchar *expr = NULL;
940
941         criteria = MATCHCRITERIA_INREPLYTO;
942         expr = $3;
943         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
944 }
945 | MATCHER_NOT_INREPLYTO match_type MATCHER_STRING
946 {
947         gint criteria = 0;
948         gchar *expr = NULL;
949
950         criteria = MATCHCRITERIA_NOT_INREPLYTO;
951         expr = $3;
952         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
953 }
954 | MATCHER_REFERENCES match_type MATCHER_STRING
955 {
956         gint criteria = 0;
957         gchar *expr = NULL;
958
959         criteria = MATCHCRITERIA_REFERENCES;
960         expr = $3;
961         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
962 }
963 | MATCHER_NOT_REFERENCES match_type MATCHER_STRING
964 {
965         gint criteria = 0;
966         gchar *expr = NULL;
967
968         criteria = MATCHCRITERIA_NOT_REFERENCES;
969         expr = $3;
970         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
971 }
972 | MATCHER_SCORE_GREATER MATCHER_INTEGER
973 {
974         gint criteria = 0;
975         gint value = 0;
976
977         criteria = MATCHCRITERIA_SCORE_GREATER;
978         value = strtol($2, NULL, 0);
979         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
980 }
981 | MATCHER_SCORE_LOWER MATCHER_INTEGER
982 {
983         gint criteria = 0;
984         gint value = 0;
985
986         criteria = MATCHCRITERIA_SCORE_LOWER;
987         value = strtol($2, NULL, 0);
988         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
989 }
990 | MATCHER_SCORE_EQUAL MATCHER_INTEGER
991 {
992         gint criteria = 0;
993         gint value = 0;
994
995         criteria = MATCHCRITERIA_SCORE_EQUAL;
996         value = strtol($2, NULL, 0);
997         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
998 }
999 | MATCHER_SIZE_GREATER MATCHER_INTEGER 
1000 {
1001         gint criteria = 0;
1002         gint value    = 0;
1003         criteria = MATCHCRITERIA_SIZE_GREATER;
1004         value = strtol($2, NULL, 0);
1005         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
1006 }
1007 | MATCHER_SIZE_SMALLER MATCHER_INTEGER
1008 {
1009         gint criteria = 0;
1010         gint value    = 0;
1011         criteria = MATCHCRITERIA_SIZE_SMALLER;
1012         value = strtol($2, NULL, 0);
1013         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
1014 }
1015 | MATCHER_SIZE_EQUAL MATCHER_INTEGER
1016 {
1017         gint criteria = 0;
1018         gint value    = 0;
1019         criteria = MATCHCRITERIA_SIZE_EQUAL;
1020         value = strtol($2, NULL, 0);
1021         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
1022 }
1023 | MATCHER_HEADER MATCHER_STRING
1024 {
1025         header = g_strdup($2);
1026 } match_type MATCHER_STRING
1027 {
1028         gint criteria = 0;
1029         gchar *expr = NULL;
1030         matcher_is_fast = FALSE;
1031         criteria = MATCHCRITERIA_HEADER;
1032         expr = $2;
1033         prop = matcherprop_new(criteria, header, match_type, expr, 0);
1034         g_free(header);
1035 }
1036 | MATCHER_NOT_HEADER MATCHER_STRING
1037 {
1038         header = g_strdup($2);
1039 } match_type MATCHER_STRING
1040 {
1041         gint criteria = 0;
1042         gchar *expr = NULL;
1043         matcher_is_fast = FALSE;
1044         criteria = MATCHCRITERIA_NOT_HEADER;
1045         expr = $2;
1046         prop = matcherprop_new(criteria, header, match_type, expr, 0);
1047         g_free(header);
1048 }
1049 | MATCHER_HEADERS_PART match_type MATCHER_STRING
1050 {
1051         gint criteria = 0;
1052         gchar *expr = NULL;
1053         matcher_is_fast = FALSE;
1054         criteria = MATCHCRITERIA_HEADERS_PART;
1055         expr = $3;
1056         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1057 }
1058 | MATCHER_NOT_HEADERS_PART match_type MATCHER_STRING
1059 {
1060         gint criteria = 0;
1061         gchar *expr = NULL;
1062         matcher_is_fast = FALSE;
1063         criteria = MATCHCRITERIA_NOT_HEADERS_PART;
1064         expr = $3;
1065         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1066 }
1067 | MATCHER_FOUND_IN_ADDRESSBOOK MATCHER_STRING
1068 {
1069         header = g_strdup($2);
1070 } MATCHER_IN MATCHER_STRING
1071 {
1072         gint criteria = 0;
1073         gchar *expr = NULL;
1074
1075         criteria = MATCHCRITERIA_FOUND_IN_ADDRESSBOOK;
1076         expr = $2;
1077         prop = matcherprop_new(criteria, header, match_type, expr, 0);
1078         g_free(header);
1079 }
1080 | MATCHER_NOT_FOUND_IN_ADDRESSBOOK MATCHER_STRING
1081 {
1082         header = g_strdup($2);
1083 } MATCHER_IN MATCHER_STRING
1084 {
1085         gint criteria = 0;
1086         gchar *expr = NULL;
1087
1088         criteria = MATCHCRITERIA_NOT_FOUND_IN_ADDRESSBOOK;
1089         expr = $2;
1090         prop = matcherprop_new(criteria, header, match_type, expr, 0);
1091         g_free(header);
1092 }
1093 | MATCHER_MESSAGE match_type MATCHER_STRING
1094 {
1095         gint criteria = 0;
1096         gchar *expr = NULL;
1097         matcher_is_fast = FALSE;
1098         criteria = MATCHCRITERIA_MESSAGE;
1099         expr = $3;
1100         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1101 }
1102 | MATCHER_NOT_MESSAGE match_type MATCHER_STRING
1103 {
1104         gint criteria = 0;
1105         gchar *expr = NULL;
1106         matcher_is_fast = FALSE;
1107         criteria = MATCHCRITERIA_NOT_MESSAGE;
1108         expr = $3;
1109         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1110 }
1111 | MATCHER_BODY_PART match_type MATCHER_STRING
1112 {
1113         gint criteria = 0;
1114         gchar *expr = NULL;
1115         matcher_is_fast = FALSE;
1116         criteria = MATCHCRITERIA_BODY_PART;
1117         expr = $3;
1118         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1119 }
1120 | MATCHER_NOT_BODY_PART match_type MATCHER_STRING
1121 {
1122         gint criteria = 0;
1123         gchar *expr = NULL;
1124         matcher_is_fast = FALSE;
1125         criteria = MATCHCRITERIA_NOT_BODY_PART;
1126         expr = $3;
1127         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1128 }
1129 | MATCHER_TEST MATCHER_STRING
1130 {
1131         gint criteria = 0;
1132         gchar *expr = NULL;
1133         matcher_is_fast = FALSE;
1134         criteria = MATCHCRITERIA_TEST;
1135         expr = $2;
1136         prop = matcherprop_new(criteria, NULL, 0, expr, 0);
1137 }
1138 | MATCHER_NOT_TEST MATCHER_STRING
1139 {
1140         gint criteria = 0;
1141         gchar *expr = NULL;
1142         matcher_is_fast = FALSE;
1143         criteria = MATCHCRITERIA_NOT_TEST;
1144         expr = $2;
1145         prop = matcherprop_new(criteria, NULL, 0, expr, 0);
1146 }
1147 ;
1148
1149 filtering_action:
1150 MATCHER_EXECUTE MATCHER_STRING
1151 {
1152         gchar *cmd = NULL;
1153         gint action_type = 0;
1154
1155         action_type = MATCHACTION_EXECUTE;
1156         cmd = $2;
1157         action = filteringaction_new(action_type, 0, cmd, 0, 0, NULL);
1158 }
1159 | MATCHER_MOVE MATCHER_STRING
1160 {
1161         gchar *destination = NULL;
1162         gint action_type = 0;
1163
1164         action_type = MATCHACTION_MOVE;
1165         destination = $2;
1166         action = filteringaction_new(action_type, 0, destination, 0, 0, NULL);
1167 }
1168 | MATCHER_SET_TAG MATCHER_STRING
1169 {
1170         gchar *destination = NULL;
1171         gint action_type = 0;
1172
1173         action_type = MATCHACTION_SET_TAG;
1174         destination = $2;
1175         action = filteringaction_new(action_type, 0, destination, 0, 0, NULL);
1176 }
1177 | MATCHER_UNSET_TAG MATCHER_STRING
1178 {
1179         gchar *destination = NULL;
1180         gint action_type = 0;
1181
1182         action_type = MATCHACTION_UNSET_TAG;
1183         destination = $2;
1184         action = filteringaction_new(action_type, 0, destination, 0, 0, NULL);
1185 }
1186 | MATCHER_CLEAR_TAGS
1187 {
1188         gint action_type = 0;
1189
1190         action_type = MATCHACTION_CLEAR_TAGS;
1191         action = filteringaction_new(action_type, 0, NULL, 0, 0, NULL);
1192 }
1193 | MATCHER_COPY MATCHER_STRING
1194 {
1195         gchar *destination = NULL;
1196         gint action_type = 0;
1197
1198         action_type = MATCHACTION_COPY;
1199         destination = $2;
1200         action = filteringaction_new(action_type, 0, destination, 0, 0, NULL);
1201 }
1202 | MATCHER_DELETE
1203 {
1204         gint action_type = 0;
1205
1206         action_type = MATCHACTION_DELETE;
1207         action = filteringaction_new(action_type, 0, NULL, 0, 0, NULL);
1208 }
1209 | MATCHER_MARK
1210 {
1211         gint action_type = 0;
1212
1213         action_type = MATCHACTION_MARK;
1214         action = filteringaction_new(action_type, 0, NULL, 0, 0, NULL);
1215 }
1216 | MATCHER_UNMARK
1217 {
1218         gint action_type = 0;
1219
1220         action_type = MATCHACTION_UNMARK;
1221         action = filteringaction_new(action_type, 0, NULL, 0, 0, NULL);
1222 }
1223 | MATCHER_LOCK
1224 {
1225         gint action_type = 0;
1226
1227         action_type = MATCHACTION_LOCK;
1228         action = filteringaction_new(action_type, 0, NULL, 0, 0, NULL);
1229 }
1230 | MATCHER_UNLOCK
1231 {
1232         gint action_type = 0;
1233
1234         action_type = MATCHACTION_UNLOCK;
1235         action = filteringaction_new(action_type, 0, NULL, 0, 0, NULL);
1236 }
1237 | MATCHER_MARK_AS_READ
1238 {
1239         gint action_type = 0;
1240
1241         action_type = MATCHACTION_MARK_AS_READ;
1242         action = filteringaction_new(action_type, 0, NULL, 0, 0, NULL);
1243 }
1244 | MATCHER_MARK_AS_UNREAD
1245 {
1246         gint action_type = 0;
1247
1248         action_type = MATCHACTION_MARK_AS_UNREAD;
1249         action = filteringaction_new(action_type, 0, NULL, 0, 0, NULL);
1250 }
1251 | MATCHER_MARK_AS_SPAM
1252 {
1253         gint action_type = 0;
1254
1255         action_type = MATCHACTION_MARK_AS_SPAM;
1256         action = filteringaction_new(action_type, 0, NULL, 0, 0, NULL);
1257 }
1258 | MATCHER_MARK_AS_HAM
1259 {
1260         gint action_type = 0;
1261
1262         action_type = MATCHACTION_MARK_AS_HAM;
1263         action = filteringaction_new(action_type, 0, NULL, 0, 0, NULL);
1264 }
1265 | MATCHER_FORWARD MATCHER_INTEGER MATCHER_STRING
1266 {
1267         gchar *destination = NULL;
1268         gint action_type = 0;
1269         gint account_id = 0;
1270
1271         action_type = MATCHACTION_FORWARD;
1272         account_id = strtol($2, NULL, 10);
1273         destination = $3;
1274         action = filteringaction_new(action_type,
1275             account_id, destination, 0, 0, NULL);
1276 }
1277 | MATCHER_FORWARD_AS_ATTACHMENT MATCHER_INTEGER MATCHER_STRING
1278 {
1279         gchar *destination = NULL;
1280         gint action_type = 0;
1281         gint account_id = 0;
1282
1283         action_type = MATCHACTION_FORWARD_AS_ATTACHMENT;
1284         account_id = strtol($2, NULL, 10);
1285         destination = $3;
1286         action = filteringaction_new(action_type,
1287             account_id, destination, 0, 0, NULL);
1288 }
1289 | MATCHER_REDIRECT MATCHER_INTEGER MATCHER_STRING
1290 {
1291         gchar *destination = NULL;
1292         gint action_type = 0;
1293         gint account_id = 0;
1294
1295         action_type = MATCHACTION_REDIRECT;
1296         account_id = strtol($2, NULL, 10);
1297         destination = $3;
1298         action = filteringaction_new(action_type,
1299             account_id, destination, 0, 0, NULL);
1300 }
1301 | MATCHER_COLOR MATCHER_INTEGER
1302 {
1303         gint action_type = 0;
1304         gint color = 0;
1305
1306         action_type = MATCHACTION_COLOR;
1307         color = strtol($2, NULL, 10);
1308         action = filteringaction_new(action_type, 0, NULL, color, 0, NULL);
1309 }
1310 | MATCHER_CHANGE_SCORE MATCHER_INTEGER
1311 {
1312         gint score = 0;
1313         
1314         score = strtol($2, NULL, 10);
1315         action = filteringaction_new(MATCHACTION_CHANGE_SCORE, 0,
1316                                      NULL, 0, score, NULL);
1317 }
1318 /* backward compatibility */
1319 | MATCHER_SCORE MATCHER_INTEGER
1320 {
1321         gint score = 0;
1322         
1323         score = strtol($2, NULL, 10);
1324         action = filteringaction_new(MATCHACTION_CHANGE_SCORE, 0,
1325                                      NULL, 0, score, NULL);
1326 }
1327 | MATCHER_SET_SCORE MATCHER_INTEGER
1328 {
1329         gint score = 0;
1330         
1331         score = strtol($2, NULL, 10);
1332         action = filteringaction_new(MATCHACTION_SET_SCORE, 0,
1333                                      NULL, 0, score, NULL);
1334 }
1335 | MATCHER_HIDE
1336 {
1337         action = filteringaction_new(MATCHACTION_HIDE, 0, NULL, 0, 0, NULL);
1338 }
1339 | MATCHER_IGNORE
1340 {
1341         action = filteringaction_new(MATCHACTION_IGNORE, 0, NULL, 0, 0, NULL);
1342 }
1343 | MATCHER_ADD_TO_ADDRESSBOOK MATCHER_STRING
1344 {
1345         header = g_strdup($2);
1346 } MATCHER_STRING
1347 {
1348         gchar *addressbook = NULL;
1349         gint action_type = 0;
1350
1351         action_type = MATCHACTION_ADD_TO_ADDRESSBOOK;
1352         addressbook = $2;
1353         action = filteringaction_new(action_type, 0, addressbook, 0, 0, header);
1354         g_free(header);
1355 }
1356 | MATCHER_STOP
1357 {
1358         action = filteringaction_new(MATCHACTION_STOP, 0, NULL, 0, 0, NULL);
1359 }
1360 ;