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