2006-07-31 [wwp] 2.4.0cvs3
[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 fprintf(stderr, "parser %d\n", account_id);
483 fflush(stderr);
484 }
485 ;
486
487 filtering:
488 filtering_action_list
489 {
490         filtering = filteringprop_new(enabled, name, account_id, cond, action_list);
491         enabled = TRUE;
492         account_id = 0;
493         g_free(name);
494         name = NULL;
495         if (enable_compatibility) {
496                 prefs_filtering = &filtering_rules;
497                 if (action_list != NULL) {
498                         FilteringAction * first_action;
499                         
500                         first_action = action_list->data;
501                         
502                         if (first_action->type == MATCHACTION_CHANGE_SCORE)
503                                 prefs_filtering = &pre_global_processing;
504                 }
505         }
506         
507         cond = NULL;
508         action_list = NULL;
509         
510         if ((matcher_parse_op == MATCHER_PARSE_FILE) &&
511             (prefs_filtering != NULL)) {
512                 *prefs_filtering = g_slist_append(*prefs_filtering,
513                                                   filtering);
514                 filtering = NULL;
515         }
516 }
517 ;
518
519 filtering_action_list:
520 filtering_action_b filtering_action_list
521 | filtering_action_b
522 ;
523
524 filtering_action_b:
525 filtering_action
526 {
527         action_list = g_slist_append(action_list, action);
528         action = NULL;
529 }
530 ;
531
532 match_type:
533 MATCHER_MATCHCASE
534 {
535         match_type = MATCHTYPE_MATCHCASE;
536 }
537 | MATCHER_MATCH
538 {
539         match_type = MATCHTYPE_MATCH;
540 }
541 | MATCHER_REGEXPCASE
542 {
543         match_type = MATCHTYPE_REGEXPCASE;
544 }
545 | MATCHER_REGEXP
546 {
547         match_type = MATCHTYPE_REGEXP;
548 }
549 ;
550
551 condition:
552 condition_list
553 {
554         cond = matcherlist_new(matchers_list, (bool_op == MATCHERBOOL_AND));
555         matchers_list = NULL;
556 }
557 ;
558
559 condition_list:
560 condition_list bool_op one_condition
561 {
562         matchers_list = g_slist_append(matchers_list, prop);
563 }
564 | one_condition
565 {
566         matchers_list = NULL;
567         matchers_list = g_slist_append(matchers_list, prop);
568 }
569 ;
570
571 bool_op:
572 MATCHER_AND
573 {
574         bool_op = MATCHERBOOL_AND;
575 }
576 | MATCHER_OR
577 {
578         bool_op = MATCHERBOOL_OR;
579 }
580 ;
581
582 one_condition:
583 MATCHER_ALL
584 {
585         gint criteria = 0;
586
587         criteria = MATCHCRITERIA_ALL;
588         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
589 }
590 | MATCHER_UNREAD
591 {
592         gint criteria = 0;
593
594         criteria = MATCHCRITERIA_UNREAD;
595         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
596 }
597 | MATCHER_NOT_UNREAD 
598 {
599         gint criteria = 0;
600
601         criteria = MATCHCRITERIA_NOT_UNREAD;
602         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
603 }
604 | MATCHER_NEW
605 {
606         gint criteria = 0;
607
608         criteria = MATCHCRITERIA_NEW;
609         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
610 }
611 | MATCHER_NOT_NEW
612 {
613         gint criteria = 0;
614
615         criteria = MATCHCRITERIA_NOT_NEW;
616         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
617 }
618 | MATCHER_MARKED
619 {
620         gint criteria = 0;
621
622         criteria = MATCHCRITERIA_MARKED;
623         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
624 }
625 | MATCHER_NOT_MARKED
626 {
627         gint criteria = 0;
628
629         criteria = MATCHCRITERIA_NOT_MARKED;
630         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
631 }
632 | MATCHER_DELETED
633 {
634         gint criteria = 0;
635
636         criteria = MATCHCRITERIA_DELETED;
637         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
638 }
639 | MATCHER_NOT_DELETED
640 {
641         gint criteria = 0;
642
643         criteria = MATCHCRITERIA_NOT_DELETED;
644         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
645 }
646 | MATCHER_REPLIED
647 {
648         gint criteria = 0;
649
650         criteria = MATCHCRITERIA_REPLIED;
651         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
652 }
653 | MATCHER_NOT_REPLIED
654 {
655         gint criteria = 0;
656
657         criteria = MATCHCRITERIA_NOT_REPLIED;
658         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
659 }
660 | MATCHER_FORWARDED
661 {
662         gint criteria = 0;
663
664         criteria = MATCHCRITERIA_FORWARDED;
665         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
666 }
667 | MATCHER_NOT_FORWARDED
668 {
669         gint criteria = 0;
670
671         criteria = MATCHCRITERIA_NOT_FORWARDED;
672         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
673 }
674 | MATCHER_LOCKED
675 {
676         gint criteria = 0;
677
678         criteria = MATCHCRITERIA_LOCKED;
679         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
680 }
681 | MATCHER_NOT_LOCKED
682 {
683         gint criteria = 0;
684
685         criteria = MATCHCRITERIA_NOT_LOCKED;
686         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
687 }
688 | MATCHER_PARTIAL
689 {
690         gint criteria = 0;
691
692         criteria = MATCHCRITERIA_PARTIAL;
693         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
694 }
695 | MATCHER_NOT_PARTIAL
696 {
697         gint criteria = 0;
698
699         criteria = MATCHCRITERIA_NOT_PARTIAL;
700         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
701 }
702 | MATCHER_COLORLABEL MATCHER_INTEGER
703 {
704         gint criteria = 0;
705         gint value = 0;
706
707         criteria = MATCHCRITERIA_COLORLABEL;
708         value = strtol($2, NULL, 10);
709         if (value < 0) value = 0;
710         else if (value > MAX_COLORLABELS) value = MAX_COLORLABELS;
711         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
712 }
713 | MATCHER_NOT_COLORLABEL MATCHER_INTEGER
714 {
715         gint criteria = 0;
716         gint value = 0;
717
718         criteria = MATCHCRITERIA_NOT_COLORLABEL;
719         value = strtol($2, NULL, 0);
720         if (value < 0) value = 0;
721         else if (value > MAX_COLORLABELS) value = MAX_COLORLABELS;
722         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
723 }
724 | MATCHER_IGNORE_THREAD
725 {
726         gint criteria = 0;
727
728         criteria = MATCHCRITERIA_IGNORE_THREAD;
729         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
730 }
731 | MATCHER_NOT_IGNORE_THREAD
732 {
733         gint criteria = 0;
734
735         criteria = MATCHCRITERIA_NOT_IGNORE_THREAD;
736         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
737 }
738 | MATCHER_SUBJECT match_type MATCHER_STRING
739 {
740         gint criteria = 0;
741         gchar *expr = NULL;
742
743         criteria = MATCHCRITERIA_SUBJECT;
744         expr = $3;
745         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
746 }
747 | MATCHER_NOT_SUBJECT match_type MATCHER_STRING
748 {
749         gint criteria = 0;
750         gchar *expr = NULL;
751
752         criteria = MATCHCRITERIA_NOT_SUBJECT;
753         expr = $3;
754         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
755 }
756 | MATCHER_FROM match_type MATCHER_STRING
757 {
758         gint criteria = 0;
759         gchar *expr = NULL;
760
761         criteria = MATCHCRITERIA_FROM;
762         expr = $3;
763         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
764 }
765 | MATCHER_NOT_FROM match_type MATCHER_STRING
766 {
767         gint criteria = 0;
768         gchar *expr = NULL;
769
770         criteria = MATCHCRITERIA_NOT_FROM;
771         expr = $3;
772         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
773 }
774 | MATCHER_TO match_type MATCHER_STRING
775 {
776         gint criteria = 0;
777         gchar *expr = NULL;
778
779         criteria = MATCHCRITERIA_TO;
780         expr = $3;
781         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
782 }
783 | MATCHER_NOT_TO match_type MATCHER_STRING
784 {
785         gint criteria = 0;
786         gchar *expr = NULL;
787
788         criteria = MATCHCRITERIA_NOT_TO;
789         expr = $3;
790         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
791 }
792 | MATCHER_CC match_type MATCHER_STRING
793 {
794         gint criteria = 0;
795         gchar *expr = NULL;
796
797         criteria = MATCHCRITERIA_CC;
798         expr = $3;
799         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
800 }
801 | MATCHER_NOT_CC match_type MATCHER_STRING
802 {
803         gint criteria = 0;
804         gchar *expr = NULL;
805
806         criteria = MATCHCRITERIA_NOT_CC;
807         expr = $3;
808         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
809 }
810 | MATCHER_TO_OR_CC match_type MATCHER_STRING
811 {
812         gint criteria = 0;
813         gchar *expr = NULL;
814
815         criteria = MATCHCRITERIA_TO_OR_CC;
816         expr = $3;
817         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
818 }
819 | MATCHER_NOT_TO_AND_NOT_CC match_type MATCHER_STRING
820 {
821         gint criteria = 0;
822         gchar *expr = NULL;
823
824         criteria = MATCHCRITERIA_NOT_TO_AND_NOT_CC;
825         expr = $3;
826         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
827 }
828 | MATCHER_AGE_GREATER MATCHER_INTEGER
829 {
830         gint criteria = 0;
831         gint value = 0;
832
833         criteria = MATCHCRITERIA_AGE_GREATER;
834         value = strtol($2, NULL, 0);
835         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
836 }
837 | MATCHER_AGE_LOWER MATCHER_INTEGER
838 {
839         gint criteria = 0;
840         gint value = 0;
841
842         criteria = MATCHCRITERIA_AGE_LOWER;
843         value = strtol($2, NULL, 0);
844         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
845 }
846 | MATCHER_NEWSGROUPS match_type MATCHER_STRING
847 {
848         gint criteria = 0;
849         gchar *expr = NULL;
850
851         criteria = MATCHCRITERIA_NEWSGROUPS;
852         expr = $3;
853         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
854 }
855 | MATCHER_NOT_NEWSGROUPS match_type MATCHER_STRING
856 {
857         gint criteria = 0;
858         gchar *expr = NULL;
859
860         criteria = MATCHCRITERIA_NOT_NEWSGROUPS;
861         expr = $3;
862         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
863 }
864 | MATCHER_INREPLYTO match_type MATCHER_STRING
865 {
866         gint criteria = 0;
867         gchar *expr = NULL;
868
869         criteria = MATCHCRITERIA_INREPLYTO;
870         expr = $3;
871         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
872 }
873 | MATCHER_NOT_INREPLYTO match_type MATCHER_STRING
874 {
875         gint criteria = 0;
876         gchar *expr = NULL;
877
878         criteria = MATCHCRITERIA_NOT_INREPLYTO;
879         expr = $3;
880         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
881 }
882 | MATCHER_REFERENCES match_type MATCHER_STRING
883 {
884         gint criteria = 0;
885         gchar *expr = NULL;
886
887         criteria = MATCHCRITERIA_REFERENCES;
888         expr = $3;
889         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
890 }
891 | MATCHER_NOT_REFERENCES match_type MATCHER_STRING
892 {
893         gint criteria = 0;
894         gchar *expr = NULL;
895
896         criteria = MATCHCRITERIA_NOT_REFERENCES;
897         expr = $3;
898         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
899 }
900 | MATCHER_SCORE_GREATER MATCHER_INTEGER
901 {
902         gint criteria = 0;
903         gint value = 0;
904
905         criteria = MATCHCRITERIA_SCORE_GREATER;
906         value = strtol($2, NULL, 0);
907         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
908 }
909 | MATCHER_SCORE_LOWER MATCHER_INTEGER
910 {
911         gint criteria = 0;
912         gint value = 0;
913
914         criteria = MATCHCRITERIA_SCORE_LOWER;
915         value = strtol($2, NULL, 0);
916         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
917 }
918 | MATCHER_SCORE_EQUAL MATCHER_INTEGER
919 {
920         gint criteria = 0;
921         gint value = 0;
922
923         criteria = MATCHCRITERIA_SCORE_EQUAL;
924         value = strtol($2, NULL, 0);
925         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
926 }
927 | MATCHER_SIZE_GREATER MATCHER_INTEGER 
928 {
929         gint criteria = 0;
930         gint value    = 0;
931         criteria = MATCHCRITERIA_SIZE_GREATER;
932         value = strtol($2, NULL, 0);
933         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
934 }
935 | MATCHER_SIZE_SMALLER MATCHER_INTEGER
936 {
937         gint criteria = 0;
938         gint value    = 0;
939         criteria = MATCHCRITERIA_SIZE_SMALLER;
940         value = strtol($2, NULL, 0);
941         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
942 }
943 | MATCHER_SIZE_EQUAL MATCHER_INTEGER
944 {
945         gint criteria = 0;
946         gint value    = 0;
947         criteria = MATCHCRITERIA_SIZE_EQUAL;
948         value = strtol($2, NULL, 0);
949         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
950 }
951 | MATCHER_HEADER MATCHER_STRING
952 {
953         header = g_strdup($2);
954 } match_type MATCHER_STRING
955 {
956         gint criteria = 0;
957         gchar *expr = NULL;
958
959         criteria = MATCHCRITERIA_HEADER;
960         expr = $2;
961         prop = matcherprop_new(criteria, header, match_type, expr, 0);
962         g_free(header);
963 }
964 | MATCHER_NOT_HEADER MATCHER_STRING
965 {
966         header = g_strdup($2);
967 } match_type MATCHER_STRING
968 {
969         gint criteria = 0;
970         gchar *expr = NULL;
971
972         criteria = MATCHCRITERIA_NOT_HEADER;
973         expr = $2;
974         prop = matcherprop_new(criteria, header, match_type, expr, 0);
975         g_free(header);
976 }
977 | MATCHER_HEADERS_PART match_type MATCHER_STRING
978 {
979         gint criteria = 0;
980         gchar *expr = NULL;
981
982         criteria = MATCHCRITERIA_HEADERS_PART;
983         expr = $3;
984         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
985 }
986 | MATCHER_NOT_HEADERS_PART match_type MATCHER_STRING
987 {
988         gint criteria = 0;
989         gchar *expr = NULL;
990
991         criteria = MATCHCRITERIA_NOT_HEADERS_PART;
992         expr = $3;
993         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
994 }
995 | MATCHER_FOUND_IN_ADDRESSBOOK MATCHER_STRING
996 {
997         header = g_strdup($2);
998 } MATCHER_IN MATCHER_STRING
999 {
1000         gint criteria = 0;
1001         gchar *expr = NULL;
1002
1003         criteria = MATCHCRITERIA_FOUND_IN_ADDRESSBOOK;
1004         expr = $2;
1005         prop = matcherprop_new(criteria, header, match_type, expr, 0);
1006         g_free(header);
1007 }
1008 | MATCHER_NOT_FOUND_IN_ADDRESSBOOK MATCHER_STRING
1009 {
1010         header = g_strdup($2);
1011 } MATCHER_IN MATCHER_STRING
1012 {
1013         gint criteria = 0;
1014         gchar *expr = NULL;
1015
1016         criteria = MATCHCRITERIA_NOT_FOUND_IN_ADDRESSBOOK;
1017         expr = $2;
1018         prop = matcherprop_new(criteria, header, match_type, expr, 0);
1019         g_free(header);
1020 }
1021 | MATCHER_MESSAGE match_type MATCHER_STRING
1022 {
1023         gint criteria = 0;
1024         gchar *expr = NULL;
1025
1026         criteria = MATCHCRITERIA_MESSAGE;
1027         expr = $3;
1028         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1029 }
1030 | MATCHER_NOT_MESSAGE match_type MATCHER_STRING
1031 {
1032         gint criteria = 0;
1033         gchar *expr = NULL;
1034
1035         criteria = MATCHCRITERIA_NOT_MESSAGE;
1036         expr = $3;
1037         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1038 }
1039 | MATCHER_BODY_PART match_type MATCHER_STRING
1040 {
1041         gint criteria = 0;
1042         gchar *expr = NULL;
1043
1044         criteria = MATCHCRITERIA_BODY_PART;
1045         expr = $3;
1046         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1047 }
1048 | MATCHER_NOT_BODY_PART match_type MATCHER_STRING
1049 {
1050         gint criteria = 0;
1051         gchar *expr = NULL;
1052
1053         criteria = MATCHCRITERIA_NOT_BODY_PART;
1054         expr = $3;
1055         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
1056 }
1057 | MATCHER_TEST MATCHER_STRING
1058 {
1059         gint criteria = 0;
1060         gchar *expr = NULL;
1061
1062         criteria = MATCHCRITERIA_TEST;
1063         expr = $2;
1064         prop = matcherprop_new(criteria, NULL, 0, expr, 0);
1065 }
1066 | MATCHER_NOT_TEST MATCHER_STRING
1067 {
1068         gint criteria = 0;
1069         gchar *expr = NULL;
1070
1071         criteria = MATCHCRITERIA_NOT_TEST;
1072         expr = $2;
1073         prop = matcherprop_new(criteria, NULL, 0, expr, 0);
1074 }
1075 ;
1076
1077 filtering_action:
1078 MATCHER_EXECUTE MATCHER_STRING
1079 {
1080         gchar *cmd = NULL;
1081         gint action_type = 0;
1082
1083         action_type = MATCHACTION_EXECUTE;
1084         cmd = $2;
1085         action = filteringaction_new(action_type, 0, cmd, 0, 0);
1086 }
1087 | MATCHER_MOVE MATCHER_STRING
1088 {
1089         gchar *destination = NULL;
1090         gint action_type = 0;
1091
1092         action_type = MATCHACTION_MOVE;
1093         destination = $2;
1094         action = filteringaction_new(action_type, 0, destination, 0, 0);
1095 }
1096 | MATCHER_COPY MATCHER_STRING
1097 {
1098         gchar *destination = NULL;
1099         gint action_type = 0;
1100
1101         action_type = MATCHACTION_COPY;
1102         destination = $2;
1103         action = filteringaction_new(action_type, 0, destination, 0, 0);
1104 }
1105 | MATCHER_DELETE
1106 {
1107         gint action_type = 0;
1108
1109         action_type = MATCHACTION_DELETE;
1110         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1111 }
1112 | MATCHER_MARK
1113 {
1114         gint action_type = 0;
1115
1116         action_type = MATCHACTION_MARK;
1117         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1118 }
1119 | MATCHER_UNMARK
1120 {
1121         gint action_type = 0;
1122
1123         action_type = MATCHACTION_UNMARK;
1124         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1125 }
1126 | MATCHER_LOCK
1127 {
1128         gint action_type = 0;
1129
1130         action_type = MATCHACTION_LOCK;
1131         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1132 }
1133 | MATCHER_UNLOCK
1134 {
1135         gint action_type = 0;
1136
1137         action_type = MATCHACTION_UNLOCK;
1138         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1139 }
1140 | MATCHER_MARK_AS_READ
1141 {
1142         gint action_type = 0;
1143
1144         action_type = MATCHACTION_MARK_AS_READ;
1145         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1146 }
1147 | MATCHER_MARK_AS_UNREAD
1148 {
1149         gint action_type = 0;
1150
1151         action_type = MATCHACTION_MARK_AS_UNREAD;
1152         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1153 }
1154 | MATCHER_FORWARD MATCHER_INTEGER MATCHER_STRING
1155 {
1156         gchar *destination = NULL;
1157         gint action_type = 0;
1158         gint account_id = 0;
1159
1160         action_type = MATCHACTION_FORWARD;
1161         account_id = strtol($2, NULL, 10);
1162         destination = $3;
1163         action = filteringaction_new(action_type,
1164             account_id, destination, 0, 0);
1165 }
1166 | MATCHER_FORWARD_AS_ATTACHMENT MATCHER_INTEGER MATCHER_STRING
1167 {
1168         gchar *destination = NULL;
1169         gint action_type = 0;
1170         gint account_id = 0;
1171
1172         action_type = MATCHACTION_FORWARD_AS_ATTACHMENT;
1173         account_id = strtol($2, NULL, 10);
1174         destination = $3;
1175         action = filteringaction_new(action_type,
1176             account_id, destination, 0, 0);
1177 }
1178 | MATCHER_REDIRECT MATCHER_INTEGER MATCHER_STRING
1179 {
1180         gchar *destination = NULL;
1181         gint action_type = 0;
1182         gint account_id = 0;
1183
1184         action_type = MATCHACTION_REDIRECT;
1185         account_id = strtol($2, NULL, 10);
1186         destination = $3;
1187         action = filteringaction_new(action_type,
1188             account_id, destination, 0, 0);
1189 }
1190 | MATCHER_COLOR MATCHER_INTEGER
1191 {
1192         gint action_type = 0;
1193         gint color = 0;
1194
1195         action_type = MATCHACTION_COLOR;
1196         color = strtol($2, NULL, 10);
1197         action = filteringaction_new(action_type, 0, NULL, color, 0);
1198 }
1199 | MATCHER_CHANGE_SCORE MATCHER_INTEGER
1200 {
1201         gint score = 0;
1202         
1203         score = strtol($2, NULL, 10);
1204         action = filteringaction_new(MATCHACTION_CHANGE_SCORE, 0,
1205                                      NULL, 0, score);
1206 }
1207 /* backward compatibility */
1208 | MATCHER_SCORE MATCHER_INTEGER
1209 {
1210         gint score = 0;
1211         
1212         score = strtol($2, NULL, 10);
1213         action = filteringaction_new(MATCHACTION_CHANGE_SCORE, 0,
1214                                      NULL, 0, score);
1215 }
1216 | MATCHER_SET_SCORE MATCHER_INTEGER
1217 {
1218         gint score = 0;
1219         
1220         score = strtol($2, NULL, 10);
1221         action = filteringaction_new(MATCHACTION_SET_SCORE, 0,
1222                                      NULL, 0, score);
1223 }
1224 | MATCHER_HIDE
1225 {
1226         action = filteringaction_new(MATCHACTION_HIDE, 0, NULL, 0, 0);
1227 }
1228 | MATCHER_IGNORE
1229 {
1230         action = filteringaction_new(MATCHACTION_IGNORE, 0, NULL, 0, 0);
1231 }
1232 | MATCHER_STOP
1233 {
1234         action = filteringaction_new(MATCHACTION_STOP, 0, NULL, 0, 0);
1235 }
1236 ;