Commit dca7b761 dca7b761362545f359968be344267c3fd93cb935 by Sergey Poznyakoff

Fix mime creation and Sieve reject/redirect actions.

* examples/mta.c (finalize_option): New variable.
(message_finalize): Don't modify the message if finalize_option
is 0.
* include/mailutils/sys/message.h (_mu_message)
<orig_header_size>: New member.
* include/mailutils/sys/mime.h (_mu_mime) <part_stream>: New member.
* libmu_sieve/actions.c (mime_create_reason)
(mime_create_ds): Use mu_body_get_streamref.
(mime_create_quote): Use mu_body_get_streamref/mu_message_get_streamref.
(sieve_action_reject): Set the To: header.
* mailbox/message.c (mu_message_get_header): Set orig_header_size.
(mu_message_get_body): Use orig_header_size instead of relying
on mu_header_size.
* mailbox/mime.c (_mime_part_size): New static.
(_mime_body_stream_size): New method.
(_mime_body_seek): Rename to _mime_body_stream_seek.
(_mime_body_read): Rewrite and rename to _mime_body_stream_read.
(_mime_body_ioctl): Rename to _mime_body_stream_ioctl.
(create_mime_body_stream): Take mu_mime_t as the 2nd parameter.
Initialize sp->stream.size and sp->mime.
(_mime_body_size): Rewrite using _mime_part_size.
(mu_mime_destroy): Destroy part_stream.
* sieve/testsuite/Redirect: Reflect new mta behavior.
* sieve/testsuite/Reject: Likewise.
1 parent 66c992c3
......@@ -73,6 +73,18 @@ int dot = 1; /* Message is terminated by a lone dot on a line */
mu_address_t recipients = NULL;
char *progname;
/* FIXME: If finalize_option is set, mta should try to finalize
received messages the way sendmail does, i.e. to add To: or
Cc: headers, if they are missing, etc. The code to do so is
already included, but the modified message is not reproduced
on diagnostic output because mta_send reads it from the stream,
which does not reflect modifications to the header.
Ideally, the mu_message_get_streamref function should notice the
change in the header (and/or the body) and return a temporary
stream, which will read the modified values. This is left as
as TODO for a later time. 2010-09-29, Sergey */
int finalize_option = 0;
int mta_stdin (int argc, char **argv);
int mta_smtp (int argc, char **argv);
......@@ -361,7 +373,7 @@ message_finalize (mu_message_t msg, int warn)
mu_message_get_header (msg, &header);
if (warn && from_person)
if (finalize_option && warn && from_person)
{
struct passwd *pwd = getpwuid (getuid ());
char *warn = malloc (strlen (pwd->pw_name) + 1 +
......@@ -400,7 +412,8 @@ message_finalize (mu_message_t msg, int warn)
free (value);
}
if (mu_header_aget_value (header, MU_HEADER_BCC, &value) == 0)
if (finalize_option &&
mu_header_aget_value (header, MU_HEADER_BCC, &value) == 0)
{
if (add_recipient (value))
{
......@@ -412,7 +425,7 @@ message_finalize (mu_message_t msg, int warn)
}
}
if (!have_to)
if (finalize_option && !have_to)
{
size_t n;
int c;
......
......@@ -47,7 +47,8 @@ struct _mu_message
mu_mime_t mime;
mu_observable_t observable;
mu_mailbox_t mailbox;
size_t orig_header_size;
/* Reference count. */
int ref;
......
......@@ -64,6 +64,7 @@ struct _mu_mime
size_t boundary_len;
size_t preamble;
size_t postamble;
mu_stream_t part_stream;
/* parser state */
char *cur_line;
ssize_t line_ndx;
......
......@@ -154,7 +154,7 @@ mime_create_reason (mu_mime_t mime, mu_message_t msg, const char *text)
mu_message_create (&newmsg, NULL);
mu_message_get_body (newmsg, &body);
mu_body_get_stream (body, &stream);
mu_body_get_streamref (body, &stream);
time (&t);
tm = localtime (&t);
......@@ -171,6 +171,8 @@ mime_create_reason (mu_mime_t mime, mu_message_t msg, const char *text)
mu_stream_printf (stream, "Reason given was as follows:\n\n");
mu_stream_printf (stream, "%s", text);
mu_stream_close (stream);
mu_stream_destroy (&stream);
mu_header_create (&hdr, content_header, strlen (content_header));
mu_message_set_header (newmsg, hdr, NULL);
mu_mime_add_part (mime, newmsg);
......@@ -196,7 +198,7 @@ mime_create_ds (mu_mime_t mime, mu_message_t orig)
mu_message_get_header (newmsg, &hdr);
mu_header_set_value (hdr, "Content-Type", "message/delivery-status", 1);
mu_message_get_body (newmsg, &body);
mu_body_get_stream (body, &stream);
mu_body_get_streamref (body, &stream);
mu_stream_printf (stream, "Reporting-UA: sieve; %s\n", PACKAGE_STRING);
mu_message_get_envelope (orig, &env);
......@@ -226,7 +228,9 @@ mime_create_ds (mu_mime_t mime, mu_message_t orig)
mu_stream_printf (stream, "Last-Attempt-Date: %s\n", datestr);
mu_stream_close (stream);
mu_mime_add_part(mime, newmsg);
mu_stream_destroy (&stream);
mu_mime_add_part (mime, newmsg);
mu_message_unref (newmsg);
}
......@@ -241,25 +245,30 @@ mime_create_quote (mu_mime_t mime, mu_message_t msg)
size_t n;
char buffer[512];
mu_body_t body;
int rc;
mu_message_create (&newmsg, NULL);
mu_message_get_header (newmsg, &hdr);
mu_header_set_value (hdr, "Content-Type", "message/rfc822", 1);
mu_message_get_body (newmsg, &body);
mu_body_get_stream (body, &ostream);
mu_message_get_stream (msg, &istream);
mu_body_get_streamref (body, &ostream);
mu_message_get_streamref (msg, &istream);
rc = 0;/* FIXME: use mu_stream_copy */
while (mu_stream_read (istream, buffer, sizeof buffer - 1, &n) == 0
&& n != 0)
{
int rc = mu_stream_write (ostream, buffer, n, NULL);
rc = mu_stream_write (ostream, buffer, n, NULL);
if (rc)
return EIO;
break;
}
mu_stream_destroy (&istream);
mu_stream_close (ostream);
mu_stream_destroy (&ostream);
mu_mime_add_part (mime, newmsg);
mu_message_unref (newmsg);
return 0;
return rc;
}
static int
......@@ -292,6 +301,7 @@ sieve_action_reject (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
mu_message_t newmsg;
char *addrtext;
mu_address_t from, to;
mu_header_t hdr;
mu_sieve_value_t *val = mu_sieve_value_get (args, 0);
if (!val)
......@@ -308,6 +318,9 @@ sieve_action_reject (mu_sieve_machine_t mach, mu_list_t args, mu_list_t tags)
mu_mime_get_message (mime, &newmsg);
mu_sieve_get_message_sender (mach->msg, &addrtext);
mu_message_get_header (newmsg, &hdr);
mu_header_prepend (hdr, MU_HEADER_TO, addrtext);
rc = mu_address_create (&to, addrtext);
if (rc)
{
......
......@@ -688,6 +688,9 @@ mu_message_get_header (mu_message_t msg, mu_header_t *phdr)
return status;
if (msg->stream)
mu_header_set_fill (header, message_header_fill, msg);
status = mu_header_size (header, &msg->orig_header_size);
if (status)
return status;
msg->header = header;
}
*phdr = msg->header;
......@@ -728,19 +731,15 @@ mu_message_get_body (mu_message_t msg, mu_body_t *pbody)
/* FIXME: I'm not sure if the second condition is really needed */
if (msg->stream/* && (msg->flags & MESSAGE_INTERNAL_STREAM)*/)
{
size_t size = 0;
mu_stream_t stream;
int flags = 0;
/* FIXME: The size cannot be used as offset, because
the headers might have been modified in between. */
status = mu_header_size (msg->header, &size);
if (status)
return status;
/* FIXME: The actual mu_header_size cannot be used as offset,
because the headers might have been modified in between. */
mu_stream_get_flags (msg->stream, &flags);
status = mu_streamref_create_abridged (&stream, msg->stream,
size, 0);
msg->orig_header_size, 0);
if (status)
{
mu_body_destroy (&body, msg);
......
......@@ -536,15 +536,52 @@ _mime_set_content_type (mu_mime_t mime)
}
static int
_mime_part_size (mu_mime_t mime, size_t *psize)
{
int i, ret;
size_t size, total = 0;
if (mime->nmtp_parts == 0)
return EINVAL;
if ((ret = _mime_set_content_type (mime)) != 0)
return ret;
for (i = 0; i < mime->nmtp_parts; i++)
{
mu_message_size (mime->mtp_parts[i]->msg, &size);
total += size;
if (mime->nmtp_parts > 1) /* boundary line */
total += strlen (mime->boundary) + 3;
}
if (mime->nmtp_parts > 1) /* ending boundary line */
total += 2;
*psize = total;
return 0;
}
struct _mime_body_stream
{
struct _mu_stream stream;
mu_mime_t mime;
};
static int
_mime_body_stream_size (mu_stream_t stream, mu_off_t *psize)
{
struct _mime_body_stream *mstr = (struct _mime_body_stream *)stream;
mu_mime_t mime = mstr->mime;
size_t sz;
int rc = _mime_part_size (mime, &sz);
if (rc == 0)
*psize = sz;
return rc;
}
/* FIXME: The seek method is defective */
static int
_mime_body_seek (mu_stream_t stream, mu_off_t off, mu_off_t *presult)
_mime_body_stream_seek (mu_stream_t stream, mu_off_t off, mu_off_t *presult)
{
struct _mime_body_stream *mstr = (struct _mime_body_stream *)stream;
mu_mime_t mime = mstr->mime;
......@@ -565,30 +602,39 @@ _mime_body_seek (mu_stream_t stream, mu_off_t off, mu_off_t *presult)
return 0;
}
#define ADD_CHAR(buf, c, offset, buflen, nbytes) do {\
*(buf)++ = c;\
(offset)++;\
(nbytes)++;\
if (--(buflen) == 0) return 0;\
} while (0)
#define ADD_CHAR(buf, c, offset, buflen, total, nbytes) \
do \
{ \
*(buf)++ = c; \
(offset)++; \
(total)++; \
if (--(buflen) == 0) \
{ \
*(nbytes) = total; \
return 0; \
} \
} \
while (0)
static int
_mime_body_read (mu_stream_t stream, char *buf, size_t buflen, size_t *nbytes)
_mime_body_stream_read (mu_stream_t stream, char *buf, size_t buflen, size_t *nbytes)
{
struct _mime_body_stream *mstr = (struct _mime_body_stream *)stream;
mu_mime_t mime = mstr->mime;
int ret = 0;
size_t part_nbytes = 0;
mu_stream_t msg_stream = NULL;
size_t total = 0;
if (mime->nmtp_parts == 0)
return EINVAL;
if ((ret = _mime_set_content_type (mime)) == 0)
{
do
{
mu_stream_destroy (&msg_stream);
size_t part_nbytes = 0;
if (buflen == 0)
break;
if (mime->nmtp_parts > 1)
{
size_t len;
......@@ -606,7 +652,8 @@ _mime_body_read (mu_stream_t stream, char *buf, size_t buflen, size_t *nbytes)
while (mime->preamble)
{
mime->preamble--;
ADD_CHAR (buf, '-', mime->cur_offset, buflen, *nbytes);
ADD_CHAR (buf, '-', mime->cur_offset, buflen,
total, nbytes);
}
len = strlen (mime->boundary) - mime->boundary_len;
while (mime->boundary_len)
......@@ -614,57 +661,89 @@ _mime_body_read (mu_stream_t stream, char *buf, size_t buflen, size_t *nbytes)
mime->boundary_len--;
ADD_CHAR (buf,
mime->boundary[len++],
mime->cur_offset, buflen, *nbytes);
mime->cur_offset, buflen,
total, nbytes);
}
while (mime->postamble)
{
mime->postamble--;
ADD_CHAR (buf, '-', mime->cur_offset, buflen, *nbytes);
ADD_CHAR (buf, '-', mime->cur_offset, buflen,
total, nbytes);
}
mime->flags &=
~(MIME_INSERT_BOUNDARY | MIME_ADDING_BOUNDARY);
mime->part_offset = 0;
ADD_CHAR (buf, '\n', mime->cur_offset, buflen, *nbytes);
ADD_CHAR (buf, '\n', mime->cur_offset, buflen,
total, nbytes);
}
if (!mime->part_stream)
{
if (mime->cur_part >= mime->nmtp_parts)
{
*nbytes = total;
return 0;
}
ret = mu_message_get_streamref (mime->mtp_parts[mime->cur_part]->msg,
&mime->part_stream);
}
if (mime->cur_part >= mime->nmtp_parts)
return 0;
mu_message_get_streamref (mime->mtp_parts[mime->cur_part]->msg,
&msg_stream);
}
else
else if (!mime->part_stream)
{
mu_body_t part_body;
if (mime->cur_part >= mime->nmtp_parts)
return 0;
{
*nbytes = total;
return 0;
}
mu_message_get_body (mime->mtp_parts[mime->cur_part]->msg,
&part_body);
mu_body_get_streamref (part_body, &msg_stream);
ret = mu_body_get_streamref (part_body, &mime->part_stream);
}
mu_stream_seek (msg_stream, mime->part_offset, MU_SEEK_SET, NULL);
ret = mu_stream_read (msg_stream, buf, buflen, &part_nbytes);
if (part_nbytes)
if (ret)
break;
ret = mu_stream_seek (mime->part_stream, mime->part_offset,
MU_SEEK_SET, NULL);
if (ret)
{
mime->part_offset += part_nbytes;
mime->cur_offset += part_nbytes;
if (nbytes)
*nbytes += part_nbytes;
mu_stream_destroy (&mime->part_stream);
break;
}
if (ret == 0 && part_nbytes == 0)
while (buflen > 0 &&
(ret = mu_stream_read (mime->part_stream, buf, buflen,
&part_nbytes)) == 0)
{
mime->flags |= MIME_INSERT_BOUNDARY;
mime->cur_part++;
ADD_CHAR (buf, '\n', mime->cur_offset, buflen, *nbytes);
if (part_nbytes)
{
mime->part_offset += part_nbytes;
mime->cur_offset += part_nbytes;
total += part_nbytes;
buflen -= part_nbytes;
buf += part_nbytes;
}
else
{
mu_stream_destroy (&mime->part_stream);
mime->flags |= MIME_INSERT_BOUNDARY;
mime->cur_part++;
ADD_CHAR (buf, '\n', mime->cur_offset, buflen,
total, nbytes);
break;
}
}
}
while (ret == 0 && part_nbytes == 0
&& mime->cur_part <= mime->nmtp_parts);
while (ret == 0 && mime->cur_part <= mime->nmtp_parts);
}
if (ret)
mu_stream_destroy (&mime->part_stream);
*nbytes = total;
return ret;
}
static int
_mime_body_ioctl (mu_stream_t stream, int code, void *arg)
_mime_body_stream_ioctl (mu_stream_t stream, int code, void *arg)
{
struct _mime_body_stream *mstr = (struct _mime_body_stream *)stream;
mu_mime_t mime = mstr->mime;
......@@ -694,16 +773,18 @@ _mime_body_ioctl (mu_stream_t stream, int code, void *arg)
}
static int
create_mime_body_stream (mu_stream_t *pstr)
create_mime_body_stream (mu_stream_t *pstr, mu_mime_t mime)
{
struct _mime_body_stream *sp =
(struct _mime_body_stream *)_mu_stream_create (sizeof (*sp),
MU_STREAM_READ | MU_STREAM_SEEK);
if (!sp)
return ENOMEM;
sp->stream.read = _mime_body_read;
sp->stream.seek = _mime_body_seek;
sp->stream.ctl = _mime_body_ioctl;
sp->stream.read = _mime_body_stream_read;
sp->stream.seek = _mime_body_stream_seek;
sp->stream.ctl = _mime_body_stream_ioctl;
sp->stream.size = _mime_body_stream_size;
sp->mime = mime;
*pstr = (mu_stream_t) sp;
return 0;
}
......@@ -714,25 +795,7 @@ _mime_body_size (mu_body_t body, size_t *psize)
{
mu_message_t msg = mu_body_get_owner (body);
mu_mime_t mime = mu_message_get_owner (msg);
int i, ret;
size_t size;
if (mime->nmtp_parts == 0)
return EINVAL;
if ((ret = _mime_set_content_type (mime)) != 0)
return ret;
for (i = 0; i < mime->nmtp_parts; i++)
{
mu_message_size (mime->mtp_parts[i]->msg, &size);
*psize += size;
if (mime->nmtp_parts > 1) /* boundary line */
*psize += strlen (mime->boundary) + 3;
}
if (mime->nmtp_parts > 1) /* ending boundary line */
*psize += 2;
return 0;
return _mime_part_size (mime, psize);
}
static int
......@@ -851,6 +914,7 @@ mu_mime_destroy (mu_mime_t *pmime)
free (mime->mtp_parts);
}
mu_stream_destroy (&mime->stream);
mu_stream_destroy (&mime->part_stream);
if (mime->msg && mime->flags & MIME_NEW_MESSAGE)
mu_message_destroy (&mime->msg, mime);
if (mime->content_type)
......@@ -973,7 +1037,7 @@ mu_mime_get_message (mu_mime_t mime, mu_message_t *msg)
mu_message_set_body (mime->msg, body, mime);
mu_body_set_size (body, _mime_body_size, mime->msg);
mu_body_set_lines (body, _mime_body_lines, mime->msg);
ret = create_mime_body_stream (&body_stream);
ret = create_mime_body_stream (&body_stream, mime);
if (ret == 0)
{
mu_body_set_stream (body, body_stream, mime->msg);
......
......@@ -26,62 +26,56 @@ PATTERN END
FILE BEGIN
ENVELOPE FROM: coyote@desert.example.org
ENVELOPE TO: <gray@gnu.org>
-re
0: X-Authentication-Warning: [^ \t]+ set sender using -f flag
1: X-Loop-Prevention: foobar@nonexistent.net
2: From: coyote@desert.example.org
3: To: roadrunner@acme.example.com
4: Subject: I have a present for you
5: X-Caffeine: C8H10N4O2
6:
7: Look, I'm sorry about the whole anvil thing, and I really
8: didn't mean to try and drop it on you from the top of the
9: cliff. I want to try to make it up to you. I've got some
10: great birdseed over here at my place--top of the line
11: stuff--and if you come by, I'll have it all wrapped up
12: for you. I'm really sorry for all the problems I've caused
13: for you over the years, but I know we can work this out.
14:
15: --
16: Wile E. Coyote "Super Genius" coyote@desert.example.org
17:
0: X-Loop-Prevention: foobar@nonexistent.net
1: From: coyote@desert.example.org
2: To: roadrunner@acme.example.com
3: Subject: I have a present for you
4: X-Caffeine: C8H10N4O2
5:
6: Look, I'm sorry about the whole anvil thing, and I really
7: didn't mean to try and drop it on you from the top of the
8: cliff. I want to try to make it up to you. I've got some
9: great birdseed over here at my place--top of the line
10: stuff--and if you come by, I'll have it all wrapped up
11: for you. I'm really sorry for all the problems I've caused
12: for you over the years, but I know we can work this out.
13:
14: --
15: Wile E. Coyote "Super Genius" coyote@desert.example.org
16:
END OF MESSAGE
ENVELOPE FROM: b1ff@de.res.example.com
ENVELOPE TO: <gray@gnu.org>
-re
0: X-Authentication-Warning: [^ \t]+ set sender using -f flag
1: X-Loop-Prevention: foobar@nonexistent.net
2: From: youcouldberich!@reply-by-postal-mail.invalid
3: To: rube@landru.example.edu
4: Subject: $$$ YOU, TOO, CAN BE A MILLIONAIRE! $$$
5: Date: TBD
6: X-Number: 0015
7:
8: YOU MAY HAVE ALREADY WON TEN MILLION DOLLARS, BUT I DOUBT
9: IT! SO JUST POST THIS TO SIX HUNDRED NEWSGROUPS! IT WILL
10: GUARANTEE THAT YOU GET AT LEAST FIVE RESPONSES WITH MONEY!
11: MONEY! MONEY! COLD HARD CASH! YOU WILL RECEIVE OVER
12: $20,000 IN LESS THAN TWO MONTHS! AND IT'S LEGAL!!!!!!!!!
13: !!!!!!!!!!!!!!!!!!111111111!!!!!!!11111111111!!1 JUST
14: SEND $5 IN SMALL, UNMARKED BILLS TO THE ADDRESSES BELOW!
15:
0: X-Loop-Prevention: foobar@nonexistent.net
1: From: youcouldberich!@reply-by-postal-mail.invalid
2: To: rube@landru.example.edu
3: Subject: $$$ YOU, TOO, CAN BE A MILLIONAIRE! $$$
4: Date: TBD
5: X-Number: 0015
6:
7: YOU MAY HAVE ALREADY WON TEN MILLION DOLLARS, BUT I DOUBT
8: IT! SO JUST POST THIS TO SIX HUNDRED NEWSGROUPS! IT WILL
9: GUARANTEE THAT YOU GET AT LEAST FIVE RESPONSES WITH MONEY!
10: MONEY! MONEY! COLD HARD CASH! YOU WILL RECEIVE OVER
11: $20,000 IN LESS THAN TWO MONTHS! AND IT'S LEGAL!!!!!!!!!
12: !!!!!!!!!!!!!!!!!!111111111!!!!!!!11111111111!!1 JUST
13: SEND $5 IN SMALL, UNMARKED BILLS TO THE ADDRESSES BELOW!
14:
END OF MESSAGE
ENVELOPE FROM: bar@dontmailme.org
ENVELOPE TO: <gray@gnu.org>
-re
0: X-Authentication-Warning: [^ \t]+ set sender using -f flag
1: X-Loop-Prevention: foobar@nonexistent.net
2: Received: (from bar@dontmailme.org)
3: by dontmailme.org id fERKR9N16790
4: for foobar@nonexistent.net; Fri, 28 Dec 2001 22:18:08 +0200
5: Date: Fri, 28 Dec 2001 23:28:08 +0200
6: From: Bar <bar@dontmailme.org>
7: To: Foo Bar <foobar@nonexistent.net>
8: Message-Id: <200112232808.fERKR9N16790@dontmailme.org>
9: Subject: Coffee
10:
11: How about some coffee?
12:
0: X-Loop-Prevention: foobar@nonexistent.net
1: Received: (from bar@dontmailme.org)
2: by dontmailme.org id fERKR9N16790
3: for foobar@nonexistent.net; Fri, 28 Dec 2001 22:18:08 +0200
4: Date: Fri, 28 Dec 2001 23:28:08 +0200
5: From: Bar <bar@dontmailme.org>
6: To: Foo Bar <foobar@nonexistent.net>
7: Message-Id: <200112232808.fERKR9N16790@dontmailme.org>
8: Subject: Coffee
9:
10: How about some coffee?
11:
END OF MESSAGE
FILE END
TEST END
......