39997d953e70883107e98ca899b95f89f9a467c8
[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 filtering:
388 filtering_action_list
389 {
390         filtering = filteringprop_new(name, cond, action_list);
391         g_free(name);
392         name = NULL;
393         if (enable_compatibility) {
394                 prefs_filtering = &filtering_rules;
395                 if (action_list != NULL) {
396                         FilteringAction * first_action;
397                         
398                         first_action = action_list->data;
399                         
400                         if (first_action->type == MATCHACTION_CHANGE_SCORE)
401                                 prefs_filtering = &pre_global_processing;
402                 }
403         }
404         
405         cond = NULL;
406         action_list = NULL;
407         
408         if ((matcher_parse_op == MATCHER_PARSE_FILE) &&
409             (prefs_filtering != NULL)) {
410                 *prefs_filtering = g_slist_append(*prefs_filtering,
411                                                   filtering);
412                 filtering = NULL;
413         }
414 }
415 ;
416
417 filtering_action_list:
418 filtering_action_b filtering_action_list
419 | filtering_action_b
420 ;
421
422 filtering_action_b:
423 filtering_action
424 {
425         action_list = g_slist_append(action_list, action);
426         action = NULL;
427 }
428 ;
429
430 match_type:
431 MATCHER_MATCHCASE
432 {
433         match_type = MATCHTYPE_MATCHCASE;
434 }
435 | MATCHER_MATCH
436 {
437         match_type = MATCHTYPE_MATCH;
438 }
439 | MATCHER_REGEXPCASE
440 {
441         match_type = MATCHTYPE_REGEXPCASE;
442 }
443 | MATCHER_REGEXP
444 {
445         match_type = MATCHTYPE_REGEXP;
446 }
447 | MATCHER_ANY_IN_ADDRESSBOOK
448 {
449         match_type = MATCHTYPE_ANY_IN_ADDRESSBOOK;
450 }
451 | MATCHER_ALL_IN_ADDRESSBOOK
452 {
453         match_type = MATCHTYPE_ALL_IN_ADDRESSBOOK;
454 }
455 ;
456
457 condition:
458 condition_list
459 {
460         cond = matcherlist_new(matchers_list, (bool_op == MATCHERBOOL_AND));
461         matchers_list = NULL;
462 }
463 ;
464
465 condition_list:
466 condition_list bool_op one_condition
467 {
468         matchers_list = g_slist_append(matchers_list, prop);
469 }
470 | one_condition
471 {
472         matchers_list = NULL;
473         matchers_list = g_slist_append(matchers_list, prop);
474 }
475 ;
476
477 bool_op:
478 MATCHER_AND
479 {
480         bool_op = MATCHERBOOL_AND;
481 }
482 | MATCHER_OR
483 {
484         bool_op = MATCHERBOOL_OR;
485 }
486 ;
487
488 one_condition:
489 MATCHER_ALL
490 {
491         gint criteria = 0;
492
493         criteria = MATCHCRITERIA_ALL;
494         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
495 }
496 | MATCHER_UNREAD
497 {
498         gint criteria = 0;
499
500         criteria = MATCHCRITERIA_UNREAD;
501         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
502 }
503 | MATCHER_NOT_UNREAD 
504 {
505         gint criteria = 0;
506
507         criteria = MATCHCRITERIA_NOT_UNREAD;
508         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
509 }
510 | MATCHER_NEW
511 {
512         gint criteria = 0;
513
514         criteria = MATCHCRITERIA_NEW;
515         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
516 }
517 | MATCHER_NOT_NEW
518 {
519         gint criteria = 0;
520
521         criteria = MATCHCRITERIA_NOT_NEW;
522         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
523 }
524 | MATCHER_MARKED
525 {
526         gint criteria = 0;
527
528         criteria = MATCHCRITERIA_MARKED;
529         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
530 }
531 | MATCHER_NOT_MARKED
532 {
533         gint criteria = 0;
534
535         criteria = MATCHCRITERIA_NOT_MARKED;
536         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
537 }
538 | MATCHER_DELETED
539 {
540         gint criteria = 0;
541
542         criteria = MATCHCRITERIA_DELETED;
543         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
544 }
545 | MATCHER_NOT_DELETED
546 {
547         gint criteria = 0;
548
549         criteria = MATCHCRITERIA_NOT_DELETED;
550         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
551 }
552 | MATCHER_REPLIED
553 {
554         gint criteria = 0;
555
556         criteria = MATCHCRITERIA_REPLIED;
557         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
558 }
559 | MATCHER_NOT_REPLIED
560 {
561         gint criteria = 0;
562
563         criteria = MATCHCRITERIA_NOT_REPLIED;
564         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
565 }
566 | MATCHER_FORWARDED
567 {
568         gint criteria = 0;
569
570         criteria = MATCHCRITERIA_FORWARDED;
571         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
572 }
573 | MATCHER_NOT_FORWARDED
574 {
575         gint criteria = 0;
576
577         criteria = MATCHCRITERIA_NOT_FORWARDED;
578         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
579 }
580 | MATCHER_LOCKED
581 {
582         gint criteria = 0;
583
584         criteria = MATCHCRITERIA_LOCKED;
585         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
586 }
587 | MATCHER_NOT_LOCKED
588 {
589         gint criteria = 0;
590
591         criteria = MATCHCRITERIA_NOT_LOCKED;
592         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
593 }
594 | MATCHER_PARTIAL
595 {
596         gint criteria = 0;
597
598         criteria = MATCHCRITERIA_PARTIAL;
599         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
600 }
601 | MATCHER_NOT_PARTIAL
602 {
603         gint criteria = 0;
604
605         criteria = MATCHCRITERIA_NOT_PARTIAL;
606         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
607 }
608 | MATCHER_COLORLABEL MATCHER_INTEGER
609 {
610         gint criteria = 0;
611         gint value = 0;
612
613         criteria = MATCHCRITERIA_COLORLABEL;
614         value = strtol($2, NULL, 10);
615         if (value < 0) value = 0;
616         else if (value > MAX_COLORLABELS) value = MAX_COLORLABELS;
617         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
618 }
619 | MATCHER_NOT_COLORLABEL MATCHER_INTEGER
620 {
621         gint criteria = 0;
622         gint value = 0;
623
624         criteria = MATCHCRITERIA_NOT_COLORLABEL;
625         value = strtol($2, NULL, 0);
626         if (value < 0) value = 0;
627         else if (value > MAX_COLORLABELS) value = MAX_COLORLABELS;
628         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
629 }
630 | MATCHER_IGNORE_THREAD
631 {
632         gint criteria = 0;
633
634         criteria = MATCHCRITERIA_IGNORE_THREAD;
635         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
636 }
637 | MATCHER_NOT_IGNORE_THREAD
638 {
639         gint criteria = 0;
640
641         criteria = MATCHCRITERIA_NOT_IGNORE_THREAD;
642         prop = matcherprop_new(criteria, NULL, 0, NULL, 0);
643 }
644 | MATCHER_SUBJECT match_type MATCHER_STRING
645 {
646         gint criteria = 0;
647         gchar *expr = NULL;
648
649         criteria = MATCHCRITERIA_SUBJECT;
650         expr = $3;
651         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
652 }
653 | MATCHER_NOT_SUBJECT match_type MATCHER_STRING
654 {
655         gint criteria = 0;
656         gchar *expr = NULL;
657
658         criteria = MATCHCRITERIA_NOT_SUBJECT;
659         expr = $3;
660         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
661 }
662 | MATCHER_FROM match_type MATCHER_STRING
663 {
664         gint criteria = 0;
665         gchar *expr = NULL;
666
667         criteria = MATCHCRITERIA_FROM;
668         expr = $3;
669         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
670 }
671 | MATCHER_NOT_FROM match_type MATCHER_STRING
672 {
673         gint criteria = 0;
674         gchar *expr = NULL;
675
676         criteria = MATCHCRITERIA_NOT_FROM;
677         expr = $3;
678         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
679 }
680 | MATCHER_TO match_type MATCHER_STRING
681 {
682         gint criteria = 0;
683         gchar *expr = NULL;
684
685         criteria = MATCHCRITERIA_TO;
686         expr = $3;
687         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
688 }
689 | MATCHER_NOT_TO match_type MATCHER_STRING
690 {
691         gint criteria = 0;
692         gchar *expr = NULL;
693
694         criteria = MATCHCRITERIA_NOT_TO;
695         expr = $3;
696         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
697 }
698 | MATCHER_CC match_type MATCHER_STRING
699 {
700         gint criteria = 0;
701         gchar *expr = NULL;
702
703         criteria = MATCHCRITERIA_CC;
704         expr = $3;
705         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
706 }
707 | MATCHER_NOT_CC match_type MATCHER_STRING
708 {
709         gint criteria = 0;
710         gchar *expr = NULL;
711
712         criteria = MATCHCRITERIA_NOT_CC;
713         expr = $3;
714         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
715 }
716 | MATCHER_TO_OR_CC match_type MATCHER_STRING
717 {
718         gint criteria = 0;
719         gchar *expr = NULL;
720
721         criteria = MATCHCRITERIA_TO_OR_CC;
722         expr = $3;
723         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
724 }
725 | MATCHER_NOT_TO_AND_NOT_CC match_type MATCHER_STRING
726 {
727         gint criteria = 0;
728         gchar *expr = NULL;
729
730         criteria = MATCHCRITERIA_NOT_TO_AND_NOT_CC;
731         expr = $3;
732         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
733 }
734 | MATCHER_AGE_GREATER MATCHER_INTEGER
735 {
736         gint criteria = 0;
737         gint value = 0;
738
739         criteria = MATCHCRITERIA_AGE_GREATER;
740         value = strtol($2, NULL, 0);
741         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
742 }
743 | MATCHER_AGE_LOWER MATCHER_INTEGER
744 {
745         gint criteria = 0;
746         gint value = 0;
747
748         criteria = MATCHCRITERIA_AGE_LOWER;
749         value = strtol($2, NULL, 0);
750         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
751 }
752 | MATCHER_NEWSGROUPS match_type MATCHER_STRING
753 {
754         gint criteria = 0;
755         gchar *expr = NULL;
756
757         criteria = MATCHCRITERIA_NEWSGROUPS;
758         expr = $3;
759         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
760 }
761 | MATCHER_NOT_NEWSGROUPS match_type MATCHER_STRING
762 {
763         gint criteria = 0;
764         gchar *expr = NULL;
765
766         criteria = MATCHCRITERIA_NOT_NEWSGROUPS;
767         expr = $3;
768         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
769 }
770 | MATCHER_INREPLYTO match_type MATCHER_STRING
771 {
772         gint criteria = 0;
773         gchar *expr = NULL;
774
775         criteria = MATCHCRITERIA_INREPLYTO;
776         expr = $3;
777         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
778 }
779 | MATCHER_NOT_INREPLYTO match_type MATCHER_STRING
780 {
781         gint criteria = 0;
782         gchar *expr = NULL;
783
784         criteria = MATCHCRITERIA_NOT_INREPLYTO;
785         expr = $3;
786         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
787 }
788 | MATCHER_REFERENCES match_type MATCHER_STRING
789 {
790         gint criteria = 0;
791         gchar *expr = NULL;
792
793         criteria = MATCHCRITERIA_REFERENCES;
794         expr = $3;
795         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
796 }
797 | MATCHER_NOT_REFERENCES match_type MATCHER_STRING
798 {
799         gint criteria = 0;
800         gchar *expr = NULL;
801
802         criteria = MATCHCRITERIA_NOT_REFERENCES;
803         expr = $3;
804         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
805 }
806 | MATCHER_SCORE_GREATER MATCHER_INTEGER
807 {
808         gint criteria = 0;
809         gint value = 0;
810
811         criteria = MATCHCRITERIA_SCORE_GREATER;
812         value = strtol($2, NULL, 0);
813         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
814 }
815 | MATCHER_SCORE_LOWER MATCHER_INTEGER
816 {
817         gint criteria = 0;
818         gint value = 0;
819
820         criteria = MATCHCRITERIA_SCORE_LOWER;
821         value = strtol($2, NULL, 0);
822         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
823 }
824 | MATCHER_SCORE_EQUAL MATCHER_INTEGER
825 {
826         gint criteria = 0;
827         gint value = 0;
828
829         criteria = MATCHCRITERIA_SCORE_EQUAL;
830         value = strtol($2, NULL, 0);
831         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
832 }
833 | MATCHER_SIZE_GREATER MATCHER_INTEGER 
834 {
835         gint criteria = 0;
836         gint value    = 0;
837         criteria = MATCHCRITERIA_SIZE_GREATER;
838         value = strtol($2, NULL, 0);
839         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
840 }
841 | MATCHER_SIZE_SMALLER MATCHER_INTEGER
842 {
843         gint criteria = 0;
844         gint value    = 0;
845         criteria = MATCHCRITERIA_SIZE_SMALLER;
846         value = strtol($2, NULL, 0);
847         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
848 }
849 | MATCHER_SIZE_EQUAL MATCHER_INTEGER
850 {
851         gint criteria = 0;
852         gint value    = 0;
853         criteria = MATCHCRITERIA_SIZE_EQUAL;
854         value = strtol($2, NULL, 0);
855         prop = matcherprop_new(criteria, NULL, 0, NULL, value);
856 }
857 | MATCHER_HEADER MATCHER_STRING
858 {
859         header = g_strdup($2);
860 } match_type MATCHER_STRING
861 {
862         gint criteria = 0;
863         gchar *expr = NULL;
864
865         criteria = MATCHCRITERIA_HEADER;
866         expr = $2;
867         prop = matcherprop_new(criteria, header, match_type, expr, 0);
868         g_free(header);
869 }
870 | MATCHER_NOT_HEADER MATCHER_STRING
871 {
872         header = g_strdup($2);
873 } match_type MATCHER_STRING
874 {
875         gint criteria = 0;
876         gchar *expr = NULL;
877
878         criteria = MATCHCRITERIA_NOT_HEADER;
879         expr = $2;
880         prop = matcherprop_new(criteria, header, match_type, expr, 0);
881         g_free(header);
882 }
883 | MATCHER_HEADERS_PART match_type MATCHER_STRING
884 {
885         gint criteria = 0;
886         gchar *expr = NULL;
887
888         criteria = MATCHCRITERIA_HEADERS_PART;
889         expr = $3;
890         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
891 }
892 | MATCHER_NOT_HEADERS_PART match_type MATCHER_STRING
893 {
894         gint criteria = 0;
895         gchar *expr = NULL;
896
897         criteria = MATCHCRITERIA_NOT_HEADERS_PART;
898         expr = $3;
899         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
900 }
901 | MATCHER_MESSAGE match_type MATCHER_STRING
902 {
903         gint criteria = 0;
904         gchar *expr = NULL;
905
906         criteria = MATCHCRITERIA_MESSAGE;
907         expr = $3;
908         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
909 }
910 | MATCHER_NOT_MESSAGE match_type MATCHER_STRING
911 {
912         gint criteria = 0;
913         gchar *expr = NULL;
914
915         criteria = MATCHCRITERIA_NOT_MESSAGE;
916         expr = $3;
917         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
918 }
919 | MATCHER_BODY_PART match_type MATCHER_STRING
920 {
921         gint criteria = 0;
922         gchar *expr = NULL;
923
924         criteria = MATCHCRITERIA_BODY_PART;
925         expr = $3;
926         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
927 }
928 | MATCHER_NOT_BODY_PART match_type MATCHER_STRING
929 {
930         gint criteria = 0;
931         gchar *expr = NULL;
932
933         criteria = MATCHCRITERIA_NOT_BODY_PART;
934         expr = $3;
935         prop = matcherprop_new(criteria, NULL, match_type, expr, 0);
936 }
937 | MATCHER_TEST MATCHER_STRING
938 {
939         gint criteria = 0;
940         gchar *expr = NULL;
941
942         criteria = MATCHCRITERIA_TEST;
943         expr = $2;
944         prop = matcherprop_new(criteria, NULL, 0, expr, 0);
945 }
946 | MATCHER_NOT_TEST MATCHER_STRING
947 {
948         gint criteria = 0;
949         gchar *expr = NULL;
950
951         criteria = MATCHCRITERIA_NOT_TEST;
952         expr = $2;
953         prop = matcherprop_new(criteria, NULL, 0, expr, 0);
954 }
955 ;
956
957 filtering_action:
958 MATCHER_EXECUTE MATCHER_STRING
959 {
960         gchar *cmd = NULL;
961         gint action_type = 0;
962
963         action_type = MATCHACTION_EXECUTE;
964         cmd = $2;
965         action = filteringaction_new(action_type, 0, cmd, 0, 0);
966 }
967 | MATCHER_MOVE MATCHER_STRING
968 {
969         gchar *destination = NULL;
970         gint action_type = 0;
971
972         action_type = MATCHACTION_MOVE;
973         destination = $2;
974         action = filteringaction_new(action_type, 0, destination, 0, 0);
975 }
976 | MATCHER_COPY MATCHER_STRING
977 {
978         gchar *destination = NULL;
979         gint action_type = 0;
980
981         action_type = MATCHACTION_COPY;
982         destination = $2;
983         action = filteringaction_new(action_type, 0, destination, 0, 0);
984 }
985 | MATCHER_DELETE
986 {
987         gint action_type = 0;
988
989         action_type = MATCHACTION_DELETE;
990         action = filteringaction_new(action_type, 0, NULL, 0, 0);
991 }
992 | MATCHER_MARK
993 {
994         gint action_type = 0;
995
996         action_type = MATCHACTION_MARK;
997         action = filteringaction_new(action_type, 0, NULL, 0, 0);
998 }
999 | MATCHER_UNMARK
1000 {
1001         gint action_type = 0;
1002
1003         action_type = MATCHACTION_UNMARK;
1004         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1005 }
1006 | MATCHER_LOCK
1007 {
1008         gint action_type = 0;
1009
1010         action_type = MATCHACTION_LOCK;
1011         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1012 }
1013 | MATCHER_UNLOCK
1014 {
1015         gint action_type = 0;
1016
1017         action_type = MATCHACTION_UNLOCK;
1018         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1019 }
1020 | MATCHER_MARK_AS_READ
1021 {
1022         gint action_type = 0;
1023
1024         action_type = MATCHACTION_MARK_AS_READ;
1025         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1026 }
1027 | MATCHER_MARK_AS_UNREAD
1028 {
1029         gint action_type = 0;
1030
1031         action_type = MATCHACTION_MARK_AS_UNREAD;
1032         action = filteringaction_new(action_type, 0, NULL, 0, 0);
1033 }
1034 | MATCHER_FORWARD MATCHER_INTEGER MATCHER_STRING
1035 {
1036         gchar *destination = NULL;
1037         gint action_type = 0;
1038         gint account_id = 0;
1039
1040         action_type = MATCHACTION_FORWARD;
1041         account_id = strtol($2, NULL, 10);
1042         destination = $3;
1043         action = filteringaction_new(action_type,
1044             account_id, destination, 0, 0);
1045 }
1046 | MATCHER_FORWARD_AS_ATTACHMENT MATCHER_INTEGER MATCHER_STRING
1047 {
1048         gchar *destination = NULL;
1049         gint action_type = 0;
1050         gint account_id = 0;
1051
1052         action_type = MATCHACTION_FORWARD_AS_ATTACHMENT;
1053         account_id = strtol($2, NULL, 10);
1054         destination = $3;
1055         action = filteringaction_new(action_type,
1056             account_id, destination, 0, 0);
1057 }
1058 | MATCHER_REDIRECT MATCHER_INTEGER MATCHER_STRING
1059 {
1060         gchar *destination = NULL;
1061         gint action_type = 0;
1062         gint account_id = 0;
1063
1064         action_type = MATCHACTION_REDIRECT;
1065         account_id = strtol($2, NULL, 10);
1066         destination = $3;
1067         action = filteringaction_new(action_type,
1068             account_id, destination, 0, 0);
1069 }
1070 | MATCHER_COLOR MATCHER_INTEGER
1071 {
1072         gint action_type = 0;
1073         gint color = 0;
1074
1075         action_type = MATCHACTION_COLOR;
1076         color = strtol($2, NULL, 10);
1077         action = filteringaction_new(action_type, 0, NULL, color, 0);
1078 }
1079 | MATCHER_CHANGE_SCORE MATCHER_INTEGER
1080 {
1081         gint score = 0;
1082         
1083         score = strtol($2, NULL, 10);
1084         action = filteringaction_new(MATCHACTION_CHANGE_SCORE, 0,
1085                                      NULL, 0, score);
1086 }
1087 /* backward compatibility */
1088 | MATCHER_SCORE MATCHER_INTEGER
1089 {
1090         gint score = 0;
1091         
1092         score = strtol($2, NULL, 10);
1093         action = filteringaction_new(MATCHACTION_CHANGE_SCORE, 0,
1094                                      NULL, 0, score);
1095 }
1096 | MATCHER_SET_SCORE MATCHER_INTEGER
1097 {
1098         gint score = 0;
1099         
1100         score = strtol($2, NULL, 10);
1101         action = filteringaction_new(MATCHACTION_SET_SCORE, 0,
1102                                      NULL, 0, score);
1103 }
1104 | MATCHER_HIDE
1105 {
1106         action = filteringaction_new(MATCHACTION_HIDE, 0, NULL, 0, 0);
1107 }
1108 | MATCHER_STOP
1109 {
1110         action = filteringaction_new(MATCHACTION_STOP, 0, NULL, 0, 0);
1111 }
1112 ;