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