Commit a43d959f a43d959feceeba5008169a7e8127b8385f64b0e9 by Sergey Poznyakoff

mh: fix burst, provide test cases.

* mh/burst.c (burst_stream): New struct.
(finish_stream): Change signature.
Keep track of current part number and flags.
(flush_stream): Rewrite.
(burst_digest): Remove extra buffering code.  Rely on the
stream buffering instead.
Fixed length-based EB detection.
Return 0 if the message was bursted successfully, 1 if it is
not in digest format.
(burst_or_copy): Revert the condition on burst_digest.

* tests/burst.at: New test.
* tests/Makefile.am (TESTSUITE_AT): Add burst.at
* tests/testsuite.at: Include burst.at
1 parent cf431d85
......@@ -134,7 +134,7 @@ struct burst_map
struct burst_map map; /* Currently built map */
struct burst_map *burst_map; /* Finished burst map */
size_t burst_count; /* Number of items in burst_map */
mu_mailbox_t tmpbox; /* Temporaty mailbox */
mu_mailbox_t tmpbox; /* Temporary mailbox */
struct obstack stk; /* Stack for building burst_map, etc. */
static int burst_or_copy (mu_message_t msg, int recursive, int copy);
......@@ -217,33 +217,70 @@ token_num(int c)
}
}
#define F_FIRST 0x01 /* First part of the message (no EB seen so far) */
#define F_ENCAPS 0x02 /* Within encapsulated part */
struct burst_stream
{
mu_stream_t stream; /* Output stream */
int flags; /* See F_ flags above */
size_t msgno; /* Number of the current message */
size_t partno; /* Number of the part within the message */
};
static void
finish_stream (mu_stream_t *pstr)
finish_stream (struct burst_stream *bs)
{
mu_message_t msg;
mu_stream_seek (*pstr, 0, SEEK_SET, NULL);
msg = mh_stream_to_message (*pstr);
if (!map.first)
mu_mailbox_uidnext (tmpbox, &map.first);
burst_or_copy (msg, recursive, 1);
mu_stream_close (*pstr);
mu_stream_destroy (pstr);
if (bs->stream)
{
mu_message_t msg;
mu_stream_seek (bs->stream, 0, SEEK_SET, NULL);
msg = mh_stream_to_message (bs->stream);
if (!map.first)
mu_mailbox_uidnext (tmpbox, &map.first);
burst_or_copy (msg, recursive, 1);
mu_message_destroy (&msg, mu_message_get_owner (msg));
mu_stream_unref (bs->stream);
bs->stream = 0;
bs->partno++;
bs->flags &= ~F_FIRST;
}
}
static void
flush_stream (mu_stream_t *pstr, char *buf, size_t size)
flush_stream (struct burst_stream *bs, char *buf, size_t size)
{
int rc;
if (size == 0)
return;
if ((rc = mu_temp_file_stream_create (pstr, NULL)))
if (!bs->stream)
{
mu_error (_("Cannot open temporary file: %s"),
mu_strerror (rc));
exit (1);
if ((rc = mu_temp_file_stream_create (&bs->stream, NULL)))
{
mu_error (_("Cannot open temporary file: %s"),
mu_strerror (rc));
exit (1);
}
mu_stream_printf (bs->stream, "X-Burst-Part: %lu %lu %02x\n",
(unsigned long) bs->msgno,
(unsigned long) bs->partno, bs->flags);
if (!bs->flags)
mu_stream_write (bs->stream, "\n", 1, NULL);
if (verbose && !inplace)
{
size_t nextuid;
mu_mailbox_uidnext (tmpbox, &nextuid);
printf (_("message %lu of digest %lu becomes message %lu\n"),
(unsigned long) bs->partno,
(unsigned long) bs->msgno,
(unsigned long) nextuid);
}
}
rc = mu_stream_write (*pstr, buf, size, NULL);
rc = mu_stream_write (bs->stream, buf, size, NULL);
if (rc)
{
mu_error (_("error writing temporary stream: %s"),
......@@ -252,95 +289,100 @@ flush_stream (mu_stream_t *pstr, char *buf, size_t size)
}
}
/* Burst an RFC 934 digest. Return 0 if OK, 1 if the message is not
a valid digest.
FIXME: On errors, cleanup and return -1
*/
int
burst_digest (mu_message_t msg)
{
mu_stream_t is, os = NULL;
char *buf;
size_t bufsize;
mu_stream_t is;
char c;
size_t n;
size_t count;
int state = S1;
size_t count = 0;
int eb_length = 0;
struct burst_stream bs;
int result;
bs.stream = NULL;
bs.flags = F_FIRST;
bs.partno = 1;
mh_message_number (msg, &bs.msgno);
mu_message_size (msg, &bufsize);
for (; bufsize > 1; bufsize >>= 1)
if ((buf = malloc (bufsize)))
break;
if (!buf)
{
mu_error (_("cannot burst message: %s"), mu_strerror (ENOMEM));
exit (1);
}
mu_message_get_streamref (msg, &is);
while (mu_stream_read (is, buf, bufsize, &n) == 0
&& n > 0)
while (mu_stream_read (is, &c, 1, &n) == 0
&& n == 1)
{
size_t start, i;
for (i = start = 0; i < n; i++)
int newstate = transtab[state - 1][token_num (c)];
int silent = 0;
if (newstate < 0)
{
int newstate = transtab[state-1][token_num(buf[i])];
if (newstate < 0)
{
newstate = -newstate;
flush_stream (&os, buf + start, i - start);
start = i + 1;
}
newstate = -newstate;
silent = 1;
}
if (state == S1)
if (state == S1)
{
/* GNU extension: check if we have seen enough dashes to
constitute a valid encapsulation boundary. */
if (newstate == S3)
{
/* GNU extension: check if we have seen enough dashes to
constitute a valid encapsulation boundary. */
if (newstate == S3)
eb_length++;
if (eb_length < eb_min_length)
continue; /* Ignore state change */
if (eb_min_length > 1)
{
eb_length++;
if (eb_length < eb_min_length)
continue; /* Ignore state change */
newstate = S4;
finish_stream (&bs);
bs.flags ^= F_ENCAPS;
}
else if (eb_length)
while (eb_length--)
flush_stream (&os, "-", 1);
eb_length = 0;
}
else if (state == S5 && newstate == S2)
{
/* As the automaton traverses from state S5 to S2, the
bursting agent should consider a new message started
and output the first character. */
os = NULL;
count++;
}
else if (state == S3 && newstate == S4)
{
/* As the automaton traverses from state S3 to S4, the
bursting agent should consider the current message ended. */
finish_stream (&os);
}
state = newstate;
else
for (; eb_length; eb_length--, count++)
flush_stream (&bs, "-", 1);
eb_length = 0;
}
else if (state == S5 && newstate == S2)
{
/* As the automaton traverses from state S5 to S2, the
bursting agent should consider a new message started
and output the first character. */
finish_stream (&bs);
}
else if (state == S3 && newstate == S4)
{
/* As the automaton traverses from state S3 to S4, the
bursting agent should consider the current message ended. */
finish_stream (&bs);
bs.flags ^= F_ENCAPS;
}
state = newstate;
if (!silent)
{
flush_stream (&bs, &c, 1);
count++;
}
flush_stream (&os, buf + start, i - start);
}
mu_stream_destroy (&is);
free (buf);
if (os)
if (bs.flags == F_FIRST)
{
mu_stream_destroy (&bs.stream);
result = 1;
}
else if (bs.stream)
{
if (count)
finish_stream (&os);
mu_off_t size = 0;
mu_stream_size (bs.stream, &size);
if (size)
finish_stream (&bs);
else
{
mu_stream_close (os);
mu_stream_destroy (&os);
}
mu_stream_destroy (&bs.stream);
result = 0;
}
return count > 0;
return result;
}
......@@ -358,7 +400,7 @@ burst_or_copy (mu_message_t msg, int recursive, int copy)
map.mime = 1;
return burst_mime (msg);
}
else if (burst_digest (msg))
else if (burst_digest (msg) == 0)
return 0;
}
......@@ -380,9 +422,6 @@ burst_or_copy (mu_message_t msg, int recursive, int copy)
mu_message_get_body (msg, &body);
mu_body_get_streamref (body, &str);
/* FIXME: Check if str is actually destroyed.
See mailbox/message_stream.c
*/
msg = mh_stream_to_message (str);
}
free (value);
......@@ -404,7 +443,7 @@ burst_or_copy (mu_message_t msg, int recursive, int copy)
map.count++;
return 0;
}
return 1;
}
......@@ -490,7 +529,6 @@ msg_copy (size_t num, const char *file)
mu_mailbox_get_message (tmpbox, num, &msg);
mu_message_get_streamref (msg, &istream);
/* FIXME: Implement RFC 934 FSA? */
rc = mu_stream_copy (ostream, istream, 0, NULL);
if (rc)
{
......@@ -499,7 +537,7 @@ msg_copy (size_t num, const char *file)
}
mu_stream_destroy (&istream);
mu_stream_close (ostream);
mu_stream_destroy (&ostream);
......
......@@ -41,6 +41,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
TESTSUITE_AT = \
ali.at\
anno.at\
burst.at\
folder.at\
inc.at\
install-mh.at\
......
# This file is part of GNU Mailutils. -*- Autotest -*-
# Copyright (C) 2010 Free Software Foundation, Inc.
#
# GNU Mailutils is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3, or (at
# your option) any later version.
#
# GNU Mailutils is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
m4_pushdef([MH_KEYWORDS],[burst])
MH_CHECK([burst digest],[burst00 burst-digest],[
mkdir Mail/inbox
AT_DATA([Mail/inbox/1],[
From: Sergey Poznyakoff <gray@example.net>
To: root@example.com
Subject: digest
Initial text.
------- Forwarded message
From: Puszcza hackers
To: Sergey Poznyakoff <gray@gnu.org>
Subject: Hello
Greetings
- ---------
How are you?
------- End of Forwarded message
Regards,
Sergey
])
burst +inbox 1 || exit $?
grep -v ^X-Envelope-Date Mail/inbox/2
grep -v ^X-Envelope-Date Mail/inbox/3
grep -v ^X-Envelope-Date Mail/inbox/4
],
[0],
[X-Burst-Part: 1 1 01
From: Sergey Poznyakoff <gray@example.net>
To: root@example.com
Subject: digest
X-Envelope-Sender: gray@example.net
Initial text.
X-Burst-Part: 1 2 02
From: Puszcza hackers
To: Sergey Poznyakoff <gray@gnu.org>
Subject: Hello
X-Envelope-Sender: GNU-Mailutils
Greetings
---------
How are you?
X-Burst-Part: 1 3 00
X-Envelope-Sender: GNU-MH
Regards,
Sergey
])
MH_CHECK([burst digest /w EB length limit],[burst01 burst-digest-eb-length],[
mkdir Mail/inbox
AT_DATA([Mail/inbox/1],[
From: Sergey Poznyakoff <gray@example.net>
To: root@example.com
Subject: digest
Initial text.
------- Forwarded message
From: Puszcza hackers
To: Sergey Poznyakoff <gray@gnu.org>
Subject: Hello
Greetings
-----
How are you?
------- End of Forwarded message
Regards,
Sergey
])
burst +inbox --length=7 1 || exit $?
grep -v ^X-Envelope-Date Mail/inbox/2
grep -v ^X-Envelope-Date Mail/inbox/3
grep -v ^X-Envelope-Date Mail/inbox/4
],
[0],
[X-Burst-Part: 1 1 01
From: Sergey Poznyakoff <gray@example.net>
To: root@example.com
Subject: digest
X-Envelope-Sender: gray@example.net
Initial text.
X-Burst-Part: 1 2 02
From: Puszcza hackers
To: Sergey Poznyakoff <gray@gnu.org>
Subject: Hello
X-Envelope-Sender: GNU-Mailutils
Greetings
-----
How are you?
X-Burst-Part: 1 3 00
X-Envelope-Sender: GNU-MH
Regards,
Sergey
])
MH_CHECK([burst mime],[burst02 burst-mime],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
burst +inbox 3 || exit $?
grep -v ^X-Envelope-Date: Mail/inbox/6
],
[0],
[Content-Type: text/plain; name="msg.1"; charset="us-ascii"
Content-ID: <5082.1026510189.1@example.net>
Content-Description: How doth
X-Envelope-Sender: gray@Trurl.gnu.org.ua
How doth the little crocodile
Improve his shining tail,
And pour the waters of the Nile
On every golden scale!
`How cheerfully he seems to grin,
How neatly spread his claws,
And welcome little fishes in
With gently smiling jaws!
])
MH_CHECK([burst mime recursive],[burst03 burst-mime-recursive],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
burst +inbox --recursive 4 || exit $?
grep -v ^X-Envelope-Date: Mail/inbox/6
grep -v ^X-Envelope-Date: Mail/inbox/7
grep -v ^X-Envelope-Date: Mail/inbox/8
grep -v ^X-Envelope-Date: Mail/inbox/9
],
[0],
[Content-Type: text/plain; name="msg.21"; charset="us-ascii"
Content-ID: <5122.1026510654.2@example.net>
Content-Description: Father William Part I
X-Envelope-Sender: gray@Trurl.gnu.org.ua
`You are old, Father William,' the young man said,
`And your hair has become very white;
And yet you incessantly stand on your head--
Do you think, at your age, it is right?'
`In my youth,' Father William replied to his son,
`I feared it might injure the brain;
But, now that I'm perfectly sure I have none,
Why, I do it again and again.'
Content-Type: application/octet-stream; name="msg.22"
Content-ID: <5122.1026510654.4@example.net>
Content-Description: Father William Part II
Content-Transfer-Encoding: base64
X-Envelope-Sender: gray@Trurl.gnu.org.ua
YFlvdSBhcmUgb2xkLCcgc2FpZCB0aGUgeW91dGgsIGBhcyBJIG1lbnRpb25lZCBiZWZvcmUsCkFu
ZCBoYXZlIGdyb3duIG1vc3QgdW5jb21tb25seSBmYXQ7CllldCB5b3UgdHVybmVkIGEgYmFjay1z
b21lcnNhdWx0IGluIGF0IHRoZSBkb29yLS0KUHJheSwgd2hhdCBpcyB0aGUgcmVhc29uIG9mIHRo
YXQ/JwoKYEluIG15IHlvdXRoLCcgc2FpZCB0aGUgc2FnZSwgYXMgaGUgc2hvb2sgaGlzIGdyZXkg
bG9ja3MsCmBJIGtlcHQgYWxsIG15IGxpbWJzIHZlcnkgc3VwcGxlCkJ5IHRoZSB1c2Ugb2YgdGhp
cyBvaW50bWVudC0tb25lIHNoaWxsaW5nIHRoZSBib3gtLQpBbGxvdyBtZSB0byBzZWxsIHlvdSBh
IGNvdXBsZT8nCg==
Content-Type: application/octet-stream; name="msg.23"
Content-ID: <5122.1026510654.6@example.net>
Content-Description: Father William Part III
Content-Transfer-Encoding: base64
X-Envelope-Sender: gray@Trurl.gnu.org.ua
YFlvdSBhcmUgb2xkLCcgc2FpZCB0aGUgeW91dGgsIGBhbmQgeW91ciBqYXdzIGFyZSB0b28gd2Vh
awpGb3IgYW55dGhpbmcgdG91Z2hlciB0aGFuIHN1ZXQ7CllldCB5b3UgZmluaXNoZWQgdGhlIGdv
b3NlLCB3aXRoIHRoZSBib25lcyBhbmQgdGhlIGJlYWstLQpQcmF5IGhvdyBkaWQgeW91IG1hbmFn
ZSB0byBkbyBpdD8nCgpgSW4gbXkgeW91dGgsJyBzYWlkIGhpcyBmYXRoZXIsIGBJIHRvb2sgdG8g
dGhlIGxhdywKQW5kIGFyZ3VlZCBlYWNoIGNhc2Ugd2l0aCBteSB3aWZlOwpBbmQgdGhlIG11c2N1
bGFyIHN0cmVuZ3RoLCB3aGljaCBpdCBnYXZlIHRvIG15IGphdywKSGFzIGxhc3RlZCB0aGUgcmVz
dCBvZiBteSBsaWZlLicK
Content-Type: application/octet-stream; name="msg.24"
Content-ID: <5122.1026510654.7@example.net>
Content-Description: Father William Part IV
Content-Transfer-Encoding: base64
X-Envelope-Sender: gray@Trurl.gnu.org.ua
YFlvdSBhcmUgb2xkLCcgc2FpZCB0aGUgeW91dGgsIGBvbmUgd291bGQgaGFyZGx5IHN1cHBvc2UK
VGhhdCB5b3VyIGV5ZSB3YXMgYXMgc3RlYWR5IGFzIGV2ZXI7CllldCB5b3UgYmFsYW5jZWQgYW4g
ZWVsIG9uIHRoZSBlbmQgb2YgeW91ciBub3NlLS0KV2hhdCBtYWRlIHlvdSBzbyBhd2Z1bGx5IGNs
ZXZlcj8nCgpgSSBoYXZlIGFuc3dlcmVkIHRocmVlIHF1ZXN0aW9ucywgYW5kIHRoYXQgaXMgZW5v
dWdoLCcKU2FpZCBoaXMgZmF0aGVyOyBgZG9uJ3QgZ2l2ZSB5b3Vyc2VsZiBhaXJzIQpEbyB5b3Ug
dGhpbmsgSSBjYW4gbGlzdGVuIGFsbCBkYXkgdG8gc3VjaCBzdHVmZj8KQmUgb2ZmLCBvciBJJ2xs
IGtpY2sgeW91IGRvd24gc3RhaXJzIScK
])
MH_CHECK([burst non-digest],[burst04 burst-non-digest],[
MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
burst +inbox 1 || exit $?
],
[0],
[],
[burst: message 1 not in digest format
])
m4_popdef[MH_KEYWORDS])
# End of burst.at
......@@ -55,3 +55,4 @@ m4_include([mhpath.at])
m4_include([mhl.at])
m4_include([anno.at])
m4_include([pick.at])
m4_include([burst.at])
......