Commit ba8d29e0 ba8d29e0c4a7fee3793bac838cd7755e323286a7 by Sam Roberts

Split the implementation of the mailutils-based sieve engine out of sieve.c,

which now contains only a utility that uses the engine to sieve mailboxes.
1 parent 47b0bd62
...@@ -32,7 +32,10 @@ SRC = \ ...@@ -32,7 +32,10 @@ SRC = \
32 sieve-lex.c \ 32 sieve-lex.c \
33 sieve-gram.c \ 33 sieve-gram.c \
34 sieve_err.c \ 34 sieve_err.c \
35 svcb.c \
36 svctx.c \
35 svfield.c \ 37 svfield.c \
38 svutil.c \
36 tree.c \ 39 tree.c \
37 util.c 40 util.c
38 41
...@@ -46,6 +49,7 @@ HDR = \ ...@@ -46,6 +49,7 @@ HDR = \
46 sieve_err.h \ 49 sieve_err.h \
47 sieve_interface.h \ 50 sieve_interface.h \
48 svfield.h \ 51 svfield.h \
52 sv.h \
49 tree.h \ 53 tree.h \
50 util.h 54 util.h
51 55
......
1 #ifndef SV_H
2 #define SV_H
3
4 #include <mailutils/mailbox.h>
5 #include <mailutils/address.h>
6 #include <mailutils/registrar.h>
7
8 #include "sieve_interface.h"
9
10 #include "svfield.h"
11
12 /** sieve context structures
13
14 The object relationship diagram is this, with the names in ""
15 being the argument name when the context's are provided as
16 arguments to callback functions.
17
18 sieve_execute_script() --> sv_msg_ctx_t, "mc"
19
20 |
21 |
22 V
23
24 sieve_script_t ---> sv_script_ctx_t, "sc"
25
26 |
27 |
28 V
29
30 sieve_interp_t ---> sv_interp_ctx_t, "ic"
31
32
33 */
34
35 typedef struct sv_interp_ctx_t
36 {
37 /* options */
38 int opt_no_actions;
39 int opt_verbose;
40 int opt_no_run;
41 int opt_watch;
42 char* opt_mbox;
43 char* opt_tickets;
44 char* opt_script;
45
46 int print_mask;
47 FILE* print_stream;
48
49 /* Ticket for use by mailbox URLs for implicit authentication. */
50 ticket_t ticket;
51
52 /* mailutils debug handle, we need to destroy it */
53 mu_debug_t debug;
54 } sv_interp_ctx_t;
55
56 typedef struct sv_script_ctx_t
57 {
58 sv_interp_ctx_t* ic;
59 } sv_script_ctx_t;
60
61 typedef struct sv_msg_ctx_t
62 {
63 int rc; /* the mailutils return code */
64 int cache_filled;
65 sv_field_cache_t cache;
66 message_t msg;
67 mailbox_t mbox;
68 char *summary;
69
70 sv_interp_ctx_t* ic;
71 } sv_msg_ctx_t;
72
73 enum /* print level masks */
74 {
75 SV_PRN_MU = 0x01,
76 SV_PRN_ACT = 0x02,
77 SV_PRN_QRY = 0x04,
78 SV_PRN_ERR = 0x08,
79 SV_PRN_NOOP
80 };
81
82 /*
83 svcb.c: sieve callbacks
84 */
85
86 int sv_register_callbacks (sieve_interp_t * i);
87
88 /*
89 sv?.c: sv print wrappers
90
91 These should call print callbacks supplied by the user of the mailutils
92 sieve implementation.
93 */
94
95 extern void sv_printv (sv_interp_ctx_t* ic, int level, const char *fmt, va_list ap);
96 extern void sv_print (sv_interp_ctx_t* ic, int level, const char* fmt, ...);
97
98 /*
99 svutil.c: utility functions and mailutil wrapper functions
100 */
101
102 /* Converts a mailutils errno to the equivalent sieve return code. */
103
104 extern int sv_mu_errno_to_rc (int eno);
105
106 extern int sv_mu_debug_print (mu_debug_t d, const char *fmt, va_list ap);
107
108 extern int sv_mu_mark_deleted (message_t msg);
109
110 extern int sv_mu_copy_debug_level (const mailbox_t from, mailbox_t to);
111
112 extern int sv_mu_save_to (const char *toname, message_t mesg, ticket_t ticket, const char **errmsg);
113
114 #endif
115
1 /* sieve callback implementations */
2
3 #include <assert.h>
4 #include <stdlib.h>
5 #include <string.h>
6
7 #include "sv.h"
8
9 /** message query callbacks **/
10
11 int
12 sv_getsize (void *mc, int *size)
13 {
14 sv_msg_ctx_t *m = (sv_msg_ctx_t *) mc;
15 size_t sz = 0;
16
17 message_size (m->msg, &sz);
18
19 *size = sz;
20
21 sv_print (m->ic, SV_PRN_QRY, "getsize -> %d\n", *size);
22
23 return SIEVE_OK;
24 }
25
26 /*
27 A given header can occur multiple times, so we return a pointer
28 to a null terminated array of pointers to the values found for
29 the named header.
30 */
31 int
32 sv_getheader (void *mc, const char *name, const char ***body)
33 {
34 sv_msg_ctx_t *m = (sv_msg_ctx_t *) mc;
35
36 m->rc = 0;
37
38 if (!m->cache_filled)
39 {
40 header_t h = 0;
41 size_t i = 0;
42 char *fn = 0;
43 char *fv = 0;
44
45 m->cache_filled = 1;
46
47 message_get_header (m->msg, &h);
48
49 header_get_field_count (h, &i);
50
51 sv_print (m->ic, SV_PRN_QRY, "getheader, filling cache with %d fields\n", i);
52
53 for (; i > 0; i--)
54 {
55 m->rc = header_aget_field_name (h, i, &fn);
56 if (m->rc)
57 break;
58 m->rc = header_aget_field_value (h, i, &fv);
59 if (m->rc)
60 break;
61
62 sv_print (m->ic, SV_PRN_QRY, "getheader, cacheing %s=%s\n", fn, fv);
63
64 m->rc = sv_field_cache_add (&m->cache, fn, fv);
65
66 if (m->rc == 0)
67 {
68 fv = 0; /* owned by the cache */
69 }
70 if (m->rc)
71 break;
72
73 /* the cache doesn't want it, and we don't need it */
74 free (fn);
75 fn = 0;
76 }
77 free (fn);
78 free (fv);
79 }
80 if (!m->rc)
81 {
82 m->rc = sv_field_cache_get (&m->cache, name, body);
83 }
84 if (m->rc)
85 {
86 sv_print (m->ic, SV_PRN_QRY, "getheader %s, failed %s\n", name, strerror (m->rc));
87 }
88 else
89 {
90 const char **b = *body;
91 int i = 1;
92 sv_print (m->ic, SV_PRN_QRY, "getheader, %s=%s", name, b[0]);
93 while (b[0] && b[i])
94 {
95 sv_print (m->ic, SV_PRN_QRY, ", %s", b[i]);
96 i++;
97 }
98 sv_print (m->ic, SV_PRN_QRY, "\n");
99 }
100 return sv_mu_errno_to_rc (m->rc);
101 }
102
103 /*
104 name will always be "to" or "from"
105
106 envelope_t doesn't seem to allow "to" to be gotten, just "from".
107 What's up?
108
109 int getenvelope(void *mc, const char *name, const char ***body)
110 {
111 static const char *buf[2];
112
113 if (buf[0] == NULL) { buf[0] = malloc(sizeof(char) * 256); buf[1] = NULL; }
114 printf("Envelope body of '%s'? ", head);
115 scanf("%s", buf[0]);
116 body = buf;
117
118 return SIEVE_OK;
119 }
120 */
121
122 /* message action callbacks */
123
124 /*
125 The actions arguments are mostly callback data provided during the
126 setup of the intepreter object, script object, and the execution of
127 a script.
128
129 The args are:
130
131 void* ac; // action context, the member of the union Action.u associated
132 // with this kind of action.
133 void* ic, // from sieve_interp_alloc(, ic);
134 void* sc, // from sieve_script_parse(, , sc, );
135 void* mc, // from sieve_execute_script(, mc);
136 const char** errmsg // fill it in if you return failure
137 */
138
139 void
140 sv_print_action (const char* a, void *ac, void *ic, void *sc, void *mc)
141 {
142 //sv_msg_ctx_t *m = (sv_msg_ctx_t *) mc;
143
144 sv_print (ic, SV_PRN_ACT, "action => %s\n", a);
145 }
146
147 int
148 sv_keep (void *ac, void *ic, void *sc, void *mc, const char **errmsg)
149 {
150 //sv_msg_ctx_t * m = (sv_msg_ctx_t *) mc;
151 //sieve_keep_context_t * a = (sieve_keep_context_t *) ac;
152
153 sv_print_action ("KEEP", ac, ic, sc, mc);
154
155 return SIEVE_OK;
156 }
157
158 int
159 sv_fileinto (void *ac, void *ic, void *sc, void *mc, const char **errmsg)
160 {
161 sieve_fileinto_context_t *a = (sieve_fileinto_context_t *) ac;
162 sv_msg_ctx_t *m = (sv_msg_ctx_t *) mc;
163 sv_interp_ctx_t *i = (sv_interp_ctx_t *) ic;
164 const char *what = "fileinto";
165 int res = 0;
166
167 sv_print_action ("FILEINTO", ac, ic, sc, mc);
168 sv_print (i, SV_PRN_ACT, " into <%s>\n", a->mailbox);
169
170 if (!i->opt_no_actions)
171 {
172 res = sv_mu_save_to (a->mailbox, m->msg, i->ticket, &what);
173 }
174
175 if (res)
176 {
177 assert(what);
178
179 *errmsg = strerror (res);
180 sv_print (i, SV_PRN_ACT, " %s failed with [%d] %s\n",
181 what, res, *errmsg);
182 }
183
184 m->rc = res;
185
186 return res ? SIEVE_FAIL : SIEVE_OK;
187 }
188
189 int
190 sv_redirect (void *ac, void *ic, void *sc, void *mc, const char **errmsg)
191 {
192 sv_print_action ("REDIRECT", ac, ic, sc, mc);
193
194 return SIEVE_OK;
195 }
196
197 int
198 sv_discard (void *ac, void *ic, void *sc, void *mc, const char **errmsg)
199 {
200 sv_msg_ctx_t *m = (sv_msg_ctx_t *) mc;
201 sv_interp_ctx_t *i = (sv_interp_ctx_t *) ic;
202 int res = 0;
203
204 sv_print_action ("DISCARD", ac, ic, sc, mc);
205
206 if (!i->opt_no_actions)
207 {
208 res = sv_mu_mark_deleted (m->msg);
209 }
210 if (res)
211 *errmsg = strerror (res);
212
213 return SIEVE_OK;
214 }
215
216 int
217 sv_reject (void *ac, void *ic, void *sc, void *mc, const char **errmsg)
218 {
219 sv_print_action ("REJECT", ac, ic, sc, mc);
220
221 return SIEVE_OK;
222 }
223
224 /*
225 int sv_notify(void *ac, void *ic, void *sc, void *mc, const char **errmsg)
226 {
227 sv_print_action("NOTIFY", ac, ic, sc, mc);
228
229 return SIEVE_OK;
230 }
231 */
232
233 int
234 sv_autorespond (void *ac, void *ic, void *sc, void *mc, const char **errmsg)
235 {
236 return SIEVE_FAIL;
237 }
238
239 int
240 sv_send_response (void *ac, void *ic, void *sc, void *mc, const char **errmsg)
241 {
242 return SIEVE_FAIL;
243 }
244
245 #if 0
246 sieve_vacation_t vacation = {
247 0, /* min response */
248 0, /* max response */
249 &sv_autorespond, /* autorespond() */
250 &sv_send_response /* send_response() */
251 };
252
253 char *markflags[] = { "\\flagged" };
254 sieve_imapflags_t mark = { markflags, 1 };
255 #endif
256
257 /* sieve error callbacks */
258
259 int
260 sv_parse_error (int lineno, const char *msg, void *ic, void *sc)
261 {
262 sv_interp_ctx_t* i = (sv_interp_ctx_t*) ic;
263
264 sv_print (i, SV_PRN_ERR, "%s:%d: %s\n", i->opt_script, lineno, msg);
265
266 return SIEVE_OK;
267 }
268
269 int
270 sv_execute_error (const char *msg, void *ic, void *sc, void *mc)
271 {
272 sv_interp_ctx_t* i = (sv_interp_ctx_t*) ic;
273
274 sv_print (i, SV_PRN_ERR, "sieve execute failed, %s\n", msg);
275
276 return SIEVE_OK;
277 }
278
279 int
280 sv_summary (const char *msg, void *ic, void *sc, void *mc)
281 {
282 sv_msg_ctx_t *m = (sv_msg_ctx_t *) mc;
283
284 m->summary = strdup (msg);
285
286 return SIEVE_OK;
287 }
288
289 /* register all these callbacks */
290
291 int
292 sv_register_callbacks (sieve_interp_t * i)
293 {
294 int res;
295
296 res = sieve_register_size (i, &sv_getsize);
297 if (res != SIEVE_OK)
298 {
299 printf ("sieve_register_size() returns %d\n", res);
300 exit (1);
301 }
302 res = sieve_register_header (i, &sv_getheader);
303 if (res != SIEVE_OK)
304 {
305 printf ("sieve_register_header() returns %d\n", res);
306 exit (1);
307 }
308 res = sieve_register_redirect (i, &sv_redirect);
309 if (res != SIEVE_OK)
310 {
311 printf ("sieve_register_redirect() returns %d\n", res);
312 exit (1);
313 }
314 res = sieve_register_keep (i, &sv_keep);
315 if (res != SIEVE_OK)
316 {
317 printf ("sieve_register_keep() returns %d\n", res);
318 exit (1);
319 }
320 #if 0
321 res = sieve_register_envelope (i, &sv_getenvelope);
322 if (res != SIEVE_OK)
323 {
324 printf ("sieve_register_envelope() returns %d\n", res);
325 exit (1);
326 }
327 #endif
328 res = sieve_register_discard (i, &sv_discard);
329 if (res != SIEVE_OK)
330 {
331 printf ("sieve_register_discard() returns %d\n", res);
332 exit (1);
333 }
334 res = sieve_register_reject (i, &sv_reject);
335 if (res != SIEVE_OK)
336 {
337 printf ("sieve_register_reject() returns %d\n", res);
338 exit (1);
339 }
340 res = sieve_register_fileinto (i, &sv_fileinto);
341 if (res != SIEVE_OK)
342 {
343 printf ("sieve_register_fileinto() returns %d\n", res);
344 exit (1);
345 }
346 #if 0
347 res = sieve_register_vacation (i, &sv_vacation);
348 if (res != SIEVE_OK)
349 {
350 printf ("sieve_register_vacation() returns %d\n", res);
351 exit (1);
352 }
353 res = sieve_register_imapflags (i, &mark);
354 if (res != SIEVE_OK)
355 {
356 printf ("sieve_register_imapflags() returns %d\n", res);
357 exit (1);
358 }
359 #endif
360
361 #if 0
362 res = sieve_register_notify (i, &sv_notify);
363 if (res != SIEVE_OK)
364 {
365 printf ("sieve_register_notify() returns %d\n", res);
366 exit (1);
367 }
368 #endif
369 res = sieve_register_parse_error (i, &sv_parse_error);
370 if (res != SIEVE_OK)
371 {
372 printf ("sieve_register_parse_error() returns %d\n", res);
373 exit (1);
374 }
375 res = sieve_register_execute_error (i, &sv_execute_error);
376 if (res != SIEVE_OK)
377 {
378 printf ("sieve_register_execute_error() returns %d\n", res);
379 exit (1);
380 }
381 res = sieve_register_summary (i, &sv_summary);
382 if (res != SIEVE_OK)
383 {
384 printf ("sieve_register_summary() returns %d\n", res);
385 exit (1);
386 }
387 return res;
388 }
389
390
1
2 #include "sv.h"
3
1 /** utility wrappers around mailutils functionality **/
2
3 #include <errno.h>
4
5 #include "sv.h"
6
7 int
8 sv_mu_errno_to_rc (int eno)
9 {
10 switch (eno)
11 {
12 case ENOMEM:
13 return SIEVE_NOMEM;
14 case ENOENT:
15 return SIEVE_FAIL;
16 case EOK:
17 return SIEVE_OK;
18 }
19 return SIEVE_INTERNAL_ERROR;
20 }
21
22 /* we hook mailutils debug output into our diagnostics using this */
23
24 int
25 sv_mu_debug_print (mu_debug_t d, const char *fmt, va_list ap)
26 {
27 sv_printv(mu_debug_get_owner(d), SV_PRN_MU, fmt, ap);
28
29 return 0;
30 }
31
32 int
33 sv_mu_copy_debug_level (const mailbox_t from, mailbox_t to)
34 {
35 mu_debug_t d = 0;
36 size_t level;
37 int rc;
38
39 if (!from || !to)
40 return EINVAL;
41
42 rc = mailbox_get_debug (from, &d);
43
44 if (!rc)
45 mu_debug_get_level (d, &level);
46
47 if (!rc)
48 rc = mailbox_get_debug (to, &d);
49
50 if (!rc)
51 mu_debug_set_level (d, level);
52
53 return 0;
54 }
55
56 int
57 sv_mu_save_to (const char *toname, message_t mesg,
58 ticket_t ticket, const char **errmsg)
59 {
60 int res = 0;
61 mailbox_t to = 0;
62 mailbox_t from = 0;
63
64 res = mailbox_create_default (&to, toname);
65
66 if (res == ENOENT)
67 *errmsg = "no handler for this type of mailbox";
68
69 if (!res && ticket)
70 {
71 folder_t folder = NULL;
72 authority_t auth = NULL;
73
74 if (!res)
75 {
76 *errmsg = "mailbox_get_folder";
77 res = mailbox_get_folder (to, &folder);
78 }
79
80 if (!res)
81 {
82 *errmsg = "folder_get_authority";
83 res = folder_get_authority (folder, &auth);
84 }
85
86 if (!res)
87 {
88 *errmsg = "authority_set_ticket";
89 res = authority_set_ticket (auth, ticket);
90 }
91 }
92 if (!res)
93 {
94 if (message_get_mailbox (mesg, &from) == 0)
95 sv_mu_copy_debug_level (from, to);
96 }
97 if (!res)
98 {
99 *errmsg = "mailbox_open";
100 res = mailbox_open (to, MU_STREAM_WRITE | MU_STREAM_CREAT);
101 }
102 if (!res)
103 {
104 *errmsg = "mailbox_append_message";
105 res = mailbox_append_message (to, mesg);
106
107 if (!res)
108 {
109 *errmsg = "mailbox_close";
110 res = mailbox_close (to);
111 }
112 else
113 {
114 mailbox_close (to);
115 }
116 }
117 mailbox_destroy (&to);
118
119 if(res == 0)
120 *errmsg = 0;
121
122 return res;
123 }
124
125 int
126 sv_mu_mark_deleted (message_t msg)
127 {
128 attribute_t attr = 0;
129 int res;
130
131 res = message_get_attribute (msg, &attr);
132
133 if (!res)
134 attribute_set_deleted (attr);
135
136 return res;
137 }
138