Commit 41f0a38f 41f0a38f900e0ee215503fa4202ede79263b940b by Sergey Poznyakoff

Implemented reject and redirect.

1 parent ef72d1bf
......@@ -76,8 +76,158 @@ sieve_action_fileinto (sieve_machine_t mach, list_t args, list_t tags)
}
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[] = {
......