From 41f0a38f900e0ee215503fa4202ede79263b940b Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Mon, 18 Nov 2002 17:07:49 +0000 Subject: Implemented reject and redirect. --- libsieve/actions.c | 332 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 330 insertions(+), 2 deletions(-) (limited to 'libsieve') diff --git a/libsieve/actions.c b/libsieve/actions.c index 2efaac5c8..e4069dac1 100644 --- a/libsieve/actions.c +++ b/libsieve/actions.c @@ -75,9 +75,159 @@ sieve_action_fileinto (sieve_machine_t mach, list_t args, list_t tags) return rc; } +int +stream_printf (stream_t stream, size_t *off, const char *fmt, ...) +{ + va_list ap; + char *buf = NULL; + size_t size, bytes; + int rc; + + va_start (ap, fmt); + vasprintf (&buf, fmt, ap); + va_end (ap); + size = strlen (buf); + rc = stream_write (stream, buf, size, *off, &bytes); + if (rc) + return rc; + *off += bytes; + if (bytes != size) + return EIO; + return 0; +} + +int +sieve_get_message_sender (message_t msg, char **ptext) +{ + int rc; + envelope_t envelope; + char *text; + size_t size; + + rc = message_get_envelope (msg, &envelope); + if (rc) + return rc; + + rc = envelope_sender (envelope, NULL, 0, &size); + if (rc) + return rc; + + if (!(text = malloc (size + 1))) + return ENOMEM; + envelope_sender (envelope, text, size + 1, NULL); + *ptext = text; + return 0; +} + +static int +build_mime (mime_t *pmime, message_t msg, const char *text) +{ + mime_t mime = NULL; + char datestr[80]; + + mime_create (&mime, NULL, 0); + { + message_t newmsg; + stream_t stream; + time_t t; + struct tm *tm; + char *sender; + size_t off = 0; + header_t hdr; + body_t body; + + message_create (&newmsg, NULL); + message_get_body (newmsg, &body); + body_get_stream (body, &stream); + + time (&t); + tm = localtime (&t); + strftime (datestr, sizeof datestr, "%a, %b %d %H:%M:%S %Y %Z", tm); + + sieve_get_message_sender (msg, &sender); + + stream_printf (stream, &off, + "\nThe original message was received at %s from %s.\n", + datestr, sender); + free (sender); + stream_printf (stream, &off, + "Message was refused by recipient's mail filtering program.\n"); + stream_printf (stream, &off, "Reason given was as follows:\n"); + stream_printf (stream, &off, "%s", text); + stream_close (stream); + mime_add_part (mime, newmsg); + } + + /* message/delivery-status */ + { + message_t newmsg; + stream_t stream; + header_t hdr; + size_t off = 0; + body_t body; + + message_create (&newmsg, NULL); + message_get_header (newmsg, &hdr); + header_set_value (hdr, "Content-Type", "message/delivery-status", 1); + message_get_body (newmsg, &body); + body_get_stream (body, &stream); + stream_printf (stream, &off, "Reporting-UA: sieve; %s\n", PACKAGE_STRING); + stream_printf (stream, &off, "Arrival-Date: %s\n", datestr); + stream_printf (stream, &off, "Final-Recipient: RFC822; %s\n", + mu_get_user_email (NULL)); + stream_printf (stream, &off, "Action: deleted\n"); + stream_printf (stream, &off, + "Disposition: automatic-action/MDN-sent-automatically;deleted\n"); + stream_printf (stream, &off, "Last-Attempt-Date: %s\n", datestr); + stream_close (stream); + mime_add_part(mime, newmsg); + } + + /* Quote original message */ + { + message_t newmsg; + stream_t istream, ostream; + header_t hdr; + size_t ioff = 0, ooff = 0, n; + char buffer[512]; + body_t body; + + message_create (&newmsg, NULL); + message_get_header (newmsg, &hdr); + header_set_value (hdr, "Content-Type", "message/rfc822", 1); + message_get_body (newmsg, &body); + body_get_stream (body, &ostream); + message_get_stream (msg, &istream); + + while (stream_read (istream, buffer, sizeof buffer - 1, ioff, &n) == 0 + && n != 0) + { + size_t sz; + stream_write (ostream, buffer, n, ooff, &sz); + if (sz != n) + return EIO; + ooff += n; + ioff += n; + } + stream_close (ostream); + mime_add_part (mime, newmsg); + } + + *pmime = mime; + + return 0; +} + int sieve_action_reject (sieve_machine_t mach, list_t args, list_t tags) { + mime_t mime = NULL; + mailer_t mailer = sieve_get_mailer (mach); + int rc; + message_t newmsg; + char *addrtext; + address_t from, to; + sieve_value_t *val = sieve_value_get (args, 0); if (!val) { @@ -87,22 +237,200 @@ sieve_action_reject (sieve_machine_t mach, list_t args, list_t tags) sieve_log_action (mach, "REJECT", NULL); if (sieve_is_dry_run (mach)) return 0; - return 0; + + rc = build_mime (&mime, mach->msg, val->v.string); + + mime_get_message (mime, &newmsg); + + sieve_get_message_sender (mach->msg, &addrtext); + rc = address_create (&to, addrtext); + if (rc) + { + sieve_error (mach, + "%d: reject - can't create to address <%s>: %s\n", + sieve_get_message_num (mach), + addrtext, mu_errstring (rc)); + free (addrtext); + goto end; + } + free (addrtext); + + rc = address_create (&from, sieve_get_daemon_email (mach)); + if (rc) + { + sieve_error (mach, + "%d: reject - can't create from address <%s>: %s\n", + sieve_get_message_num (mach), + sieve_get_daemon_email (mach), + mu_errstring (rc)); + goto end; + } + + rc = mailer_open (mailer, 0); + if (rc) + { + url_t url = NULL; + mailer_get_url (mailer, &url); + + sieve_error (mach, + "%d: redirect - can't open mailer %s: %s\n", + sieve_get_message_num (mach), + url_to_string (url), + mu_errstring (rc)); + goto end; + } + + rc = mailer_send_message (mailer, newmsg, from, to); + mailer_close (mailer); + + end: + sieve_mark_deleted (mach->msg, rc == 0); + mime_destroy (&mime); + address_destroy (&from); + address_destroy (&to); + + return rc; +} + +/* rfc3028 says: + "Implementations SHOULD take measures to implement loop control," + We do this by appending an "X-Sender" header to each message + being redirected. If one of the "X-Sender" headers of the message + contains our email address, we assume it is a loop and bail out. */ + +static int +check_redirect_loop (message_t msg) +{ + header_t hdr = NULL; + size_t i, num = 0; + char buf[512]; + int loop = 0; + char *email = mu_get_user_email (NULL); + + message_get_header (msg, &hdr); + header_get_field_count (hdr, &num); + for (i = 1; !loop && i <= num; i++) + { + header_get_field_name (hdr, i, buf, sizeof buf, NULL); + if (strcasecmp (buf, "X-Sender") == 0) + { + size_t j, cnt = 0; + address_t addr; + + header_get_field_value (hdr, i, buf, sizeof buf, NULL); + if (address_create (&addr, buf)) + continue; + + address_get_count (addr, &cnt); + for (j = 1; !loop && j <= cnt; j++) + { + address_get_email (addr, j, buf, sizeof buf, NULL); + if (strcasecmp (buf, email) == 0) + loop = 1; + } + address_destroy (&addr); + } + } + return loop; } int sieve_action_redirect (sieve_machine_t mach, list_t args, list_t tags) { + message_t msg, newmsg = NULL; + address_t addr = NULL, from = NULL; + header_t hdr = NULL; + int rc; + size_t size; + char *fromaddr; + mailer_t mailer = sieve_get_mailer (mach); + sieve_value_t *val = sieve_value_get (args, 0); if (!val) { sieve_error (mach, "redirect: can't get address!"); sieve_abort (mach); } + + rc = address_create (&addr, val->v.string); + if (rc) + { + sieve_error (mach, + "%d: redirect - parsing to `%s' failed: %s\n", + sieve_get_message_num (mach), + val->v.string, mu_errstring (rc)); + return 1; + } + sieve_log_action (mach, "REDIRECT", "to %s", val->v.string); if (sieve_is_dry_run (mach)) return 0; - return 0; + + msg = sieve_get_message (mach); + if (check_redirect_loop (msg)) + { + sieve_error (mach, "%d: Redirection loop detected", + sieve_get_message_num (mach)); + goto end; + } + + rc = sieve_get_message_sender (msg, &fromaddr); + if (rc) + { + sieve_error (mach, + "%d: redirect - can't get envelope sender: %s\n", + sieve_get_message_num (mach), mu_errstring (rc)); + goto end; + } + + rc = address_create (&from, fromaddr); + if (rc) + { + sieve_error (mach, + "%d: redirect - can't create from address <%s>: %s\n", + sieve_get_message_num (mach), + fromaddr, mu_errstring (rc)); + free (fromaddr); + goto end; + } + + free (fromaddr); + + rc = message_create_copy (&newmsg, msg); + if (rc) + { + sieve_error (mach, "%d: can't copy message: %s", + sieve_get_message_num (mach), + mu_errstring (rc)); + goto end; + } + message_get_header (newmsg, &hdr); + header_set_value (hdr, "X-Sender", mu_get_user_email (NULL), 0); + + rc = mailer_open (mailer, 0); + if (rc) + { + url_t url = NULL; + mailer_get_url (mailer, &url); + + sieve_error (mach, + "%d: redirect - can't open mailer %s: %s\n", + sieve_get_message_num (mach), + url_to_string (url), + mu_errstring (rc)); + goto end; + } + + rc = mailer_send_message (mailer, newmsg, from, addr); + mailer_close (mailer); + + end: + sieve_mark_deleted (mach->msg, rc == 0); + message_destroy (&newmsg, NULL); + address_destroy (&from); + address_destroy (&addr); + + return rc; } sieve_data_type fileinto_args[] = { -- cgit v1.2.1