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 #define EXT_LEN 4096
61 
62 /* build a sieve interpreter */
sieve_interp_alloc(void * interp_context)63 EXPORTED sieve_interp_t *sieve_interp_alloc(void *interp_context)
64 {
65     sieve_interp_t *i;
66     static int initonce;
67 
68     if (!initonce) {
69         initialize_siev_error_table();
70         initonce = 1;
71     }
72 
73     i = (sieve_interp_t *) xmalloc(sizeof(sieve_interp_t));
74 
75     i->redirect = i->discard = i->reject = i->fileinto = i->keep = NULL;
76     i->getsize = NULL;
77     i->getheader = NULL;
78     i->getenvelope = NULL;
79     i->getbody = NULL;
80     i->getinclude = NULL;
81     i->vacation = NULL;
82     i->notify = NULL;
83 
84     i->markflags = NULL;
85 
86     i->interp_context = interp_context;
87     i->err = NULL;
88     i->lastitem = NULL;
89     i->extensions[0] = '\0';
90 
91     i->time = time(NULL);
92 
93     return i;
94 }
95 
sieve_listextensions(sieve_interp_t * i)96 EXPORTED const char *sieve_listextensions(sieve_interp_t *i)
97 {
98     if (i->extensions[0] == '\0') {
99         unsigned long config_sieve_extensions =
100             config_getbitfield(IMAPOPT_SIEVE_EXTENSIONS);
101 
102         /* add comparators */
103         strlcat(i->extensions, "comparator-i;ascii-numeric", EXT_LEN);
104 
105         /* add actions */
106         if (i->fileinto &&
107             (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_FILEINTO))
108             strlcat(i->extensions, " fileinto", EXT_LEN);
109         if (i->reject &&
110             (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_REJECT))
111             strlcat(i->extensions, " reject", EXT_LEN);
112         if (i->vacation &&
113             (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_VACATION_SECONDS))
114             strlcat(i->extensions, " vacation vacation-seconds", EXT_LEN);
115         else if (i->vacation &&
116             (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_VACATION))
117             strlcat(i->extensions, " vacation", EXT_LEN);
118         if (i->markflags &&
119             (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_IMAPFLAGS))
120             strlcat(i->extensions, " imapflags", EXT_LEN);
121         if (i->notify &&
122             (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_NOTIFY))
123             strlcat(i->extensions, " notify", EXT_LEN);
124         if (i->getinclude &&
125             (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_INCLUDE))
126             strlcat(i->extensions, " include", EXT_LEN);
127 
128         /* add tests */
129         if (i->getenvelope &&
130             (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_ENVELOPE))
131             strlcat(i->extensions, " envelope", EXT_LEN);
132         if (i->getbody &&
133             (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_BODY))
134             strlcat(i->extensions, " body", EXT_LEN);
135         if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_IMAP4FLAGS)
136             strlcat(i->extensions, " imap4flags", EXT_LEN);
137         if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_DATE)
138             strlcat(i->extensions, " date", EXT_LEN);
139         if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_MAILBOX)
140             strlcat(i->extensions, " mailbox", EXT_LEN);
141         if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_MBOXMETADATA)
142             strlcat(i->extensions, " mboxmetadata", EXT_LEN);
143         if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_SERVERMETADATA)
144             strlcat(i->extensions, " servermetadata", EXT_LEN);
145 
146         /* add match-types */
147         if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_RELATIONAL)
148             strlcat(i->extensions, " relational", EXT_LEN);
149 #ifdef ENABLE_REGEX
150         if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_REGEX)
151             strlcat(i->extensions, " regex", EXT_LEN);
152 #endif
153 
154         /* add misc extensions */
155         if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_SUBADDRESS)
156             strlcat(i->extensions, " subaddress", EXT_LEN);
157         if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_COPY)
158             strlcat(i->extensions, " copy", EXT_LEN);
159         if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_INDEX)
160             strlcat(i->extensions, " index", EXT_LEN);
161         if (config_sieve_extensions & IMAP_ENUM_SIEVE_EXTENSIONS_VARIABLES)
162             strlcat(i->extensions, " variables", EXT_LEN);
163     }
164 
165     return i->extensions;
166 }
167 
sieve_interp_free(sieve_interp_t ** interp)168 EXPORTED int sieve_interp_free(sieve_interp_t **interp)
169 {
170     if (*interp) {
171         free((*interp)->lastitem);
172         free(*interp);
173         *interp = NULL;
174     }
175 
176     return SIEVE_OK;
177 }
178 
179 /* add the callbacks */
sieve_register_redirect(sieve_interp_t * interp,sieve_callback * f)180 EXPORTED void sieve_register_redirect(sieve_interp_t *interp, sieve_callback *f)
181 {
182     interp->redirect = f;
183 }
184 
sieve_register_discard(sieve_interp_t * interp,sieve_callback * f)185 EXPORTED void sieve_register_discard(sieve_interp_t *interp, sieve_callback *f)
186 {
187     interp->discard = f;
188 }
189 
sieve_register_reject(sieve_interp_t * interp,sieve_callback * f)190 EXPORTED void sieve_register_reject(sieve_interp_t *interp, sieve_callback *f)
191 {
192     interp->reject = f;
193 }
194 
sieve_register_fileinto(sieve_interp_t * interp,sieve_callback * f)195 EXPORTED void sieve_register_fileinto(sieve_interp_t *interp, sieve_callback *f)
196 {
197     interp->fileinto = f;
198 }
199 
sieve_register_keep(sieve_interp_t * interp,sieve_callback * f)200 EXPORTED void sieve_register_keep(sieve_interp_t *interp, sieve_callback *f)
201 {
202     interp->keep = f;
203 }
204 
sieve_register_imapflags(sieve_interp_t * interp,const strarray_t * mark)205 EXPORTED void sieve_register_imapflags(sieve_interp_t *interp, const strarray_t *mark)
206 {
207     static strarray_t default_mark = STRARRAY_INITIALIZER;
208 
209     if (!default_mark.count)
210         strarray_append(&default_mark, "\\flagged");
211 
212     interp->markflags =
213         (mark && mark->data && mark->count) ? mark : &default_mark;
214 }
215 
sieve_register_notify(sieve_interp_t * interp,sieve_callback * f)216 EXPORTED void sieve_register_notify(sieve_interp_t *interp, sieve_callback *f)
217 {
218     interp->notify = f;
219 }
220 
221 /* add the callbacks for messages. again, undefined if used after
222    sieve_script_parse */
sieve_register_size(sieve_interp_t * interp,sieve_get_size * f)223 EXPORTED void sieve_register_size(sieve_interp_t *interp, sieve_get_size *f)
224 {
225     interp->getsize = f;
226 }
227 
sieve_register_mailboxexists(sieve_interp_t * interp,sieve_get_mailboxexists * f)228 EXPORTED void sieve_register_mailboxexists(sieve_interp_t *interp, sieve_get_mailboxexists *f)
229 {
230     interp->getmailboxexists = f;
231 }
232 
sieve_register_metadata(sieve_interp_t * interp,sieve_get_metadata * f)233 EXPORTED void sieve_register_metadata(sieve_interp_t *interp, sieve_get_metadata *f)
234 {
235     interp->getmetadata = f;
236 }
237 
sieve_register_header(sieve_interp_t * interp,sieve_get_header * f)238 EXPORTED void sieve_register_header(sieve_interp_t *interp, sieve_get_header *f)
239 {
240     interp->getheader = f;
241 }
242 
sieve_register_fname(sieve_interp_t * interp,sieve_get_fname * f)243 EXPORTED void sieve_register_fname(sieve_interp_t *interp, sieve_get_fname *f)
244 {
245     interp->getfname = f;
246 }
247 
sieve_register_envelope(sieve_interp_t * interp,sieve_get_envelope * f)248 EXPORTED void sieve_register_envelope(sieve_interp_t *interp, sieve_get_envelope *f)
249 {
250     interp->getenvelope = f;
251 }
252 
sieve_register_include(sieve_interp_t * interp,sieve_get_include * f)253 EXPORTED void sieve_register_include(sieve_interp_t *interp, sieve_get_include *f)
254 {
255     interp->getinclude = f;
256 }
257 
sieve_register_body(sieve_interp_t * interp,sieve_get_body * f)258 EXPORTED void sieve_register_body(sieve_interp_t *interp, sieve_get_body *f)
259 {
260     interp->getbody = f;
261 }
262 
sieve_register_vacation(sieve_interp_t * interp,sieve_vacation_t * v)263 EXPORTED int sieve_register_vacation(sieve_interp_t *interp, sieve_vacation_t *v)
264 {
265     if (!interp->getenvelope) {
266         return SIEVE_NOT_FINALIZED; /* we need envelope for vacation! */
267     }
268 
269     if (v->min_response == 0)
270         v->min_response = config_getint(IMAPOPT_SIEVE_VACATION_MIN_RESPONSE);
271     if (v->max_response == 0)
272         v->max_response = config_getint(IMAPOPT_SIEVE_VACATION_MAX_RESPONSE);
273     if (v->min_response < 0 || v->max_response < 7 * DAY2SEC || !v->autorespond
274         || !v->send_response) {
275         return SIEVE_FAIL;
276     }
277 
278     interp->vacation = v;
279     return SIEVE_OK;
280 }
281 
sieve_register_parse_error(sieve_interp_t * interp,sieve_parse_error * f)282 EXPORTED void sieve_register_parse_error(sieve_interp_t *interp, sieve_parse_error *f)
283 {
284     interp->err = f;
285 }
286 
sieve_register_execute_error(sieve_interp_t * interp,sieve_execute_error * f)287 EXPORTED void sieve_register_execute_error(sieve_interp_t *interp, sieve_execute_error *f)
288 {
289     interp->execute_err = f;
290 }
291 
interp_verify(sieve_interp_t * i)292 int interp_verify(sieve_interp_t *i)
293 {
294     if (i->redirect && i->keep && i->getsize && i->getheader) {
295         return SIEVE_OK;
296     } else {
297         return SIEVE_NOT_FINALIZED;
298     }
299 }
300