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 /* 1 /*
2 * sieve interpreter 2 sieve interpreter
3 * 3
4 * The summary is a hack, I should collect the actions list myself in 4 The mu_sieve_context needs a parse_error(), execute_error(), and
5 * my action callbacks, and log them better. 5 debug() callbacks. Pass as much as we know into them.
6 */ 6
7 Then we can request trace info on:
8
9 MU_TRACE
10 MU_PROT
11 MU_SV_HEADER_CACHE
12 MU_SV_ACTIONS
13
14 */
7 15
8 #ifdef HAVE_CONFIG_H 16 #ifdef HAVE_CONFIG_H
9 #include <config.h> 17 #include <config.h>
...@@ -23,213 +31,12 @@ ...@@ -23,213 +31,12 @@
23 #include <strings.h> 31 #include <strings.h>
24 #endif 32 #endif
25 33
26 #include <mailutils/mailbox.h> 34 #include "sv.h"
27 #include <mailutils/address.h>
28 #include <mailutils/registrar.h>
29
30 #include "sieve_interface.h"
31 #include "message.h"
32
33 #include "svfield.h"
34 35
35 #ifndef EOK 36 #ifndef EOK
36 # define EOK 0 37 # define EOK 0
37 #endif 38 #endif
38 39
39 /** utility wrappers around mailutils functionality **/
40
41 int
42 mu_copy_debug_level (const mailbox_t from, mailbox_t to)
43 {
44 mu_debug_t d = 0;
45 size_t level;
46 int rc;
47
48 if (!from || !to)
49 return EINVAL;
50
51 rc = mailbox_get_debug (from, &d);
52
53 if (!rc)
54 mu_debug_get_level (d, &level);
55
56 if (!rc)
57 rc = mailbox_get_debug (to, &d);
58
59 if (!rc)
60 mu_debug_set_level (d, level);
61
62 return 0;
63 }
64
65 int
66 mu_save_to (const char *toname, message_t mesg,
67 ticket_t ticket, const char **errmsg)
68 {
69 int res = 0;
70 mailbox_t to = 0;
71 mailbox_t from = 0;
72
73 res = mailbox_create_default (&to, toname);
74
75 if (res == ENOENT)
76 *errmsg = "no handler for this type of mailbox";
77
78 if (ticket)
79 {
80 folder_t folder = NULL;
81 authority_t auth = NULL;
82
83 if (!res)
84 {
85 *errmsg = "mailbox_get_folder";
86 res = mailbox_get_folder (to, &folder);
87 }
88
89 if (!res)
90 {
91 *errmsg = "folder_get_authority";
92 res = folder_get_authority (folder, &auth);
93 }
94
95 if (!res)
96 {
97 *errmsg = "authority_set_ticket";
98 res = authority_set_ticket (auth, ticket);
99 }
100 }
101 if (!res)
102 {
103 if (message_get_mailbox (mesg, &from) == 0)
104 mu_copy_debug_level (from, to);
105 }
106 if (!res)
107 {
108 *errmsg = "mailbox_open";
109 res = mailbox_open (to, MU_STREAM_WRITE | MU_STREAM_CREAT);
110 }
111 if (!res)
112 {
113 *errmsg = "mailbox_open";
114 res = mailbox_append_message (to, mesg);
115
116 if (!res)
117 {
118 *errmsg = "mailbox_close";
119 res = mailbox_close (to);
120 }
121 else
122 {
123 mailbox_close (to);
124 }
125 }
126 mailbox_destroy (&to);
127
128 if(res == 0)
129 *errmsg = 0;
130
131 return res;
132 }
133
134 int
135 mu_mark_deleted (message_t msg)
136 {
137 attribute_t attr = 0;
138 int res;
139
140 res = message_get_attribute (msg, &attr);
141
142 if (!res)
143 attribute_set_deleted (attr);
144
145 return res;
146 }
147
148 static int
149 sv_errno (int rc)
150 {
151 switch (rc)
152 {
153 case ENOMEM:
154 return SIEVE_NOMEM;
155 case ENOENT:
156 return SIEVE_FAIL;
157 case EOK:
158 return SIEVE_OK;
159 }
160 return SIEVE_INTERNAL_ERROR;
161 }
162
163 /** sieve context structures
164
165 The object relationship diagram is this, with the names in ""
166 being the argument name when the context's are provided as
167 arguments to callback functions.
168
169 sieve_execute_script() --> sv_msg_ctx_t, "mc"
170
171 |
172 |
173 V
174
175 sieve_script_t ---> sv_script_ctx_t, "sc"
176
177 |
178 |
179 V
180
181 sieve_interp_t ---> sv_interp_ctx_t, "ic"
182
183
184 */
185
186 typedef struct sv_interp_ctx_t
187 {
188 /* cmd line options */
189 int opt_no_actions;
190 int opt_verbose;
191 int opt_no_run;
192 int opt_watch;
193 char* opt_mbox;
194 char* opt_tickets;
195 char* opt_script;
196
197 int print_mask;
198 FILE* print_stream;
199
200 /* Ticket for use by mailbox URLs for implicit authentication. */
201 ticket_t ticket;
202
203 /* mailutils debug handle, we need to destroy it */
204 mu_debug_t debug;
205 } sv_interp_ctx_t;
206
207 typedef struct sv_script_ctx_t
208 {
209 sv_interp_ctx_t* ic;
210 } sv_script_ctx_t;
211
212 typedef struct sv_msg_ctx_t
213 {
214 int rc; /* the mailutils return code */
215 int cache_filled;
216 sv_field_cache_t cache;
217 message_t msg;
218 mailbox_t mbox;
219 char *summary;
220
221 sv_interp_ctx_t* ic;
222 } sv_msg_ctx_t;
223
224 enum /* print level masks */
225 {
226 SV_PRN_MU = 0x1,
227 SV_PRN_ACT = 0x2,
228 SV_PRN_QRY = 0x4,
229 SV_PRN_PRS = 0x8,
230 SV_PRN_NOOP
231 };
232
233 void 40 void
234 sv_printv (sv_interp_ctx_t* ic, int level, const char *fmt, va_list ap) 41 sv_printv (sv_interp_ctx_t* ic, int level, const char *fmt, va_list ap)
235 { 42 {
...@@ -238,7 +45,9 @@ sv_printv (sv_interp_ctx_t* ic, int level, const char *fmt, va_list ap) ...@@ -238,7 +45,9 @@ sv_printv (sv_interp_ctx_t* ic, int level, const char *fmt, va_list ap)
238 if(level & ic->print_mask) 45 if(level & ic->print_mask)
239 vfprintf(ic->print_stream ? ic->print_stream : stdout, fmt, ap); 46 vfprintf(ic->print_stream ? ic->print_stream : stdout, fmt, ap);
240 } 47 }
241 void sv_print (sv_interp_ctx_t* ic, int level, const char* fmt, ...) 48
49 void
50 sv_print (sv_interp_ctx_t* ic, int level, const char* fmt, ...)
242 { 51 {
243 va_list ap; 52 va_list ap;
244 va_start(ap, fmt); 53 va_start(ap, fmt);
...@@ -246,443 +55,6 @@ void sv_print (sv_interp_ctx_t* ic, int level, const char* fmt, ...) ...@@ -246,443 +55,6 @@ void sv_print (sv_interp_ctx_t* ic, int level, const char* fmt, ...)
246 va_end(ap); 55 va_end(ap);
247 } 56 }
248 57
249 /* we hook mailutils debug output into our diagnostics using this */
250 int
251 sv_mu_debug_print (mu_debug_t d, const char *fmt, va_list ap)
252 {
253 sv_printv(mu_debug_get_owner(d), SV_PRN_MU, fmt, ap);
254
255 return 0;
256 }
257
258 /** message query callbacks **/
259
260 int
261 sv_getsize (void *mc, int *size)
262 {
263 sv_msg_ctx_t *m = (sv_msg_ctx_t *) mc;
264 size_t sz = 0;
265
266 message_size (m->msg, &sz);
267
268 *size = sz;
269
270 sv_print (m->ic, SV_PRN_QRY, "getsize -> %d\n", *size);
271
272 return SIEVE_OK;
273 }
274
275 /*
276 A given header can occur multiple times, so we return a pointer
277 to a null terminated array of pointers to the values found for
278 the named header.
279 */
280 int
281 sv_getheader (void *mc, const char *name, const char ***body)
282 {
283 sv_msg_ctx_t *m = (sv_msg_ctx_t *) mc;
284
285 m->rc = 0;
286
287 if (!m->cache_filled)
288 {
289 header_t h = 0;
290 size_t i = 0;
291 char *fn = 0;
292 char *fv = 0;
293
294 m->cache_filled = 1;
295
296 message_get_header (m->msg, &h);
297
298 header_get_field_count (h, &i);
299
300 sv_print (m->ic, SV_PRN_QRY, "getheader, filling cache with %d fields\n", i);
301
302 for (; i > 0; i--)
303 {
304 m->rc = header_aget_field_name (h, i, &fn);
305 if (m->rc)
306 break;
307 m->rc = header_aget_field_value (h, i, &fv);
308 if (m->rc)
309 break;
310
311 sv_print (m->ic, SV_PRN_QRY, "getheader, cacheing %s=%s\n", fn, fv);
312
313 m->rc = sv_field_cache_add (&m->cache, fn, fv);
314
315 if (m->rc == 0)
316 {
317 fv = 0; /* owned by the cache */
318 }
319 if (m->rc)
320 break;
321
322 /* the cache doesn't want it, and we don't need it */
323 free (fn);
324 fn = 0;
325 }
326 free (fn);
327 free (fv);
328 }
329 if (!m->rc)
330 {
331 m->rc = sv_field_cache_get (&m->cache, name, body);
332 }
333 if (m->rc)
334 {
335 sv_print (m->ic, SV_PRN_QRY, "getheader %s, failed %s\n", name, strerror (m->rc));
336 }
337 else
338 {
339 const char **b = *body;
340 int i = 1;
341 sv_print (m->ic, SV_PRN_QRY, "getheader, %s=%s", name, b[0]);
342 while (b[0] && b[i])
343 {
344 sv_print (m->ic, SV_PRN_QRY, ", %s", b[i]);
345 i++;
346 }
347 sv_print (m->ic, SV_PRN_QRY, "\n");
348 }
349 return sv_errno (m->rc);
350 }
351
352 /*
353 name will always be "to" or "from"
354
355 envelope_t doesn't seem to allow "to" to be gotten, just "from".
356 What's up?
357
358 int getenvelope(void *mc, const char *name, const char ***body)
359 {
360 static const char *buf[2];
361
362 if (buf[0] == NULL) { buf[0] = malloc(sizeof(char) * 256); buf[1] = NULL; }
363 printf("Envelope body of '%s'? ", head);
364 scanf("%s", buf[0]);
365 *body = buf;
366
367 return SIEVE_OK;
368 }
369 */
370
371 /* message action callbacks */
372
373 /*
374 The actions arguments are mostly callback data provided during the
375 setup of the intepreter object, script object, and the execution of
376 a script.
377
378 The args are:
379
380 void* ac; // action context, the member of the union Action.u associated
381 // with this kind of action.
382 void* ic, // from sieve_interp_alloc(, ic);
383 void* sc, // from sieve_script_parse(, , sc, );
384 void* mc, // from sieve_execute_script(, mc);
385 const char** errmsg // fill it in if you return failure
386 */
387
388 const char *
389 str_action (action_t a)
390 {
391 switch (a)
392 {
393 case ACTION_NONE:
394 return "NONE";
395 case ACTION_REJECT:
396 return "REJECT";
397 case ACTION_FILEINTO:
398 return "FILEINTO";
399 case ACTION_KEEP:
400 return "KEEP";
401 case ACTION_REDIRECT:
402 return "REDIRECT";
403 case ACTION_DISCARD:
404 return "DISCARD";
405 case ACTION_VACATION:
406 return "VACATION";
407 case ACTION_SETFLAG:
408 return "SETFLAG";
409 case ACTION_ADDFLAG:
410 return "ADDFLAG";
411 case ACTION_REMOVEFLAG:
412 return "REMOVEFLAG";
413 case ACTION_MARK:
414 return "MARK";
415 case ACTION_UNMARK:
416 return "UNMARK";
417 case ACTION_NOTIFY:
418 return "NOTIFY";
419 case ACTION_DENOTIFY:
420 return "DENOTIFY";
421 }
422 return "UNKNOWN";
423 }
424 const char *
425 str_sieve_error (int e)
426 {
427 switch (e)
428 {
429 case SIEVE_FAIL:
430 return "SIEVE_FAIL";
431 case SIEVE_NOT_FINALIZED:
432 return "SIEVE_NOT_FINALIZED";
433 case SIEVE_PARSE_ERROR:
434 return "SIEVE_PARSE_ERROR";
435 case SIEVE_RUN_ERROR:
436 return "SIEVE_RUN_ERROR";
437 case SIEVE_INTERNAL_ERROR:
438 return "SIEVE_INTERNAL_ERROR";
439 case SIEVE_NOMEM:
440 return "SIEVE_NOMEM";
441 case SIEVE_DONE:
442 return "SIEVE_DONE";
443 }
444 return "UNKNOWN";
445 }
446
447
448 void
449 sv_print_action (action_t a, void *ac, void *ic, void *sc, void *mc)
450 {
451 //sv_msg_ctx_t *m = (sv_msg_ctx_t *) mc;
452
453 sv_print (ic, SV_PRN_ACT, "action => %s\n", str_action (a));
454 }
455
456 int
457 sv_keep (void *ac, void *ic, void *sc, void *mc, const char **errmsg)
458 {
459 //sv_msg_ctx_t * m = (sv_msg_ctx_t *) mc;
460 //sieve_keep_context_t * a = (sieve_keep_context_t *) ac;
461
462 sv_print_action (ACTION_KEEP, ac, ic, sc, mc);
463
464 return SIEVE_OK;
465 }
466
467 int
468 sv_fileinto (void *ac, void *ic, void *sc, void *mc, const char **errmsg)
469 {
470 sieve_fileinto_context_t *a = (sieve_fileinto_context_t *) ac;
471 sv_msg_ctx_t *m = (sv_msg_ctx_t *) mc;
472 sv_interp_ctx_t *i = (sv_interp_ctx_t *) ic;
473 int res = 0;
474
475 sv_print_action (ACTION_FILEINTO, ac, ic, sc, mc);
476 sv_print (i, SV_PRN_ACT, " into <%s>\n", a->mailbox);
477
478 if (!i->opt_no_actions)
479 {
480 res = mu_save_to (a->mailbox, m->msg, i->ticket, errmsg);
481 }
482 if (res && !errmsg)
483 *errmsg = strerror (res);
484
485 if (res)
486 sv_print (i, SV_PRN_ACT, " fail with [%d] %s\n", res, *errmsg);
487
488 return res ? SIEVE_FAIL : SIEVE_OK;
489 }
490
491 int
492 sv_redirect (void *ac, void *ic, void *sc, void *mc, const char **errmsg)
493 {
494 sv_print_action (ACTION_REDIRECT, ac, ic, sc, mc);
495
496 return SIEVE_OK;
497 }
498
499 int
500 sv_discard (void *ac, void *ic, void *sc, void *mc, const char **errmsg)
501 {
502 sv_msg_ctx_t *m = (sv_msg_ctx_t *) mc;
503 sv_interp_ctx_t *i = (sv_interp_ctx_t *) ic;
504 int res = 0;
505
506 sv_print_action (ACTION_DISCARD, ac, ic, sc, mc);
507
508 if (!i->opt_no_actions)
509 {
510 res = mu_mark_deleted (m->msg);
511 }
512 if (res)
513 *errmsg = strerror (res);
514
515 return SIEVE_OK;
516 }
517
518 int
519 sv_reject (void *ac, void *ic, void *sc, void *mc, const char **errmsg)
520 {
521 sv_print_action (ACTION_REJECT, ac, ic, sc, mc);
522
523 return SIEVE_OK;
524 }
525
526 /*
527 int sv_notify(void *ac, void *ic, void *sc, void *mc, const char **errmsg)
528 {
529 sv_print_action(ACTION_NOTIFY, ac, ic, sc, mc);
530
531 return SIEVE_OK;
532 }
533 */
534
535 int
536 sv_autorespond (void *ac, void *ic, void *sc, void *mc, const char **errmsg)
537 {
538 return SIEVE_FAIL;
539 }
540
541 int
542 sv_send_response (void *ac, void *ic, void *sc, void *mc, const char **errmsg)
543 {
544 return SIEVE_FAIL;
545 }
546
547 #if 0
548 sieve_vacation_t vacation = {
549 0, /* min response */
550 0, /* max response */
551 &sv_autorespond, /* autorespond() */
552 &sv_send_response /* send_response() */
553 };
554
555 char *markflags[] = { "\\flagged" };
556 sieve_imapflags_t mark = { markflags, 1 };
557 #endif
558
559 int
560 sv_parse_error (int lineno, const char *msg, void *ic, void *sc)
561 {
562 sv_interp_ctx_t* i = (sv_interp_ctx_t*) ic;
563
564 sv_print (i, SV_PRN_PRS, "%s:%d: %s\n", i->opt_script, lineno, msg);
565
566 return SIEVE_OK;
567 }
568
569 int
570 sv_execute_error (const char *msg, void *ic, void *sc, void *mc)
571 {
572 fprintf (stderr, "runtime error: %s\n", msg);
573
574 return SIEVE_OK;
575 }
576
577 int
578 sv_summary (const char *msg, void *ic, void *sc, void *mc)
579 {
580 sv_msg_ctx_t *m = (sv_msg_ctx_t *) mc;
581
582 m->summary = strdup (msg);
583
584 return SIEVE_OK;
585 }
586
587 int
588 sieve_register_mailutils (sieve_interp_t * i)
589 {
590 int res;
591
592 res = sieve_register_size (i, &sv_getsize);
593 if (res != SIEVE_OK)
594 {
595 printf ("sieve_register_size() returns %d\n", res);
596 exit (1);
597 }
598 res = sieve_register_header (i, &sv_getheader);
599 if (res != SIEVE_OK)
600 {
601 printf ("sieve_register_header() returns %d\n", res);
602 exit (1);
603 }
604 res = sieve_register_redirect (i, &sv_redirect);
605 if (res != SIEVE_OK)
606 {
607 printf ("sieve_register_redirect() returns %d\n", res);
608 exit (1);
609 }
610 res = sieve_register_keep (i, &sv_keep);
611 if (res != SIEVE_OK)
612 {
613 printf ("sieve_register_keep() returns %d\n", res);
614 exit (1);
615 }
616 #if 0
617 res = sieve_register_envelope (i, &sv_getenvelope);
618 if (res != SIEVE_OK)
619 {
620 printf ("sieve_register_envelope() returns %d\n", res);
621 exit (1);
622 }
623 #endif
624 res = sieve_register_discard (i, &sv_discard);
625 if (res != SIEVE_OK)
626 {
627 printf ("sieve_register_discard() returns %d\n", res);
628 exit (1);
629 }
630 res = sieve_register_reject (i, &sv_reject);
631 if (res != SIEVE_OK)
632 {
633 printf ("sieve_register_reject() returns %d\n", res);
634 exit (1);
635 }
636 res = sieve_register_fileinto (i, &sv_fileinto);
637 if (res != SIEVE_OK)
638 {
639 printf ("sieve_register_fileinto() returns %d\n", res);
640 exit (1);
641 }
642 #if 0
643 res = sieve_register_vacation (i, &sv_vacation);
644 if (res != SIEVE_OK)
645 {
646 printf ("sieve_register_vacation() returns %d\n", res);
647 exit (1);
648 }
649 res = sieve_register_imapflags (i, &mark);
650 if (res != SIEVE_OK)
651 {
652 printf ("sieve_register_imapflags() returns %d\n", res);
653 exit (1);
654 }
655 #endif
656
657 #if 0
658 res = sieve_register_notify (i, &sv_notify);
659 if (res != SIEVE_OK)
660 {
661 printf ("sieve_register_notify() returns %d\n", res);
662 exit (1);
663 }
664 #endif
665 res = sieve_register_parse_error (i, &sv_parse_error);
666 if (res != SIEVE_OK)
667 {
668 printf ("sieve_register_parse_error() returns %d\n", res);
669 exit (1);
670 }
671 res = sieve_register_execute_error (i, &sv_execute_error);
672 if (res != SIEVE_OK)
673 {
674 printf ("sieve_register_execute_error() returns %d\n", res);
675 exit (1);
676 }
677 res = sieve_register_summary (i, &sv_summary);
678 if (res != SIEVE_OK)
679 {
680 printf ("sieve_register_summary() returns %d\n", res);
681 exit (1);
682 }
683 return res;
684 }
685
686 const char USAGE[] = 58 const char USAGE[] =
687 "usage: sieve [-hnvcd] [-D mask] [-f mbox] [-t tickets] script\n"; 59 "usage: sieve [-hnvcd] [-D mask] [-f mbox] [-t tickets] script\n";
688 60
...@@ -858,7 +230,7 @@ main (int argc, char *argv[]) ...@@ -858,7 +230,7 @@ main (int argc, char *argv[])
858 fprintf (stderr, "sieve_interp_alloc() returns %d\n", res); 230 fprintf (stderr, "sieve_interp_alloc() returns %d\n", res);
859 return 1; 231 return 1;
860 } 232 }
861 res = sieve_register_mailutils (interp); 233 res = sv_register_callbacks (interp);
862 234
863 f = fopen (ic.opt_script, "r"); 235 f = fopen (ic.opt_script, "r");
864 236
...@@ -870,7 +242,7 @@ main (int argc, char *argv[]) ...@@ -870,7 +242,7 @@ main (int argc, char *argv[])
870 res = sieve_script_parse (interp, f, &sc, &script); 242 res = sieve_script_parse (interp, f, &sc, &script);
871 if (res != SIEVE_OK) 243 if (res != SIEVE_OK)
872 { 244 {
873 printf ("script parse failed: %s\n", str_sieve_error (res)); 245 printf ("script parse failed: %s\n", sieve_errstr (res));
874 return 1; 246 return 1;
875 } 247 }
876 fclose (f); 248 fclose (f);
...@@ -881,7 +253,8 @@ main (int argc, char *argv[]) ...@@ -881,7 +253,8 @@ main (int argc, char *argv[])
881 mailbox_messages_count (mbox, &count); 253 mailbox_messages_count (mbox, &count);
882 if (ic.opt_verbose) 254 if (ic.opt_verbose)
883 { 255 {
884 fprintf (stderr, "mbox has %d messages...\n", count); 256 fprintf (stderr, "mbox %s has %d messages...\n",
257 ic.opt_mbox, count);
885 } 258 }
886 for (i = 1; i <= count; ++i) 259 for (i = 1; i <= count; ++i)
887 { 260 {
...@@ -891,7 +264,7 @@ main (int argc, char *argv[]) ...@@ -891,7 +264,7 @@ main (int argc, char *argv[])
891 264
892 if ((res = mailbox_get_message (mbox, i, &mc.msg)) != 0) 265 if ((res = mailbox_get_message (mbox, i, &mc.msg)) != 0)
893 { 266 {
894 fprintf (stderr, "mailbox_get_message(%d): %s\n", i, 267 fprintf (stderr, "mailbox_get_message(msg %d): %s\n", i,
895 strerror (res)); 268 strerror (res));
896 exit (1); 269 exit (1);
897 } 270 }
...@@ -901,8 +274,8 @@ main (int argc, char *argv[]) ...@@ -901,8 +274,8 @@ main (int argc, char *argv[])
901 274
902 if (res != SIEVE_OK) 275 if (res != SIEVE_OK)
903 { 276 {
904 printf ("sieve_execute_script(%d): sieve %d rc %s\n", 277 printf ("sieve_execute_script(msg %d) failed: %s (because %s)\n",
905 i, res, strerror (mc.rc)); 278 i, sieve_errstr(res), strerror (mc.rc));
906 exit (1); 279 exit (1);
907 } 280 }
908 sv_field_cache_release (&mc.cache); 281 sv_field_cache_release (&mc.cache);
...@@ -938,10 +311,3 @@ main (int argc, char *argv[]) ...@@ -938,10 +311,3 @@ main (int argc, char *argv[])
938 return 0; 311 return 0;
939 } 312 }
940 313
941 void
942 fatal (char *message, int rc)
943 {
944 fprintf (stderr, "fatal error: %s\n", message);
945 exit (rc);
946 }
947
......
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