2007-02-20 [wwp] 2.7.2cvs55
[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 int matcher_parserlex(void);
77
78 void matcher_parser_start_parsing(FILE *f)
79 {
80         matcher_parserlineno = 1;
81         matcher_parserrestart(f);
82         account_id = 0;
83         matcher_parserparse();
84 }
85
86  
87 void * matcher_parser_scan_string(const char * str);
88  
89 FilteringProp *matcher_parser_get_filtering(gchar *str)
90 {
91         void *bufstate;
92         void *tmp_str = NULL;
93         
94         /* little hack to allow passing rules with no names */
95         if (!strncmp(str, "rulename ", 9))
96                 tmp_str = g_strdup(str);
97         else 
98                 tmp_str = g_strconcat("rulename \"\" ", str, NULL);
99
100         /* bad coding to enable the sub-grammar matching
101            in yacc */
102         matcher_parserlineno = 1;
103         matcher_parse_op = MATCHER_PARSE_NO_EOL;
104         matcher_parserrestart(NULL);
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_parser_init();
150         bufstate = matcher_parser_scan_string(str);
151         matcher_parserparse();
152         matcher_parse_op = MATCHER_PARSE_FILE;
153         matcher_parser_delete_buffer(bufstate);
154         return cond;
155 }
156
157 MatcherList *matcher_parser_get_enabled(gchar *str)
158 {
159         void *bufstate;
160
161         if (!check_quote_symetry(str)) {
162                 cond = NULL;
163                 return cond;
164         }
165         
166         /* bad coding to enable the sub-grammar matching
167            in yacc */
168         matcher_parserlineno = 1;
169         matcher_parse_op = MATCHER_PARSE_ENABLED;
170         matcher_parserrestart(NULL);
171         matcher_parser_init();
172         bufstate = matcher_parser_scan_string(str);
173         matcher_parserparse();
174         matcher_parse_op = MATCHER_PARSE_FILE;
175         matcher_parser_delete_buffer(bufstate);
176         return cond;
177 }
178
179 MatcherList *matcher_parser_get_account(gchar *str)
180 {
181         void *bufstate;
182
183         if (!check_quote_symetry(str)) {
184                 cond = NULL;
185                 return cond;
186         }
187         
188         /* bad coding to enable the sub-grammar matching
189            in yacc */
190         matcher_parserlineno = 1;
191         matcher_parse_op = MATCHER_PARSE_ACCOUNT;
192         matcher_parserrestart(NULL);
193         matcher_parser_init();
194         bufstate = matcher_parser_scan_string(str);
195         matcher_parserparse();
196         matcher_parse_op = MATCHER_PARSE_FILE;
197         matcher_parser_delete_buffer(bufstate);
198         return cond;
199 }
200
201 MatcherList *matcher_parser_get_cond(gchar *str, gboolean *is_fast)
202 {
203         void *bufstate;
204
205         if (!check_quote_symetry(str)) {
206                 cond = NULL;
207                 return cond;
208         }
209         
210         matcher_is_fast = TRUE;
211         /* bad coding to enable the sub-grammar matching
212            in yacc */
213         matcher_parserlineno = 1;
214         matcher_parse_op = MATCHER_PARSE_CONDITION;
215         matcher_parserrestart(NULL);
216         matcher_parser_init();
217         bufstate = matcher_parser_scan_string(str);
218         matcher_parserparse();
219         matcher_parse_op = MATCHER_PARSE_FILE;
220         matcher_parser_delete_buffer(bufstate);
221         if (is_fast)
222                 *is_fast = matcher_is_fast;
223         return cond;
224 }
225
226 GSList *matcher_parser_get_action_list(gchar *str)
227 {
228         void *bufstate;
229
230         if (!check_quote_symetry(str)) {
231                 action_list = NULL;
232                 return action_list;
233         }
234         
235         /* bad coding to enable the sub-grammar matching
236            in yacc */
237         matcher_parserlineno = 1;
238         matcher_parse_op = MATCHER_PARSE_FILTERING_ACTION;
239         matcher_parserrestart(NULL);
240         matcher_parser_init();
241         bufstate = matcher_parser_scan_string(str);
242         matcher_parserparse();
243         matcher_parse_op = MATCHER_PARSE_FILE;
244         matcher_parser_delete_buffer(bufstate);
245         return action_list;
246 }
247
248 MatcherProp *matcher_parser_get_prop(gchar *str)
249 {
250         MatcherList *list;
251         MatcherProp *prop;
252
253         matcher_parserlineno = 1;
254         list = matcher_parser_get_cond(str, NULL);
255         if (list == NULL)
256                 return NULL;
257
258         if (list->matchers == NULL)
259                 return NULL;
260
261         if (list->matchers->next != NULL)
262                 return NULL;
263
264         prop = list->matchers->data;
265
266         g_slist_free(list->matchers);
267         g_free(list);
268
269         return prop;
270 }
271
272 void matcher_parsererror(char *str)
273 {
274         GSList *l;
275
276         if (matchers_list) {
277                 for (l = matchers_list; l != NULL; l = g_slist_next(l)) {
278                         matcherprop_free((MatcherProp *)
279                                          l->data);
280                         l->data = NULL;
281                 }
282                 g_slist_free(matchers_list);
283                 matchers_list = NULL;
284         }
285         cond = NULL;
286         g_warning("filtering parsing: %i: %s\n",
287                   matcher_parserlineno, str);
288         error = 1;
289 }
290
291 int matcher_parserwrap(void)
292 {
293         return 1;
294 }
295 %}
296
297 %union {
298         char *str;
299         int value;
300 }
301 %token MATCHER_ALL MATCHER_UNREAD  MATCHER_NOT_UNREAD 
302 %token MATCHER_NEW  MATCHER_NOT_NEW  MATCHER_MARKED
303 %token MATCHER_NOT_MARKED  MATCHER_DELETED  MATCHER_NOT_DELETED
304 %token MATCHER_REPLIED  MATCHER_NOT_REPLIED  MATCHER_FORWARDED
305 %token MATCHER_NOT_FORWARDED  MATCHER_SUBJECT  MATCHER_NOT_SUBJECT
306 %token MATCHER_FROM  MATCHER_NOT_FROM  MATCHER_TO  MATCHER_NOT_TO
307 %token MATCHER_CC  MATCHER_NOT_CC  MATCHER_TO_OR_CC  MATCHER_NOT_TO_AND_NOT_CC
308 %token MATCHER_AGE_GREATER  MATCHER_AGE_LOWER  MATCHER_NEWSGROUPS
309 %token MATCHER_NOT_NEWSGROUPS  MATCHER_INREPLYTO  MATCHER_NOT_INREPLYTO
310 %token MATCHER_REFERENCES  MATCHER_NOT_REFERENCES  MATCHER_SCORE_GREATER
311 %token MATCHER_SCORE_LOWER  MATCHER_HEADER  MATCHER_NOT_HEADER
312 %token MATCHER_HEADERS_PART  MATCHER_NOT_HEADERS_PART  MATCHER_MESSAGE
313 %token MATCHER_NOT_MESSAGE  MATCHER_BODY_PART  MATCHER_NOT_BODY_PART
314 %token MATCHER_TEST  MATCHER_NOT_TEST  MATCHER_MATCHCASE  MATCHER_MATCH
315 %token MATCHER_REGEXPCASE  MATCHER_REGEXP  MATCHER_SCORE  MATCHER_MOVE
316 %token MATCHER_FOUND_IN_ADDRESSBOOK MATCHER_NOT_FOUND_IN_ADDRESSBOOK MATCHER_IN
317 %token MATCHER_COPY  MATCHER_DELETE  MATCHER_MARK  MATCHER_UNMARK
318 %token MATCHER_LOCK MATCHER_UNLOCK
319 %token MATCHER_EXECUTE
320 %token MATCHER_MARK_AS_READ  MATCHER_MARK_AS_UNREAD  MATCHER_FORWARD
321 %token MATCHER_FORWARD_AS_ATTACHMENT  MATCHER_EOL
322 %token MATCHER_OR MATCHER_AND  
323 %token MATCHER_COLOR MATCHER_SCORE_EQUAL MATCHER_REDIRECT 
324 %token MATCHER_SIZE_GREATER MATCHER_SIZE_SMALLER MATCHER_SIZE_EQUAL
325 %token MATCHER_LOCKED MATCHER_NOT_LOCKED
326 %token MATCHER_PARTIAL MATCHER_NOT_PARTIAL
327 %token MATCHER_COLORLABEL MATCHER_NOT_COLORLABEL
328 %token MATCHER_IGNORE_THREAD MATCHER_NOT_IGNORE_THREAD
329 %token MATCHER_CHANGE_SCORE MATCHER_SET_SCORE
330 %token MATCHER_STOP MATCHER_HIDE MATCHER_IGNORE
331 %token MATCHER_SPAM MATCHER_NOT_SPAM
332
333 %start file
334
335 %token MATCHER_ENABLED MATCHER_DISABLED
336 %token MATCHER_RULENAME
337 %token MATCHER_ACCOUNT
338 %token <str> MATCHER_STRING
339 %token <str> MATCHER_SECTION
340 %token <str> MATCHER_INTEGER
341
342 %%
343
344 file:
345 {
346         if (matcher_parse_op == MATCHER_PARSE_FILE) {
347                 prefs_filtering = &pre_global_processing;
348         }
349 }
350 file_line_list;
351
352 file_line_list:
353 file_line
354 file_line_list
355 | file_line
356 ;
357
358 file_line:
359 section_notification
360
361 { action_list = NULL; }
362 instruction
363 | error MATCHER_EOL
364 {
365         yyerrok;
366 };
367
368 section_notification:
369 MATCHER_SECTION MATCHER_EOL
370 {
371         gchar *folder = $1;
372         FolderItem *item = NULL;
373
374         if (matcher_parse_op == MATCHER_PARSE_FILE) {
375                 enable_compatibility = 0;
376                 if (!strcmp(folder, "global")) {
377                         /* backward compatibility */
378                         enable_compatibility = 1;
379                 }
380                 else if (!strcmp(folder, "preglobal")) {
381                         prefs_filtering = &pre_global_processing;
382                 }
383                 else if (!strcmp(folder, "postglobal")) {
384                         prefs_filtering = &post_global_processing;
385                 }
386                 else if (!strcmp(folder, "filtering")) {
387                         prefs_filtering = &filtering_rules;
388                 }
389                 else {
390                         item = folder_find_item_from_identifier(folder);
391                         if (item != NULL) {
392                                 prefs_filtering = &item->prefs->processing;
393                         } else {
394                                 prefs_filtering = NULL;
395                         }
396                 }
397         }
398 }
399 ;
400
401 instruction:
402 enabled name account condition filtering MATCHER_EOL
403 | enabled name account condition filtering
404 | enabled name condition filtering MATCHER_EOL
405 | enabled name condition filtering
406 | name condition filtering MATCHER_EOL
407 | name condition filtering
408 {
409         if (matcher_parse_op == MATCHER_PARSE_NO_EOL)
410                 YYACCEPT;
411         else {
412                 matcher_parsererror("parse error [no eol]");
413                 YYERROR;
414         }
415 }
416 | enabled
417 {
418         if (matcher_parse_op == MATCHER_PARSE_ENABLED)
419                 YYACCEPT;
420         else {
421                 matcher_parsererror("parse error [enabled]");
422                 YYERROR;
423         }
424 }
425 | account
426 {
427         if (matcher_parse_op == MATCHER_PARSE_ACCOUNT)
428                 YYACCEPT;
429         else {
430                 matcher_parsererror("parse error [account]");
431                 YYERROR;
432         }
433 }
434 | name
435 {
436         if (matcher_parse_op == MATCHER_PARSE_NAME)
437                 YYACCEPT;
438         else {
439                 matcher_parsererror("parse error [name]");
440                 YYERROR;
441         }
442 }
443 | condition
444 {
445         if (matcher_parse_op == MATCHER_PARSE_CONDITION)
446                 YYACCEPT;
447         else {
448                 matcher_parsererror("parse error [condition]");
449                 YYERROR;
450         }
451 }
452 | filtering_action_list
453 {
454         if (matcher_parse_op == MATCHER_PARSE_FILTERING_ACTION)
455                 YYACCEPT;
456         else {
457                 matcher_parsererror("parse error [filtering action]");
458                 YYERROR;
459         }
460 }
461 | MATCHER_EOL
462 ;
463
464 enabled:
465 MATCHER_ENABLED
466 {
467         enabled = TRUE;
468 }
469 | MATCHER_DISABLED
470 {
471         enabled = FALSE;
472 }
473 ;
474
475 name:
476 MATCHER_RULENAME MATCHER_STRING
477 {
478         name = g_strdup($2);
479 }
480 ;
481
482 account:
483 MATCHER_ACCOUNT MATCHER_INTEGER
484 {
485         account_id = strtol($2, NULL, 10);
486 }
487 ;
488
489 filtering:
490 filtering_action_list
491 {
492         filtering = filteringprop_new(enabled, name, account_id, cond, action_list);
493         enabled = TRUE;
494         account_id = 0;
495         g_free(name);
496         name = NULL;
497         if (enable_compatibility) {
498                 prefs_filtering = &filtering_rules;
499                 if (action_list != NULL) {
500                         FilteringAction * first_action;
501                         
502                         first_action = action_list->data;
503                         
504                         if (first_action->type == MATCHACTION_CHANGE_SCORE)
505                                 prefs_filtering = &pre_global_processing;
506                 }
507         }
508         
509         cond = NULL;
510         action_list = NULL;
511         
512         if ((matcher_parse_op == MATCHER_PARSE_FILE) &&
513             (prefs_filtering != NULL)) {
514                 *prefs_filtering = g_slist_append(*prefs_filtering,
515                                                   filtering);
516                 filtering = NULL;
517         }
518 }
519 ;
520
521 filtering_action_list:
522 filtering_action_b filtering_action_list
523 | filtering_action_b
524 ;
525
526 filtering_action_b:
527 filtering_action
528 {
529         action_list = g_slist_append(action_list, action);
530         action = NULL;
531 }
532 ;
533
534 match_type:
535 MATCHER_MATCHCASE
536 {
537         match_type = MATCHTYPE_MATCHCASE;
538 }
539 | MATCHER_MATCH
540 {
541         match_type = MATCHTYPE_MATCH;
542 }
543 | MATCHER_REGEXPCASE
544 {
545         match_type = MATCHTYPE_REGEXPCASE;
546 }
547 | MATCHER_REGEXP
548 {
549         match_type = MATCHTYPE_REGEXP;
550 }
551 ;
552
553 condition:
554 condition_list
555 {
556         cond = matcherlist_new(matchers_list, (bool_op == MATCHERBOOL_AND));
557         matchers_list = NULL;
558 }
559 ;
560
561 condition_list:
562 condition_list bool_op one_condition
563 {
564         matchers_list = g_slist_append(matchers_list, prop);
565 }
566 | one_condition
567 {
568         matchers_list = NULL;
569         matchers_list = g_slist_append(matchers_list, prop);
570 }
571 ;
572
573 bool_op:
574 MATCHER_AND
575 {
576         bool_op = MATCHERBOOL_AND;
577 }
578 | MATCHER_OR
579 {
580         bool_op = MATCHERBOOL_OR;
581 }
582 ;
583
584 one_condition:
585 MATCHER_ALL
586 {
587         gint criteria = 0;
588
589         criteria = MATCHCRITERIA_ALL;
590         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
591 }
592 | MATCHER_UNREAD
593 {
594         gint criteria = 0;
595
596         criteria = MATCHCRITERIA_UNREAD;
597         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
598 }
599 | MATCHER_NOT_UNREAD 
600 {
601         gint criteria = 0;
602
603         criteria = MATCHCRITERIA_NOT_UNREAD;
604         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
605 }
606 | MATCHER_NEW
607 {
608         gint criteria = 0;
609
610         criteria = MATCHCRITERIA_NEW;
611         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
612 }
613 | MATCHER_NOT_NEW
614 {
615         gint criteria = 0;
616
617         criteria = MATCHCRITERIA_NOT_NEW;
618         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
619 }
620 | MATCHER_MARKED
621 {
622         gint criteria = 0;
623
624         criteria = MATCHCRITERIA_MARKED;
625         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
626 }
627 | MATCHER_NOT_MARKED
628 {
629         gint criteria = 0;
630
631         criteria = MATCHCRITERIA_NOT_MARKED;
632         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
633 }
634 | MATCHER_DELETED
635 {
636         gint criteria = 0;
637
638         criteria = MATCHCRITERIA_DELETED;
639         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
640 }
641 | MATCHER_NOT_DELETED
642 {
643         gint criteria = 0;
644
645         criteria = MATCHCRITERIA_NOT_DELETED;
646         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
647 }
648 | MATCHER_REPLIED
649 {
650         gint criteria = 0;
651
652         criteria = MATCHCRITERIA_REPLIED;
653         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
654 }
655 | MATCHER_NOT_REPLIED
656 {
657         gint criteria = 0;
658
659         criteria = MATCHCRITERIA_NOT_REPLIED;
660         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
661 }
662 | MATCHER_FORWARDED
663 {
664         gint criteria = 0;
665
666         criteria = MATCHCRITERIA_FORWARDED;
667         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
668 }
669 | MATCHER_NOT_FORWARDED
670 {
671         gint criteria = 0;
672
673         criteria = MATCHCRITERIA_NOT_FORWARDED;
674         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
675 }
676 | MATCHER_LOCKED
677 {
678         gint criteria = 0;
679
680         criteria = MATCHCRITERIA_LOCKED;
681         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
682 }
683 | MATCHER_NOT_LOCKED
684 {
685         gint criteria = 0;
686
687         criteria = MATCHCRITERIA_NOT_LOCKED;
688         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
689 }
690 | MATCHER_SPAM
691 {
692         gint criteria = 0;
693
694         criteria = MATCHCRITERIA_SPAM;
695         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
696 }
697 | MATCHER_NOT_SPAM 
698 {
699         gint criteria = 0;
700
701         criteria = MATCHCRITERIA_NOT_SPAM;
702         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
703 }
704 | MATCHER_PARTIAL
705 {
706         gint criteria = 0;
707
708         criteria = MATCHCRITERIA_PARTIAL;
709         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
710 }
711 | MATCHER_NOT_PARTIAL
712 {
713         gint criteria = 0;
714
715         criteria = MATCHCRITERIA_NOT_PARTIAL;
716         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
717 }
718 | MATCHER_COLORLABEL MATCHER_INTEGER
719 {
720         gint criteria = 0;
721         gint value = 0;
722
723         criteria = MATCHCRITERIA_COLORLABEL;
724         value = strtol($2, NULL, 10);
725         if (value < 0) value = 0;
726         else if (value > MAX_COLORLABELS) value = MAX_COLORLABELS;
727         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
728 }
729 | MATCHER_NOT_COLORLABEL MATCHER_INTEGER
730 {
731         gint criteria = 0;
732         gint value = 0;
733
734         criteria = MATCHCRITERIA_NOT_COLORLABEL;
735         value = strtol($2, NULL, 0);
736         if (value < 0) value = 0;
737         else if (value > MAX_COLORLABELS) value = MAX_COLORLABELS;
738         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
739 }
740 | MATCHER_IGNORE_THREAD
741 {
742         gint criteria = 0;
743
744         criteria = MATCHCRITERIA_IGNORE_THREAD;
745         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
746 }
747 | MATCHER_NOT_IGNORE_THREAD
748 {
749         gint criteria = 0;
750
751         criteria = MATCHCRITERIA_NOT_IGNORE_THREAD;
752         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
753 }
754 | MATCHER_SUBJECT match_type MATCHER_STRING
755 {
756         gint criteria = 0;
757         gchar *expr = NULL;
758
759         criteria = MATCHCRITERIA_SUBJECT;
760         expr = $3;
761         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
762 }
763 | MATCHER_NOT_SUBJECT match_type MATCHER_STRING
764 {
765         gint criteria = 0;
766         gchar *expr = NULL;
767
768         criteria = MATCHCRITERIA_NOT_SUBJECT;
769         expr = $3;
770         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
771 }
772 | MATCHER_FROM match_type MATCHER_STRING
773 {
774         gint criteria = 0;
775         gchar *expr = NULL;
776
777         criteria = MATCHCRITERIA_FROM;
778         expr = $3;
779         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
780 }
781 | MATCHER_NOT_FROM match_type MATCHER_STRING
782 {
783         gint criteria = 0;
784         gchar *expr = NULL;
785
786         criteria = MATCHCRITERIA_NOT_FROM;
787         expr = $3;
788         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
789 }
790 | MATCHER_TO match_type MATCHER_STRING
791 {
792         gint criteria = 0;
793         gchar *expr = NULL;
794
795         criteria = MATCHCRITERIA_TO;
796         expr = $3;
797         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
798 }
799 | MATCHER_NOT_TO match_type MATCHER_STRING
800 {
801         gint criteria = 0;
802         gchar *expr = NULL;
803
804         criteria = MATCHCRITERIA_NOT_TO;
805         expr = $3;
806         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
807 }
808 | MATCHER_CC match_type MATCHER_STRING
809 {
810         gint criteria = 0;
811         gchar *expr = NULL;
812
813         criteria = MATCHCRITERIA_CC;
814         expr = $3;
815         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
816 }
817 | MATCHER_NOT_CC match_type MATCHER_STRING
818 {
819         gint criteria = 0;
820         gchar *expr = NULL;
821
822         criteria = MATCHCRITERIA_NOT_CC;
823         expr = $3;
824         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
825 }
826 | MATCHER_TO_OR_CC match_type MATCHER_STRING
827 {
828         gint criteria = 0;
829         gchar *expr = NULL;
830
831         criteria = MATCHCRITERIA_TO_OR_CC;
832         expr = $3;
833         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
834 }
835 | MATCHER_NOT_TO_AND_NOT_CC match_type MATCHER_STRING
836 {
837         gint criteria = 0;
838         gchar *expr = NULL;
839
840         criteria = MATCHCRITERIA_NOT_TO_AND_NOT_CC;
841         expr = $3;
842         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
843 }
844 | MATCHER_AGE_GREATER MATCHER_INTEGER
845 {
846         gint criteria = 0;
847         gint value = 0;
848
849         criteria = MATCHCRITERIA_AGE_GREATER;
850         value = strtol($2, NULL, 0);
851         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
852 }
853 | MATCHER_AGE_LOWER MATCHER_INTEGER
854 {
855         gint criteria = 0;
856         gint value = 0;
857
858         criteria = MATCHCRITERIA_AGE_LOWER;
859         value = strtol($2, NULL, 0);
860         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
861 }
862 | MATCHER_NEWSGROUPS match_type MATCHER_STRING
863 {
864         gint criteria = 0;
865         gchar *expr = NULL;
866
867         criteria = MATCHCRITERIA_NEWSGROUPS;
868         expr = $3;
869         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
870 }
871 | MATCHER_NOT_NEWSGROUPS match_type MATCHER_STRING
872 {
873         gint criteria = 0;
874         gchar *expr = NULL;
875
876         criteria = MATCHCRITERIA_NOT_NEWSGROUPS;
877         expr = $3;
878         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
879 }
880 | MATCHER_INREPLYTO match_type MATCHER_STRING
881 {
882         gint criteria = 0;
883         gchar *expr = NULL;
884
885         criteria = MATCHCRITERIA_INREPLYTO;
886         expr = $3;
887         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
888 }
889 | MATCHER_NOT_INREPLYTO match_type MATCHER_STRING
890 {
891         gint criteria = 0;
892         gchar *expr = NULL;
893
894         criteria = MATCHCRITERIA_NOT_INREPLYTO;
895         expr = $3;
896         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
897 }
898 | MATCHER_REFERENCES match_type MATCHER_STRING
899 {
900         gint criteria = 0;
901         gchar *expr = NULL;
902
903         criteria = MATCHCRITERIA_REFERENCES;
904         expr = $3;
905         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
906 }
907 | MATCHER_NOT_REFERENCES match_type MATCHER_STRING
908 {
909         gint criteria = 0;
910         gchar *expr = NULL;
911
912         criteria = MATCHCRITERIA_NOT_REFERENCES;
913         expr = $3;
914         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
915 }
916 | MATCHER_SCORE_GREATER MATCHER_INTEGER
917 {
918         gint criteria = 0;
919         gint value = 0;
920
921         criteria = MATCHCRITERIA_SCORE_GREATER;
922         value = strtol($2, NULL, 0);
923         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
924 }
925 | MATCHER_SCORE_LOWER MATCHER_INTEGER
926 {
927         gint criteria = 0;
928         gint value = 0;
929
930         criteria = MATCHCRITERIA_SCORE_LOWER;
931         value = strtol($2, NULL, 0);
932         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
933 }
934 | MATCHER_SCORE_EQUAL MATCHER_INTEGER
935 {
936         gint criteria = 0;
937         gint value = 0;
938
939         criteria = MATCHCRITERIA_SCORE_EQUAL;
940         value = strtol($2, NULL, 0);
941         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
942 }
943 | MATCHER_SIZE_GREATER MATCHER_INTEGER 
944 {
945         gint criteria = 0;
946         gint value    = 0;
947         criteria = MATCHCRITERIA_SIZE_GREATER;
948         value = strtol($2, NULL, 0);
949         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
950 }
951 | MATCHER_SIZE_SMALLER MATCHER_INTEGER
952 {
953         gint criteria = 0;
954         gint value    = 0;
955         criteria = MATCHCRITERIA_SIZE_SMALLER;
956         value = strtol($2, NULL, 0);
957         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
958 }
959 | MATCHER_SIZE_EQUAL MATCHER_INTEGER
960 {
961         gint criteria = 0;
962         gint value    = 0;
963         criteria = MATCHCRITERIA_SIZE_EQUAL;
964         value = strtol($2, NULL, 0);
965         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
966 }
967 | MATCHER_HEADER MATCHER_STRING
968 {
969         header = g_strdup($2);
970 } match_type MATCHER_STRING
971 {
972         gint criteria = 0;
973         gchar *expr = NULL;
974         matcher_is_fast = FALSE;
975         criteria = MATCHCRITERIA_HEADER;
976         expr = $2;
977         prop = matcherprop_new(criteria, header, match_type, expr, 0);
978         g_free(header);
979 }
980 | MATCHER_NOT_HEADER MATCHER_STRING
981 {
982         header = g_strdup($2);
983 } match_type MATCHER_STRING
984 {
985         gint criteria = 0;
986         gchar *expr = NULL;
987         matcher_is_fast = FALSE;
988         criteria = MATCHCRITERIA_NOT_HEADER;
989         expr = $2;
990         prop = matcherprop_new(criteria, header, match_type, expr, 0);
991         g_free(header);
992 }
993 | MATCHER_HEADERS_PART match_type MATCHER_STRING
994 {
995         gint criteria = 0;
996         gchar *expr = NULL;
997         matcher_is_fast = FALSE;
998         criteria = MATCHCRITERIA_HEADERS_PART;
999         expr = $3;
1000         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1001 }
1002 | MATCHER_NOT_HEADERS_PART match_type MATCHER_STRING
1003 {
1004         gint criteria = 0;
1005         gchar *expr = NULL;
1006         matcher_is_fast = FALSE;
1007         criteria = MATCHCRITERIA_NOT_HEADERS_PART;
1008         expr = $3;
1009         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1010 }
1011 | MATCHER_FOUND_IN_ADDRESSBOOK MATCHER_STRING
1012 {
1013         header = g_strdup($2);
1014 } MATCHER_IN MATCHER_STRING
1015 {
1016         gint criteria = 0;
1017         gchar *expr = NULL;
1018
1019         criteria = MATCHCRITERIA_FOUND_IN_ADDRESSBOOK;
1020         expr = $2;
1021         prop = matcherprop_new(criteria, header, match_type, expr, 0);
1022         g_free(header);
1023 }
1024 | MATCHER_NOT_FOUND_IN_ADDRESSBOOK MATCHER_STRING
1025 {
1026         header = g_strdup($2);
1027 } MATCHER_IN MATCHER_STRING
1028 {
1029         gint criteria = 0;
1030         gchar *expr = NULL;
1031
1032         criteria = MATCHCRITERIA_NOT_FOUND_IN_ADDRESSBOOK;
1033         expr = $2;
1034         prop = matcherprop_new(criteria, header, match_type, expr, 0);
1035         g_free(header);
1036 }
1037 | MATCHER_MESSAGE match_type MATCHER_STRING
1038 {
1039         gint criteria = 0;
1040         gchar *expr = NULL;
1041         matcher_is_fast = FALSE;
1042         criteria = MATCHCRITERIA_MESSAGE;
1043         expr = $3;
1044         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1045 }
1046 | MATCHER_NOT_MESSAGE match_type MATCHER_STRING
1047 {
1048         gint criteria = 0;
1049         gchar *expr = NULL;
1050         matcher_is_fast = FALSE;
1051         criteria = MATCHCRITERIA_NOT_MESSAGE;
1052         expr = $3;
1053         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1054 }
1055 | MATCHER_BODY_PART match_type MATCHER_STRING
1056 {
1057         gint criteria = 0;
1058         gchar *expr = NULL;
1059         matcher_is_fast = FALSE;
1060         criteria = MATCHCRITERIA_BODY_PART;
1061         expr = $3;
1062         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1063 }
1064 | MATCHER_NOT_BODY_PART match_type MATCHER_STRING
1065 {
1066         gint criteria = 0;
1067         gchar *expr = NULL;
1068         matcher_is_fast = FALSE;
1069         criteria = MATCHCRITERIA_NOT_BODY_PART;
1070         expr = $3;
1071         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1072 }
1073 | MATCHER_TEST MATCHER_STRING
1074 {
1075         gint criteria = 0;
1076         gchar *expr = NULL;
1077         matcher_is_fast = FALSE;
1078         criteria = MATCHCRITERIA_TEST;
1079         expr = $2;
1080         prop = matcherprop_new(criteria, NULL, 0, expr, 0);
1081 }
1082 | MATCHER_NOT_TEST MATCHER_STRING
1083 {
1084         gint criteria = 0;
1085         gchar *expr = NULL;
1086         matcher_is_fast = FALSE;
1087         criteria = MATCHCRITERIA_NOT_TEST;
1088         expr = $2;
1089         prop = matcherprop_new(criteria, NULL, 0, expr, 0);
1090 }
1091 ;
1092
1093 filtering_action:
1094 MATCHER_EXECUTE MATCHER_STRING
1095 {
1096         gchar *cmd = NULL;
1097         gint action_type = 0;
1098
1099         action_type = MATCHACTION_EXECUTE;
1100         cmd = $2;
1101         action = filteringaction_new(action_type, 0, cmd, 0, 0);
1102 }
1103 | MATCHER_MOVE MATCHER_STRING
1104 {
1105         gchar *destination = NULL;
1106         gint action_type = 0;
1107
1108         action_type = MATCHACTION_MOVE;
1109         destination = $2;
1110         action = filteringaction_new(action_type, 0, destination, 0, 0);
1111 }
1112 | MATCHER_COPY MATCHER_STRING
1113 {
1114         gchar *destination = NULL;
1115         gint action_type = 0;
1116
1117         action_type = MATCHACTION_COPY;
1118         destination = $2;
1119         action = filteringaction_new(action_type, 0, destination, 0, 0);
1120 }
1121 | MATCHER_DELETE
1122 {
1123         gint action_type = 0;
1124
1125         action_type = MATCHACTION_DELETE;
1126         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1127 }
1128 | MATCHER_MARK
1129 {
1130         gint action_type = 0;
1131
1132         action_type = MATCHACTION_MARK;
1133         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1134 }
1135 | MATCHER_UNMARK
1136 {
1137         gint action_type = 0;
1138
1139         action_type = MATCHACTION_UNMARK;
1140         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1141 }
1142 | MATCHER_LOCK
1143 {
1144         gint action_type = 0;
1145
1146         action_type = MATCHACTION_LOCK;
1147         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1148 }
1149 | MATCHER_UNLOCK
1150 {
1151         gint action_type = 0;
1152
1153         action_type = MATCHACTION_UNLOCK;
1154         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1155 }
1156 | MATCHER_MARK_AS_READ
1157 {
1158         gint action_type = 0;
1159
1160         action_type = MATCHACTION_MARK_AS_READ;
1161         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1162 }
1163 | MATCHER_MARK_AS_UNREAD
1164 {
1165         gint action_type = 0;
1166
1167         action_type = MATCHACTION_MARK_AS_UNREAD;
1168         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1169 }
1170 | MATCHER_FORWARD MATCHER_INTEGER MATCHER_STRING
1171 {
1172         gchar *destination = NULL;
1173         gint action_type = 0;
1174         gint account_id = 0;
1175
1176         action_type = MATCHACTION_FORWARD;
1177         account_id = strtol($2, NULL, 10);
1178         destination = $3;
1179         action = filteringaction_new(action_type,
1180             account_id, destination, 0, 0);
1181 }
1182 | MATCHER_FORWARD_AS_ATTACHMENT MATCHER_INTEGER MATCHER_STRING
1183 {
1184         gchar *destination = NULL;
1185         gint action_type = 0;
1186         gint account_id = 0;
1187
1188         action_type = MATCHACTION_FORWARD_AS_ATTACHMENT;
1189         account_id = strtol($2, NULL, 10);
1190         destination = $3;
1191         action = filteringaction_new(action_type,
1192             account_id, destination, 0, 0);
1193 }
1194 | MATCHER_REDIRECT MATCHER_INTEGER MATCHER_STRING
1195 {
1196         gchar *destination = NULL;
1197         gint action_type = 0;
1198         gint account_id = 0;
1199
1200         action_type = MATCHACTION_REDIRECT;
1201         account_id = strtol($2, NULL, 10);
1202         destination = $3;
1203         action = filteringaction_new(action_type,
1204             account_id, destination, 0, 0);
1205 }
1206 | MATCHER_COLOR MATCHER_INTEGER
1207 {
1208         gint action_type = 0;
1209         gint color = 0;
1210
1211         action_type = MATCHACTION_COLOR;
1212         color = strtol($2, NULL, 10);
1213         action = filteringaction_new(action_type, 0, NULL, color, 0);
1214 }
1215 | MATCHER_CHANGE_SCORE MATCHER_INTEGER
1216 {
1217         gint score = 0;
1218         
1219         score = strtol($2, NULL, 10);
1220         action = filteringaction_new(MATCHACTION_CHANGE_SCORE, 0,
1221                                      NULL, 0, score);
1222 }
1223 /* backward compatibility */
1224 | MATCHER_SCORE MATCHER_INTEGER
1225 {
1226         gint score = 0;
1227         
1228         score = strtol($2, NULL, 10);
1229         action = filteringaction_new(MATCHACTION_CHANGE_SCORE, 0,
1230                                      NULL, 0, score);
1231 }
1232 | MATCHER_SET_SCORE MATCHER_INTEGER
1233 {
1234         gint score = 0;
1235         
1236         score = strtol($2, NULL, 10);
1237         action = filteringaction_new(MATCHACTION_SET_SCORE, 0,
1238                                      NULL, 0, score);
1239 }
1240 | MATCHER_HIDE
1241 {
1242         action = filteringaction_new(MATCHACTION_HIDE, 0, NULL, 0, 0);
1243 }
1244 | MATCHER_IGNORE
1245 {
1246         action = filteringaction_new(MATCHACTION_IGNORE, 0, NULL, 0, 0);
1247 }
1248 | MATCHER_STOP
1249 {
1250         action = filteringaction_new(MATCHACTION_STOP, 0, NULL, 0, 0);
1251 }
1252 ;