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