2006-12-15 [wwp] 2.6.1cvs40
[claws.git] / src / matcher_parser_parse.y
1
2 %{
3
4 /*
5  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
6  * Copyright (c) 2001-2002 by Hiroyuki Yamamoto & The Claws Mail Team.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  */
22
23 #include "defs.h"
24
25 #include <glib.h>
26 #include <glib/gi18n.h>
27
28 #include "utils.h"
29 #include "filtering.h"
30 #include "matcher.h"
31 #include "matcher_parser.h"
32 #include "matcher_parser_lex.h"
33 #include "procmsg.h"
34
35 #define MAX_COLORLABELS (MSG_CLABEL_7 - MSG_CLABEL_NONE)
36
37 static gint error = 0;
38 static gint bool_op = 0;
39 static gint match_type = 0;
40 static gchar *header = NULL;
41
42 static MatcherProp *prop;
43
44 static GSList *matchers_list = NULL;
45
46 static gboolean enabled = TRUE;
47 static gchar *name = NULL;
48 static gint account_id = 0;
49 static MatcherList *cond;
50 static GSList *action_list = NULL;
51 static FilteringAction *action = NULL;
52 static gboolean matcher_is_fast = TRUE;
53
54 static FilteringProp *filtering;
55
56 static GSList **prefs_filtering = NULL;
57 static int enable_compatibility = 0;
58
59 enum {
60         MATCHER_PARSE_FILE,
61         MATCHER_PARSE_NO_EOL,
62         MATCHER_PARSE_ENABLED,
63         MATCHER_PARSE_NAME,
64         MATCHER_PARSE_ACCOUNT,
65         MATCHER_PARSE_CONDITION,
66         MATCHER_PARSE_FILTERING_ACTION,
67 };
68
69 static int matcher_parse_op = MATCHER_PARSE_FILE;
70
71
72 /* ******************************************************************** */
73 /* redeclarations to avoid warnings */
74 void matcher_parserrestart(FILE *input_file);
75 void matcher_parser_init(void);
76 void matcher_parser_switch_to_buffer(void * new_buffer);
77 void matcher_parser_delete_buffer(void * b);
78 int matcher_parserlex(void);
79
80 void matcher_parser_start_parsing(FILE *f)
81 {
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_parser_init();
107         bufstate = matcher_parser_scan_string((const char *) tmp_str);
108         matcher_parser_switch_to_buffer(bufstate);
109         if (matcher_parserparse() != 0)
110                 filtering = NULL;
111         matcher_parse_op = MATCHER_PARSE_FILE;
112         matcher_parser_delete_buffer(bufstate);
113         g_free(tmp_str);
114         return filtering;
115 }
116
117 static gboolean check_quote_symetry(gchar *str)
118 {
119         const gchar *walk;
120         int ret = 0;
121         
122         if (str == NULL)
123                 return TRUE; /* heh, that's symetric */
124         if (*str == '\0')
125                 return TRUE;
126         for (walk = str; *walk; walk++) {
127                 if (*walk == '\"') {
128                         if (walk == str         /* first char */
129                         || *(walk - 1) != '\\') /* not escaped */
130                                 ret ++;
131                 }
132         }
133         return !(ret % 2);
134 }
135
136 MatcherList *matcher_parser_get_name(gchar *str)
137 {
138         void *bufstate;
139
140         if (!check_quote_symetry(str)) {
141                 cond = NULL;
142                 return cond;
143         }
144         
145         /* bad coding to enable the sub-grammar matching
146            in yacc */
147         matcher_parserlineno = 1;
148         matcher_parse_op = MATCHER_PARSE_NAME;
149         matcher_parserrestart(NULL);
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_parser_init();
173         bufstate = matcher_parser_scan_string(str);
174         matcher_parserparse();
175         matcher_parse_op = MATCHER_PARSE_FILE;
176         matcher_parser_delete_buffer(bufstate);
177         return cond;
178 }
179
180 MatcherList *matcher_parser_get_account(gchar *str)
181 {
182         void *bufstate;
183
184         if (!check_quote_symetry(str)) {
185                 cond = NULL;
186                 return cond;
187         }
188         
189         /* bad coding to enable the sub-grammar matching
190            in yacc */
191         matcher_parserlineno = 1;
192         matcher_parse_op = MATCHER_PARSE_ACCOUNT;
193         matcher_parserrestart(NULL);
194         matcher_parser_init();
195         bufstate = matcher_parser_scan_string(str);
196         matcher_parserparse();
197         matcher_parse_op = MATCHER_PARSE_FILE;
198         matcher_parser_delete_buffer(bufstate);
199         return cond;
200 }
201
202 MatcherList *matcher_parser_get_cond(gchar *str, gboolean *is_fast)
203 {
204         void *bufstate;
205
206         if (!check_quote_symetry(str)) {
207                 cond = NULL;
208                 return cond;
209         }
210         
211         matcher_is_fast = TRUE;
212         /* bad coding to enable the sub-grammar matching
213            in yacc */
214         matcher_parserlineno = 1;
215         matcher_parse_op = MATCHER_PARSE_CONDITION;
216         matcher_parserrestart(NULL);
217         matcher_parser_init();
218         bufstate = matcher_parser_scan_string(str);
219         matcher_parserparse();
220         matcher_parse_op = MATCHER_PARSE_FILE;
221         matcher_parser_delete_buffer(bufstate);
222         if (is_fast)
223                 *is_fast = matcher_is_fast;
224         return cond;
225 }
226
227 GSList *matcher_parser_get_action_list(gchar *str)
228 {
229         void *bufstate;
230
231         if (!check_quote_symetry(str)) {
232                 action_list = NULL;
233                 return action_list;
234         }
235         
236         /* bad coding to enable the sub-grammar matching
237            in yacc */
238         matcher_parserlineno = 1;
239         matcher_parse_op = MATCHER_PARSE_FILTERING_ACTION;
240         matcher_parserrestart(NULL);
241         matcher_parser_init();
242         bufstate = matcher_parser_scan_string(str);
243         matcher_parserparse();
244         matcher_parse_op = MATCHER_PARSE_FILE;
245         matcher_parser_delete_buffer(bufstate);
246         return action_list;
247 }
248
249 MatcherProp *matcher_parser_get_prop(gchar *str)
250 {
251         MatcherList *list;
252         MatcherProp *prop;
253
254         matcher_parserlineno = 1;
255         list = matcher_parser_get_cond(str, NULL);
256         if (list == NULL)
257                 return NULL;
258
259         if (list->matchers == NULL)
260                 return NULL;
261
262         if (list->matchers->next != NULL)
263                 return NULL;
264
265         prop = list->matchers->data;
266
267         g_slist_free(list->matchers);
268         g_free(list);
269
270         return prop;
271 }
272
273 void matcher_parsererror(char *str)
274 {
275         GSList *l;
276
277         if (matchers_list) {
278                 for (l = matchers_list; l != NULL; l = g_slist_next(l)) {
279                         matcherprop_free((MatcherProp *)
280                                          l->data);
281                         l->data = NULL;
282                 }
283                 g_slist_free(matchers_list);
284                 matchers_list = NULL;
285         }
286         cond = NULL;
287         g_warning("filtering parsing: %i: %s\n",
288                   matcher_parserlineno, str);
289         error = 1;
290 }
291
292 int matcher_parserwrap(void)
293 {
294         return 1;
295 }
296 %}
297
298 %union {
299         char *str;
300         int value;
301 }
302 %token MATCHER_ALL MATCHER_UNREAD  MATCHER_NOT_UNREAD 
303 %token MATCHER_NEW  MATCHER_NOT_NEW  MATCHER_MARKED
304 %token MATCHER_NOT_MARKED  MATCHER_DELETED  MATCHER_NOT_DELETED
305 %token MATCHER_REPLIED  MATCHER_NOT_REPLIED  MATCHER_FORWARDED
306 %token MATCHER_NOT_FORWARDED  MATCHER_SUBJECT  MATCHER_NOT_SUBJECT
307 %token MATCHER_FROM  MATCHER_NOT_FROM  MATCHER_TO  MATCHER_NOT_TO
308 %token MATCHER_CC  MATCHER_NOT_CC  MATCHER_TO_OR_CC  MATCHER_NOT_TO_AND_NOT_CC
309 %token MATCHER_AGE_GREATER  MATCHER_AGE_LOWER  MATCHER_NEWSGROUPS
310 %token MATCHER_NOT_NEWSGROUPS  MATCHER_INREPLYTO  MATCHER_NOT_INREPLYTO
311 %token MATCHER_REFERENCES  MATCHER_NOT_REFERENCES  MATCHER_SCORE_GREATER
312 %token MATCHER_SCORE_LOWER  MATCHER_HEADER  MATCHER_NOT_HEADER
313 %token MATCHER_HEADERS_PART  MATCHER_NOT_HEADERS_PART  MATCHER_MESSAGE
314 %token MATCHER_NOT_MESSAGE  MATCHER_BODY_PART  MATCHER_NOT_BODY_PART
315 %token MATCHER_TEST  MATCHER_NOT_TEST  MATCHER_MATCHCASE  MATCHER_MATCH
316 %token MATCHER_REGEXPCASE  MATCHER_REGEXP  MATCHER_SCORE  MATCHER_MOVE
317 %token MATCHER_FOUND_IN_ADDRESSBOOK MATCHER_NOT_FOUND_IN_ADDRESSBOOK MATCHER_IN
318 %token MATCHER_COPY  MATCHER_DELETE  MATCHER_MARK  MATCHER_UNMARK
319 %token MATCHER_LOCK MATCHER_UNLOCK
320 %token MATCHER_EXECUTE
321 %token MATCHER_MARK_AS_READ  MATCHER_MARK_AS_UNREAD  MATCHER_FORWARD
322 %token MATCHER_FORWARD_AS_ATTACHMENT  MATCHER_EOL  MATCHER_STRING  
323 %token MATCHER_OR MATCHER_AND  
324 %token MATCHER_COLOR MATCHER_SCORE_EQUAL MATCHER_REDIRECT 
325 %token MATCHER_SIZE_GREATER MATCHER_SIZE_SMALLER MATCHER_SIZE_EQUAL
326 %token MATCHER_LOCKED MATCHER_NOT_LOCKED
327 %token MATCHER_PARTIAL MATCHER_NOT_PARTIAL
328 %token MATCHER_COLORLABEL MATCHER_NOT_COLORLABEL
329 %token MATCHER_IGNORE_THREAD MATCHER_NOT_IGNORE_THREAD
330 %token MATCHER_CHANGE_SCORE MATCHER_SET_SCORE
331 %token MATCHER_STOP MATCHER_HIDE MATCHER_IGNORE
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_PARTIAL
691 {
692         gint criteria = 0;
693
694         criteria = MATCHCRITERIA_PARTIAL;
695         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
696 }
697 | MATCHER_NOT_PARTIAL
698 {
699         gint criteria = 0;
700
701         criteria = MATCHCRITERIA_NOT_PARTIAL;
702         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
703 }
704 | MATCHER_COLORLABEL MATCHER_INTEGER
705 {
706         gint criteria = 0;
707         gint value = 0;
708
709         criteria = MATCHCRITERIA_COLORLABEL;
710         value = strtol($2, NULL, 10);
711         if (value < 0) value = 0;
712         else if (value > MAX_COLORLABELS) value = MAX_COLORLABELS;
713         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
714 }
715 | MATCHER_NOT_COLORLABEL MATCHER_INTEGER
716 {
717         gint criteria = 0;
718         gint value = 0;
719
720         criteria = MATCHCRITERIA_NOT_COLORLABEL;
721         value = strtol($2, NULL, 0);
722         if (value < 0) value = 0;
723         else if (value > MAX_COLORLABELS) value = MAX_COLORLABELS;
724         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
725 }
726 | MATCHER_IGNORE_THREAD
727 {
728         gint criteria = 0;
729
730         criteria = MATCHCRITERIA_IGNORE_THREAD;
731         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
732 }
733 | MATCHER_NOT_IGNORE_THREAD
734 {
735         gint criteria = 0;
736
737         criteria = MATCHCRITERIA_NOT_IGNORE_THREAD;
738         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
739 }
740 | MATCHER_SUBJECT match_type MATCHER_STRING
741 {
742         gint criteria = 0;
743         gchar *expr = NULL;
744
745         criteria = MATCHCRITERIA_SUBJECT;
746         expr = $3;
747         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
748 }
749 | MATCHER_NOT_SUBJECT match_type MATCHER_STRING
750 {
751         gint criteria = 0;
752         gchar *expr = NULL;
753
754         criteria = MATCHCRITERIA_NOT_SUBJECT;
755         expr = $3;
756         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
757 }
758 | MATCHER_FROM match_type MATCHER_STRING
759 {
760         gint criteria = 0;
761         gchar *expr = NULL;
762
763         criteria = MATCHCRITERIA_FROM;
764         expr = $3;
765         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
766 }
767 | MATCHER_NOT_FROM match_type MATCHER_STRING
768 {
769         gint criteria = 0;
770         gchar *expr = NULL;
771
772         criteria = MATCHCRITERIA_NOT_FROM;
773         expr = $3;
774         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
775 }
776 | MATCHER_TO match_type MATCHER_STRING
777 {
778         gint criteria = 0;
779         gchar *expr = NULL;
780
781         criteria = MATCHCRITERIA_TO;
782         expr = $3;
783         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
784 }
785 | MATCHER_NOT_TO match_type MATCHER_STRING
786 {
787         gint criteria = 0;
788         gchar *expr = NULL;
789
790         criteria = MATCHCRITERIA_NOT_TO;
791         expr = $3;
792         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
793 }
794 | MATCHER_CC match_type MATCHER_STRING
795 {
796         gint criteria = 0;
797         gchar *expr = NULL;
798
799         criteria = MATCHCRITERIA_CC;
800         expr = $3;
801         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
802 }
803 | MATCHER_NOT_CC match_type MATCHER_STRING
804 {
805         gint criteria = 0;
806         gchar *expr = NULL;
807
808         criteria = MATCHCRITERIA_NOT_CC;
809         expr = $3;
810         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
811 }
812 | MATCHER_TO_OR_CC match_type MATCHER_STRING
813 {
814         gint criteria = 0;
815         gchar *expr = NULL;
816
817         criteria = MATCHCRITERIA_TO_OR_CC;
818         expr = $3;
819         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
820 }
821 | MATCHER_NOT_TO_AND_NOT_CC match_type MATCHER_STRING
822 {
823         gint criteria = 0;
824         gchar *expr = NULL;
825
826         criteria = MATCHCRITERIA_NOT_TO_AND_NOT_CC;
827         expr = $3;
828         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
829 }
830 | MATCHER_AGE_GREATER MATCHER_INTEGER
831 {
832         gint criteria = 0;
833         gint value = 0;
834
835         criteria = MATCHCRITERIA_AGE_GREATER;
836         value = strtol($2, NULL, 0);
837         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
838 }
839 | MATCHER_AGE_LOWER MATCHER_INTEGER
840 {
841         gint criteria = 0;
842         gint value = 0;
843
844         criteria = MATCHCRITERIA_AGE_LOWER;
845         value = strtol($2, NULL, 0);
846         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
847 }
848 | MATCHER_NEWSGROUPS match_type MATCHER_STRING
849 {
850         gint criteria = 0;
851         gchar *expr = NULL;
852
853         criteria = MATCHCRITERIA_NEWSGROUPS;
854         expr = $3;
855         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
856 }
857 | MATCHER_NOT_NEWSGROUPS match_type MATCHER_STRING
858 {
859         gint criteria = 0;
860         gchar *expr = NULL;
861
862         criteria = MATCHCRITERIA_NOT_NEWSGROUPS;
863         expr = $3;
864         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
865 }
866 | MATCHER_INREPLYTO match_type MATCHER_STRING
867 {
868         gint criteria = 0;
869         gchar *expr = NULL;
870
871         criteria = MATCHCRITERIA_INREPLYTO;
872         expr = $3;
873         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
874 }
875 | MATCHER_NOT_INREPLYTO match_type MATCHER_STRING
876 {
877         gint criteria = 0;
878         gchar *expr = NULL;
879
880         criteria = MATCHCRITERIA_NOT_INREPLYTO;
881         expr = $3;
882         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
883 }
884 | MATCHER_REFERENCES match_type MATCHER_STRING
885 {
886         gint criteria = 0;
887         gchar *expr = NULL;
888
889         criteria = MATCHCRITERIA_REFERENCES;
890         expr = $3;
891         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
892 }
893 | MATCHER_NOT_REFERENCES match_type MATCHER_STRING
894 {
895         gint criteria = 0;
896         gchar *expr = NULL;
897
898         criteria = MATCHCRITERIA_NOT_REFERENCES;
899         expr = $3;
900         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
901 }
902 | MATCHER_SCORE_GREATER MATCHER_INTEGER
903 {
904         gint criteria = 0;
905         gint value = 0;
906
907         criteria = MATCHCRITERIA_SCORE_GREATER;
908         value = strtol($2, NULL, 0);
909         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
910 }
911 | MATCHER_SCORE_LOWER MATCHER_INTEGER
912 {
913         gint criteria = 0;
914         gint value = 0;
915
916         criteria = MATCHCRITERIA_SCORE_LOWER;
917         value = strtol($2, NULL, 0);
918         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
919 }
920 | MATCHER_SCORE_EQUAL MATCHER_INTEGER
921 {
922         gint criteria = 0;
923         gint value = 0;
924
925         criteria = MATCHCRITERIA_SCORE_EQUAL;
926         value = strtol($2, NULL, 0);
927         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
928 }
929 | MATCHER_SIZE_GREATER MATCHER_INTEGER 
930 {
931         gint criteria = 0;
932         gint value    = 0;
933         criteria = MATCHCRITERIA_SIZE_GREATER;
934         value = strtol($2, NULL, 0);
935         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
936 }
937 | MATCHER_SIZE_SMALLER MATCHER_INTEGER
938 {
939         gint criteria = 0;
940         gint value    = 0;
941         criteria = MATCHCRITERIA_SIZE_SMALLER;
942         value = strtol($2, NULL, 0);
943         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
944 }
945 | MATCHER_SIZE_EQUAL MATCHER_INTEGER
946 {
947         gint criteria = 0;
948         gint value    = 0;
949         criteria = MATCHCRITERIA_SIZE_EQUAL;
950         value = strtol($2, NULL, 0);
951         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
952 }
953 | MATCHER_HEADER MATCHER_STRING
954 {
955         header = g_strdup($2);
956 } match_type MATCHER_STRING
957 {
958         gint criteria = 0;
959         gchar *expr = NULL;
960         matcher_is_fast = FALSE;
961         criteria = MATCHCRITERIA_HEADER;
962         expr = $2;
963         prop = matcherprop_new(criteria, header, match_type, expr, 0);
964         g_free(header);
965 }
966 | MATCHER_NOT_HEADER MATCHER_STRING
967 {
968         header = g_strdup($2);
969 } match_type MATCHER_STRING
970 {
971         gint criteria = 0;
972         gchar *expr = NULL;
973         matcher_is_fast = FALSE;
974         criteria = MATCHCRITERIA_NOT_HEADER;
975         expr = $2;
976         prop = matcherprop_new(criteria, header, match_type, expr, 0);
977         g_free(header);
978 }
979 | MATCHER_HEADERS_PART match_type MATCHER_STRING
980 {
981         gint criteria = 0;
982         gchar *expr = NULL;
983         matcher_is_fast = FALSE;
984         criteria = MATCHCRITERIA_HEADERS_PART;
985         expr = $3;
986         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
987 }
988 | MATCHER_NOT_HEADERS_PART match_type MATCHER_STRING
989 {
990         gint criteria = 0;
991         gchar *expr = NULL;
992         matcher_is_fast = FALSE;
993         criteria = MATCHCRITERIA_NOT_HEADERS_PART;
994         expr = $3;
995         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
996 }
997 | MATCHER_FOUND_IN_ADDRESSBOOK MATCHER_STRING
998 {
999         header = g_strdup($2);
1000 } MATCHER_IN MATCHER_STRING
1001 {
1002         gint criteria = 0;
1003         gchar *expr = NULL;
1004
1005         criteria = MATCHCRITERIA_FOUND_IN_ADDRESSBOOK;
1006         expr = $2;
1007         prop = matcherprop_new(criteria, header, match_type, expr, 0);
1008         g_free(header);
1009 }
1010 | MATCHER_NOT_FOUND_IN_ADDRESSBOOK MATCHER_STRING
1011 {
1012         header = g_strdup($2);
1013 } MATCHER_IN MATCHER_STRING
1014 {
1015         gint criteria = 0;
1016         gchar *expr = NULL;
1017
1018         criteria = MATCHCRITERIA_NOT_FOUND_IN_ADDRESSBOOK;
1019         expr = $2;
1020         prop = matcherprop_new(criteria, header, match_type, expr, 0);
1021         g_free(header);
1022 }
1023 | MATCHER_MESSAGE match_type MATCHER_STRING
1024 {
1025         gint criteria = 0;
1026         gchar *expr = NULL;
1027         matcher_is_fast = FALSE;
1028         criteria = MATCHCRITERIA_MESSAGE;
1029         expr = $3;
1030         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1031 }
1032 | MATCHER_NOT_MESSAGE match_type MATCHER_STRING
1033 {
1034         gint criteria = 0;
1035         gchar *expr = NULL;
1036         matcher_is_fast = FALSE;
1037         criteria = MATCHCRITERIA_NOT_MESSAGE;
1038         expr = $3;
1039         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1040 }
1041 | MATCHER_BODY_PART match_type MATCHER_STRING
1042 {
1043         gint criteria = 0;
1044         gchar *expr = NULL;
1045         matcher_is_fast = FALSE;
1046         criteria = MATCHCRITERIA_BODY_PART;
1047         expr = $3;
1048         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1049 }
1050 | MATCHER_NOT_BODY_PART match_type MATCHER_STRING
1051 {
1052         gint criteria = 0;
1053         gchar *expr = NULL;
1054         matcher_is_fast = FALSE;
1055         criteria = MATCHCRITERIA_NOT_BODY_PART;
1056         expr = $3;
1057         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1058 }
1059 | MATCHER_TEST MATCHER_STRING
1060 {
1061         gint criteria = 0;
1062         gchar *expr = NULL;
1063         matcher_is_fast = FALSE;
1064         criteria = MATCHCRITERIA_TEST;
1065         expr = $2;
1066         prop = matcherprop_new(criteria, NULL, 0, expr, 0);
1067 }
1068 | MATCHER_NOT_TEST MATCHER_STRING
1069 {
1070         gint criteria = 0;
1071         gchar *expr = NULL;
1072         matcher_is_fast = FALSE;
1073         criteria = MATCHCRITERIA_NOT_TEST;
1074         expr = $2;
1075         prop = matcherprop_new(criteria, NULL, 0, expr, 0);
1076 }
1077 ;
1078
1079 filtering_action:
1080 MATCHER_EXECUTE MATCHER_STRING
1081 {
1082         gchar *cmd = NULL;
1083         gint action_type = 0;
1084
1085         action_type = MATCHACTION_EXECUTE;
1086         cmd = $2;
1087         action = filteringaction_new(action_type, 0, cmd, 0, 0);
1088 }
1089 | MATCHER_MOVE MATCHER_STRING
1090 {
1091         gchar *destination = NULL;
1092         gint action_type = 0;
1093
1094         action_type = MATCHACTION_MOVE;
1095         destination = $2;
1096         action = filteringaction_new(action_type, 0, destination, 0, 0);
1097 }
1098 | MATCHER_COPY MATCHER_STRING
1099 {
1100         gchar *destination = NULL;
1101         gint action_type = 0;
1102
1103         action_type = MATCHACTION_COPY;
1104         destination = $2;
1105         action = filteringaction_new(action_type, 0, destination, 0, 0);
1106 }
1107 | MATCHER_DELETE
1108 {
1109         gint action_type = 0;
1110
1111         action_type = MATCHACTION_DELETE;
1112         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1113 }
1114 | MATCHER_MARK
1115 {
1116         gint action_type = 0;
1117
1118         action_type = MATCHACTION_MARK;
1119         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1120 }
1121 | MATCHER_UNMARK
1122 {
1123         gint action_type = 0;
1124
1125         action_type = MATCHACTION_UNMARK;
1126         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1127 }
1128 | MATCHER_LOCK
1129 {
1130         gint action_type = 0;
1131
1132         action_type = MATCHACTION_LOCK;
1133         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1134 }
1135 | MATCHER_UNLOCK
1136 {
1137         gint action_type = 0;
1138
1139         action_type = MATCHACTION_UNLOCK;
1140         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1141 }
1142 | MATCHER_MARK_AS_READ
1143 {
1144         gint action_type = 0;
1145
1146         action_type = MATCHACTION_MARK_AS_READ;
1147         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1148 }
1149 | MATCHER_MARK_AS_UNREAD
1150 {
1151         gint action_type = 0;
1152
1153         action_type = MATCHACTION_MARK_AS_UNREAD;
1154         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1155 }
1156 | MATCHER_FORWARD MATCHER_INTEGER MATCHER_STRING
1157 {
1158         gchar *destination = NULL;
1159         gint action_type = 0;
1160         gint account_id = 0;
1161
1162         action_type = MATCHACTION_FORWARD;
1163         account_id = strtol($2, NULL, 10);
1164         destination = $3;
1165         action = filteringaction_new(action_type,
1166             account_id, destination, 0, 0);
1167 }
1168 | MATCHER_FORWARD_AS_ATTACHMENT MATCHER_INTEGER MATCHER_STRING
1169 {
1170         gchar *destination = NULL;
1171         gint action_type = 0;
1172         gint account_id = 0;
1173
1174         action_type = MATCHACTION_FORWARD_AS_ATTACHMENT;
1175         account_id = strtol($2, NULL, 10);
1176         destination = $3;
1177         action = filteringaction_new(action_type,
1178             account_id, destination, 0, 0);
1179 }
1180 | MATCHER_REDIRECT MATCHER_INTEGER MATCHER_STRING
1181 {
1182         gchar *destination = NULL;
1183         gint action_type = 0;
1184         gint account_id = 0;
1185
1186         action_type = MATCHACTION_REDIRECT;
1187         account_id = strtol($2, NULL, 10);
1188         destination = $3;
1189         action = filteringaction_new(action_type,
1190             account_id, destination, 0, 0);
1191 }
1192 | MATCHER_COLOR MATCHER_INTEGER
1193 {
1194         gint action_type = 0;
1195         gint color = 0;
1196
1197         action_type = MATCHACTION_COLOR;
1198         color = strtol($2, NULL, 10);
1199         action = filteringaction_new(action_type, 0, NULL, color, 0);
1200 }
1201 | MATCHER_CHANGE_SCORE MATCHER_INTEGER
1202 {
1203         gint score = 0;
1204         
1205         score = strtol($2, NULL, 10);
1206         action = filteringaction_new(MATCHACTION_CHANGE_SCORE, 0,
1207                                      NULL, 0, score);
1208 }
1209 /* backward compatibility */
1210 | MATCHER_SCORE MATCHER_INTEGER
1211 {
1212         gint score = 0;
1213         
1214         score = strtol($2, NULL, 10);
1215         action = filteringaction_new(MATCHACTION_CHANGE_SCORE, 0,
1216                                      NULL, 0, score);
1217 }
1218 | MATCHER_SET_SCORE MATCHER_INTEGER
1219 {
1220         gint score = 0;
1221         
1222         score = strtol($2, NULL, 10);
1223         action = filteringaction_new(MATCHACTION_SET_SCORE, 0,
1224                                      NULL, 0, score);
1225 }
1226 | MATCHER_HIDE
1227 {
1228         action = filteringaction_new(MATCHACTION_HIDE, 0, NULL, 0, 0);
1229 }
1230 | MATCHER_IGNORE
1231 {
1232         action = filteringaction_new(MATCHACTION_IGNORE, 0, NULL, 0, 0);
1233 }
1234 | MATCHER_STOP
1235 {
1236         action = filteringaction_new(MATCHACTION_STOP, 0, NULL, 0, 0);
1237 }
1238 ;