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 ...@@ -134,7 +134,7 @@ struct burst_map
134 struct burst_map map; /* Currently built map */ 134 struct burst_map map; /* Currently built map */
135 struct burst_map *burst_map; /* Finished burst map */ 135 struct burst_map *burst_map; /* Finished burst map */
136 size_t burst_count; /* Number of items in burst_map */ 136 size_t burst_count; /* Number of items in burst_map */
137 mu_mailbox_t tmpbox; /* Temporaty mailbox */ 137 mu_mailbox_t tmpbox; /* Temporary mailbox */
138 struct obstack stk; /* Stack for building burst_map, etc. */ 138 struct obstack stk; /* Stack for building burst_map, etc. */
139 139
140 static int burst_or_copy (mu_message_t msg, int recursive, int copy); 140 static int burst_or_copy (mu_message_t msg, int recursive, int copy);
...@@ -217,33 +217,70 @@ token_num(int c) ...@@ -217,33 +217,70 @@ token_num(int c)
217 } 217 }
218 } 218 }
219 219
220 #define F_FIRST 0x01 /* First part of the message (no EB seen so far) */
221 #define F_ENCAPS 0x02 /* Within encapsulated part */
222
223 struct burst_stream
224 {
225 mu_stream_t stream; /* Output stream */
226 int flags; /* See F_ flags above */
227 size_t msgno; /* Number of the current message */
228 size_t partno; /* Number of the part within the message */
229 };
230
220 static void 231 static void
221 finish_stream (mu_stream_t *pstr) 232 finish_stream (struct burst_stream *bs)
222 { 233 {
234 if (bs->stream)
235 {
223 mu_message_t msg; 236 mu_message_t msg;
224 mu_stream_seek (*pstr, 0, SEEK_SET, NULL); 237
225 msg = mh_stream_to_message (*pstr); 238 mu_stream_seek (bs->stream, 0, SEEK_SET, NULL);
239 msg = mh_stream_to_message (bs->stream);
226 if (!map.first) 240 if (!map.first)
227 mu_mailbox_uidnext (tmpbox, &map.first); 241 mu_mailbox_uidnext (tmpbox, &map.first);
228 burst_or_copy (msg, recursive, 1); 242 burst_or_copy (msg, recursive, 1);
229 mu_stream_close (*pstr); 243 mu_message_destroy (&msg, mu_message_get_owner (msg));
230 mu_stream_destroy (pstr); 244 mu_stream_unref (bs->stream);
245 bs->stream = 0;
246
247 bs->partno++;
248 bs->flags &= ~F_FIRST;
249 }
231 } 250 }
232 251
233 static void 252 static void
234 flush_stream (mu_stream_t *pstr, char *buf, size_t size) 253 flush_stream (struct burst_stream *bs, char *buf, size_t size)
235 { 254 {
236 int rc; 255 int rc;
237 256
238 if (size == 0) 257 if (size == 0)
239 return; 258 return;
240 if ((rc = mu_temp_file_stream_create (pstr, NULL))) 259 if (!bs->stream)
260 {
261 if ((rc = mu_temp_file_stream_create (&bs->stream, NULL)))
241 { 262 {
242 mu_error (_("Cannot open temporary file: %s"), 263 mu_error (_("Cannot open temporary file: %s"),
243 mu_strerror (rc)); 264 mu_strerror (rc));
244 exit (1); 265 exit (1);
245 } 266 }
246 rc = mu_stream_write (*pstr, buf, size, NULL); 267 mu_stream_printf (bs->stream, "X-Burst-Part: %lu %lu %02x\n",
268 (unsigned long) bs->msgno,
269 (unsigned long) bs->partno, bs->flags);
270 if (!bs->flags)
271 mu_stream_write (bs->stream, "\n", 1, NULL);
272
273 if (verbose && !inplace)
274 {
275 size_t nextuid;
276 mu_mailbox_uidnext (tmpbox, &nextuid);
277 printf (_("message %lu of digest %lu becomes message %lu\n"),
278 (unsigned long) bs->partno,
279 (unsigned long) bs->msgno,
280 (unsigned long) nextuid);
281 }
282 }
283 rc = mu_stream_write (bs->stream, buf, size, NULL);
247 if (rc) 284 if (rc)
248 { 285 {
249 mu_error (_("error writing temporary stream: %s"), 286 mu_error (_("error writing temporary stream: %s"),
...@@ -252,44 +289,38 @@ flush_stream (mu_stream_t *pstr, char *buf, size_t size) ...@@ -252,44 +289,38 @@ flush_stream (mu_stream_t *pstr, char *buf, size_t size)
252 } 289 }
253 } 290 }
254 291
292 /* Burst an RFC 934 digest. Return 0 if OK, 1 if the message is not
293 a valid digest.
294 FIXME: On errors, cleanup and return -1
295 */
255 int 296 int
256 burst_digest (mu_message_t msg) 297 burst_digest (mu_message_t msg)
257 { 298 {
258 mu_stream_t is, os = NULL; 299 mu_stream_t is;
259 char *buf; 300 char c;
260 size_t bufsize;
261 size_t n; 301 size_t n;
302 size_t count;
262 int state = S1; 303 int state = S1;
263 size_t count = 0;
264 int eb_length = 0; 304 int eb_length = 0;
305 struct burst_stream bs;
306 int result;
265 307
266 mu_message_size (msg, &bufsize); 308 bs.stream = NULL;
267 309 bs.flags = F_FIRST;
268 for (; bufsize > 1; bufsize >>= 1) 310 bs.partno = 1;
269 if ((buf = malloc (bufsize))) 311 mh_message_number (msg, &bs.msgno);
270 break;
271
272 if (!buf)
273 {
274 mu_error (_("cannot burst message: %s"), mu_strerror (ENOMEM));
275 exit (1);
276 }
277 312
278 mu_message_get_streamref (msg, &is); 313 mu_message_get_streamref (msg, &is);
279 while (mu_stream_read (is, buf, bufsize, &n) == 0 314 while (mu_stream_read (is, &c, 1, &n) == 0
280 && n > 0) 315 && n == 1)
281 {
282 size_t start, i;
283
284 for (i = start = 0; i < n; i++)
285 { 316 {
286 int newstate = transtab[state-1][token_num(buf[i])]; 317 int newstate = transtab[state - 1][token_num (c)];
318 int silent = 0;
287 319
288 if (newstate < 0) 320 if (newstate < 0)
289 { 321 {
290 newstate = -newstate; 322 newstate = -newstate;
291 flush_stream (&os, buf + start, i - start); 323 silent = 1;
292 start = i + 1;
293 } 324 }
294 325
295 if (state == S1) 326 if (state == S1)
...@@ -301,10 +332,16 @@ burst_digest (mu_message_t msg) ...@@ -301,10 +332,16 @@ burst_digest (mu_message_t msg)
301 eb_length++; 332 eb_length++;
302 if (eb_length < eb_min_length) 333 if (eb_length < eb_min_length)
303 continue; /* Ignore state change */ 334 continue; /* Ignore state change */
335 if (eb_min_length > 1)
336 {
337 newstate = S4;
338 finish_stream (&bs);
339 bs.flags ^= F_ENCAPS;
340 }
304 } 341 }
305 else if (eb_length) 342 else
306 while (eb_length--) 343 for (; eb_length; eb_length--, count++)
307 flush_stream (&os, "-", 1); 344 flush_stream (&bs, "-", 1);
308 eb_length = 0; 345 eb_length = 0;
309 } 346 }
310 else if (state == S5 && newstate == S2) 347 else if (state == S5 && newstate == S2)
...@@ -312,35 +349,40 @@ burst_digest (mu_message_t msg) ...@@ -312,35 +349,40 @@ burst_digest (mu_message_t msg)
312 /* As the automaton traverses from state S5 to S2, the 349 /* As the automaton traverses from state S5 to S2, the
313 bursting agent should consider a new message started 350 bursting agent should consider a new message started
314 and output the first character. */ 351 and output the first character. */
315 os = NULL; 352 finish_stream (&bs);
316 count++;
317 } 353 }
318 else if (state == S3 && newstate == S4) 354 else if (state == S3 && newstate == S4)
319 { 355 {
320 /* As the automaton traverses from state S3 to S4, the 356 /* As the automaton traverses from state S3 to S4, the
321 bursting agent should consider the current message ended. */ 357 bursting agent should consider the current message ended. */
322 finish_stream (&os); 358 finish_stream (&bs);
359 bs.flags ^= F_ENCAPS;
323 } 360 }
324
325 state = newstate; 361 state = newstate;
362 if (!silent)
363 {
364 flush_stream (&bs, &c, 1);
365 count++;
326 } 366 }
327
328 flush_stream (&os, buf + start, i - start);
329 } 367 }
330 mu_stream_destroy (&is); 368 mu_stream_destroy (&is);
331 369
332 free (buf); 370 if (bs.flags == F_FIRST)
333 if (os)
334 { 371 {
335 if (count) 372 mu_stream_destroy (&bs.stream);
336 finish_stream (&os); 373 result = 1;
337 else
338 {
339 mu_stream_close (os);
340 mu_stream_destroy (&os);
341 } 374 }
375 else if (bs.stream)
376 {
377 mu_off_t size = 0;
378 mu_stream_size (bs.stream, &size);
379 if (size)
380 finish_stream (&bs);
381 else
382 mu_stream_destroy (&bs.stream);
383 result = 0;
342 } 384 }
343 return count > 0; 385 return result;
344 } 386 }
345 387
346 388
...@@ -358,7 +400,7 @@ burst_or_copy (mu_message_t msg, int recursive, int copy) ...@@ -358,7 +400,7 @@ burst_or_copy (mu_message_t msg, int recursive, int copy)
358 map.mime = 1; 400 map.mime = 1;
359 return burst_mime (msg); 401 return burst_mime (msg);
360 } 402 }
361 else if (burst_digest (msg)) 403 else if (burst_digest (msg) == 0)
362 return 0; 404 return 0;
363 } 405 }
364 406
...@@ -380,9 +422,6 @@ burst_or_copy (mu_message_t msg, int recursive, int copy) ...@@ -380,9 +422,6 @@ burst_or_copy (mu_message_t msg, int recursive, int copy)
380 422
381 mu_message_get_body (msg, &body); 423 mu_message_get_body (msg, &body);
382 mu_body_get_streamref (body, &str); 424 mu_body_get_streamref (body, &str);
383 /* FIXME: Check if str is actually destroyed.
384 See mailbox/message_stream.c
385 */
386 msg = mh_stream_to_message (str); 425 msg = mh_stream_to_message (str);
387 } 426 }
388 free (value); 427 free (value);
...@@ -490,7 +529,6 @@ msg_copy (size_t num, const char *file) ...@@ -490,7 +529,6 @@ msg_copy (size_t num, const char *file)
490 529
491 mu_mailbox_get_message (tmpbox, num, &msg); 530 mu_mailbox_get_message (tmpbox, num, &msg);
492 mu_message_get_streamref (msg, &istream); 531 mu_message_get_streamref (msg, &istream);
493 /* FIXME: Implement RFC 934 FSA? */
494 rc = mu_stream_copy (ostream, istream, 0, NULL); 532 rc = mu_stream_copy (ostream, istream, 0, NULL);
495 if (rc) 533 if (rc)
496 { 534 {
......
...@@ -41,6 +41,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac ...@@ -41,6 +41,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
41 TESTSUITE_AT = \ 41 TESTSUITE_AT = \
42 ali.at\ 42 ali.at\
43 anno.at\ 43 anno.at\
44 burst.at\
44 folder.at\ 45 folder.at\
45 inc.at\ 46 inc.at\
46 install-mh.at\ 47 install-mh.at\
......
1 # This file is part of GNU Mailutils. -*- Autotest -*-
2 # Copyright (C) 2010 Free Software Foundation, Inc.
3 #
4 # GNU Mailutils is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License as
6 # published by the Free Software Foundation; either version 3, or (at
7 # your option) any later version.
8 #
9 # GNU Mailutils is distributed in the hope that it will be useful, but
10 # WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 # General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
16
17 m4_pushdef([MH_KEYWORDS],[burst])
18
19 MH_CHECK([burst digest],[burst00 burst-digest],[
20 mkdir Mail/inbox
21 AT_DATA([Mail/inbox/1],[
22 From: Sergey Poznyakoff <gray@example.net>
23 To: root@example.com
24 Subject: digest
25
26 Initial text.
27
28 ------- Forwarded message
29 From: Puszcza hackers
30 To: Sergey Poznyakoff <gray@gnu.org>
31 Subject: Hello
32
33 Greetings
34 - ---------
35 How are you?
36 ------- End of Forwarded message
37
38 Regards,
39 Sergey
40 ])
41
42 burst +inbox 1 || exit $?
43 grep -v ^X-Envelope-Date Mail/inbox/2
44 grep -v ^X-Envelope-Date Mail/inbox/3
45 grep -v ^X-Envelope-Date Mail/inbox/4
46 ],
47 [0],
48 [X-Burst-Part: 1 1 01
49 From: Sergey Poznyakoff <gray@example.net>
50 To: root@example.com
51 Subject: digest
52 X-Envelope-Sender: gray@example.net
53
54 Initial text.
55
56 X-Burst-Part: 1 2 02
57 From: Puszcza hackers
58 To: Sergey Poznyakoff <gray@gnu.org>
59 Subject: Hello
60 X-Envelope-Sender: GNU-Mailutils
61
62 Greetings
63 ---------
64 How are you?
65 X-Burst-Part: 1 3 00
66 X-Envelope-Sender: GNU-MH
67
68 Regards,
69 Sergey
70 ])
71
72 MH_CHECK([burst digest /w EB length limit],[burst01 burst-digest-eb-length],[
73 mkdir Mail/inbox
74 AT_DATA([Mail/inbox/1],[
75 From: Sergey Poznyakoff <gray@example.net>
76 To: root@example.com
77 Subject: digest
78
79 Initial text.
80
81 ------- Forwarded message
82 From: Puszcza hackers
83 To: Sergey Poznyakoff <gray@gnu.org>
84 Subject: Hello
85
86 Greetings
87 -----
88 How are you?
89 ------- End of Forwarded message
90
91 Regards,
92 Sergey
93 ])
94
95 burst +inbox --length=7 1 || exit $?
96 grep -v ^X-Envelope-Date Mail/inbox/2
97 grep -v ^X-Envelope-Date Mail/inbox/3
98 grep -v ^X-Envelope-Date Mail/inbox/4
99 ],
100 [0],
101 [X-Burst-Part: 1 1 01
102 From: Sergey Poznyakoff <gray@example.net>
103 To: root@example.com
104 Subject: digest
105 X-Envelope-Sender: gray@example.net
106
107 Initial text.
108
109 X-Burst-Part: 1 2 02
110 From: Puszcza hackers
111 To: Sergey Poznyakoff <gray@gnu.org>
112 Subject: Hello
113 X-Envelope-Sender: GNU-Mailutils
114
115 Greetings
116 -----
117 How are you?
118 X-Burst-Part: 1 3 00
119 X-Envelope-Sender: GNU-MH
120
121 Regards,
122 Sergey
123 ])
124
125 MH_CHECK([burst mime],[burst02 burst-mime],[
126 MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
127 burst +inbox 3 || exit $?
128 grep -v ^X-Envelope-Date: Mail/inbox/6
129 ],
130 [0],
131 [Content-Type: text/plain; name="msg.1"; charset="us-ascii"
132 Content-ID: <5082.1026510189.1@example.net>
133 Content-Description: How doth
134 X-Envelope-Sender: gray@Trurl.gnu.org.ua
135
136 How doth the little crocodile
137 Improve his shining tail,
138 And pour the waters of the Nile
139 On every golden scale!
140
141 `How cheerfully he seems to grin,
142 How neatly spread his claws,
143 And welcome little fishes in
144 With gently smiling jaws!
145 ])
146
147 MH_CHECK([burst mime recursive],[burst03 burst-mime-recursive],[
148 MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
149 burst +inbox --recursive 4 || exit $?
150 grep -v ^X-Envelope-Date: Mail/inbox/6
151 grep -v ^X-Envelope-Date: Mail/inbox/7
152 grep -v ^X-Envelope-Date: Mail/inbox/8
153 grep -v ^X-Envelope-Date: Mail/inbox/9
154 ],
155 [0],
156 [Content-Type: text/plain; name="msg.21"; charset="us-ascii"
157 Content-ID: <5122.1026510654.2@example.net>
158 Content-Description: Father William Part I
159 X-Envelope-Sender: gray@Trurl.gnu.org.ua
160
161 `You are old, Father William,' the young man said,
162 `And your hair has become very white;
163 And yet you incessantly stand on your head--
164 Do you think, at your age, it is right?'
165
166 `In my youth,' Father William replied to his son,
167 `I feared it might injure the brain;
168 But, now that I'm perfectly sure I have none,
169 Why, I do it again and again.'
170
171 Content-Type: application/octet-stream; name="msg.22"
172 Content-ID: <5122.1026510654.4@example.net>
173 Content-Description: Father William Part II
174 Content-Transfer-Encoding: base64
175 X-Envelope-Sender: gray@Trurl.gnu.org.ua
176
177 YFlvdSBhcmUgb2xkLCcgc2FpZCB0aGUgeW91dGgsIGBhcyBJIG1lbnRpb25lZCBiZWZvcmUsCkFu
178 ZCBoYXZlIGdyb3duIG1vc3QgdW5jb21tb25seSBmYXQ7CllldCB5b3UgdHVybmVkIGEgYmFjay1z
179 b21lcnNhdWx0IGluIGF0IHRoZSBkb29yLS0KUHJheSwgd2hhdCBpcyB0aGUgcmVhc29uIG9mIHRo
180 YXQ/JwoKYEluIG15IHlvdXRoLCcgc2FpZCB0aGUgc2FnZSwgYXMgaGUgc2hvb2sgaGlzIGdyZXkg
181 bG9ja3MsCmBJIGtlcHQgYWxsIG15IGxpbWJzIHZlcnkgc3VwcGxlCkJ5IHRoZSB1c2Ugb2YgdGhp
182 cyBvaW50bWVudC0tb25lIHNoaWxsaW5nIHRoZSBib3gtLQpBbGxvdyBtZSB0byBzZWxsIHlvdSBh
183 IGNvdXBsZT8nCg==
184 Content-Type: application/octet-stream; name="msg.23"
185 Content-ID: <5122.1026510654.6@example.net>
186 Content-Description: Father William Part III
187 Content-Transfer-Encoding: base64
188 X-Envelope-Sender: gray@Trurl.gnu.org.ua
189
190 YFlvdSBhcmUgb2xkLCcgc2FpZCB0aGUgeW91dGgsIGBhbmQgeW91ciBqYXdzIGFyZSB0b28gd2Vh
191 awpGb3IgYW55dGhpbmcgdG91Z2hlciB0aGFuIHN1ZXQ7CllldCB5b3UgZmluaXNoZWQgdGhlIGdv
192 b3NlLCB3aXRoIHRoZSBib25lcyBhbmQgdGhlIGJlYWstLQpQcmF5IGhvdyBkaWQgeW91IG1hbmFn
193 ZSB0byBkbyBpdD8nCgpgSW4gbXkgeW91dGgsJyBzYWlkIGhpcyBmYXRoZXIsIGBJIHRvb2sgdG8g
194 dGhlIGxhdywKQW5kIGFyZ3VlZCBlYWNoIGNhc2Ugd2l0aCBteSB3aWZlOwpBbmQgdGhlIG11c2N1
195 bGFyIHN0cmVuZ3RoLCB3aGljaCBpdCBnYXZlIHRvIG15IGphdywKSGFzIGxhc3RlZCB0aGUgcmVz
196 dCBvZiBteSBsaWZlLicK
197 Content-Type: application/octet-stream; name="msg.24"
198 Content-ID: <5122.1026510654.7@example.net>
199 Content-Description: Father William Part IV
200 Content-Transfer-Encoding: base64
201 X-Envelope-Sender: gray@Trurl.gnu.org.ua
202
203 YFlvdSBhcmUgb2xkLCcgc2FpZCB0aGUgeW91dGgsIGBvbmUgd291bGQgaGFyZGx5IHN1cHBvc2UK
204 VGhhdCB5b3VyIGV5ZSB3YXMgYXMgc3RlYWR5IGFzIGV2ZXI7CllldCB5b3UgYmFsYW5jZWQgYW4g
205 ZWVsIG9uIHRoZSBlbmQgb2YgeW91ciBub3NlLS0KV2hhdCBtYWRlIHlvdSBzbyBhd2Z1bGx5IGNs
206 ZXZlcj8nCgpgSSBoYXZlIGFuc3dlcmVkIHRocmVlIHF1ZXN0aW9ucywgYW5kIHRoYXQgaXMgZW5v
207 dWdoLCcKU2FpZCBoaXMgZmF0aGVyOyBgZG9uJ3QgZ2l2ZSB5b3Vyc2VsZiBhaXJzIQpEbyB5b3Ug
208 dGhpbmsgSSBjYW4gbGlzdGVuIGFsbCBkYXkgdG8gc3VjaCBzdHVmZj8KQmUgb2ZmLCBvciBJJ2xs
209 IGtpY2sgeW91IGRvd24gc3RhaXJzIScK
210 ])
211
212 MH_CHECK([burst non-digest],[burst04 burst-non-digest],[
213 MUT_MBCOPY($abs_top_srcdir/testsuite/mh/mbox1,[Mail/inbox])
214 burst +inbox 1 || exit $?
215 ],
216 [0],
217 [],
218 [burst: message 1 not in digest format
219 ])
220
221 m4_popdef[MH_KEYWORDS])
222 # End of burst.at
223
...@@ -55,3 +55,4 @@ m4_include([mhpath.at]) ...@@ -55,3 +55,4 @@ m4_include([mhpath.at])
55 m4_include([mhl.at]) 55 m4_include([mhl.at])
56 m4_include([anno.at]) 56 m4_include([anno.at])
57 m4_include([pick.at]) 57 m4_include([pick.at])
58 m4_include([burst.at])
......