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