1 /* interp.c -- sieve script interpreter builder
2 * Larry Greenfield
3 *
4 * Copyright (c) 1994-2008 Carnegie Mellon University. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 *
18 * 3. The name "Carnegie Mellon University" must not be used to
19 * endorse or promote products derived from this software without
20 * prior written permission. For permission or any legal
21 * details, please contact
22 * Carnegie Mellon University
23 * Center for Technology Transfer and Enterprise Creation
24 * 4615 Forbes Avenue
25 * Suite 302
26 * Pittsburgh, PA 15213
27 * (412) 268-7393, fax: (412) 268-7395
28 * innovation@andrew.cmu.edu
29 *
30 * 4. Redistributions of any form whatsoever must retain the following
31 * acknowledgment:
32 * "This product includes software developed by Computing Services
33 * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
34 *
35 * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
36 * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
37 * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
38 * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
39 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
40 * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
41 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
42 */
43
44 #ifdef HAVE_CONFIG_H
45 #include <config.h>
46 #endif
47
48 #include <stdlib.h>
49 #include <string.h>
50
51 #include "xmalloc.h"
52 #include "xstrlcat.h"
53
54 #include "sieve_interface.h"
55 #include "interp.h"
56 #include "libconfig.h"
57 #include "times.h"
58 #include "util.h"
59
60 /* build a sieve interpreter */
sieve_interp_alloc(void * interp_context)61 EXPORTED sieve_interp_t *sieve_interp_alloc(void *interp_context)
62 {
63 sieve_interp_t *i;
64 static int initonce;
65
66 if (!initonce) {
67 initialize_siev_error_table();
68 initonce = 1;
69 }
70
71 i = (sieve_interp_t *) xzmalloc(sizeof(sieve_interp_t));
72
73 i->interp_context = interp_context;
74 i->extensions = NULL;
75
76 i->time = time(NULL);
77
78 return i;
79 }
80
sieve_listextensions(sieve_interp_t * i)81 EXPORTED const strarray_t *sieve_listextensions(sieve_interp_t *i)
82 {
83 if (i->extensions == NULL) {
84 unsigned long config_sieve_extensions =
85 config_getbitfield(IMAPOPT_SIEVE_EXTENSIONS);
86 struct buf buf = BUF_INITIALIZER;
87 int ext_pos;
88
89 /* strarray of ManageSieve capability/value pairs */
90 i->extensions = strarray_new();
91
92 /* Add SIEVE capability */
93 strarray_append(i->extensions, "SIEVE");
94
95 /* Add placeholder for Sieve extensions string */
96 ext_pos = strarray_append(i->extensions, NULL);
97
98 /* Build Sieve extensions string */
99 buf_setcstr(&buf, "encoded-character");
100
101 /* add comparators */
102 buf_appendcstr(&buf, " comparator-i;ascii-numeric");
103
104 /* add actions */
105 if (i->fileinto &&
106 (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_FILEINTO))
107 buf_appendcstr(&buf, " fileinto");
108 if (i->reject &&
109 (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_REJECT))
110 buf_appendcstr(&buf, " reject ereject");
111 if (i->vacation &&
112 (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_VACATION_SECONDS))
113 buf_appendcstr(&buf, " vacation vacation-seconds");
114 else if (i->vacation &&
115 (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_VACATION))
116 buf_appendcstr(&buf, " vacation");
117 if (i->notify &&
118 (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_NOTIFY)) {
119 buf_appendcstr(&buf, " notify enotify");
120
121 /* Add NOTIFY capability */
122 strarray_append(i->extensions, "NOTIFY");
123 strarray_append(i->extensions, "mailto");
124 }
125 if (i->getinclude &&
126 (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_INCLUDE))
127 buf_appendcstr(&buf, " include");
128 if (i->addheader &&
129 (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_EDITHEADER))
130 buf_appendcstr(&buf, " editheader");
131 #if 0 /* Don't advertise this to ManageSieve clients -
132 We probably don't want end users adding this action themselves */
133 if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_VND_CYRUS_LOG)
134 buf_appendcstr(&buf, " vnd.cyrus.log");
135 #endif
136 if (i->snooze &&
137 (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_SNOOZE))
138 buf_appendcstr(&buf, " vnd.cyrus.snooze");
139
140 /* add tests */
141 if (i->getenvelope &&
142 (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_ENVELOPE))
143 buf_appendcstr(&buf, " envelope");
144 if (i->getenvironment &&
145 (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_ENVIRONMENT))
146 buf_appendcstr(&buf, " environment");
147 if (i->getbody &&
148 (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_BODY))
149 buf_appendcstr(&buf, " body");
150 if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_IMAP4FLAGS)
151 buf_appendcstr(&buf, " imap4flags");
152 if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_DATE)
153 buf_appendcstr(&buf, " date");
154 if ((config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_IHAVE))
155 buf_appendcstr(&buf, " ihave");
156 if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_MAILBOX)
157 buf_appendcstr(&buf, " mailbox");
158 if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_MBOXMETADATA)
159 buf_appendcstr(&buf, " mboxmetadata");
160 if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_SERVERMETADATA)
161 buf_appendcstr(&buf, " servermetadata");
162 if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_DUPLICATE)
163 buf_appendcstr(&buf, " duplicate");
164 if (i->jmapquery &&
165 (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_VND_CYRUS_JMAPQUERY))
166 buf_appendcstr(&buf, " vnd.cyrus.jmapquery");
167
168 /* add match-types */
169 if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_RELATIONAL)
170 buf_appendcstr(&buf, " relational");
171 #ifdef ENABLE_REGEX
172 if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_REGEX)
173 buf_appendcstr(&buf, " regex");
174 #endif
175 if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_EXTLISTS) {
176 buf_appendcstr(&buf, " extlists");
177
178 /* Add EXTLISTS capability */
179 strarray_append(i->extensions, "EXTLISTS");
180 strarray_append(i->extensions, "urn:ietf:params:sieve:addrbook");
181 }
182
183 /* add misc extensions */
184 if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_SUBADDRESS)
185 buf_appendcstr(&buf, " subaddress");
186 if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_COPY)
187 buf_appendcstr(&buf, " copy");
188 if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_INDEX)
189 buf_appendcstr(&buf, " index");
190 if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_VARIABLES)
191 buf_appendcstr(&buf, " variables");
192 if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_REDIRECT_DELIVERBY)
193 buf_appendcstr(&buf, " redirect-deliverby");
194 if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_REDIRECT_DSN)
195 buf_appendcstr(&buf, " redirect-dsn");
196 if (i->getspecialuseexists &&
197 (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_SPECIAL_USE))
198 buf_appendcstr(&buf, " special-use");
199 if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_FCC)
200 buf_appendcstr(&buf, " fcc");
201 if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_MAILBOXID)
202 buf_appendcstr(&buf, " mailboxid");
203
204 /* Set Sieve extensions string */
205 strarray_setm(i->extensions, ext_pos, buf_release(&buf));
206 }
207
208 return i->extensions;
209 }
210
sieve_interp_free(sieve_interp_t ** interp)211 EXPORTED int sieve_interp_free(sieve_interp_t **interp)
212 {
213 if (*interp) {
214 free((*interp)->lastitem);
215 strarray_free((*interp)->extensions);
216 free(*interp);
217 *interp = NULL;
218 }
219
220 return SIEVE_OK;
221 }
222
223 /* add the callbacks */
sieve_register_redirect(sieve_interp_t * interp,sieve_callback * f)224 EXPORTED void sieve_register_redirect(sieve_interp_t *interp, sieve_callback *f)
225 {
226 interp->redirect = f;
227 }
228
sieve_register_discard(sieve_interp_t * interp,sieve_callback * f)229 EXPORTED void sieve_register_discard(sieve_interp_t *interp, sieve_callback *f)
230 {
231 interp->discard = f;
232 }
233
sieve_register_reject(sieve_interp_t * interp,sieve_callback * f)234 EXPORTED void sieve_register_reject(sieve_interp_t *interp, sieve_callback *f)
235 {
236 interp->reject = f;
237 }
238
sieve_register_fileinto(sieve_interp_t * interp,sieve_callback * f)239 EXPORTED void sieve_register_fileinto(sieve_interp_t *interp, sieve_callback *f)
240 {
241 interp->fileinto = f;
242 }
243
sieve_register_snooze(sieve_interp_t * interp,sieve_callback * f)244 EXPORTED void sieve_register_snooze(sieve_interp_t *interp, sieve_callback *f)
245 {
246 interp->snooze = f;
247 }
248
sieve_register_keep(sieve_interp_t * interp,sieve_callback * f)249 EXPORTED void sieve_register_keep(sieve_interp_t *interp, sieve_callback *f)
250 {
251 interp->keep = f;
252 }
253
sieve_register_notify(sieve_interp_t * interp,sieve_callback * f,const strarray_t * methods)254 EXPORTED void sieve_register_notify(sieve_interp_t *interp,
255 sieve_callback *f, const strarray_t *methods)
256 {
257 static strarray_t default_methods = STRARRAY_INITIALIZER;
258
259 if (!default_methods.count)
260 strarray_append(&default_methods, "mailto:");
261
262 interp->notifymethods =
263 (methods && methods->data && methods->count) ? methods : &default_methods;
264
265 interp->notify = f;
266 }
267
268 /* add the callbacks for messages. again, undefined if used after
269 sieve_script_parse */
sieve_register_size(sieve_interp_t * interp,sieve_get_size * f)270 EXPORTED void sieve_register_size(sieve_interp_t *interp, sieve_get_size *f)
271 {
272 interp->getsize = f;
273 }
274
sieve_register_mailboxexists(sieve_interp_t * interp,sieve_get_mailboxexists * f)275 EXPORTED void sieve_register_mailboxexists(sieve_interp_t *interp, sieve_get_mailboxexists *f)
276 {
277 interp->getmailboxexists = f;
278 }
279
sieve_register_mailboxidexists(sieve_interp_t * interp,sieve_get_mailboxidexists * f)280 EXPORTED void sieve_register_mailboxidexists(sieve_interp_t *interp, sieve_get_mailboxidexists *f)
281 {
282 interp->getmailboxidexists = f;
283 }
284
sieve_register_metadata(sieve_interp_t * interp,sieve_get_metadata * f)285 EXPORTED void sieve_register_metadata(sieve_interp_t *interp, sieve_get_metadata *f)
286 {
287 interp->getmetadata = f;
288 }
289
sieve_register_specialuseexists(sieve_interp_t * interp,sieve_get_specialuseexists * f)290 EXPORTED void sieve_register_specialuseexists(sieve_interp_t *interp, sieve_get_specialuseexists *f)
291 {
292 interp->getspecialuseexists = f;
293 }
294
sieve_register_header(sieve_interp_t * interp,sieve_get_header * f)295 EXPORTED void sieve_register_header(sieve_interp_t *interp, sieve_get_header *f)
296 {
297 interp->getheader = f;
298 }
299
sieve_register_headersection(sieve_interp_t * interp,sieve_get_headersection * f)300 EXPORTED void sieve_register_headersection(sieve_interp_t *interp,
301 sieve_get_headersection *f)
302 {
303 interp->getheadersection = f;
304 }
305
sieve_register_addheader(sieve_interp_t * interp,sieve_add_header * f)306 EXPORTED int sieve_register_addheader(sieve_interp_t *interp, sieve_add_header *f)
307 {
308 if (!interp->getheadersection) {
309 return SIEVE_NOT_FINALIZED; /* we need getheadersection for editheader! */
310 }
311
312 interp->addheader = f;
313 return SIEVE_OK;
314 }
315
sieve_register_deleteheader(sieve_interp_t * interp,sieve_delete_header * f)316 EXPORTED int sieve_register_deleteheader(sieve_interp_t *interp, sieve_delete_header *f)
317 {
318 if (!interp->getheadersection) {
319 return SIEVE_NOT_FINALIZED; /* we need getheadersection for editheader! */
320 }
321
322 interp->deleteheader = f;
323 return SIEVE_OK;
324 }
325
sieve_register_fname(sieve_interp_t * interp,sieve_get_fname * f)326 EXPORTED void sieve_register_fname(sieve_interp_t *interp, sieve_get_fname *f)
327 {
328 interp->getfname = f;
329 }
330
sieve_register_envelope(sieve_interp_t * interp,sieve_get_envelope * f)331 EXPORTED void sieve_register_envelope(sieve_interp_t *interp, sieve_get_envelope *f)
332 {
333 interp->getenvelope = f;
334 }
335
sieve_register_include(sieve_interp_t * interp,sieve_get_include * f)336 EXPORTED void sieve_register_include(sieve_interp_t *interp, sieve_get_include *f)
337 {
338 interp->getinclude = f;
339 }
340
sieve_register_logger(sieve_interp_t * interp,sieve_logger * f)341 EXPORTED void sieve_register_logger(sieve_interp_t *interp, sieve_logger *f)
342 {
343 interp->log = f;
344 }
345
sieve_register_environment(sieve_interp_t * interp,sieve_get_environment * f)346 EXPORTED void sieve_register_environment(sieve_interp_t *interp,
347 sieve_get_environment *f)
348 {
349 interp->getenvironment = f;
350 }
351
sieve_register_body(sieve_interp_t * interp,sieve_get_body * f)352 EXPORTED void sieve_register_body(sieve_interp_t *interp, sieve_get_body *f)
353 {
354 interp->getbody = f;
355 }
356
sieve_register_vacation(sieve_interp_t * interp,sieve_vacation_t * v)357 EXPORTED int sieve_register_vacation(sieve_interp_t *interp, sieve_vacation_t *v)
358 {
359 if (!interp->getenvelope) {
360 return SIEVE_NOT_FINALIZED; /* we need envelope for vacation! */
361 }
362
363 if (v->min_response == 0)
364 v->min_response = config_getduration(IMAPOPT_SIEVE_VACATION_MIN_RESPONSE, 's');
365 if (v->max_response == 0)
366 v->max_response = config_getduration(IMAPOPT_SIEVE_VACATION_MAX_RESPONSE, 's');
367 if (v->min_response < 0 || v->max_response < 7 * DAY2SEC || !v->autorespond
368 || !v->send_response) {
369 return SIEVE_FAIL;
370 }
371
372 interp->vacation = v;
373 return SIEVE_OK;
374 }
375
sieve_register_extlists(sieve_interp_t * interp,sieve_list_validator * v,sieve_list_comparator * c)376 EXPORTED void sieve_register_extlists(sieve_interp_t *interp,
377 sieve_list_validator *v,
378 sieve_list_comparator *c)
379 {
380 interp->isvalidlist = v;
381 interp->listcompare = c;
382 }
383
sieve_register_duplicate(sieve_interp_t * interp,sieve_duplicate_t * d)384 EXPORTED int sieve_register_duplicate(sieve_interp_t *interp,
385 sieve_duplicate_t *d)
386 {
387 if (!interp->getheader) {
388 return SIEVE_NOT_FINALIZED; /* we need header for duplicate! */
389 }
390
391 if (!(d->check && d->track)) {
392 return SIEVE_FAIL;
393 }
394
395 if (d->max_expiration > 7776000) d->max_expiration = 7776000; /* 90 days */
396
397 interp->duplicate = d;
398 return SIEVE_OK;
399 }
400
sieve_register_jmapquery(sieve_interp_t * interp,sieve_jmapquery * f)401 EXPORTED void sieve_register_jmapquery(sieve_interp_t *interp, sieve_jmapquery *f)
402 {
403 interp->jmapquery = f;
404 }
405
sieve_register_parse_error(sieve_interp_t * interp,sieve_parse_error * f)406 EXPORTED void sieve_register_parse_error(sieve_interp_t *interp, sieve_parse_error *f)
407 {
408 interp->err = f;
409 }
410
sieve_register_execute_error(sieve_interp_t * interp,sieve_execute_error * f)411 EXPORTED void sieve_register_execute_error(sieve_interp_t *interp, sieve_execute_error *f)
412 {
413 interp->execute_err = f;
414 }
415
interp_verify(sieve_interp_t * i)416 int interp_verify(sieve_interp_t *i)
417 {
418 if (i->redirect && i->keep && i->getsize && i->getheader) {
419 return SIEVE_OK;
420 } else {
421 return SIEVE_NOT_FINALIZED;
422 }
423 }
424
425 /* Array of Sieve capabilities */
426 static const struct sieve_capa_t {
427 const char *str;
428 unsigned long long flag;
429 } sieve_capabilities[] =
430 {
431 /* Sieve "base" - RFC 5228 */
432 { "comparator-i;octet", SIEVE_CAPA_BASE },
433 { "comparator-i;ascii-casemap", SIEVE_CAPA_BASE },
434 { "comparator-i;ascii-numeric", SIEVE_CAPA_COMP_NUMERIC },
435
436 { "encoded-character", SIEVE_CAPA_ENCODED_CHAR },
437 { "envelope", SIEVE_CAPA_ENVELOPE },
438 { "fileinto", SIEVE_CAPA_FILEINTO },
439
440 /* Regular Expressions - draft-ietf-sieve-regex */
441 { "regex", SIEVE_CAPA_REGEX },
442
443 /* Copy - RFC 3894 */
444 { "copy", SIEVE_CAPA_COPY },
445
446 /* Body - RFC 5173 */
447 { "body", SIEVE_CAPA_BODY },
448
449 /* Environment - RFC 5183 */
450 { "environment", SIEVE_CAPA_ENVIRONMENT },
451
452 /* Variables - RFC 5229 */
453 { "variables", SIEVE_CAPA_VARIABLES },
454
455 /* Vacation - RFC 5230 */
456 { "vacation", SIEVE_CAPA_VACATION },
457
458 /* Relational - RFC 5231 */
459 { "relational", SIEVE_CAPA_RELATIONAL },
460
461 /* IMAP4 Flags - RFC 5232 */
462 { "imap4flags", SIEVE_CAPA_IMAP4FLAGS },
463 { "imapflags", SIEVE_CAPA_IMAP4FLAGS }, /* draft-melnikov-sieve-imapflags-04 */
464
465 /* Subaddress - RFC 5233 */
466 { "subaddress", SIEVE_CAPA_SUBADDRESS },
467
468 /* Spamtest & Virustest - RFC 5235 */
469 { "spamtest", SIEVE_CAPA_SPAM },
470 { "spamtestplus", SIEVE_CAPA_SPAMPLUS },
471 { "virustest", SIEVE_CAPA_VIRUS },
472
473 /* Date & Index - RFC 5260 */
474 { "date", SIEVE_CAPA_DATE },
475 { "index", SIEVE_CAPA_INDEX },
476
477 /* Editheader - RFC 5293 */
478 { "editheader", SIEVE_CAPA_EDITHEADER },
479
480 /* [Extended] Reject - RFC 5429 */
481 { "ereject", SIEVE_CAPA_EREJECT },
482 { "reject", SIEVE_CAPA_REJECT },
483
484 /* Notifications - RFC 5435 */
485 { "enotify", SIEVE_CAPA_ENOTIFY },
486 { "notify", SIEVE_CAPA_NOTIFY }, /* draft-martin-sieve-notify-01 */
487
488 /* Ihave - RFC 5463 */
489 { "ihave", SIEVE_CAPA_IHAVE },
490
491 /* Mailbox & Metadata - RFC 5490 */
492 { "mailbox", SIEVE_CAPA_MAILBOX },
493 { "mboxmetadata", SIEVE_CAPA_MBOXMETA },
494 { "servermetadata", SIEVE_CAPA_SERVERMETA },
495
496 /* MIME Part Handling - RFC 5703 */
497 { "enclose", SIEVE_CAPA_ENCLOSE },
498 { "extracttest", SIEVE_CAPA_EXTRACT },
499 { "foreverypart", SIEVE_CAPA_FOREVERYPART },
500 { "mime", SIEVE_CAPA_MIME },
501 { "replace", SIEVE_CAPA_REPLACE },
502
503 /* DSN & Deliver-By - RFC 6009 */
504 { "envelope-deliverby", SIEVE_CAPA_ENV_DELBY },
505 { "envelope-dsn", SIEVE_CAPA_ENV_DSN },
506 { "redirect-deliverby", SIEVE_CAPA_REDIR_DELBY },
507 { "redirect-dsn", SIEVE_CAPA_REDIR_DSN },
508
509 /* Vacation :seconds - RFC 6131 */
510 { "vacation-seconds", SIEVE_CAPA_VACATION_SEC },
511
512 /* External Lists - RFC 6134 */
513 { "extlists", SIEVE_CAPA_EXTLISTS },
514
515 /* Convert - RFC 6558 */
516 { "convert", SIEVE_CAPA_CONVERT },
517
518 /* Include - RFC 6609 */
519 { "include", SIEVE_CAPA_INCLUDE },
520
521 /* IMAP Events - RFC 6785 */
522 { "imapsieve", SIEVE_CAPA_IMAP },
523
524 /* Duplicate - RFC 7352 */
525 { "duplicate", SIEVE_CAPA_DUPLICATE },
526
527 /* Special-Use - RFC 8579 */
528 { "special-use", SIEVE_CAPA_SPECIAL_USE },
529
530 /* Fcc - RFC 8580 */
531 { "fcc", SIEVE_CAPA_FCC },
532
533 /* Mailboxid - draft-ietf-extra-sieve-mailboxid */
534 { "mailboxid", SIEVE_CAPA_MAILBOXID },
535
536 /* Log - vnd.cyrus.log */
537 { "vnd.cyrus.log", SIEVE_CAPA_LOG },
538 { "x-cyrus-log", SIEVE_CAPA_LOG }, // legacy capability
539
540 /* JMAP Query - vnd.cyrus.jmapquery */
541 { "vnd.cyrus.jmapquery", SIEVE_CAPA_JMAPQUERY },
542 { "x-cyrus-jmapquery", SIEVE_CAPA_JMAPQUERY }, // legacy capability
543
544 /* Snooze - draft-ietf-extra-sieve-snooze */
545 { "snooze", SIEVE_CAPA_SNOOZE },
546 { "vnd.cyrus.snooze", SIEVE_CAPA_SNOOZE }, // legacy capability
547 { "x-cyrus-snooze", SIEVE_CAPA_SNOOZE }, // legacy capability
548
549 { NULL, 0 }
550 };
551
552
lookup_capability_string(unsigned long long flag)553 EXPORTED const char *lookup_capability_string(unsigned long long flag)
554 {
555 const struct sieve_capa_t *capa;
556
557 for (capa = sieve_capabilities; capa->str; capa++) {
558 if (flag == capa->flag) return capa->str;
559 }
560
561 return NULL;
562 }
563
lookup_capability(const char * str)564 unsigned long long lookup_capability(const char *str)
565 {
566 const struct sieve_capa_t *capa;
567
568 for (capa = sieve_capabilities; capa->str; capa++) {
569 if (!strcmp(str, capa->str)) return capa->flag;
570 }
571
572 return 0;
573 }
574
extension_isactive(sieve_interp_t * interp,const char * str)575 unsigned long long extension_isactive(sieve_interp_t *interp, const char *str)
576 {
577 unsigned long config_ext = config_getbitfield(IMAPOPT_SIEVE_EXTENSIONS);
578 unsigned long long capa = lookup_capability(str);
579
580 switch (capa) {
581 case SIEVE_CAPA_BASE:
582 case SIEVE_CAPA_COMP_NUMERIC:
583 case SIEVE_CAPA_ENCODED_CHAR:
584 /* always enabled */
585 break;
586
587 case SIEVE_CAPA_ENVELOPE:
588 if (!(interp->getenvelope &&
589 (config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_ENVELOPE))) capa = 0;
590 break;
591
592 case SIEVE_CAPA_FILEINTO:
593 if (!(interp->fileinto &&
594 (config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_FILEINTO))) capa = 0;
595 break;
596
597 case SIEVE_CAPA_REGEX:
598 if (!(config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_REGEX)) capa = 0;
599 break;
600
601 case SIEVE_CAPA_COPY:
602 if (!(config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_COPY)) capa = 0;
603 break;
604
605 case SIEVE_CAPA_ENVIRONMENT:
606 if (!(interp->getenvironment &&
607 (config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_ENVIRONMENT))) capa = 0;
608 break;
609
610 case SIEVE_CAPA_BODY:
611 if (!(interp->getbody &&
612 (config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_BODY))) capa = 0;
613 break;
614
615 case SIEVE_CAPA_VARIABLES:
616 if (!(config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_VARIABLES)) capa = 0;
617 break;
618
619 case SIEVE_CAPA_VACATION:
620 if (!(interp->vacation &&
621 (config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_VACATION))) capa = 0;
622 break;
623
624 case SIEVE_CAPA_RELATIONAL:
625 if (!(config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_RELATIONAL)) capa = 0;
626 break;
627
628 case SIEVE_CAPA_IMAP4FLAGS:
629 if (!(config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_IMAP4FLAGS)) capa = 0;
630 break;
631
632 case SIEVE_CAPA_SUBADDRESS:
633 if (!(config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_SUBADDRESS)) capa = 0;
634 break;
635
636 case SIEVE_CAPA_DATE:
637 if (!(config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_DATE)) capa = 0;
638 break;
639
640 case SIEVE_CAPA_INDEX:
641 if (!(config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_INDEX)) capa = 0;
642 break;
643
644 case SIEVE_CAPA_EDITHEADER:
645 if (!(interp->addheader && interp->deleteheader &&
646 (config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_EDITHEADER))) capa = 0;
647 break;
648
649 case SIEVE_CAPA_EREJECT:
650 case SIEVE_CAPA_REJECT:
651 if (!(interp->reject &&
652 (config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_REJECT))) capa = 0;
653 break;
654
655 case SIEVE_CAPA_ENOTIFY:
656 case SIEVE_CAPA_NOTIFY:
657 if (!(interp->notify &&
658 (config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_NOTIFY))) capa = 0;
659 break;
660
661 case SIEVE_CAPA_IHAVE:
662 if (!(config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_IHAVE)) capa = 0;
663 break;
664
665 case SIEVE_CAPA_MAILBOX:
666 if (!(interp->getmailboxexists &&
667 (config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_MAILBOX))) capa = 0;
668 break;
669
670 case SIEVE_CAPA_MBOXMETA:
671 if (!(interp->getmetadata &&
672 (config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_MBOXMETADATA))) capa = 0;
673 break;
674
675 case SIEVE_CAPA_SERVERMETA:
676 if (!(interp->getmetadata &&
677 (config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_SERVERMETADATA))) capa = 0;
678 break;
679
680 case SIEVE_CAPA_VACATION_SEC:
681 if (!(interp->vacation &&
682 (config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_VACATION_SECONDS))) {
683 capa = 0;
684 } else {
685 /* Note that "vacation-seconds" implies "vacation", and a script
686 * with "vacation-seconds" in a "require" list MAY omit "vacation"
687 * from that list. */
688 capa |= SIEVE_CAPA_VACATION;
689 }
690 break;
691
692 case SIEVE_CAPA_EXTLISTS:
693 if (!(interp->isvalidlist && interp->listcompare &&
694 (config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_EXTLISTS) &&
695 (config_getbitfield(IMAPOPT_HTTPMODULES) & IMAP_ENUM_HTTPMODULES_CARDDAV)))
696 capa = 0;
697 break;
698
699 case SIEVE_CAPA_INCLUDE:
700 if (!(interp->getinclude &&
701 (config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_INCLUDE))) capa = 0;
702 break;
703
704 case SIEVE_CAPA_DUPLICATE:
705 if (!(interp->duplicate &&
706 (config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_DUPLICATE))) capa = 0;
707 break;
708
709 case SIEVE_CAPA_SPECIAL_USE:
710 if (!(interp->getspecialuseexists &&
711 (config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_SPECIAL_USE))) capa = 0;
712 break;
713
714 case SIEVE_CAPA_FCC:
715 if (!(config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_FCC)) capa = 0;
716 break;
717
718 case SIEVE_CAPA_REDIR_DELBY:
719 if (!(config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_REDIRECT_DELIVERBY))
720 capa = 0;
721 break;
722
723 case SIEVE_CAPA_REDIR_DSN:
724 if (!(config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_REDIRECT_DSN)) capa = 0;
725 break;
726
727 case SIEVE_CAPA_MAILBOXID:
728 if (!(interp->getmailboxidexists &&
729 (config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_MAILBOXID))) capa = 0;
730 break;
731
732 case SIEVE_CAPA_LOG:
733 if (!(interp->log &&
734 (config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_VND_CYRUS_LOG))) capa = 0;
735 break;
736
737 case SIEVE_CAPA_JMAPQUERY:
738 if (!(interp->jmapquery &&
739 (config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_VND_CYRUS_JMAPQUERY)))
740 capa = 0;
741 break;
742
743 case SIEVE_CAPA_SNOOZE:
744 if (!(interp->snooze &&
745 (config_ext & IMAP_ENUM_SIEVE_EXTENSIONS_SNOOZE))) capa = 0;
746 break;
747
748 default:
749 /* not supported */
750 capa = 0;
751 break;
752 }
753
754 return (capa);
755 }
756