abe5b2ab1b3b927eb61117d02d3f51b4a4242a4f
[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 Sylpheed Claws 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 MatcherList *cond;
47 static GSList *action_list = NULL;
48 static FilteringAction *action = NULL;
49
50 static FilteringProp *filtering;
51
52 static GSList **prefs_filtering = NULL;
53 static int enable_compatibility = 0;
54
55 enum {
56         MATCHER_PARSE_FILE,
57         MATCHER_PARSE_NO_EOL,
58         MATCHER_PARSE_CONDITION,
59         MATCHER_PARSE_FILTERING_ACTION,
60 };
61
62 static int matcher_parse_op = MATCHER_PARSE_FILE;
63
64
65 /* ******************************************************************** */
66
67 void matcher_parser_start_parsing(FILE *f)
68 {
69         matcher_parserrestart(f);
70         matcher_parserparse();
71 }
72
73  
74 void * matcher_parser_scan_string(const char * str);
75  
76 FilteringProp *matcher_parser_get_filtering(gchar *str)
77 {
78         void *bufstate;
79
80         /* bad coding to enable the sub-grammar matching
81            in yacc */
82         matcher_parserlineno = 1;
83         matcher_parse_op = MATCHER_PARSE_NO_EOL;
84         matcher_parserrestart(NULL);
85         matcher_parser_init();
86         bufstate = matcher_parser_scan_string((const char *) str);
87         matcher_parser_switch_to_buffer(bufstate);
88         if (matcher_parserparse() != 0)
89                 filtering = NULL;
90         matcher_parse_op = MATCHER_PARSE_FILE;
91         matcher_parser_delete_buffer(bufstate);
92         return filtering;
93 }
94
95 static gboolean check_quote_symetry(gchar *str)
96 {
97         const gchar *walk;
98         int ret = 0;
99         
100         if (str == NULL)
101                 return TRUE; /* heh, that's symetric */
102         if (*str == '\0')
103                 return TRUE;
104         for (walk = str; *walk; walk++) {
105                 if (*walk == '\"') {
106                         if (walk == str         /* first char */
107                         || *(walk - 1) != '\\') /* not escaped */
108                                 ret ++;
109                 }
110         }
111         return !(ret % 2);
112 }
113
114 MatcherList *matcher_parser_get_cond(gchar *str)
115 {
116         void *bufstate;
117
118         if (!check_quote_symetry(str)) {
119                 cond = NULL;
120                 return cond;
121         }
122         
123         /* bad coding to enable the sub-grammar matching
124            in yacc */
125         matcher_parserlineno = 1;
126         matcher_parse_op = MATCHER_PARSE_CONDITION;
127         matcher_parserrestart(NULL);
128         matcher_parser_init();
129         bufstate = matcher_parser_scan_string(str);
130         matcher_parserparse();
131         matcher_parse_op = MATCHER_PARSE_FILE;
132         matcher_parser_delete_buffer(bufstate);
133         return cond;
134 }
135
136 GSList *matcher_parser_get_action_list(gchar *str)
137 {
138         void *bufstate;
139
140         if (!check_quote_symetry(str)) {
141                 action_list = NULL;
142                 return action_list;
143         }
144         
145         /* bad coding to enable the sub-grammar matching
146            in yacc */
147         matcher_parserlineno = 1;
148         matcher_parse_op = MATCHER_PARSE_FILTERING_ACTION;
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 action_list;
156 }
157
158 MatcherProp *matcher_parser_get_prop(gchar *str)
159 {
160         MatcherList *list;
161         MatcherProp *prop;
162
163         matcher_parserlineno = 1;
164         list = matcher_parser_get_cond(str);
165         if (list == NULL)
166                 return NULL;
167
168         if (list->matchers == NULL)
169                 return NULL;
170
171         if (list->matchers->next != NULL)
172                 return NULL;
173
174         prop = list->matchers->data;
175
176         g_slist_free(list->matchers);
177         g_free(list);
178
179         return prop;
180 }
181
182 void matcher_parsererror(char *str)
183 {
184         GSList *l;
185
186         if (matchers_list) {
187                 for (l = matchers_list; l != NULL; l = g_slist_next(l)) {
188                         matcherprop_free((MatcherProp *)
189                                          l->data);
190                         l->data = NULL;
191                 }
192                 g_slist_free(matchers_list);
193                 matchers_list = NULL;
194         }
195         cond = NULL;
196         g_warning("filtering parsing: %i: %s\n",
197                   matcher_parserlineno, str);
198         error = 1;
199 }
200
201 int matcher_parserwrap(void)
202 {
203         return 1;
204 }
205 %}
206
207 %union {
208         char *str;
209         int value;
210 }
211
212 %token MATCHER_ALL MATCHER_UNREAD  MATCHER_NOT_UNREAD 
213 %token MATCHER_NEW  MATCHER_NOT_NEW  MATCHER_MARKED
214 %token MATCHER_NOT_MARKED  MATCHER_DELETED  MATCHER_NOT_DELETED
215 %token MATCHER_REPLIED  MATCHER_NOT_REPLIED  MATCHER_FORWARDED
216 %token MATCHER_NOT_FORWARDED  MATCHER_SUBJECT  MATCHER_NOT_SUBJECT
217 %token MATCHER_FROM  MATCHER_NOT_FROM  MATCHER_TO  MATCHER_NOT_TO
218 %token MATCHER_CC  MATCHER_NOT_CC  MATCHER_TO_OR_CC  MATCHER_NOT_TO_AND_NOT_CC
219 %token MATCHER_AGE_GREATER  MATCHER_AGE_LOWER  MATCHER_NEWSGROUPS
220 %token MATCHER_NOT_NEWSGROUPS  MATCHER_INREPLYTO  MATCHER_NOT_INREPLYTO
221 %token MATCHER_REFERENCES  MATCHER_NOT_REFERENCES  MATCHER_SCORE_GREATER
222 %token MATCHER_SCORE_LOWER  MATCHER_HEADER  MATCHER_NOT_HEADER
223 %token MATCHER_HEADERS_PART  MATCHER_NOT_HEADERS_PART  MATCHER_MESSAGE
224 %token MATCHER_NOT_MESSAGE  MATCHER_BODY_PART  MATCHER_NOT_BODY_PART
225 %token MATCHER_TEST  MATCHER_NOT_TEST  MATCHER_MATCHCASE  MATCHER_MATCH
226 %token MATCHER_REGEXPCASE  MATCHER_REGEXP  MATCHER_SCORE  MATCHER_MOVE
227 %token MATCHER_ANY_IN_ADDRESSBOOK MATCHER_ALL_IN_ADDRESSBOOK
228 %token MATCHER_COPY  MATCHER_DELETE  MATCHER_MARK  MATCHER_UNMARK
229 %token MATCHER_LOCK MATCHER_UNLOCK
230 %token MATCHER_EXECUTE
231 %token MATCHER_MARK_AS_READ  MATCHER_MARK_AS_UNREAD  MATCHER_FORWARD
232 %token MATCHER_FORWARD_AS_ATTACHMENT  MATCHER_EOL  MATCHER_STRING  
233 %token MATCHER_OR MATCHER_AND  
234 %token MATCHER_COLOR MATCHER_SCORE_EQUAL MATCHER_REDIRECT 
235 %token MATCHER_SIZE_GREATER MATCHER_SIZE_SMALLER MATCHER_SIZE_EQUAL
236 %token MATCHER_LOCKED MATCHER_NOT_LOCKED
237 %token MATCHER_PARTIAL MATCHER_NOT_PARTIAL
238 %token MATCHER_COLORLABEL MATCHER_NOT_COLORLABEL
239 %token MATCHER_IGNORE_THREAD MATCHER_NOT_IGNORE_THREAD
240 %token MATCHER_CHANGE_SCORE MATCHER_SET_SCORE
241 %token MATCHER_STOP MATCHER_HIDE
242
243 %start file
244
245 %token <str> MATCHER_STRING
246 %token <str> MATCHER_SECTION
247 %token <str> MATCHER_INTEGER
248
249 %%
250
251 file:
252 {
253         if (matcher_parse_op == MATCHER_PARSE_FILE) {
254                 prefs_filtering = &pre_global_processing;
255         }
256 }
257 file_line_list;
258
259 file_line_list:
260 file_line
261 file_line_list
262 | file_line
263 ;
264
265 file_line:
266 section_notification
267
268 { action_list = NULL; }
269 instruction
270 | error MATCHER_EOL
271 {
272         yyerrok;
273 };
274
275 section_notification:
276 MATCHER_SECTION MATCHER_EOL
277 {
278         gchar *folder = $1;
279         FolderItem *item = NULL;
280
281         if (matcher_parse_op == MATCHER_PARSE_FILE) {
282                 enable_compatibility = 0;
283                 if (!strcmp(folder, "global")) {
284                         /* backward compatibility */
285                         enable_compatibility = 1;
286                 }
287                 else if (!strcmp(folder, "preglobal")) {
288                         prefs_filtering = &pre_global_processing;
289                 }
290                 else if (!strcmp(folder, "postglobal")) {
291                         prefs_filtering = &post_global_processing;
292                 }
293                 else if (!strcmp(folder, "filtering")) {
294                         prefs_filtering = &filtering_rules;
295                 }
296                 else {
297                         item = folder_find_item_from_identifier(folder);
298                         if (item != NULL) {
299                                 prefs_filtering = &item->prefs->processing;
300                         } else {
301                                 prefs_filtering = NULL;
302                         }
303                 }
304         }
305 }
306 ;
307
308 instruction:
309 condition filtering MATCHER_EOL
310 | condition filtering
311 {
312         if (matcher_parse_op == MATCHER_PARSE_NO_EOL)
313                 YYACCEPT;
314         else {
315                 matcher_parsererror("parse error");
316                 YYERROR;
317         }
318 }
319 | condition
320 {
321         if (matcher_parse_op == MATCHER_PARSE_CONDITION)
322                 YYACCEPT;
323         else {
324                 matcher_parsererror("parse error");
325                 YYERROR;
326         }
327 }
328 | filtering_action_list
329 {
330         if (matcher_parse_op == MATCHER_PARSE_FILTERING_ACTION)
331                 YYACCEPT;
332         else {
333                 matcher_parsererror("parse error");
334                 YYERROR;
335         }
336 }
337 | MATCHER_EOL
338 ;
339
340 filtering:
341 filtering_action_list
342 {
343         filtering = filteringprop_new(cond, action_list);
344         
345         if (enable_compatibility) {
346                 prefs_filtering = &filtering_rules;
347                 if (action_list != NULL) {
348                         FilteringAction * first_action;
349                         
350                         first_action = action_list->data;
351                         
352                         if (first_action->type == MATCHACTION_CHANGE_SCORE)
353                                 prefs_filtering = &pre_global_processing;
354                 }
355         }
356         
357         cond = NULL;
358         action_list = NULL;
359         
360         if ((matcher_parse_op == MATCHER_PARSE_FILE) &&
361             (prefs_filtering != NULL)) {
362                 *prefs_filtering = g_slist_append(*prefs_filtering,
363                                                   filtering);
364                 filtering = NULL;
365         }
366 }
367 ;
368
369 filtering_action_list:
370 filtering_action_b filtering_action_list
371 | filtering_action_b
372 ;
373
374 filtering_action_b:
375 filtering_action
376 {
377         action_list = g_slist_append(action_list, action);
378         action = NULL;
379 }
380 ;
381
382 match_type:
383 MATCHER_MATCHCASE
384 {
385         match_type = MATCHTYPE_MATCHCASE;
386 }
387 | MATCHER_MATCH
388 {
389         match_type = MATCHTYPE_MATCH;
390 }
391 | MATCHER_REGEXPCASE
392 {
393         match_type = MATCHTYPE_REGEXPCASE;
394 }
395 | MATCHER_REGEXP
396 {
397         match_type = MATCHTYPE_REGEXP;
398 }
399 | MATCHER_ANY_IN_ADDRESSBOOK
400 {
401         match_type = MATCHTYPE_ANY_IN_ADDRESSBOOK;
402 }
403 | MATCHER_ALL_IN_ADDRESSBOOK
404 {
405         match_type = MATCHTYPE_ALL_IN_ADDRESSBOOK;
406 }
407 ;
408
409 condition:
410 condition_list
411 {
412         cond = matcherlist_new(matchers_list, (bool_op == MATCHERBOOL_AND));
413         matchers_list = NULL;
414 }
415 ;
416
417 condition_list:
418 condition_list bool_op one_condition
419 {
420         matchers_list = g_slist_append(matchers_list, prop);
421 }
422 | one_condition
423 {
424         matchers_list = NULL;
425         matchers_list = g_slist_append(matchers_list, prop);
426 }
427 ;
428
429 bool_op:
430 MATCHER_AND
431 {
432         bool_op = MATCHERBOOL_AND;
433 }
434 | MATCHER_OR
435 {
436         bool_op = MATCHERBOOL_OR;
437 }
438 ;
439
440 one_condition:
441 MATCHER_ALL
442 {
443         gint criteria = 0;
444
445         criteria = MATCHCRITERIA_ALL;
446         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
447 }
448 | MATCHER_UNREAD
449 {
450         gint criteria = 0;
451
452         criteria = MATCHCRITERIA_UNREAD;
453         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
454 }
455 | MATCHER_NOT_UNREAD 
456 {
457         gint criteria = 0;
458
459         criteria = MATCHCRITERIA_NOT_UNREAD;
460         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
461 }
462 | MATCHER_NEW
463 {
464         gint criteria = 0;
465
466         criteria = MATCHCRITERIA_NEW;
467         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
468 }
469 | MATCHER_NOT_NEW
470 {
471         gint criteria = 0;
472
473         criteria = MATCHCRITERIA_NOT_NEW;
474         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
475 }
476 | MATCHER_MARKED
477 {
478         gint criteria = 0;
479
480         criteria = MATCHCRITERIA_MARKED;
481         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
482 }
483 | MATCHER_NOT_MARKED
484 {
485         gint criteria = 0;
486
487         criteria = MATCHCRITERIA_NOT_MARKED;
488         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
489 }
490 | MATCHER_DELETED
491 {
492         gint criteria = 0;
493
494         criteria = MATCHCRITERIA_DELETED;
495         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
496 }
497 | MATCHER_NOT_DELETED
498 {
499         gint criteria = 0;
500
501         criteria = MATCHCRITERIA_NOT_DELETED;
502         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
503 }
504 | MATCHER_REPLIED
505 {
506         gint criteria = 0;
507
508         criteria = MATCHCRITERIA_REPLIED;
509         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
510 }
511 | MATCHER_NOT_REPLIED
512 {
513         gint criteria = 0;
514
515         criteria = MATCHCRITERIA_NOT_REPLIED;
516         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
517 }
518 | MATCHER_FORWARDED
519 {
520         gint criteria = 0;
521
522         criteria = MATCHCRITERIA_FORWARDED;
523         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
524 }
525 | MATCHER_NOT_FORWARDED
526 {
527         gint criteria = 0;
528
529         criteria = MATCHCRITERIA_NOT_FORWARDED;
530         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
531 }
532 | MATCHER_LOCKED
533 {
534         gint criteria = 0;
535
536         criteria = MATCHCRITERIA_LOCKED;
537         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
538 }
539 | MATCHER_NOT_LOCKED
540 {
541         gint criteria = 0;
542
543         criteria = MATCHCRITERIA_NOT_LOCKED;
544         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
545 }
546 | MATCHER_PARTIAL
547 {
548         gint criteria = 0;
549
550         criteria = MATCHCRITERIA_PARTIAL;
551         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
552 }
553 | MATCHER_NOT_PARTIAL
554 {
555         gint criteria = 0;
556
557         criteria = MATCHCRITERIA_NOT_PARTIAL;
558         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
559 }
560 | MATCHER_COLORLABEL MATCHER_INTEGER
561 {
562         gint criteria = 0;
563         gint value = 0;
564
565         criteria = MATCHCRITERIA_COLORLABEL;
566         value = strtol($2, NULL, 10);
567         if (value < 0) value = 0;
568         else if (value > MAX_COLORLABELS) value = MAX_COLORLABELS;
569         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
570 }
571 | MATCHER_NOT_COLORLABEL MATCHER_INTEGER
572 {
573         gint criteria = 0;
574         gint value = 0;
575
576         criteria = MATCHCRITERIA_NOT_COLORLABEL;
577         value = strtol($2, NULL, 0);
578         if (value < 0) value = 0;
579         else if (value > MAX_COLORLABELS) value = MAX_COLORLABELS;
580         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
581 }
582 | MATCHER_IGNORE_THREAD
583 {
584         gint criteria = 0;
585
586         criteria = MATCHCRITERIA_IGNORE_THREAD;
587         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
588 }
589 | MATCHER_NOT_IGNORE_THREAD
590 {
591         gint criteria = 0;
592
593         criteria = MATCHCRITERIA_NOT_IGNORE_THREAD;
594         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
595 }
596 | MATCHER_SUBJECT match_type MATCHER_STRING
597 {
598         gint criteria = 0;
599         gchar *expr = NULL;
600
601         criteria = MATCHCRITERIA_SUBJECT;
602         expr = $3;
603         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
604 }
605 | MATCHER_NOT_SUBJECT match_type MATCHER_STRING
606 {
607         gint criteria = 0;
608         gchar *expr = NULL;
609
610         criteria = MATCHCRITERIA_NOT_SUBJECT;
611         expr = $3;
612         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
613 }
614 | MATCHER_FROM match_type MATCHER_STRING
615 {
616         gint criteria = 0;
617         gchar *expr = NULL;
618
619         criteria = MATCHCRITERIA_FROM;
620         expr = $3;
621         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
622 }
623 | MATCHER_NOT_FROM match_type MATCHER_STRING
624 {
625         gint criteria = 0;
626         gchar *expr = NULL;
627
628         criteria = MATCHCRITERIA_NOT_FROM;
629         expr = $3;
630         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
631 }
632 | MATCHER_TO match_type MATCHER_STRING
633 {
634         gint criteria = 0;
635         gchar *expr = NULL;
636
637         criteria = MATCHCRITERIA_TO;
638         expr = $3;
639         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
640 }
641 | MATCHER_NOT_TO match_type MATCHER_STRING
642 {
643         gint criteria = 0;
644         gchar *expr = NULL;
645
646         criteria = MATCHCRITERIA_NOT_TO;
647         expr = $3;
648         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
649 }
650 | MATCHER_CC match_type MATCHER_STRING
651 {
652         gint criteria = 0;
653         gchar *expr = NULL;
654
655         criteria = MATCHCRITERIA_CC;
656         expr = $3;
657         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
658 }
659 | MATCHER_NOT_CC match_type MATCHER_STRING
660 {
661         gint criteria = 0;
662         gchar *expr = NULL;
663
664         criteria = MATCHCRITERIA_NOT_CC;
665         expr = $3;
666         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
667 }
668 | MATCHER_TO_OR_CC match_type MATCHER_STRING
669 {
670         gint criteria = 0;
671         gchar *expr = NULL;
672
673         criteria = MATCHCRITERIA_TO_OR_CC;
674         expr = $3;
675         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
676 }
677 | MATCHER_NOT_TO_AND_NOT_CC match_type MATCHER_STRING
678 {
679         gint criteria = 0;
680         gchar *expr = NULL;
681
682         criteria = MATCHCRITERIA_NOT_TO_AND_NOT_CC;
683         expr = $3;
684         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
685 }
686 | MATCHER_AGE_GREATER MATCHER_INTEGER
687 {
688         gint criteria = 0;
689         gint value = 0;
690
691         criteria = MATCHCRITERIA_AGE_GREATER;
692         value = strtol($2, NULL, 0);
693         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
694 }
695 | MATCHER_AGE_LOWER MATCHER_INTEGER
696 {
697         gint criteria = 0;
698         gint value = 0;
699
700         criteria = MATCHCRITERIA_AGE_LOWER;
701         value = strtol($2, NULL, 0);
702         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
703 }
704 | MATCHER_NEWSGROUPS match_type MATCHER_STRING
705 {
706         gint criteria = 0;
707         gchar *expr = NULL;
708
709         criteria = MATCHCRITERIA_NEWSGROUPS;
710         expr = $3;
711         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
712 }
713 | MATCHER_NOT_NEWSGROUPS match_type MATCHER_STRING
714 {
715         gint criteria = 0;
716         gchar *expr = NULL;
717
718         criteria = MATCHCRITERIA_NOT_NEWSGROUPS;
719         expr = $3;
720         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
721 }
722 | MATCHER_INREPLYTO match_type MATCHER_STRING
723 {
724         gint criteria = 0;
725         gchar *expr = NULL;
726
727         criteria = MATCHCRITERIA_INREPLYTO;
728         expr = $3;
729         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
730 }
731 | MATCHER_NOT_INREPLYTO match_type MATCHER_STRING
732 {
733         gint criteria = 0;
734         gchar *expr = NULL;
735
736         criteria = MATCHCRITERIA_NOT_INREPLYTO;
737         expr = $3;
738         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
739 }
740 | MATCHER_REFERENCES match_type MATCHER_STRING
741 {
742         gint criteria = 0;
743         gchar *expr = NULL;
744
745         criteria = MATCHCRITERIA_REFERENCES;
746         expr = $3;
747         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
748 }
749 | MATCHER_NOT_REFERENCES match_type MATCHER_STRING
750 {
751         gint criteria = 0;
752         gchar *expr = NULL;
753
754         criteria = MATCHCRITERIA_NOT_REFERENCES;
755         expr = $3;
756         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
757 }
758 | MATCHER_SCORE_GREATER MATCHER_INTEGER
759 {
760         gint criteria = 0;
761         gint value = 0;
762
763         criteria = MATCHCRITERIA_SCORE_GREATER;
764         value = strtol($2, NULL, 0);
765         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
766 }
767 | MATCHER_SCORE_LOWER MATCHER_INTEGER
768 {
769         gint criteria = 0;
770         gint value = 0;
771
772         criteria = MATCHCRITERIA_SCORE_LOWER;
773         value = strtol($2, NULL, 0);
774         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
775 }
776 | MATCHER_SCORE_EQUAL MATCHER_INTEGER
777 {
778         gint criteria = 0;
779         gint value = 0;
780
781         criteria = MATCHCRITERIA_SCORE_EQUAL;
782         value = strtol($2, NULL, 0);
783         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
784 }
785 | MATCHER_SIZE_GREATER MATCHER_INTEGER 
786 {
787         gint criteria = 0;
788         gint value    = 0;
789         criteria = MATCHCRITERIA_SIZE_GREATER;
790         value = strtol($2, NULL, 0);
791         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
792 }
793 | MATCHER_SIZE_SMALLER MATCHER_INTEGER
794 {
795         gint criteria = 0;
796         gint value    = 0;
797         criteria = MATCHCRITERIA_SIZE_SMALLER;
798         value = strtol($2, NULL, 0);
799         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
800 }
801 | MATCHER_SIZE_EQUAL MATCHER_INTEGER
802 {
803         gint criteria = 0;
804         gint value    = 0;
805         criteria = MATCHCRITERIA_SIZE_EQUAL;
806         value = strtol($2, NULL, 0);
807         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
808 }
809 | MATCHER_HEADER MATCHER_STRING
810 {
811         header = g_strdup($2);
812 } match_type MATCHER_STRING
813 {
814         gint criteria = 0;
815         gchar *expr = NULL;
816
817         criteria = MATCHCRITERIA_HEADER;
818         expr = $2;
819         prop = matcherprop_new(criteria, header, match_type, expr, 0);
820         g_free(header);
821 }
822 | MATCHER_NOT_HEADER MATCHER_STRING
823 {
824         header = g_strdup($2);
825 } match_type MATCHER_STRING
826 {
827         gint criteria = 0;
828         gchar *expr = NULL;
829
830         criteria = MATCHCRITERIA_NOT_HEADER;
831         expr = $2;
832         prop = matcherprop_new(criteria, header, match_type, expr, 0);
833         g_free(header);
834 }
835 | MATCHER_HEADERS_PART match_type MATCHER_STRING
836 {
837         gint criteria = 0;
838         gchar *expr = NULL;
839
840         criteria = MATCHCRITERIA_HEADERS_PART;
841         expr = $3;
842         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
843 }
844 | MATCHER_NOT_HEADERS_PART match_type MATCHER_STRING
845 {
846         gint criteria = 0;
847         gchar *expr = NULL;
848
849         criteria = MATCHCRITERIA_NOT_HEADERS_PART;
850         expr = $3;
851         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
852 }
853 | MATCHER_MESSAGE match_type MATCHER_STRING
854 {
855         gint criteria = 0;
856         gchar *expr = NULL;
857
858         criteria = MATCHCRITERIA_MESSAGE;
859         expr = $3;
860         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
861 }
862 | MATCHER_NOT_MESSAGE match_type MATCHER_STRING
863 {
864         gint criteria = 0;
865         gchar *expr = NULL;
866
867         criteria = MATCHCRITERIA_NOT_MESSAGE;
868         expr = $3;
869         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
870 }
871 | MATCHER_BODY_PART match_type MATCHER_STRING
872 {
873         gint criteria = 0;
874         gchar *expr = NULL;
875
876         criteria = MATCHCRITERIA_BODY_PART;
877         expr = $3;
878         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
879 }
880 | MATCHER_NOT_BODY_PART match_type MATCHER_STRING
881 {
882         gint criteria = 0;
883         gchar *expr = NULL;
884
885         criteria = MATCHCRITERIA_NOT_BODY_PART;
886         expr = $3;
887         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
888 }
889 | MATCHER_TEST MATCHER_STRING
890 {
891         gint criteria = 0;
892         gchar *expr = NULL;
893
894         criteria = MATCHCRITERIA_TEST;
895         expr = $2;
896         prop = matcherprop_new(criteria, NULL, 0, expr, 0);
897 }
898 | MATCHER_NOT_TEST MATCHER_STRING
899 {
900         gint criteria = 0;
901         gchar *expr = NULL;
902
903         criteria = MATCHCRITERIA_NOT_TEST;
904         expr = $2;
905         prop = matcherprop_new(criteria, NULL, 0, expr, 0);
906 }
907 ;
908
909 filtering_action:
910 MATCHER_EXECUTE MATCHER_STRING
911 {
912         gchar *cmd = NULL;
913         gint action_type = 0;
914
915         action_type = MATCHACTION_EXECUTE;
916         cmd = $2;
917         action = filteringaction_new(action_type, 0, cmd, 0, 0);
918 }
919 | MATCHER_MOVE MATCHER_STRING
920 {
921         gchar *destination = NULL;
922         gint action_type = 0;
923
924         action_type = MATCHACTION_MOVE;
925         destination = $2;
926         action = filteringaction_new(action_type, 0, destination, 0, 0);
927 }
928 | MATCHER_COPY MATCHER_STRING
929 {
930         gchar *destination = NULL;
931         gint action_type = 0;
932
933         action_type = MATCHACTION_COPY;
934         destination = $2;
935         action = filteringaction_new(action_type, 0, destination, 0, 0);
936 }
937 | MATCHER_DELETE
938 {
939         gint action_type = 0;
940
941         action_type = MATCHACTION_DELETE;
942         action = filteringaction_new(action_type, 0, NULL, 0, 0);
943 }
944 | MATCHER_MARK
945 {
946         gint action_type = 0;
947
948         action_type = MATCHACTION_MARK;
949         action = filteringaction_new(action_type, 0, NULL, 0, 0);
950 }
951 | MATCHER_UNMARK
952 {
953         gint action_type = 0;
954
955         action_type = MATCHACTION_UNMARK;
956         action = filteringaction_new(action_type, 0, NULL, 0, 0);
957 }
958 | MATCHER_LOCK
959 {
960         gint action_type = 0;
961
962         action_type = MATCHACTION_LOCK;
963         action = filteringaction_new(action_type, 0, NULL, 0, 0);
964 }
965 | MATCHER_UNLOCK
966 {
967         gint action_type = 0;
968
969         action_type = MATCHACTION_UNLOCK;
970         action = filteringaction_new(action_type, 0, NULL, 0, 0);
971 }
972 | MATCHER_MARK_AS_READ
973 {
974         gint action_type = 0;
975
976         action_type = MATCHACTION_MARK_AS_READ;
977         action = filteringaction_new(action_type, 0, NULL, 0, 0);
978 }
979 | MATCHER_MARK_AS_UNREAD
980 {
981         gint action_type = 0;
982
983         action_type = MATCHACTION_MARK_AS_UNREAD;
984         action = filteringaction_new(action_type, 0, NULL, 0, 0);
985 }
986 | MATCHER_FORWARD MATCHER_INTEGER MATCHER_STRING
987 {
988         gchar *destination = NULL;
989         gint action_type = 0;
990         gint account_id = 0;
991
992         action_type = MATCHACTION_FORWARD;
993         account_id = strtol($2, NULL, 10);
994         destination = $3;
995         action = filteringaction_new(action_type,
996             account_id, destination, 0, 0);
997 }
998 | MATCHER_FORWARD_AS_ATTACHMENT MATCHER_INTEGER MATCHER_STRING
999 {
1000         gchar *destination = NULL;
1001         gint action_type = 0;
1002         gint account_id = 0;
1003
1004         action_type = MATCHACTION_FORWARD_AS_ATTACHMENT;
1005         account_id = strtol($2, NULL, 10);
1006         destination = $3;
1007         action = filteringaction_new(action_type,
1008             account_id, destination, 0, 0);
1009 }
1010 | MATCHER_REDIRECT MATCHER_INTEGER MATCHER_STRING
1011 {
1012         gchar *destination = NULL;
1013         gint action_type = 0;
1014         gint account_id = 0;
1015
1016         action_type = MATCHACTION_REDIRECT;
1017         account_id = strtol($2, NULL, 10);
1018         destination = $3;
1019         action = filteringaction_new(action_type,
1020             account_id, destination, 0, 0);
1021 }
1022 | MATCHER_COLOR MATCHER_INTEGER
1023 {
1024         gint action_type = 0;
1025         gint color = 0;
1026
1027         action_type = MATCHACTION_COLOR;
1028         color = strtol($2, NULL, 10);
1029         action = filteringaction_new(action_type, 0, NULL, color, 0);
1030 }
1031 | MATCHER_CHANGE_SCORE MATCHER_INTEGER
1032 {
1033         gint score = 0;
1034         
1035         score = strtol($2, NULL, 10);
1036         action = filteringaction_new(MATCHACTION_CHANGE_SCORE, 0,
1037                                      NULL, 0, score);
1038 }
1039 /* backward compatibility */
1040 | MATCHER_SCORE MATCHER_INTEGER
1041 {
1042         gint score = 0;
1043         
1044         score = strtol($2, NULL, 10);
1045         action = filteringaction_new(MATCHACTION_CHANGE_SCORE, 0,
1046                                      NULL, 0, score);
1047 }
1048 | MATCHER_SET_SCORE MATCHER_INTEGER
1049 {
1050         gint score = 0;
1051         
1052         score = strtol($2, NULL, 10);
1053         action = filteringaction_new(MATCHACTION_SET_SCORE, 0,
1054                                      NULL, 0, score);
1055 }
1056 | MATCHER_HIDE
1057 {
1058         action = filteringaction_new(MATCHACTION_HIDE, 0, NULL, 0, 0);
1059 }
1060 | MATCHER_STOP
1061 {
1062         action = filteringaction_new(MATCHACTION_STOP, 0, NULL, 0, 0);
1063 }
1064 ;