1 %{
2 /* sieve.y -- sieve parser
3 * Larry Greenfield
4 *
5 * Copyright (c) 1994-2008 Carnegie Mellon University. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * 3. The name "Carnegie Mellon University" must not be used to
20 * endorse or promote products derived from this software without
21 * prior written permission. For permission or any legal
22 * details, please contact
23 * Carnegie Mellon University
24 * Center for Technology Transfer and Enterprise Creation
25 * 4615 Forbes Avenue
26 * Suite 302
27 * Pittsburgh, PA 15213
28 * (412) 268-7393, fax: (412) 268-7395
29 * innovation@andrew.cmu.edu
30 *
31 * 4. Redistributions of any form whatsoever must retain the following
32 * acknowledgment:
33 * "This product includes software developed by Computing Services
34 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
35 *
36 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
37 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
38 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
39 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
40 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
41 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
42 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
43 */
44
45 #ifdef HAVE_CONFIG_H
46 #include <config.h>
47 #endif
48
49 #include <stdlib.h>
50 #include <assert.h>
51 #include <string.h>
52 #include "xmalloc.h"
53 #include "sieve/comparator.h"
54 #include "sieve/interp.h"
55 #include "sieve/script.h"
56 #include "sieve/tree.h"
57 #include "sieve/flags.h"
58 #include "sieve/grammar.h"
59 #include "sieve/sieve_err.h"
60
61 #include "imapurl.h"
62 #include "lib/gmtoff.h"
63 #include "util.h"
64 #include "imparse.h"
65 #include "libconfig.h"
66 #include "times.h"
67
68 #define ERR_BUF_SIZE 1024
69
70 /*
71 * Definitions
72 */
73
74 extern int addrparse(sieve_script_t*);
75 typedef struct yy_buffer_state *YY_BUFFER_STATE;
76 extern YY_BUFFER_STATE addr_scan_string(const char*);
77 extern void addr_delete_buffer(YY_BUFFER_STATE);
78
79 extern int sievelineno;
80
81 struct vtags {
82 int seconds;
83 strarray_t *addresses;
84 char *subject;
85 char *from;
86 char *handle;
87 int mime;
88 };
89
90 struct comptags {
91 int match;
92 int relation;
93 char *comparator; /* only used where comparator can be defined */
94 int index; /* only used where index extension is defined */
95 };
96
97 struct aetags {
98 struct comptags comptags; /* MUST be first so we can typecast */
99 int addrtag;
100 };
101
102 struct btags {
103 struct comptags comptags; /* MUST be first so we can typecast */
104 int transform;
105 int offset;
106 strarray_t *content_types;
107 };
108
109 struct ntags {
110 char *method;
111 char *id;
112 strarray_t *options;
113 int priority;
114 char *message;
115 };
116
117 struct dtags {
118 struct comptags comptags; /* MUST be first so we can typecast */
119 void *pattern;
120 int priority;
121 };
122
123 struct itags {
124 int location;
125 int once;
126 int optional;
127 };
128
129 struct dttags {
130 struct comptags comptags; /* MUST be first so we can typecast */
131 int zonetag;
132 char *zone;
133 };
134
135 struct ftags {
136 int copy;
137 int create;
138 strarray_t *flags;
139 };
140
141 struct stags {
142 int mod40; /* :lower or :upper */
143 int mod30; /* :lowerfirst or :upperfirst */
144 int mod20; /* :quotewildcard */
145 int mod10; /* :length */
146 };
147
148 static char *check_reqs(sieve_script_t *script, strarray_t *sl);
149
150 static test_t *build_address(int t, struct aetags *ae,
151 strarray_t *sl, strarray_t *pl);
152 static test_t *build_header(int t, struct comptags *c,
153 strarray_t *sl, strarray_t *pl);
154 static test_t *build_body(int t, struct btags *b, strarray_t *pl);
155 static test_t *build_date(int t, struct dttags *dt,
156 char *hn, int part, strarray_t *kl);
157 static test_t *build_mailboxtest(int t, struct comptags *c, const char *extname,
158 const char *keyname, strarray_t *keylist);
159
160 static commandlist_t *build_vacation(int t, struct vtags *h, char *s);
161 static commandlist_t *build_notify(int t, struct ntags *n);
162 static commandlist_t *build_denotify(int t, struct dtags *n);
163 static commandlist_t *build_keep(int t, struct ftags *f);
164 static commandlist_t *build_fileinto(int t, struct ftags *f, char *folder);
165 static commandlist_t *build_redirect(int t, int c, char *a);
166 static commandlist_t *build_include(int, struct itags *, char*);
167 static commandlist_t *build_set(int t, struct stags *s,
168 char *variable, char *value);
169 static commandlist_t *build_flag(int t, char *variable, strarray_t *flags);
170
171 static struct aetags *new_aetags(void);
172 static struct aetags *canon_aetags(struct aetags *ae);
173 static void free_aetags(struct aetags *ae);
174
175 static struct comptags *new_comptags(void);
176 static struct comptags *init_comptags(struct comptags *c);
177 static struct comptags *canon_comptags(struct comptags *c);
178 static void free_comptags(struct comptags *c, int destroy);
179
180 static struct btags *new_btags(void);
181 static struct btags *canon_btags(struct btags *b);
182 static void free_btags(struct btags *b);
183
184 static struct vtags *new_vtags(void);
185 static struct vtags *canon_vtags(sieve_script_t *script, struct vtags *v);
186 static void free_vtags(struct vtags *v);
187
188 static struct ntags *new_ntags(void);
189 static struct ntags *canon_ntags(struct ntags *n);
190 static void free_ntags(struct ntags *n);
191
192 static struct dtags *new_dtags(void);
193 static struct dtags *canon_dtags(struct dtags *d);
194 static void free_dtags(struct dtags *d);
195
196 static struct itags *new_itags(void);
197
198 static struct dttags *new_dttags(void);
199 static struct dttags *canon_dttags(struct dttags *dt);
200 static void free_dttags(struct dttags *b);
201
202 static struct ftags *new_ftags(void);
203 static struct ftags *canon_ftags(struct ftags *f);
204 static void free_ftags(struct ftags *f);
205
206 static struct stags *new_stags(void);
207 static struct stags *canon_stags(struct stags *s);
208 static void free_stags(struct stags *s);
209
210 static int verify_stringlist(sieve_script_t*, strarray_t *sl,
211 int (*verify)(sieve_script_t*, char *));
212 static int verify_patternlist(sieve_script_t *parse_script,
213 strarray_t *sl, struct comptags *c,
214 int (*verify)(sieve_script_t*, char *));
215 static int verify_mailbox(sieve_script_t*, char *s);
216 static int verify_address(sieve_script_t*, char *s);
217 static int verify_header(sieve_script_t*, char *s);
218 static int verify_addrheader(sieve_script_t*, char *s);
219 static int verify_envelope(sieve_script_t*, char *s);
220 static int verify_relat(sieve_script_t*, char *s);
221 static int verify_zone(sieve_script_t*, char *s);
222 static int verify_date_part(sieve_script_t *parse_script, char *dp);
223 static int verify_utf8(sieve_script_t*, char *s);
224 static int verify_identifier(sieve_script_t*, char *s);
225
226 static void parse_error(sieve_script_t *parse_script, int err, ...);
227 void yyerror(sieve_script_t*, const char *msg);
228 extern int yylex(void*, sieve_script_t*);
229 extern void sieverestart(FILE *f);
230
231 #define YYERROR_VERBOSE /* i want better error messages! */
232
233 /* byacc default is 500, bison default is 10000 - go with the
234 larger to support big sieve scripts (see Bug #3461) */
235 #define YYSTACKSIZE 10000
236 %}
237
238 %union {
239 int nval;
240 char *sval;
241 strarray_t *sl;
242 test_t *test;
243 testlist_t *testl;
244 commandlist_t *cl;
245 struct vtags *vtag;
246 struct aetags *aetag;
247 struct comptags *ctag;
248 struct btags *btag;
249 struct ntags *ntag;
250 struct dtags *dtag;
251 struct itags *itag;
252 struct dttags *dttag;
253 struct ftags *ftag;
254 struct stags *stag;
255 }
256
257 %token <nval> NUMBER
258 %token <sval> STRING
259 %token IF ELSIF ELSE
260 %token REJCT FILEINTO REDIRECT KEEP STOP DISCARD VACATION REQUIRE
261 %token MARK UNMARK FLAGS
262 %token NOTIFY DENOTIFY
263 %token ANYOF ALLOF EXISTS SFALSE STRUE HEADER NOT SIZE ADDRESS ENVELOPE BODY
264 %token COMPARATOR IS CONTAINS MATCHES REGEX COUNT VALUE OVER UNDER
265 %token GT GE LT LE EQ NE
266 %token ALL LOCALPART DOMAIN USER DETAIL
267 %token RAW TEXT CONTENT
268 %token DAYS ADDRESSES SUBJECT FROM HANDLE MIME SECONDS
269 %token METHOD ID OPTIONS LOW NORMAL HIGH ANY MESSAGE
270 %token INCLUDE PERSONAL GLOBAL RETURN OPTIONAL ONCE
271 %token COPY
272 %token DATE CURRENTDATE INDEX LAST ZONE ORIGINALZONE
273 %token MAILBOXEXISTS CREATE
274 %token METADATA METADATAEXISTS
275 %token SERVERMETADATA SERVERMETADATAEXISTS
276 %token YEAR MONTH DAY JULIAN HOUR MINUTE SECOND TIME ISO8601 STD11 WEEKDAY
277 %token <nval> STRINGT SET LOWER UPPER LOWERFIRST UPPERFIRST QUOTEWILDCARD LENGTH
278 %token <nval> SETFLAG ADDFLAG REMOVEFLAG HASFLAG
279
280 %type <cl> commands command action elsif block
281 %type <sl> stringlist strings
282 %type <test> test
283 %type <nval> match relmatch sizetag addrparttag copy rtags creat datepart
284 %type <testl> testlist tests
285 %type <ctag> htags strtags hftags mtags
286 %type <aetag> atags etags
287 %type <btag> btags
288 %type <vtag> vtags
289 %type <ntag> ntags
290 %type <dtag> dtags
291 %type <itag> itags
292 %type <dttag> dttags cdtags
293 %type <nval> priority
294 %type <ftag> ftags
295 %type <stag> stags
296 %type <nval> mod40 mod30 mod20 mod10
297 %type <sval> flagtags
298 %type <nval> flagaction
299
300 %name-prefix "sieve"
301 %defines
302 %destructor { free_tree($$); } commands command action elsif block
303
304 %param { sieve_script_t *parse_script }
305 %pure-parser
306
307
308 /*
309 * Rules
310 */
311
312 %%
313
314 start: reqs { parse_script->cmds = NULL; }
315 | reqs commands { parse_script->cmds = $2; }
316 ;
317
318 reqs: /* empty */
319 | require reqs
320 ;
321
322 require: REQUIRE stringlist ';'
323 {
324 char *err = check_reqs(parse_script, $2);
325 if (err) {
326 yyerror(parse_script, err);
327 free(err);
328 YYERROR;
329 }
330 }
331 ;
332
333 commands: command { $$ = $1; }
334 | command commands { $1->next = $2; $$ = $1; }
335 ;
336
337 command: action ';' { $$ = $1; }
338 | IF test block elsif { $$ = new_if($2, $3, $4); }
339 | error ';' { $$ = new_command(STOP); }
340 ;
341
342 elsif: /* empty */ { $$ = NULL; }
343 | ELSIF test block elsif { $$ = new_if($2, $3, $4); }
344 | ELSE block { $$ = $2; }
345 ;
346
347 action: REJCT STRING
348 {
349 if (!parse_script->support.reject) {
350 parse_error(parse_script,
351 SIEVE_MISSING_REQUIRE,
352 "reject");
353 YYERROR; /* pe should call yyerror() */
354 }
355 if (!verify_utf8(parse_script, $2)) {
356 YYERROR; /* vu should call yyerror() */
357 }
358 $$ = new_command(REJCT);
359 $$->u.reject = $2;
360 }
361
362 | FILEINTO ftags STRING
363 {
364 if (!parse_script->support.fileinto) {
365 parse_error(parse_script,
366 SIEVE_MISSING_REQUIRE,
367 "fileinto");
368 YYERROR; /* pe should call yyerror() */
369 }
370 if (!verify_mailbox(parse_script, $3)) {
371 YYERROR; /* vm should call yyerror() */
372 }
373 $$ = build_fileinto(FILEINTO,
374 canon_ftags($2), $3);
375 }
376
377 | REDIRECT rtags STRING
378 {
379 if (!verify_address(parse_script, $3)) {
380 YYERROR; /* va should call yyerror() */
381 }
382 $$ = build_redirect(REDIRECT, $2, $3);
383 }
384
385 | KEEP ftags { $$ = build_keep(KEEP,canon_ftags($2)); }
386 | STOP { $$ = new_command(STOP); }
387 | DISCARD { $$ = new_command(DISCARD); }
388
389 | VACATION vtags STRING
390 {
391 if (!parse_script->support.vacation) {
392 parse_error(parse_script,
393 SIEVE_MISSING_REQUIRE,
394 "vacation");
395 YYERROR; /* pe should call yyerror() */
396 }
397 if (($2->mime == -1) &&
398 !verify_utf8(parse_script, $3)) {
399 YYERROR; /* vu should call yyerror() */
400 }
401 $$ = build_vacation(VACATION,
402 canon_vtags(parse_script, $2),
403 $3);
404 }
405
406 | flagaction flagtags stringlist
407 {
408 if (!(parse_script->support.imapflags ||
409 parse_script->support.imap4flags)) {
410 parse_error(parse_script,
411 SIEVE_MISSING_REQUIRE,
412 "imap[4]flags");
413 YYERROR; /* pe should call yyerror() */
414 }
415 if (!parse_script->support.variables) {
416 verify_flaglist($3);
417 }
418 if (!$3->count) strarray_add($3, "");
419 $$ = build_flag($1, $2, $3);
420 }
421
422 | MARK
423 {
424 if (!parse_script->support.imapflags) {
425 parse_error(parse_script,
426 SIEVE_MISSING_REQUIRE,
427 "imapflags");
428 YYERROR; /* pe should call yyerror() */
429 }
430 $$ = new_command(MARK);
431 }
432
433 | UNMARK
434 {
435 if (!parse_script->support.imapflags) {
436 parse_error(parse_script,
437 SIEVE_MISSING_REQUIRE,
438 "imapflags");
439 YYERROR; /* pe should call yyerror() */
440 }
441 $$ = new_command(UNMARK);
442 }
443
444 | NOTIFY ntags
445 {
446 if (!parse_script->support.notify) {
447 parse_error(parse_script,
448 SIEVE_MISSING_REQUIRE,
449 "notify");
450 $$ = new_command(NOTIFY);
451 YYERROR; /* pe should call yyerror() */
452 }
453 $$ = build_notify(NOTIFY, canon_ntags($2));
454 }
455
456 | DENOTIFY dtags
457 {
458 if (!parse_script->support.notify) {
459 parse_error(parse_script,
460 SIEVE_MISSING_REQUIRE,
461 "notify");
462 $$ = new_command(DENOTIFY);
463 YYERROR; /* pe should call yyerror() */
464 }
465 $$ = build_denotify(DENOTIFY,
466 canon_dtags($2));
467 if ($$ == NULL) {
468 parse_error(parse_script,
469 SIEVE_BUILD_FAILURE,
470 "denotify action");
471 YYERROR; /* pe should call yyerror() */
472 }
473 }
474
475 | INCLUDE itags STRING
476 {
477 if (!parse_script->support.include) {
478 parse_error(parse_script,
479 SIEVE_MISSING_REQUIRE,
480 "include");
481 YYERROR; /* pe should call yyerror() */
482 }
483 int i;
484 for (i = 0; $3[i] != '\0'; i++) {
485 if ($3[i] == '/') {
486 parse_error(parse_script,
487 SIEVE_INVALID_VALUE,
488 "script-name");
489 YYERROR; /* pe should call yyerror() */
490 break;
491 }
492 }
493 $$ = build_include(INCLUDE, $2, $3);
494 }
495
496 | RETURN
497 {
498 if (!parse_script->support.include) {
499 parse_error(parse_script,
500 SIEVE_MISSING_REQUIRE,
501 "include");
502 YYERROR; /* pe should call yyerror() */
503 }
504 $$ = new_command(RETURN);
505 }
506
507 | SET stags STRING STRING
508 {
509 if (!parse_script->support.variables) {
510 parse_error(parse_script,
511 SIEVE_MISSING_REQUIRE,
512 "variables");
513 YYERROR; /* pe should call yyerror() */
514 }
515 if (!verify_identifier(parse_script, $3)) {
516 YYERROR; /* vi should call yyerror() */
517 }
518 if (!verify_utf8(parse_script, $4)) {
519 YYERROR; /* vu should call yyerror() */
520 }
521 $$ = build_set(SET, canon_stags($2), $3, $4);
522 }
523 ;
524
525 flagaction: ADDFLAG
526 | SETFLAG
527 | REMOVEFLAG
528 ;
529
530 flagtags: /* empty */ { $$ = NULL; }
531 | flagtags STRING
532 {
533 if (!(parse_script->support.imap4flags)) {
534 parse_error(parse_script,
535 SIEVE_MISSING_REQUIRE,
536 "imap4flags");
537 YYERROR; /* pe should call yyerror() */
538 }
539 if ($1) {
540 parse_error(parse_script,
541 SIEVE_DUPLICATE_ARG,
542 "variablename");
543 YYERROR; /* pe should call yyerror() */
544 }
545 if (!is_identifier($2)) {
546 YYERROR; /* id should call yyerror() */
547 }
548 $$ = $2;
549 }
550 ;
551
552 stags: /* empty */ { $$ = new_stags(); }
553 | stags mod40
554 {
555 if ($$->mod40) {
556 parse_error(parse_script,
557 SIEVE_DUPLICATE_TAG,
558 "precedence 40 modifier");
559 YYERROR; /* pe should call yyerror() */
560 }
561 else $$->mod40 = $2;
562 }
563 | stags mod30
564 {
565 if ($$->mod30) {
566 parse_error(parse_script,
567 SIEVE_DUPLICATE_TAG,
568 "precedence 30 modifier");
569 YYERROR; /* pe should call yyerror() */
570 }
571 else $$->mod30 = $2;
572 }
573 | stags mod20
574 {
575 if ($$->mod20) {
576 parse_error(parse_script,
577 SIEVE_DUPLICATE_TAG,
578 "precedence 20 modifier");
579 YYERROR; /* pe should call yyerror() */
580 }
581 else $$->mod20 = $2;
582 }
583 /* TODO: :encodeurl
584 Requires "enotify" extension, which has not been implemented yet.
585
586 RFC 5435 (Sieve Extension: Notifications)
587 6. Modifier encodeurl to the 'set' Action
588
589 Usage: ":encodeurl"
590
591 When the Sieve script specifies both "variables" [Variables] and
592 "enotify" capabilities in the "require", a new "set" action modifier
593 (see [Variables]) ":encodeurl" becomes available to Sieve scripts.
594 This modifier performs percent-encoding of any octet in the string
595 that doesn't belong to the "unreserved" set (see [URI]). The
596 percent-encoding procedure is described in [URI].
597
598 The ":encodeurl" modifier has precedence 15.
599
600 Example 6:
601 require ["enotify", "variables"];
602
603 set :encodeurl "body_param" "Safe body&evil=evilbody";
604
605 notify "mailto:tim@example.com?body=${body_param}";
606
607 */
608 | stags mod10
609 {
610 if ($$->mod10) {
611 parse_error(parse_script,
612 SIEVE_DUPLICATE_TAG,
613 "precedence 10 modifier");
614 YYERROR; /* pe should call yyerror() */
615 }
616 else $$->mod10 = $2;
617 }
618 ;
619
620 mod40: LOWER
621 | UPPER
622 ;
623 mod30: LOWERFIRST
624 | UPPERFIRST
625 ;
626 mod20: QUOTEWILDCARD
627 ;
628 mod10: LENGTH
629 ;
630
631 itags: /* empty */ { $$ = new_itags(); }
632 | itags PERSONAL
633 {
634 if ($$->location != -1) {
635 parse_error(parse_script,
636 SIEVE_DUPLICATE_TAG,
637 "location");
638 YYERROR; /* pe should call yyerror() */
639 }
640 else $$->location = PERSONAL;
641 }
642 | itags GLOBAL
643 {
644 if ($$->location != -1) {
645 parse_error(parse_script,
646 SIEVE_DUPLICATE_TAG,
647 "location");
648 YYERROR; /* pe should call yyerror() */
649 }
650 else $$->location = GLOBAL;
651 }
652 | itags ONCE
653 {
654 if ($$->once != -1) {
655 parse_error(parse_script,
656 SIEVE_DUPLICATE_TAG,
657 ":once");
658 YYERROR; /* pe should call yyerror() */
659 }
660 else $$->once = 1;
661 }
662 | itags OPTIONAL
663 { if ($$->optional != -1) {
664 parse_error(parse_script,
665 SIEVE_DUPLICATE_TAG,
666 ":optional");
667 YYERROR; /* pe should call yyerror() */
668 }
669 else $$->optional = 1;
670 }
671 ;
672
673 ntags: /* empty */ { $$ = new_ntags(); }
674 | ntags ID STRING
675 {
676 if ($$->id != NULL) {
677 parse_error(parse_script,
678 SIEVE_DUPLICATE_TAG,
679 ":id");
680 YYERROR; /* pe should call yyerror() */
681 }
682 else $$->id = $3;
683 }
684 | ntags METHOD STRING
685 {
686 if ($$->method != NULL) {
687 parse_error(parse_script,
688 SIEVE_DUPLICATE_TAG,
689 ":method");
690 YYERROR; /* pe should call yyerror() */
691 }
692 else $$->method = $3;
693 }
694 | ntags OPTIONS stringlist
695 {
696 if ($$->options != NULL) {
697 parse_error(parse_script,
698 SIEVE_DUPLICATE_TAG,
699 ":options");
700 YYERROR; /* pe should call yyerror() */
701 }
702 else $$->options = $3;
703 }
704 | ntags priority
705 {
706 if ($$->priority != -1) {
707 parse_error(parse_script,
708 SIEVE_DUPLICATE_TAG,
709 "priority");
710 YYERROR; /* pe should call yyerror() */
711 }
712 else $$->priority = $2;
713 }
714 | ntags MESSAGE STRING
715 {
716 if ($$->message != NULL) {
717 parse_error(parse_script,
718 SIEVE_DUPLICATE_TAG,
719 ":message");
720 YYERROR; /* pe should call yyerror() */
721 }
722 else $$->message = $3;
723 }
724 ;
725
726 dtags: /* empty */ { $$ = new_dtags(); }
727 | dtags priority
728 {
729 if ($$->priority != -1) {
730 parse_error(parse_script,
731 SIEVE_DUPLICATE_TAG,
732 "priority");
733 YYERROR; /* pe should call yyerror() */
734 }
735 else $$->priority = $2;
736 }
737 | dtags matchtags STRING
738 {
739 $$->pattern = $3;
740
741 strarray_t sa = STRARRAY_INITIALIZER;
742 strarray_appendm(&sa, $3);
743 if (!verify_patternlist(parse_script, &sa,
744 &($$->comptags),
745 NULL)) {
746 YYERROR; /* vp should call yyerror() */
747 }
748 strarray_fini(&sa);
749 }
750 ;
751
752 priority: LOW { $$ = LOW; }
753 | NORMAL { $$ = NORMAL; }
754 | HIGH { $$ = HIGH; }
755 ;
756
757 vtags: /* empty */ { $$ = new_vtags(); }
758 | vtags DAYS NUMBER
759 {
760 if ($$->seconds != -1) {
761 parse_error(parse_script,
762 SIEVE_DUPLICATE_TAG,
763 "period");
764 YYERROR; /* pe should call yyerror() */
765 }
766 else $$->seconds = $3 * DAY2SEC;
767 }
768 | vtags SECONDS NUMBER
769 {
770 if (!parse_script->support.vacation_seconds) {
771 parse_error(parse_script,
772 SIEVE_MISSING_REQUIRE,
773 "vacation-seconds");
774 YYERROR; /* pe should call yyerror() */
775 }
776 if ($$->seconds != -1) {
777 parse_error(parse_script,
778 SIEVE_DUPLICATE_TAG,
779 "period");
780 YYERROR; /* pe should call yyerror() */
781 }
782 $$->seconds = $3;
783 }
784 | vtags ADDRESSES stringlist
785 {
786 if ($$->addresses != NULL) {
787 parse_error(parse_script,
788 SIEVE_DUPLICATE_TAG,
789 ":addresses");
790 YYERROR; /* pe should call yyerror() */
791 }
792 if (!verify_stringlist(parse_script, $3,
793 verify_address)) {
794 YYERROR;
795 }
796 $$->addresses = $3;
797 }
798 | vtags SUBJECT STRING
799 {
800 if ($$->subject != NULL) {
801 parse_error(parse_script,
802 SIEVE_DUPLICATE_TAG,
803 ":subject");
804 YYERROR; /* pe should call yyerror() */
805 }
806 if (!verify_utf8(parse_script, $3)) {
807 YYERROR; /* vu should call yyerror() */
808 }
809 $$->subject = $3;
810 }
811 | vtags FROM STRING
812 {
813 if ($$->from != NULL) {
814 parse_error(parse_script,
815 SIEVE_DUPLICATE_TAG,
816 ":from");
817 YYERROR; /* pe should call yyerror() */
818 }
819 if (!verify_address(parse_script, $3)) {
820 YYERROR; /* va should call yyerror() */
821 }
822 $$->from = $3;
823 }
824 | vtags HANDLE STRING
825 {
826 if ($$->handle != NULL) {
827 parse_error(parse_script,
828 SIEVE_DUPLICATE_TAG,
829 ":handle");
830 YYERROR; /* pe should call yyerror() */
831 }
832 if (!verify_utf8(parse_script, $3)) {
833 YYERROR; /* vu should call yyerror() */
834 }
835 $$->handle = $3;
836 }
837 | vtags MIME
838 {
839 if ($$->mime != -1) {
840 parse_error(parse_script,
841 SIEVE_DUPLICATE_TAG,
842 ":mime");
843 YYERROR; /* pe should call yyerror() */
844 }
845 $$->mime = MIME;
846 }
847 ;
848
849 stringlist: '[' strings ']' { $$ = $2; }
850 | STRING {
851 $$ = strarray_new();
852 strarray_appendm($$, $1);
853 }
854 ;
855
856 strings: STRING {
857 $$ = strarray_new();
858 strarray_appendm($$, $1);
859 }
860 | strings ',' STRING {
861 $$ = $1;
862 strarray_appendm($$, $3);
863 }
864 ;
865
866 block: '{' commands '}' { $$ = $2; }
867 | '{' '}' { $$ = NULL; }
868 ;
869
870 test: ANYOF testlist { $$ = new_test(ANYOF); $$->u.tl = $2; }
871 | ALLOF testlist { $$ = new_test(ALLOF); $$->u.tl = $2; }
872 | EXISTS stringlist { $$ = new_test(EXISTS); $$->u.sl = $2; }
873 | SFALSE { $$ = new_test(SFALSE); }
874 | STRUE { $$ = new_test(STRUE); }
875
876 | HEADER htags stringlist stringlist
877 {
878 if (!verify_stringlist(parse_script,
879 $3, verify_header)) {
880 YYERROR; /* vh should call yyerror() */
881 }
882 $2 = canon_comptags($2);
883
884 if (!verify_patternlist(parse_script,
885 $4, $2,
886 verify_utf8)) {
887 YYERROR; /* vp should call yyerror() */
888 }
889
890 $$ = build_header(HEADER, $2, $3, $4);
891 if ($$ == NULL) {
892 parse_error(parse_script,
893 SIEVE_BUILD_FAILURE,
894 "header test");
895 YYERROR; /* pe should call yyerror() */
896 }
897 }
898
899 | STRINGT strtags stringlist stringlist
900 {
901 if (!parse_script->support.variables) {
902 parse_error(parse_script,
903 SIEVE_MISSING_REQUIRE,
904 "variables");
905 YYERROR; /* pe should call yyerror() */
906 }
907 if (!verify_stringlist(parse_script,
908 $3, verify_utf8)) {
909 YYERROR; /* vu should call yyerror() */
910 }
911 $2 = canon_comptags($2);
912
913 if (!verify_patternlist(parse_script,
914 $4, $2,
915 verify_utf8)) {
916 YYERROR; /* vp should call yyerror() */
917 }
918
919 $$ = build_header(STRINGT, $2, $3, $4);
920 if ($$ == NULL) {
921 parse_error(parse_script,
922 SIEVE_BUILD_FAILURE,
923 "string test");
924 YYERROR; /* pe should call yyerror() */
925 }
926 }
927
928 /* Per RFC 5232, the variables list (penultimate argument) is optional,
929 but defining the grammar this way results in a shift/reduce conflict.
930 Therefore, we have to flatten the grammar into two rules.
931 */
932 | HASFLAG hftags stringlist stringlist
933 {
934 if (!parse_script->support.imap4flags) {
935 parse_error(parse_script,
936 SIEVE_MISSING_REQUIRE,
937 "imap4flags");
938 YYERROR; /* pe should call yyerror() */
939 }
940 if (!parse_script->support.variables) {
941 parse_error(parse_script,
942 SIEVE_MISSING_REQUIRE,
943 "variables");
944 YYERROR; /* pe should call yyerror() */
945 }
946 if (!verify_stringlist(parse_script, $3,
947 verify_identifier)) {
948 YYERROR; /* vi should call yyerror() */
949 }
950 $2 = canon_comptags($2);
951
952 if (!verify_patternlist(parse_script,
953 $4, $2,
954 verify_utf8)) {
955 YYERROR; /* vp should call yyerror() */
956 }
957
958 $$ = build_header(HASFLAG, $2, $3, $4);
959 if ($$ == NULL) {
960 parse_error(parse_script,
961 SIEVE_BUILD_FAILURE,
962 "hasflag test");
963 YYERROR; /* pe should call yyerror() */
964 }
965 }
966
967 | HASFLAG hftags stringlist
968 {
969 if (!parse_script->support.imap4flags) {
970 parse_error(parse_script,
971 SIEVE_MISSING_REQUIRE,
972 "imap4flags");
973 YYERROR; /* pe should call yyerror() */
974 }
975 $2 = canon_comptags($2);
976
977 if (!verify_patternlist(parse_script,
978 $3, $2,
979 verify_utf8)) {
980 YYERROR; /* vp should call yyerror() */
981 }
982
983 $$ = build_header(HASFLAG, $2, NULL, $3);
984 if ($$ == NULL) {
985 parse_error(parse_script,
986 SIEVE_BUILD_FAILURE,
987 "hasflag test");
988 YYERROR; /* pe should call yyerror() */
989 }
990 }
991
992 | ADDRESS atags stringlist stringlist
993 {
994 if (!verify_stringlist(parse_script, $3,
995 verify_addrheader)) {
996 YYERROR; /* vah should call yyerror() */
997 }
998 $2 = canon_aetags($2);
999
1000 if (!verify_patternlist(parse_script, $4,
1001 &($2->comptags),
1002 NULL)) {
1003 YYERROR; /* vp should call yyerror() */
1004 }
1005
1006 $$ = build_address(ADDRESS, $2, $3, $4);
1007 if ($$ == NULL) {
1008 parse_error(parse_script,
1009 SIEVE_BUILD_FAILURE,
1010 "address test");
1011 YYERROR; /* pe should call yyerror() */
1012 }
1013 }
1014
1015 | ENVELOPE etags stringlist stringlist
1016 {
1017 if (!parse_script->support.envelope) {
1018 parse_error(parse_script,
1019 SIEVE_MISSING_REQUIRE,
1020 "envelope");
1021 YYERROR; /* pe should call yyerror() */
1022 }
1023 if (!verify_stringlist(parse_script, $3,
1024 verify_envelope)) {
1025 YYERROR;
1026 }
1027 $2 = canon_aetags($2);
1028
1029 if (!verify_patternlist(parse_script, $4,
1030 &($2->comptags),
1031 NULL)) {
1032 YYERROR; /* vp should call yyerror() */
1033 }
1034
1035 $$ = build_address(ENVELOPE, $2, $3, $4);
1036 if ($$ == NULL) {
1037 parse_error(parse_script,
1038 SIEVE_BUILD_FAILURE,
1039 "envelope test");
1040 YYERROR; /* pe should call yyerror() */
1041 }
1042 }
1043
1044 | BODY btags stringlist
1045 {
1046 if (!parse_script->support.body) {
1047 parse_error(parse_script,
1048 SIEVE_MISSING_REQUIRE,
1049 "body");
1050 YYERROR; /* pe should call yyerror() */
1051 }
1052 $2 = canon_btags($2);
1053
1054 if (!verify_patternlist(parse_script, $3,
1055 &($2->comptags),
1056 verify_utf8)) {
1057 YYERROR; /* vp should call yyerror() */
1058 }
1059
1060 $$ = build_body(BODY, $2, $3);
1061 if ($$ == NULL) {
1062 parse_error(parse_script,
1063 SIEVE_BUILD_FAILURE,
1064 "body test");
1065 YYERROR; /* pe should call yyerror() */
1066 }
1067 }
1068
1069 | NOT test { $$ = new_test(NOT); $$->u.t = $2; }
1070 | SIZE sizetag NUMBER { $$ = new_test(SIZE); $$->u.sz.t = $2;
1071 $$->u.sz.n = $3; }
1072
1073 | DATE dttags STRING datepart stringlist
1074 {
1075 if (!parse_script->support.date) {
1076 parse_error(parse_script,
1077 SIEVE_MISSING_REQUIRE,
1078 "date");
1079 YYERROR; /* pe should call yyerror() */
1080 }
1081 if (!verify_header(parse_script, $3)) {
1082 YYERROR; /* vh should call yyerror() */
1083 }
1084 $2 = canon_dttags($2);
1085
1086 if (!verify_patternlist(parse_script, $5,
1087 &($2->comptags),
1088 NULL)) {
1089 YYERROR; /* vp should call yyerror() */
1090 }
1091
1092 $$ = build_date(DATE, $2, $3, $4, $5);
1093 if ($$ == NULL) {
1094 parse_error(parse_script,
1095 SIEVE_BUILD_FAILURE,
1096 "date test");
1097 YYERROR; /* pe should call yyerror() */
1098 }
1099 }
1100
1101 | CURRENTDATE cdtags datepart stringlist
1102 {
1103 if (!parse_script->support.date) {
1104 parse_error(parse_script,
1105 SIEVE_MISSING_REQUIRE,
1106 "date");
1107 YYERROR; /* pe should call yyerror() */
1108 }
1109 $2 = canon_dttags($2);
1110
1111 if (!verify_patternlist(parse_script, $4,
1112 &($2->comptags),
1113 NULL)) {
1114 YYERROR; /* vp should call yyerror() */
1115 }
1116
1117 $$ = build_date(CURRENTDATE,
1118 $2, NULL, $3, $4);
1119 if ($$ == NULL) {
1120 parse_error(parse_script,
1121 SIEVE_BUILD_FAILURE,
1122 "currentdate test");
1123 YYERROR; /* pe should call yyerror() */
1124 }
1125 }
1126
1127 | MAILBOXEXISTS stringlist
1128 {
1129 if (!parse_script->support.mailbox) {
1130 parse_error(parse_script,
1131 SIEVE_MISSING_REQUIRE,
1132 "mailbox");
1133 YYERROR; /* pe should call yyerror() */
1134 }
1135
1136 $$ = build_mailboxtest(MAILBOXEXISTS, NULL,
1137 NULL, NULL, $2);
1138 if ($$ == NULL) {
1139 parse_error(parse_script,
1140 SIEVE_BUILD_FAILURE,
1141 "mailboxexists test");
1142 YYERROR; /* pe should call yyerror() */
1143 }
1144 }
1145
1146 | METADATA mtags STRING STRING stringlist
1147 {
1148 if (!parse_script->support.mboxmetadata) {
1149 parse_error(parse_script,
1150 SIEVE_MISSING_REQUIRE,
1151 "mboxmetadata");
1152 YYERROR; /* pe should call yyerror() */
1153 }
1154
1155 $$ = build_mailboxtest(METADATA,
1156 $2, $3, $4, $5);
1157 if ($$ == NULL) {
1158 parse_error(parse_script,
1159 SIEVE_BUILD_FAILURE,
1160 "metadata test");
1161 YYERROR; /* pe should call yyerror() */
1162 }
1163 }
1164
1165 | METADATAEXISTS STRING stringlist
1166 {
1167 if (!parse_script->support.mboxmetadata) {
1168 parse_error(parse_script,
1169 SIEVE_MISSING_REQUIRE,
1170 "mboxmetadata");
1171 YYERROR; /* pe should call yyerror() */
1172 }
1173
1174 $$ = build_mailboxtest(METADATAEXISTS,
1175 NULL, $2, NULL, $3);
1176 if ($$ == NULL) {
1177 parse_error(parse_script,
1178 SIEVE_BUILD_FAILURE,
1179 "metadataexists test");
1180 YYERROR; /* pe should call yyerror() */
1181 }
1182 }
1183
1184 | SERVERMETADATA mtags STRING stringlist
1185 {
1186 if (!parse_script->support.servermetadata) {
1187 parse_error(parse_script,
1188 SIEVE_MISSING_REQUIRE,
1189 "servermetadata");
1190 YYERROR; /* pe should call yyerror() */
1191 }
1192
1193 $$ = build_mailboxtest(SERVERMETADATA,
1194 $2, NULL, $3, $4);
1195 if ($$ == NULL) {
1196 parse_error(parse_script,
1197 SIEVE_BUILD_FAILURE,
1198 "servermetadata test");
1199 YYERROR; /* pe should call yyerror() */
1200 }
1201 }
1202
1203 | SERVERMETADATAEXISTS stringlist
1204 {
1205 if (!parse_script->support.servermetadata) {
1206 parse_error(parse_script,
1207 SIEVE_MISSING_REQUIRE,
1208 "servermetadata");
1209 YYERROR; /* pe should call yyerror() */
1210 }
1211
1212 $$ = build_mailboxtest(SERVERMETADATAEXISTS,
1213 NULL, NULL, NULL, $2);
1214 if ($$ == NULL) {
1215 parse_error(parse_script,
1216 SIEVE_BUILD_FAILURE,
1217 "servermetadataexists test");
1218 YYERROR; /* pe should call yyerror() */
1219 }
1220 }
1221
1222 | error { $$ = NULL; }
1223 ;
1224
1225 atags: /* empty */ { $$ = new_aetags(); }
1226 | atags addrparttag
1227 {
1228 $$ = $1;
1229 if ($$->addrtag != -1) {
1230 parse_error(parse_script,
1231 SIEVE_DUPLICATE_TAG,
1232 "address-part");
1233 YYERROR; /* pe should call yyerror() */
1234 }
1235 else $$->addrtag = $2;
1236 }
1237 | atags matchtags
1238 | atags comparator
1239 | atags idxtags
1240 ;
1241
1242 etags: /* empty */ { $$ = new_aetags(); }
1243 | etags addrparttag
1244 {
1245 $$ = $1;
1246 if ($$->addrtag != -1) {
1247 parse_error(parse_script,
1248 SIEVE_DUPLICATE_TAG,
1249 "address-part");
1250 YYERROR; /* pe should call yyerror() */
1251 }
1252 else $$->addrtag = $2;
1253 }
1254 | etags matchtags
1255 | etags comparator
1256 ;
1257
1258 /* $0 is the symbol which precedes comptags (e.g. aetags).
1259 We typecast this pointer into struct comptags *
1260 */
1261 matchtags: match
1262 {
1263 struct comptags *ctags = $<ctag>0;
1264 if (ctags->match != -1) {
1265 parse_error(parse_script,
1266 SIEVE_DUPLICATE_TAG,
1267 "match-type");
1268 YYERROR; /* pe should call yyerror() */
1269 }
1270 else ctags->match = $1;
1271 }
1272 | relmatch STRING
1273 {
1274 struct comptags *ctags = $<ctag>0;
1275 if (ctags->match != -1) {
1276 parse_error(parse_script,
1277 SIEVE_DUPLICATE_TAG,
1278 "match-type");
1279 YYERROR; /* pe should call yyerror() */
1280 }
1281 else {
1282 ctags->match = $1;
1283 ctags->relation =
1284 verify_relat(parse_script, $2);
1285 if (ctags->relation == -1) {
1286 YYERROR; /*vr called yyerror()*/
1287 }
1288 }
1289 }
1290 ;
1291
1292 /* $0 is the symbol which precedes comparator (e.g. aetags).
1293 We typecast this pointer into struct comptags *
1294 */
1295 comparator: COMPARATOR STRING
1296 {
1297 struct comptags *ctags = $<ctag>0;
1298 if (ctags->comparator != NULL) {
1299 parse_error(parse_script,
1300 SIEVE_DUPLICATE_TAG,
1301 ":comparator");
1302 YYERROR; /* pe should call yyerror() */
1303 }
1304 else if (!strcmp($2, "i;ascii-numeric") &&
1305 !parse_script->support.i_ascii_numeric) {
1306 parse_error(parse_script,
1307 SIEVE_MISSING_REQUIRE,
1308 "comparator-i;ascii-numeric");
1309 YYERROR; /* pe should call yyerror() */
1310 }
1311 else ctags->comparator = $2;
1312 }
1313 ;
1314
1315 /* $0 is the symbol which precedes idxtags (e.g. aetags).
1316 We typecast this pointer into struct comptags *
1317
1318 Note: This rule forces :index to occur before :last
1319 even though RFC 5228 states that tagged arguments can appear in any order.
1320 */
1321 idxtags: INDEX NUMBER
1322 {
1323 struct comptags *ctags = $<ctag>0;
1324 if (!parse_script->support.index) {
1325 parse_error(parse_script,
1326 SIEVE_MISSING_REQUIRE,
1327 "index");
1328 YYERROR; /* pe should call yyerror() */
1329 }
1330 if (ctags->index != 0) {
1331 parse_error(parse_script,
1332 SIEVE_DUPLICATE_TAG,
1333 ":index");
1334 YYERROR; /* pe should call yyerror() */
1335 }
1336 if ($2 <= 0) {
1337 parse_error(parse_script,
1338 SIEVE_INVALID_VALUE,
1339 ":index");
1340 YYERROR; /* pe should call yyerror() */
1341 }
1342 else ctags->index = $2;
1343 }
1344 | LAST
1345 { struct comptags *ctags = $<ctag>0;
1346 if (!parse_script->support.index) {
1347 parse_error(parse_script,
1348 SIEVE_MISSING_REQUIRE,
1349 "index");
1350 YYERROR; /* pe should call yyerror() */
1351 }
1352 if (ctags->index == 0) {
1353 parse_error(parse_script,
1354 SIEVE_MISSING_TAG,
1355 ":index");
1356 YYERROR; /* pe should call yyerror() */
1357 }
1358 else if (ctags->index < 0) {
1359 parse_error(parse_script,
1360 SIEVE_DUPLICATE_TAG,
1361 ":last");
1362 YYERROR; /* pe should call yyerror() */
1363 }
1364 else ctags->index *= -1;
1365 }
1366 ;
1367
1368 htags: /* empty */ { $$ = new_comptags(); }
1369 | htags matchtags
1370 | htags comparator
1371 | htags idxtags
1372 ;
1373
1374 strtags:/* empty */ { $$ = new_comptags(); }
1375 | strtags matchtags
1376 | strtags comparator
1377 ;
1378
1379 hftags:/* empty */ { $$ = new_comptags(); }
1380 | hftags matchtags
1381 | hftags comparator
1382 ;
1383
1384 mtags: /* empty */ { $$ = new_comptags(); }
1385 | mtags matchtags
1386 | mtags comparator
1387 ;
1388
1389 btags: /* empty */ { $$ = new_btags(); }
1390 | btags RAW
1391 {
1392 $$ = $1;
1393 if ($$->transform != -1) {
1394 parse_error(parse_script,
1395 SIEVE_DUPLICATE_TAG,
1396 "transform");
1397 YYERROR; /* pe should call yyerror() */
1398 }
1399 else $$->transform = RAW;
1400 }
1401 | btags TEXT
1402 {
1403 $$ = $1;
1404 if ($$->transform != -1) {
1405 parse_error(parse_script,
1406 SIEVE_DUPLICATE_TAG,
1407 "transform");
1408 YYERROR; /* pe should call yyerror() */
1409 }
1410 else $$->transform = TEXT;
1411 }
1412 | btags CONTENT stringlist
1413 {
1414 $$ = $1;
1415 if ($$->transform != -1) {
1416 parse_error(parse_script,
1417 SIEVE_DUPLICATE_TAG,
1418 "transform");
1419 YYERROR; /* pe should call yyerror() */
1420 }
1421 else {
1422 $$->transform = CONTENT;
1423 $$->content_types = $3;
1424 }
1425 }
1426 | btags matchtags
1427 | btags comparator
1428 ;
1429
1430 dttags: /* empty */ { $$ = new_dttags(); }
1431 | dttags ORIGINALZONE
1432 {
1433 $$ = $1;
1434 if ($$->zonetag != -1) {
1435 parse_error(parse_script,
1436 SIEVE_DUPLICATE_TAG,
1437 ":originalzone");
1438 YYERROR; /* pe should call yyerror() */
1439 }
1440 else $$->zonetag = ORIGINALZONE;
1441 }
1442 | dttags zone
1443 | dttags matchtags
1444 | dttags comparator
1445 | dttags idxtags
1446 ;
1447
1448 cdtags: /* empty */ { $$ = new_dttags(); }
1449 | cdtags zone
1450 | cdtags matchtags
1451 | cdtags comparator
1452 ;
1453
1454 /* $0 is the symbol which precedes zone (e.g. dttags).
1455 We typecast this pointer into struct comptags *
1456 */
1457 zone: ZONE STRING
1458 {
1459 struct dttags *dttags = $<dttag>0;
1460 if (dttags->zonetag != -1) {
1461 parse_error(parse_script,
1462 SIEVE_DUPLICATE_TAG,
1463 ":zone");
1464 YYERROR; /* pe should call yyerror() */
1465 }
1466 else if (verify_zone(parse_script, $2) == -1) {
1467 YYERROR; /*vr called yyerror()*/
1468 }
1469 else {
1470 dttags->zone = $2;
1471 dttags->zonetag = ZONE;
1472 }
1473 }
1474 ;
1475
1476 datepart: STRING
1477 {
1478 $$ = verify_date_part(parse_script, $1);
1479 if ($$ == -1) {
1480 YYERROR; /* vdp called yyerror() */
1481 }
1482 }
1483 ;
1484
1485 addrparttag: ALL { $$ = ALL; }
1486 | LOCALPART { $$ = LOCALPART; }
1487 | DOMAIN { $$ = DOMAIN; }
1488 | USER
1489 {
1490 if (!parse_script->support.subaddress) {
1491 parse_error(parse_script,
1492 SIEVE_MISSING_REQUIRE,
1493 "subaddress");
1494 YYERROR; /* pe should call yyerror() */
1495 }
1496 $$ = USER;
1497 }
1498 | DETAIL
1499 {
1500 if (!parse_script->support.subaddress) {
1501 parse_error(parse_script,
1502 SIEVE_MISSING_REQUIRE,
1503 "subaddress");
1504 YYERROR; /* pe should call yyerror() */
1505 }
1506 $$ = DETAIL;
1507 }
1508 ;
1509 match: IS { $$ = IS; }
1510 | CONTAINS { $$ = CONTAINS; }
1511 | MATCHES { $$ = MATCHES; }
1512 | REGEX
1513 {
1514 if (!parse_script->support.regex) {
1515 parse_error(parse_script,
1516 SIEVE_MISSING_REQUIRE,
1517 "regex");
1518 YYERROR; /* pe should call yyerror() */
1519 }
1520 $$ = REGEX;
1521 }
1522 ;
1523
1524 relmatch: COUNT
1525 {
1526 if (!parse_script->support.relational) {
1527 parse_error(parse_script,
1528 SIEVE_MISSING_REQUIRE,
1529 "relational");
1530 YYERROR; /* pe should call yyerror() */
1531 }
1532 $$ = COUNT;
1533 }
1534 | VALUE
1535 {
1536 if (!parse_script->support.relational) {
1537 parse_error(parse_script,
1538 SIEVE_MISSING_REQUIRE,
1539 "relational");
1540 YYERROR; /* pe should call yyerror() */
1541 }
1542 $$ = VALUE;
1543 }
1544 ;
1545
1546
1547 sizetag: OVER { $$ = OVER; }
1548 | UNDER { $$ = UNDER; }
1549 ;
1550
1551 copy: COPY
1552 {
1553 if (!parse_script->support.copy) {
1554 parse_error(parse_script,
1555 SIEVE_MISSING_REQUIRE,
1556 "copy");
1557 YYERROR; /* pe should call yyerror() */
1558 }
1559 $$ = 1;
1560 }
1561 ;
1562
1563 creat: CREATE
1564 {
1565 if (!parse_script->support.mailbox) {
1566 parse_error(parse_script,
1567 SIEVE_MISSING_REQUIRE,
1568 "mailbox");
1569 YYERROR; /* pe should call yyerror() */
1570 }
1571 $$ = 1;
1572 }
1573 ;
1574
1575 ftags: /* empty */ { $$ = new_ftags(); }
1576 | ftags copy
1577 {
1578 $$ = $1;
1579 if ($$->copy) {
1580 parse_error(parse_script,
1581 SIEVE_DUPLICATE_TAG,
1582 ":copy");
1583 YYERROR; /* pe should call yyerror() */
1584 }
1585 else $$->copy = $2;
1586 }
1587 | ftags creat
1588 {
1589 $$ = $1;
1590 if ($$->create) {
1591 parse_error(parse_script,
1592 SIEVE_DUPLICATE_TAG,
1593 ":create");
1594 YYERROR; /* pe should call yyerror() */
1595 }
1596 else $$->create = $2;
1597 }
1598 | ftags FLAGS stringlist
1599 {
1600 if (!parse_script->support.imap4flags) {
1601 parse_error(parse_script,
1602 SIEVE_MISSING_REQUIRE,
1603 "imap4flags");
1604 YYERROR; /* pe should call yyerror() */
1605 }
1606 if ($$->flags != NULL) {
1607 parse_error(parse_script,
1608 SIEVE_DUPLICATE_TAG,
1609 ":flags");
1610 YYERROR; /* pe should call yyerror() */
1611 }
1612
1613 $$ = $1;
1614 if (!parse_script->support.variables) {
1615 verify_flaglist($3);
1616 }
1617 if (!$3->count) strarray_add($3, "");
1618 $$->flags = $3;
1619 }
1620 ;
1621
1622 rtags: /* empty */ { $$ = 0; }
1623 | rtags copy
1624 {
1625 $$ = $1;
1626 if ($$) {
1627 parse_error(parse_script,
1628 SIEVE_DUPLICATE_TAG,
1629 ":copy");
1630 YYERROR; /* pe should call yyerror() */
1631 }
1632 else $$ = $2;
1633 }
1634 ;
1635
1636 testlist: '(' tests ')' { $$ = $2; }
1637 ;
1638
1639 tests: test { $$ = new_testlist($1, NULL); }
1640 | test ',' tests { $$ = new_testlist($1, $3); }
1641 ;
1642
1643 %%
1644
1645
1646 /*
1647 * Actions
1648 */
1649
1650 void yyerror(sieve_script_t *parse_script, const char *msg)
1651 {
1652 parse_script->err++;
1653 if (parse_script->interp.err) {
1654 parse_script->interp.err(sievelineno, msg,
1655 parse_script->interp.interp_context,
1656 parse_script->script_context);
1657 }
1658 }
1659
parse_error(sieve_script_t * parse_script,int err,...)1660 static void parse_error(sieve_script_t *parse_script, int err, ...)
1661 {
1662 va_list args;
1663
1664 va_start(args, err);
1665 vsnprintf(parse_script->sieveerr, ERR_BUF_SIZE, error_message(err), args);
1666 yyerror(parse_script, parse_script->sieveerr);
1667 va_end(args);
1668 }
1669
check_reqs(sieve_script_t * parse_script,strarray_t * sa)1670 static char *check_reqs(sieve_script_t *parse_script, strarray_t *sa)
1671 {
1672 char *s;
1673 struct buf errs = BUF_INITIALIZER;
1674 char *res;
1675
1676 while ((s = strarray_shift(sa))) {
1677 if (!script_require(parse_script, s)) {
1678 if (!errs.len)
1679 buf_printf(&errs,
1680 "Unsupported feature(s) in \"require\": \"%s\"", s);
1681 else buf_printf(&errs, ", \"%s\"", s);
1682 }
1683 free(s);
1684 }
1685 strarray_free(sa);
1686
1687 res = buf_release(&errs);
1688 if (!res[0]) {
1689 free(res);
1690 return NULL;
1691 }
1692
1693 return res;
1694 }
1695
build_address(int t,struct aetags * ae,strarray_t * sl,strarray_t * pl)1696 static test_t *build_address(int t, struct aetags *ae,
1697 strarray_t *sl, strarray_t *pl)
1698 {
1699 test_t *ret = new_test(t); /* can be either ADDRESS or ENVELOPE */
1700
1701 assert((t == ADDRESS) || (t == ENVELOPE));
1702
1703 if (ret) {
1704 ret->u.ae.comptag = ae->comptags.match;
1705 ret->u.ae.relation=ae->comptags.relation;
1706 ret->u.ae.comparator=xstrdup(ae->comptags.comparator);
1707 ret->u.ae.index = ae->comptags.index;
1708 ret->u.ae.sl = sl;
1709 ret->u.ae.pl = pl;
1710 ret->u.ae.addrpart = ae->addrtag;
1711 free_aetags(ae);
1712
1713 }
1714 return ret;
1715 }
1716
build_header(int t,struct comptags * c,strarray_t * sl,strarray_t * pl)1717 static test_t *build_header(int t, struct comptags *c,
1718 strarray_t *sl, strarray_t *pl)
1719 {
1720 test_t *ret = new_test(t); /* can be HEADER or HASFLAG or STRINGT */
1721
1722 assert((t == HEADER) || (t == HASFLAG) || (t == STRINGT));
1723
1724 if (ret) {
1725 ret->u.h.comptag = c->match;
1726 ret->u.h.relation = c->relation;
1727 ret->u.h.comparator = xstrdup(c->comparator);
1728 ret->u.h.index = c->index;
1729 ret->u.h.sl = sl;
1730 ret->u.h.pl = pl;
1731 free_comptags(c, 1);
1732 }
1733 return ret;
1734 }
1735
build_body(int t,struct btags * b,strarray_t * pl)1736 static test_t *build_body(int t, struct btags *b, strarray_t *pl)
1737 {
1738 test_t *ret = new_test(t); /* can be BODY */
1739
1740 assert(t == BODY);
1741
1742 if (ret) {
1743 ret->u.b.comptag = b->comptags.match;
1744 ret->u.b.relation = b->comptags.relation;
1745 ret->u.b.comparator = xstrdup(b->comptags.comparator);
1746 ret->u.b.transform = b->transform;
1747 ret->u.b.offset = b->offset;
1748 ret->u.b.content_types = b->content_types; b->content_types = NULL;
1749 ret->u.b.pl = pl;
1750 free_btags(b);
1751 }
1752 return ret;
1753 }
1754
build_mailboxtest(int t,struct comptags * c,const char * extname,const char * keyname,strarray_t * keylist)1755 static test_t *build_mailboxtest(int t, struct comptags *c,
1756 const char *extname, const char *keyname,
1757 strarray_t *keylist)
1758 {
1759 test_t *ret = new_test(t);
1760
1761 if (ret) {
1762 ret->u.mbx.extname = xstrdupnull(extname);
1763 ret->u.mbx.keyname = xstrdupnull(keyname);
1764 ret->u.mbx.keylist = keylist;
1765 if (c) {
1766 canon_comptags(c);
1767 ret->u.mbx.comptag = c->match;
1768 ret->u.mbx.relation = c->relation;
1769 ret->u.mbx.comparator = xstrdup(c->comparator);
1770 free_comptags(c, 1);
1771 }
1772 }
1773
1774 return ret;
1775 }
1776
build_vacation(int t,struct vtags * v,char * reason)1777 static commandlist_t *build_vacation(int t, struct vtags *v, char *reason)
1778 {
1779 commandlist_t *ret = new_command(t);
1780
1781 assert(t == VACATION);
1782
1783 if (ret) {
1784 ret->u.v.subject = v->subject; v->subject = NULL;
1785 ret->u.v.from = v->from; v->from = NULL;
1786 ret->u.v.handle = v->handle; v->handle = NULL;
1787 ret->u.v.seconds = v->seconds;
1788 ret->u.v.mime = v->mime;
1789 ret->u.v.addresses = v->addresses; v->addresses = NULL;
1790 free_vtags(v);
1791 ret->u.v.message = reason;
1792 }
1793 return ret;
1794 }
1795
build_notify(int t,struct ntags * n)1796 static commandlist_t *build_notify(int t, struct ntags *n)
1797 {
1798 commandlist_t *ret = new_command(t);
1799
1800 assert(t == NOTIFY);
1801 if (ret) {
1802 ret->u.n.method = n->method; n->method = NULL;
1803 ret->u.n.id = n->id; n->id = NULL;
1804 ret->u.n.options = n->options; n->options = NULL;
1805 ret->u.n.priority = n->priority;
1806 ret->u.n.message = n->message; n->message = NULL;
1807 free_ntags(n);
1808 }
1809 return ret;
1810 }
1811
build_denotify(int t,struct dtags * d)1812 static commandlist_t *build_denotify(int t, struct dtags *d)
1813 {
1814 commandlist_t *ret = new_command(t);
1815
1816 assert(t == DENOTIFY);
1817
1818 if (ret) {
1819 ret->u.d.comptag = d->comptags.match;
1820 ret->u.d.relation = d->comptags.relation;
1821 ret->u.d.pattern = xstrdupnull(d->pattern);
1822 ret->u.d.priority = d->priority;
1823 free_dtags(d);
1824 }
1825 return ret;
1826 }
1827
build_keep(int t,struct ftags * f)1828 static commandlist_t *build_keep(int t, struct ftags *f)
1829 {
1830 commandlist_t *ret = new_command(t);
1831
1832 assert(t == KEEP);
1833
1834 if (ret) {
1835 ret->u.k.copy = f->copy;
1836 ret->u.k.flags = f->flags; f->flags = NULL;
1837 free_ftags(f);
1838 }
1839 return ret;
1840 }
1841
build_fileinto(int t,struct ftags * f,char * folder)1842 static commandlist_t *build_fileinto(int t, struct ftags *f, char *folder)
1843 {
1844 commandlist_t *ret = new_command(t);
1845
1846 assert(t == FILEINTO);
1847
1848 if (ret) {
1849 ret->u.f.copy = f->copy;
1850 ret->u.f.create = f->create;
1851 ret->u.f.flags = f->flags; f->flags = NULL;
1852 if (config_getswitch(IMAPOPT_SIEVE_UTF8FILEINTO)) {
1853 ret->u.f.folder = xmalloc(5 * strlen(folder) + 1);
1854 UTF8_to_mUTF7(ret->u.f.folder, folder);
1855 }
1856 else {
1857 ret->u.f.folder = xstrdup(folder);
1858 }
1859 free_ftags(f);
1860 }
1861 return ret;
1862 }
1863
build_redirect(int t,int copy,char * address)1864 static commandlist_t *build_redirect(int t, int copy, char *address)
1865 {
1866 commandlist_t *ret = new_command(t);
1867
1868 assert(t == REDIRECT);
1869
1870 if (ret) {
1871 ret->u.r.copy = copy;
1872 ret->u.r.address = address;
1873 }
1874 return ret;
1875 }
1876
build_include(int t,struct itags * i,char * script)1877 static commandlist_t *build_include(int t, struct itags *i, char* script)
1878 {
1879 commandlist_t *ret = new_command(t);
1880
1881 assert(t == INCLUDE);
1882
1883 if (i->location == -1) i->location = PERSONAL;
1884 if (i->once == -1) i->once = 0;
1885 if (i->optional == -1) i->optional = 0;
1886
1887 if (ret) {
1888 ret->u.inc.location = i->location;
1889 ret->u.inc.once = i->once;
1890 ret->u.inc.optional = i->optional;
1891 ret->u.inc.script = script;
1892 free(i);
1893 }
1894 return ret;
1895 }
1896
build_date(int t,struct dttags * dt,char * hn,int part,strarray_t * kl)1897 static test_t *build_date(int t, struct dttags *dt,
1898 char *hn, int part, strarray_t *kl)
1899 {
1900 test_t *ret = new_test(t);
1901 assert(t == DATE || t == CURRENTDATE);
1902
1903 if (ret) {
1904 ret->u.dt.comptag = dt->comptags.match;
1905 ret->u.dt.relation = dt->comptags.relation;
1906 ret->u.dt.comparator = xstrdup(dt->comptags.comparator);
1907 ret->u.dt.index = dt->comptags.index;
1908 ret->u.dt.zone = xstrdupnull(dt->zone);
1909 ret->u.dt.zonetag = dt->zonetag;
1910 ret->u.dt.date_part = part;
1911 ret->u.dt.header_name = xstrdupnull(hn);
1912 ret->u.dt.kl = kl;
1913 free_dttags(dt);
1914 }
1915 return ret;
1916 }
1917
build_set(int t,struct stags * s,char * variable,char * value)1918 static commandlist_t *build_set(int t, struct stags *s,
1919 char *variable, char *value)
1920 {
1921 commandlist_t *ret = new_command(t);
1922
1923 assert(t == SET);
1924
1925 if (ret) {
1926 ret->u.s.mod40 = s->mod40;
1927 ret->u.s.mod30 = s->mod30;
1928 ret->u.s.mod20 = s->mod20;
1929 ret->u.s.mod10 = s->mod10;
1930 ret->u.s.variable = xstrdup(variable);
1931 ret->u.s.value = xstrdup(value);
1932
1933 free_stags(s);
1934 }
1935
1936 return ret;
1937 }
1938
build_flag(int t,char * variable,strarray_t * flags)1939 static commandlist_t *build_flag(int t, char *variable, strarray_t *flags)
1940 {
1941 commandlist_t *ret = new_command(t);
1942
1943 assert(t == SETFLAG || t == ADDFLAG || t == REMOVEFLAG);
1944
1945 if (ret) {
1946 ret->u.fl.variable = xstrdup(variable ? variable : "");
1947 ret->u.fl.flags = flags;
1948 }
1949
1950 return ret;
1951 }
1952
new_aetags(void)1953 static struct aetags *new_aetags(void)
1954 {
1955 struct aetags *r = (struct aetags *) xmalloc(sizeof(struct aetags));
1956
1957 init_comptags(&r->comptags);
1958 r->addrtag = -1;
1959
1960 return r;
1961 }
1962
canon_aetags(struct aetags * ae)1963 static struct aetags *canon_aetags(struct aetags *ae)
1964 {
1965 canon_comptags(&ae->comptags);
1966 if (ae->addrtag == -1) { ae->addrtag = ALL; }
1967 return ae;
1968 }
1969
free_aetags(struct aetags * ae)1970 static void free_aetags(struct aetags *ae)
1971 {
1972 free_comptags(&ae->comptags, 0);
1973 free(ae);
1974 }
1975
new_comptags(void)1976 static struct comptags *new_comptags(void)
1977 {
1978 struct comptags *c = (struct comptags *) xmalloc(sizeof(struct comptags));
1979
1980 return init_comptags(c);
1981 }
1982
init_comptags(struct comptags * c)1983 static struct comptags *init_comptags(struct comptags *c)
1984 {
1985 c->match = c->relation = -1;
1986 c->comparator = NULL;
1987 c->index = 0;
1988
1989 return c;
1990 }
1991
canon_comptags(struct comptags * c)1992 static struct comptags *canon_comptags(struct comptags *c)
1993 {
1994 if (c->match == -1) c->match = IS;
1995 if (c->comparator == NULL) c->comparator = xstrdup("i;ascii-casemap");
1996 return c;
1997 }
1998
free_comptags(struct comptags * c,int destroy)1999 static void free_comptags(struct comptags *c, int destroy)
2000 {
2001 free(c->comparator);
2002 if (destroy) free(c);
2003 }
2004
new_btags(void)2005 static struct btags *new_btags(void)
2006 {
2007 struct btags *r = (struct btags *) xmalloc(sizeof(struct btags));
2008
2009 init_comptags(&r->comptags);
2010 r->transform = r->offset = -1;
2011 r->content_types = NULL;
2012
2013 return r;
2014 }
2015
canon_btags(struct btags * b)2016 static struct btags *canon_btags(struct btags *b)
2017 {
2018 canon_comptags(&b->comptags);
2019 if (b->transform == -1) b->transform = TEXT;
2020 if (b->content_types == NULL) {
2021 b->content_types = strarray_new();
2022 if (b->transform == RAW) strarray_append(b->content_types, "");
2023 else strarray_append(b->content_types, "text");
2024 }
2025 if (b->offset == -1) b->offset = 0;
2026 return b;
2027 }
2028
free_btags(struct btags * b)2029 static void free_btags(struct btags *b)
2030 {
2031 free_comptags(&b->comptags, 0);
2032 if (b->content_types) strarray_free(b->content_types);
2033 free(b);
2034 }
2035
new_vtags(void)2036 static struct vtags *new_vtags(void)
2037 {
2038 struct vtags *r = (struct vtags *) xmalloc(sizeof(struct vtags));
2039
2040 r->seconds = -1;
2041 r->addresses = NULL;
2042 r->subject = NULL;
2043 r->from = NULL;
2044 r->handle = NULL;
2045 r->mime = -1;
2046
2047 return r;
2048 }
2049
canon_vtags(sieve_script_t * parse_script,struct vtags * v)2050 static struct vtags *canon_vtags(sieve_script_t *parse_script, struct vtags *v)
2051 {
2052 assert(parse_script->interp.vacation != NULL);
2053
2054 if (v->seconds == -1) v->seconds = 7 * DAY2SEC;
2055 if (v->seconds < parse_script->interp.vacation->min_response)
2056 v->seconds = parse_script->interp.vacation->min_response;
2057 if (v->seconds > parse_script->interp.vacation->max_response)
2058 v->seconds = parse_script->interp.vacation->max_response;
2059 if (v->mime == -1) v->mime = 0;
2060
2061 return v;
2062 }
2063
free_vtags(struct vtags * v)2064 static void free_vtags(struct vtags *v)
2065 {
2066 strarray_free(v->addresses);
2067 free(v->subject);
2068 free(v->from);
2069 free(v->handle);
2070 free(v);
2071 }
2072
new_itags()2073 static struct itags *new_itags()
2074 {
2075 struct itags *r = (struct itags *) xmalloc(sizeof(struct itags));
2076
2077 r->once = -1;
2078 r->location = -1;
2079 r->optional = -1;
2080
2081 return r;
2082 }
2083
new_dttags(void)2084 static struct dttags *new_dttags(void)
2085 {
2086 struct dttags *dt = (struct dttags *) xmalloc(sizeof(struct dttags));
2087
2088 init_comptags(&dt->comptags);
2089 dt->zonetag = -1;
2090 dt->zone = NULL;
2091 return dt;
2092 }
2093
canon_dttags(struct dttags * dt)2094 static struct dttags *canon_dttags(struct dttags *dt)
2095 {
2096 char zone[14];
2097 int gmoffset;
2098 int hours;
2099 int minutes;
2100 struct tm tm;
2101 time_t t;
2102
2103 canon_comptags(&dt->comptags);
2104 if (dt->comptags.index == 0) dt->comptags.index = 1;
2105 if (dt->zonetag == -1) {
2106 t = time(NULL);
2107 localtime_r(&t, &tm);
2108 gmoffset = gmtoff_of(&tm, t) / 60;
2109 hours = abs(gmoffset) / 60;
2110 minutes = abs(gmoffset) % 60;
2111 snprintf(zone, sizeof(zone), "%c%02d%02d",
2112 (gmoffset >= 0 ? '+' : '-'), hours, minutes);
2113 dt->zone = xstrdup(zone);
2114 dt->zonetag = ZONE;
2115 }
2116 return dt;
2117 }
2118
free_dttags(struct dttags * dt)2119 static void free_dttags(struct dttags *dt)
2120 {
2121 free_comptags(&dt->comptags, 0);
2122 free(dt->zone);
2123 free(dt);
2124 }
2125
2126
new_ntags(void)2127 static struct ntags *new_ntags(void)
2128 {
2129 struct ntags *r = (struct ntags *) xmalloc(sizeof(struct ntags));
2130
2131 r->method = NULL;
2132 r->id = NULL;
2133 r->options = NULL;
2134 r->priority = -1;
2135 r->message = NULL;
2136
2137 return r;
2138 }
2139
canon_ntags(struct ntags * n)2140 static struct ntags *canon_ntags(struct ntags *n)
2141 {
2142 if (n->priority == -1) n->priority = NORMAL;
2143 if (n->message == NULL) n->message = xstrdup("$from$: $subject$");
2144 if (n->method == NULL) n->method = xstrdup("default");
2145 return n;
2146 }
canon_dtags(struct dtags * d)2147 static struct dtags *canon_dtags(struct dtags *d)
2148 {
2149 canon_comptags(&d->comptags);
2150 if (d->priority == -1) d->priority = ANY;
2151 return d;
2152 }
2153
free_ntags(struct ntags * n)2154 static void free_ntags(struct ntags *n)
2155 {
2156 free(n->method);
2157 free(n->id);
2158 strarray_free(n->options);
2159 free(n->message);
2160 free(n);
2161 }
2162
new_dtags(void)2163 static struct dtags *new_dtags(void)
2164 {
2165 struct dtags *r = (struct dtags *) xzmalloc(sizeof(struct dtags));
2166
2167 init_comptags(&r->comptags);
2168 r->comptags.comparator = xstrdup("i;ascii-casemap");
2169 r->priority = -1;
2170
2171 return r;
2172 }
2173
free_dtags(struct dtags * d)2174 static void free_dtags(struct dtags *d)
2175 {
2176 if (!d) return;
2177 free_comptags(&d->comptags, 0);
2178 free(d);
2179 }
2180
new_ftags(void)2181 static struct ftags *new_ftags(void)
2182 {
2183 struct ftags *f = (struct ftags *) xzmalloc(sizeof(struct ftags));
2184 return f;
2185 }
2186
canon_ftags(struct ftags * f)2187 static struct ftags *canon_ftags(struct ftags *f)
2188 {
2189 return f;
2190 }
2191
new_stags(void)2192 static struct stags *new_stags(void)
2193 {
2194 struct stags *s = (struct stags *) xmalloc(sizeof(struct stags));
2195
2196 s->mod40 = 0;
2197 s->mod30 = 0;
2198 s->mod20 = 0;
2199 s->mod10 = 0;
2200
2201 return s;
2202 }
2203
canon_stags(struct stags * s)2204 static struct stags *canon_stags(struct stags *s)
2205 {
2206 return s;
2207 }
2208
free_stags(struct stags * s)2209 static void free_stags(struct stags *s)
2210 {
2211 free(s);
2212 }
2213
free_ftags(struct ftags * f)2214 static void free_ftags(struct ftags *f)
2215 {
2216 if (!f) return;
2217 strarray_free(f->flags);
2218 free(f);
2219 }
2220
verify_identifier(sieve_script_t * parse_script,char * s)2221 static int verify_identifier(sieve_script_t *parse_script, char *s)
2222 {
2223 /* identifier = (ALPHA / "_") *(ALPHA / DIGIT / "_") */
2224
2225 if (!is_identifier(s)) {
2226 snprintf(parse_script->sieveerr, ERR_BUF_SIZE,
2227 "string '%s': not a valid sieve identifier", s);
2228 yyerror(parse_script, parse_script->sieveerr);
2229 return 0;
2230 }
2231 return 1;
2232 }
2233
verify_stringlist(sieve_script_t * parse_script,strarray_t * sa,int (* verify)(sieve_script_t *,char *))2234 static int verify_stringlist(sieve_script_t *parse_script, strarray_t *sa,
2235 int (*verify)(sieve_script_t*, char *))
2236 {
2237 int i;
2238
2239 for (i = 0 ; i < sa->count ; i++) {
2240 if (!verify(parse_script, sa->data[i])) return 0;
2241 }
2242 return 1;
2243 }
2244
verify_address(sieve_script_t * parse_script,char * s)2245 static int verify_address(sieve_script_t *parse_script, char *s)
2246 {
2247 parse_script->addrerr[0] = '\0'; /* paranoia */
2248 YY_BUFFER_STATE buffer = addr_scan_string(s);
2249 if (addrparse(parse_script)) {
2250 snprintf(parse_script->sieveerr, ERR_BUF_SIZE,
2251 "address '%s': %s", s, parse_script->addrerr);
2252 yyerror(parse_script, parse_script->sieveerr);
2253 addr_delete_buffer(buffer);
2254 return 0;
2255 }
2256 addr_delete_buffer(buffer);
2257 return 1;
2258 }
2259
verify_mailbox(sieve_script_t * parse_script,char * s)2260 static int verify_mailbox(sieve_script_t *parse_script, char *s)
2261 {
2262 if (!verify_utf8(parse_script, s)) return 0;
2263
2264 /* xxx if not a mailbox, call yyerror */
2265 return 1;
2266 }
2267
verify_header(sieve_script_t * parse_script,char * hdr)2268 static int verify_header(sieve_script_t *parse_script, char *hdr)
2269 {
2270 char *h = hdr;
2271
2272 while (*h) {
2273 /* field-name = 1*ftext
2274 ftext = %d33-57 / %d59-126
2275 ; Any character except
2276 ; controls, SP, and
2277 ; ":". */
2278 if (!((*h >= 33 && *h <= 57) || (*h >= 59 && *h <= 126))) {
2279 snprintf(parse_script->sieveerr, ERR_BUF_SIZE,
2280 "header '%s': not a valid header", hdr);
2281 yyerror(parse_script, parse_script->sieveerr);
2282 return 0;
2283 }
2284 h++;
2285 }
2286 return 1;
2287 }
2288
verify_addrheader(sieve_script_t * parse_script,char * hdr)2289 static int verify_addrheader(sieve_script_t *parse_script, char *hdr)
2290 {
2291 const char **h, *hdrs[] = {
2292 "from", "sender", "reply-to", /* RFC2822 originator fields */
2293 "to", "cc", "bcc", /* RFC2822 destination fields */
2294 "resent-from", "resent-sender", /* RFC2822 resent fields */
2295 "resent-to", "resent-cc", "resent-bcc",
2296 "return-path", /* RFC2822 trace fields */
2297 "disposition-notification-to", /* RFC2298 MDN request fields */
2298 "delivered-to", /* non-standard (loop detection) */
2299 "approved", /* RFC1036 moderator/control fields */
2300 NULL
2301 };
2302
2303 if (!config_getswitch(IMAPOPT_RFC3028_STRICT))
2304 return verify_header(parse_script, hdr);
2305
2306 for (lcase(hdr), h = hdrs; *h; h++) {
2307 if (!strcmp(*h, hdr)) return 1;
2308 }
2309
2310 snprintf(parse_script->sieveerr, ERR_BUF_SIZE,
2311 "header '%s': not a valid header for an address test", hdr);
2312 yyerror(parse_script, parse_script->sieveerr);
2313 return 0;
2314 }
2315
verify_envelope(sieve_script_t * parse_script,char * env)2316 static int verify_envelope(sieve_script_t *parse_script, char *env)
2317 {
2318 lcase(env);
2319 if (!config_getswitch(IMAPOPT_RFC3028_STRICT) ||
2320 !strcmp(env, "from") || !strcmp(env, "to") || !strcmp(env, "auth")) {
2321 return 1;
2322 }
2323
2324 snprintf(parse_script->sieveerr, ERR_BUF_SIZE,
2325 "env-part '%s': not a valid part for an envelope test", env);
2326 yyerror(parse_script, parse_script->sieveerr);
2327 return 0;
2328 }
2329
verify_relat(sieve_script_t * parse_script,char * r)2330 static int verify_relat(sieve_script_t *parse_script, char *r)
2331 {
2332 /* this really should have been a token to begin with.*/
2333 lcase(r);
2334 if (!strcmp(r, "gt")) return GT;
2335 else if (!strcmp(r, "ge")) return GE;
2336 else if (!strcmp(r, "lt")) return LT;
2337 else if (!strcmp(r, "le")) return LE;
2338 else if (!strcmp(r, "ne")) return NE;
2339 else if (!strcmp(r, "eq")) return EQ;
2340 else {
2341 snprintf(parse_script->sieveerr, ERR_BUF_SIZE,
2342 "flag '%s': not a valid relational operation", r);
2343 yyerror(parse_script, parse_script->sieveerr);
2344 return -1;
2345 }
2346 }
2347
verify_zone(sieve_script_t * parse_script,char * tz)2348 static int verify_zone(sieve_script_t *parse_script, char *tz)
2349 {
2350 int valid = 0;
2351 unsigned hours;
2352 unsigned minutes;
2353 char sign;
2354
2355 if (sscanf(tz, "%c%02u%02u", &sign, &hours, &minutes) != 3) {
2356 valid |= -1;
2357 }
2358
2359 // test sign
2360 switch (sign) {
2361 case '+':
2362 case '-':
2363 break;
2364
2365 default:
2366 valid |= -1;
2367 break;
2368 }
2369
2370 // test minutes
2371 if (minutes > 59) {
2372 valid |= -1;
2373 }
2374
2375 if (valid != 0) {
2376 snprintf(parse_script->sieveerr, ERR_BUF_SIZE,
2377 "flag '%s': not a valid timezone offset", tz);
2378 yyerror(parse_script, parse_script->sieveerr);
2379 }
2380
2381 return valid;
2382 }
2383
verify_date_part(sieve_script_t * parse_script,char * dp)2384 static int verify_date_part(sieve_script_t *parse_script, char *dp)
2385 {
2386 lcase(dp);
2387 if (!strcmp(dp, "year")) return YEAR;
2388 else if (!strcmp(dp, "month")) return MONTH;
2389 else if (!strcmp(dp, "day")) return DAY;
2390 else if (!strcmp(dp, "date")) return DATE;
2391 else if (!strcmp(dp, "julian")) return JULIAN;
2392 else if (!strcmp(dp, "hour")) return HOUR;
2393 else if (!strcmp(dp, "minute")) return MINUTE;
2394 else if (!strcmp(dp, "second")) return SECOND;
2395 else if (!strcmp(dp, "time")) return TIME;
2396 else if (!strcmp(dp, "iso8601")) return ISO8601;
2397 else if (!strcmp(dp, "std11")) return STD11;
2398 else if (!strcmp(dp, "zone")) return ZONE;
2399 else if (!strcmp(dp, "weekday")) return WEEKDAY;
2400 else {
2401 snprintf(parse_script->sieveerr, ERR_BUF_SIZE,
2402 "'%s': not a valid date-part", dp);
2403 yyerror(parse_script, parse_script->sieveerr);
2404 }
2405
2406 return -1;
2407 }
2408
2409 #ifdef ENABLE_REGEX
verify_regex(sieve_script_t * parse_script,char * s,int cflags)2410 static int verify_regex(sieve_script_t *parse_script, char *s, int cflags)
2411 {
2412 int ret;
2413 regex_t *reg = (regex_t *) xmalloc(sizeof(regex_t));
2414
2415 if ((ret = regcomp(reg, s, cflags)) != 0) {
2416 (void) regerror(ret, reg, parse_script->sieveerr, ERR_BUF_SIZE);
2417 yyerror(parse_script, parse_script->sieveerr);
2418 free(reg);
2419 return 0;
2420 }
2421 free(reg);
2422 return 1;
2423 }
2424
verify_regexs(sieve_script_t * parse_script,const strarray_t * sa,char * comp)2425 static int verify_regexs(sieve_script_t *parse_script,
2426 const strarray_t *sa, char *comp)
2427 {
2428 int i;
2429 int cflags = REG_EXTENDED | REG_NOSUB;
2430
2431 #ifdef HAVE_PCREPOSIX_H
2432 /* support UTF8 comparisons */
2433 cflags |= REG_UTF8;
2434 #endif
2435
2436 if (!strcmp(comp, "i;ascii-casemap")) {
2437 cflags |= REG_ICASE;
2438 }
2439
2440 for (i = 0 ; i < sa->count ; i++) {
2441 if ((verify_regex(parse_script, sa->data[i], cflags)) == 0)
2442 return 0;
2443 }
2444 return 1;
2445 }
2446 #else
2447
verify_regexs(sieve_script_t * parse_script,const strarray_t * sa,char * comp)2448 static int verify_regexs(sieve_script_t *parse_script __attribute__((unused)),
2449 const strarray_t *sa __attribute__((unused)),
2450 char *comp __attribute__((unused)))
2451 {
2452 return 0;
2453 }
2454 #endif /* ENABLE_REGEX */
2455
verify_patternlist(sieve_script_t * parse_script,strarray_t * sa,struct comptags * c,int (* verify)(sieve_script_t *,char *))2456 static int verify_patternlist(sieve_script_t *parse_script,
2457 strarray_t *sa, struct comptags *c,
2458 int (*verify)(sieve_script_t*, char *))
2459 {
2460 if (verify && !verify_stringlist(parse_script, sa, verify)) return 0;
2461
2462 return (c->match == REGEX) ?
2463 verify_regexs(parse_script, sa, c->comparator) : 1;
2464 }
2465
2466 /*
2467 * Valid UTF-8 check (from RFC 2640 Annex B.1)
2468 *
2469 * The following routine checks if a byte sequence is valid UTF-8. This
2470 * is done by checking for the proper tagging of the first and following
2471 * bytes to make sure they conform to the UTF-8 format. It then checks
2472 * to assure that the data part of the UTF-8 sequence conforms to the
2473 * proper range allowed by the encoding. Note: This routine will not
2474 * detect characters that have not been assigned and therefore do not
2475 * exist.
2476 */
verify_utf8(sieve_script_t * parse_script,char * s)2477 static int verify_utf8(sieve_script_t *parse_script, char *s)
2478 {
2479 const char *buf = s;
2480 const char *endbuf = s + strlen(s);
2481 unsigned char byte2mask = 0x00, c;
2482 int trailing = 0; /* trailing (continuation) bytes to follow */
2483
2484 while (buf != endbuf) {
2485 c = *buf++;
2486 if (trailing) {
2487 if ((c & 0xC0) == 0x80) { /* Does trailing byte
2488 follow UTF-8 format? */
2489 if (byte2mask) { /* Need to check 2nd byte
2490 for proper range? */
2491 if (c & byte2mask) /* Are appropriate bits set? */
2492 byte2mask = 0x00;
2493 else
2494 break;
2495 }
2496 trailing--;
2497 }
2498 else
2499 break;
2500 }
2501 else {
2502 if ((c & 0x80) == 0x00) /* valid 1 byte UTF-8 */
2503 continue;
2504 else if ((c & 0xE0) == 0xC0) /* valid 2 byte UTF-8 */
2505 if (c & 0x1E) { /* Is UTF-8 byte
2506 in proper range? */
2507 trailing = 1;
2508 }
2509 else
2510 break;
2511 else if ((c & 0xF0) == 0xE0) { /* valid 3 byte UTF-8 */
2512 if (!(c & 0x0F)) { /* Is UTF-8 byte
2513 in proper range? */
2514 byte2mask = 0x20; /* If not, set mask
2515 to check next byte */
2516 }
2517 trailing = 2;
2518 }
2519 else if ((c & 0xF8) == 0xF0) { /* valid 4 byte UTF-8 */
2520 if (!(c & 0x07)) { /* Is UTF-8 byte
2521 in proper range? */
2522 byte2mask = 0x30; /* If not, set mask
2523 to check next byte */
2524 }
2525 trailing = 3;
2526 }
2527 else if ((c & 0xFC) == 0xF8) { /* valid 5 byte UTF-8 */
2528 if (!(c & 0x03)) { /* Is UTF-8 byte
2529 in proper range? */
2530 byte2mask = 0x38; /* If not, set mask
2531 to check next byte */
2532 }
2533 trailing = 4;
2534 }
2535 else if ((c & 0xFE) == 0xFC) { /* valid 6 byte UTF-8 */
2536 if (!(c & 0x01)) { /* Is UTF-8 byte
2537 in proper range? */
2538 byte2mask = 0x3C; /* If not, set mask
2539 to check next byte */
2540 }
2541 trailing = 5;
2542 }
2543 else
2544 break;
2545 }
2546 }
2547
2548 if ((buf != endbuf) || trailing) {
2549 snprintf(parse_script->sieveerr, ERR_BUF_SIZE,
2550 "string '%s': not valid utf8", s);
2551 yyerror(parse_script, parse_script->sieveerr);
2552 return 0;
2553 }
2554
2555 return 1;
2556 }
2557