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