2007-02-20 [colin] 2.7.2cvs56
[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 "procmsg.h"
32
33 #define MAX_COLORLABELS (MSG_CLABEL_7 - MSG_CLABEL_NONE)
34
35 static gint error = 0;
36 static gint bool_op = 0;
37 static gint match_type = 0;
38 static gchar *header = NULL;
39
40 static MatcherProp *prop;
41
42 static GSList *matchers_list = NULL;
43
44 static gboolean enabled = TRUE;
45 static gchar *name = NULL;
46 static gint account_id = 0;
47 static MatcherList *cond;
48 static GSList *action_list = NULL;
49 static FilteringAction *action = NULL;
50 static gboolean matcher_is_fast = TRUE;
51
52 static FilteringProp *filtering;
53
54 static GSList **prefs_filtering = NULL;
55 static int enable_compatibility = 0;
56
57 enum {
58         MATCHER_PARSE_FILE,
59         MATCHER_PARSE_NO_EOL,
60         MATCHER_PARSE_ENABLED,
61         MATCHER_PARSE_NAME,
62         MATCHER_PARSE_ACCOUNT,
63         MATCHER_PARSE_CONDITION,
64         MATCHER_PARSE_FILTERING_ACTION,
65 };
66
67 static int matcher_parse_op = MATCHER_PARSE_FILE;
68
69
70 /* ******************************************************************** */
71 /* redeclarations to avoid warnings */
72 void matcher_parserrestart(FILE *input_file);
73 void matcher_parser_init(void);
74 void matcher_parser_switch_to_buffer(void * new_buffer);
75 void matcher_parser_delete_buffer(void * b);
76 void matcher_parserpop_buffer_state(void);
77 int matcher_parserlex(void);
78
79 void matcher_parser_start_parsing(FILE *f)
80 {
81         matcher_parserlineno = 1;
82         matcher_parserrestart(f);
83         account_id = 0;
84         matcher_parserparse();
85 }
86
87  
88 void * matcher_parser_scan_string(const char * str);
89  
90 FilteringProp *matcher_parser_get_filtering(gchar *str)
91 {
92         void *bufstate;
93         void *tmp_str = NULL;
94         
95         /* little hack to allow passing rules with no names */
96         if (!strncmp(str, "rulename ", 9))
97                 tmp_str = g_strdup(str);
98         else 
99                 tmp_str = g_strconcat("rulename \"\" ", str, NULL);
100
101         /* bad coding to enable the sub-grammar matching
102            in yacc */
103         matcher_parserlineno = 1;
104         matcher_parse_op = MATCHER_PARSE_NO_EOL;
105         matcher_parserrestart(NULL);
106         matcher_parserpop_buffer_state();
107         matcher_parser_init();
108         bufstate = matcher_parser_scan_string((const char *) tmp_str);
109         matcher_parser_switch_to_buffer(bufstate);
110         if (matcher_parserparse() != 0)
111                 filtering = NULL;
112         matcher_parse_op = MATCHER_PARSE_FILE;
113         matcher_parser_delete_buffer(bufstate);
114         g_free(tmp_str);
115         return filtering;
116 }
117
118 static gboolean check_quote_symetry(gchar *str)
119 {
120         const gchar *walk;
121         int ret = 0;
122         
123         if (str == NULL)
124                 return TRUE; /* heh, that's symetric */
125         if (*str == '\0')
126                 return TRUE;
127         for (walk = str; *walk; walk++) {
128                 if (*walk == '\"') {
129                         if (walk == str         /* first char */
130                         || *(walk - 1) != '\\') /* not escaped */
131                                 ret ++;
132                 }
133         }
134         return !(ret % 2);
135 }
136
137 MatcherList *matcher_parser_get_name(gchar *str)
138 {
139         void *bufstate;
140
141         if (!check_quote_symetry(str)) {
142                 cond = NULL;
143                 return cond;
144         }
145         
146         /* bad coding to enable the sub-grammar matching
147            in yacc */
148         matcher_parserlineno = 1;
149         matcher_parse_op = MATCHER_PARSE_NAME;
150         matcher_parserrestart(NULL);
151         matcher_parserpop_buffer_state();
152         matcher_parser_init();
153         bufstate = matcher_parser_scan_string(str);
154         matcher_parserparse();
155         matcher_parse_op = MATCHER_PARSE_FILE;
156         matcher_parser_delete_buffer(bufstate);
157         return cond;
158 }
159
160 MatcherList *matcher_parser_get_enabled(gchar *str)
161 {
162         void *bufstate;
163
164         if (!check_quote_symetry(str)) {
165                 cond = NULL;
166                 return cond;
167         }
168         
169         /* bad coding to enable the sub-grammar matching
170            in yacc */
171         matcher_parserlineno = 1;
172         matcher_parse_op = MATCHER_PARSE_ENABLED;
173         matcher_parserrestart(NULL);
174         matcher_parserpop_buffer_state();
175         matcher_parser_init();
176         bufstate = matcher_parser_scan_string(str);
177         matcher_parserparse();
178         matcher_parse_op = MATCHER_PARSE_FILE;
179         matcher_parser_delete_buffer(bufstate);
180         return cond;
181 }
182
183 MatcherList *matcher_parser_get_account(gchar *str)
184 {
185         void *bufstate;
186
187         if (!check_quote_symetry(str)) {
188                 cond = NULL;
189                 return cond;
190         }
191         
192         /* bad coding to enable the sub-grammar matching
193            in yacc */
194         matcher_parserlineno = 1;
195         matcher_parse_op = MATCHER_PARSE_ACCOUNT;
196         matcher_parserrestart(NULL);
197         matcher_parserpop_buffer_state();
198         matcher_parser_init();
199         bufstate = matcher_parser_scan_string(str);
200         matcher_parserparse();
201         matcher_parse_op = MATCHER_PARSE_FILE;
202         matcher_parser_delete_buffer(bufstate);
203         return cond;
204 }
205
206 MatcherList *matcher_parser_get_cond(gchar *str, gboolean *is_fast)
207 {
208         void *bufstate;
209
210         if (!check_quote_symetry(str)) {
211                 cond = NULL;
212                 return cond;
213         }
214         
215         matcher_is_fast = TRUE;
216         /* bad coding to enable the sub-grammar matching
217            in yacc */
218         matcher_parserlineno = 1;
219         matcher_parse_op = MATCHER_PARSE_CONDITION;
220         matcher_parserrestart(NULL);
221         matcher_parserpop_buffer_state();
222         matcher_parser_init();
223         bufstate = matcher_parser_scan_string(str);
224         matcher_parserparse();
225         matcher_parse_op = MATCHER_PARSE_FILE;
226         matcher_parser_delete_buffer(bufstate);
227         if (is_fast)
228                 *is_fast = matcher_is_fast;
229         return cond;
230 }
231
232 GSList *matcher_parser_get_action_list(gchar *str)
233 {
234         void *bufstate;
235
236         if (!check_quote_symetry(str)) {
237                 action_list = NULL;
238                 return action_list;
239         }
240         
241         /* bad coding to enable the sub-grammar matching
242            in yacc */
243         matcher_parserlineno = 1;
244         matcher_parse_op = MATCHER_PARSE_FILTERING_ACTION;
245         matcher_parserrestart(NULL);
246         matcher_parserpop_buffer_state();
247         matcher_parser_init();
248         bufstate = matcher_parser_scan_string(str);
249         matcher_parserparse();
250         matcher_parse_op = MATCHER_PARSE_FILE;
251         matcher_parser_delete_buffer(bufstate);
252         return action_list;
253 }
254
255 MatcherProp *matcher_parser_get_prop(gchar *str)
256 {
257         MatcherList *list;
258         MatcherProp *prop;
259
260         matcher_parserlineno = 1;
261         list = matcher_parser_get_cond(str, NULL);
262         if (list == NULL)
263                 return NULL;
264
265         if (list->matchers == NULL)
266                 return NULL;
267
268         if (list->matchers->next != NULL)
269                 return NULL;
270
271         prop = list->matchers->data;
272
273         g_slist_free(list->matchers);
274         g_free(list);
275
276         return prop;
277 }
278
279 void matcher_parsererror(char *str)
280 {
281         GSList *l;
282
283         if (matchers_list) {
284                 for (l = matchers_list; l != NULL; l = g_slist_next(l)) {
285                         matcherprop_free((MatcherProp *)
286                                          l->data);
287                         l->data = NULL;
288                 }
289                 g_slist_free(matchers_list);
290                 matchers_list = NULL;
291         }
292         cond = NULL;
293         g_warning("filtering parsing: %i: %s\n",
294                   matcher_parserlineno, str);
295         error = 1;
296 }
297
298 int matcher_parserwrap(void)
299 {
300         return 1;
301 }
302 %}
303
304 %union {
305         char *str;
306         int value;
307 }
308 %token MATCHER_ALL MATCHER_UNREAD  MATCHER_NOT_UNREAD 
309 %token MATCHER_NEW  MATCHER_NOT_NEW  MATCHER_MARKED
310 %token MATCHER_NOT_MARKED  MATCHER_DELETED  MATCHER_NOT_DELETED
311 %token MATCHER_REPLIED  MATCHER_NOT_REPLIED  MATCHER_FORWARDED
312 %token MATCHER_NOT_FORWARDED  MATCHER_SUBJECT  MATCHER_NOT_SUBJECT
313 %token MATCHER_FROM  MATCHER_NOT_FROM  MATCHER_TO  MATCHER_NOT_TO
314 %token MATCHER_CC  MATCHER_NOT_CC  MATCHER_TO_OR_CC  MATCHER_NOT_TO_AND_NOT_CC
315 %token MATCHER_AGE_GREATER  MATCHER_AGE_LOWER  MATCHER_NEWSGROUPS
316 %token MATCHER_NOT_NEWSGROUPS  MATCHER_INREPLYTO  MATCHER_NOT_INREPLYTO
317 %token MATCHER_REFERENCES  MATCHER_NOT_REFERENCES  MATCHER_SCORE_GREATER
318 %token MATCHER_SCORE_LOWER  MATCHER_HEADER  MATCHER_NOT_HEADER
319 %token MATCHER_HEADERS_PART  MATCHER_NOT_HEADERS_PART  MATCHER_MESSAGE
320 %token MATCHER_NOT_MESSAGE  MATCHER_BODY_PART  MATCHER_NOT_BODY_PART
321 %token MATCHER_TEST  MATCHER_NOT_TEST  MATCHER_MATCHCASE  MATCHER_MATCH
322 %token MATCHER_REGEXPCASE  MATCHER_REGEXP  MATCHER_SCORE  MATCHER_MOVE
323 %token MATCHER_FOUND_IN_ADDRESSBOOK MATCHER_NOT_FOUND_IN_ADDRESSBOOK MATCHER_IN
324 %token MATCHER_COPY  MATCHER_DELETE  MATCHER_MARK  MATCHER_UNMARK
325 %token MATCHER_LOCK MATCHER_UNLOCK
326 %token MATCHER_EXECUTE
327 %token MATCHER_MARK_AS_READ  MATCHER_MARK_AS_UNREAD  MATCHER_FORWARD
328 %token MATCHER_FORWARD_AS_ATTACHMENT  MATCHER_EOL
329 %token MATCHER_OR MATCHER_AND  
330 %token MATCHER_COLOR MATCHER_SCORE_EQUAL MATCHER_REDIRECT 
331 %token MATCHER_SIZE_GREATER MATCHER_SIZE_SMALLER MATCHER_SIZE_EQUAL
332 %token MATCHER_LOCKED MATCHER_NOT_LOCKED
333 %token MATCHER_PARTIAL MATCHER_NOT_PARTIAL
334 %token MATCHER_COLORLABEL MATCHER_NOT_COLORLABEL
335 %token MATCHER_IGNORE_THREAD MATCHER_NOT_IGNORE_THREAD
336 %token MATCHER_CHANGE_SCORE MATCHER_SET_SCORE
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 > MAX_COLORLABELS) value = MAX_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 > MAX_COLORLABELS) value = MAX_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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
1176 }
1177 | MATCHER_FORWARD MATCHER_INTEGER MATCHER_STRING
1178 {
1179         gchar *destination = NULL;
1180         gint action_type = 0;
1181         gint account_id = 0;
1182
1183         action_type = MATCHACTION_FORWARD;
1184         account_id = strtol($2, NULL, 10);
1185         destination = $3;
1186         action = filteringaction_new(action_type,
1187             account_id, destination, 0, 0);
1188 }
1189 | MATCHER_FORWARD_AS_ATTACHMENT MATCHER_INTEGER MATCHER_STRING
1190 {
1191         gchar *destination = NULL;
1192         gint action_type = 0;
1193         gint account_id = 0;
1194
1195         action_type = MATCHACTION_FORWARD_AS_ATTACHMENT;
1196         account_id = strtol($2, NULL, 10);
1197         destination = $3;
1198         action = filteringaction_new(action_type,
1199             account_id, destination, 0, 0);
1200 }
1201 | MATCHER_REDIRECT MATCHER_INTEGER MATCHER_STRING
1202 {
1203         gchar *destination = NULL;
1204         gint action_type = 0;
1205         gint account_id = 0;
1206
1207         action_type = MATCHACTION_REDIRECT;
1208         account_id = strtol($2, NULL, 10);
1209         destination = $3;
1210         action = filteringaction_new(action_type,
1211             account_id, destination, 0, 0);
1212 }
1213 | MATCHER_COLOR MATCHER_INTEGER
1214 {
1215         gint action_type = 0;
1216         gint color = 0;
1217
1218         action_type = MATCHACTION_COLOR;
1219         color = strtol($2, NULL, 10);
1220         action = filteringaction_new(action_type, 0, NULL, color, 0);
1221 }
1222 | MATCHER_CHANGE_SCORE MATCHER_INTEGER
1223 {
1224         gint score = 0;
1225         
1226         score = strtol($2, NULL, 10);
1227         action = filteringaction_new(MATCHACTION_CHANGE_SCORE, 0,
1228                                      NULL, 0, score);
1229 }
1230 /* backward compatibility */
1231 | MATCHER_SCORE MATCHER_INTEGER
1232 {
1233         gint score = 0;
1234         
1235         score = strtol($2, NULL, 10);
1236         action = filteringaction_new(MATCHACTION_CHANGE_SCORE, 0,
1237                                      NULL, 0, score);
1238 }
1239 | MATCHER_SET_SCORE MATCHER_INTEGER
1240 {
1241         gint score = 0;
1242         
1243         score = strtol($2, NULL, 10);
1244         action = filteringaction_new(MATCHACTION_SET_SCORE, 0,
1245                                      NULL, 0, score);
1246 }
1247 | MATCHER_HIDE
1248 {
1249         action = filteringaction_new(MATCHACTION_HIDE, 0, NULL, 0, 0);
1250 }
1251 | MATCHER_IGNORE
1252 {
1253         action = filteringaction_new(MATCHACTION_IGNORE, 0, NULL, 0, 0);
1254 }
1255 | MATCHER_STOP
1256 {
1257         action = filteringaction_new(MATCHACTION_STOP, 0, NULL, 0, 0);
1258 }
1259 ;