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