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