diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-11-23 21:54:28 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-11-23 21:54:28 +0200 |
commit | 78132d34760448ad268a92908b2a75f6394f6fec (patch) | |
tree | d18ddaf794ff38bcbc0c58167c32b95e307140d3 | |
parent | a0b4f3b1203503ba7e8f8d545d16fa77d740e4e7 (diff) | |
download | mailutils-78132d34760448ad268a92908b2a75f6394f6fec.tar.gz mailutils-78132d34760448ad268a92908b2a75f6394f6fec.tar.bz2 |
MIME: part boundary in not required to be followed by a newlie.
* libmailutils/mime/mime.c: Part boundary can be eitherr followd
by a newline, or appear at the very end of input.
* testsuite/Makefile.am: Add mime01.at
* testsuite/testsuite.at: Include mime01.at.
* testsuite/mime01.at: New file.
* testsuite/mime.at: Update expected output. Don't filter output
through tr & sed.
* testsuite/mimetest.c: Change output to make sure no trailing
whitespace could be produced.
-rw-r--r-- | libmailutils/mime/mime.c | 134 | ||||
-rw-r--r-- | testsuite/Makefile.am | 1 | ||||
-rw-r--r-- | testsuite/mime.at | 109 | ||||
-rw-r--r-- | testsuite/mime01.at | 130 | ||||
-rw-r--r-- | testsuite/mimetest.c | 20 | ||||
-rw-r--r-- | testsuite/testsuite.at | 1 |
6 files changed, 269 insertions, 126 deletions
diff --git a/libmailutils/mime/mime.c b/libmailutils/mime/mime.c index e4463d307..123a8642c 100644 --- a/libmailutils/mime/mime.c +++ b/libmailutils/mime/mime.c @@ -260,7 +260,7 @@ _mime_append_header_line (mu_mime_t mime) static int _mime_parse_mpart_message (mu_mime_t mime) { - char *cp, *cp2; + char *cp; size_t blength, mb_length, mb_offset, mb_lines; int ret; size_t nbytes; @@ -294,9 +294,76 @@ _mime_parse_mpart_message (mu_mime_t mime) &nbytes)) == 0 && nbytes) { cp = mime->cur_buf; - while (nbytes) + + while (1) { mime->cur_line[mime->line_ndx] = *cp; + if (mime->parser_state == MIME_STATE_SCAN_BOUNDARY + && (nbytes == 0 || *cp == '\n')) + { + char *cp2 = mime->cur_line[0] == '\n' + ? mime->cur_line + 1 : mime->cur_line; + if (mime->line_ndx >= blength + && ((memcmp (cp2, "--", 2) == 0 + && memcmp (cp2 + 2, mime->boundary, blength) == 0) + || memcmp (cp2, mime->boundary, blength) == 0)) + { + mime->parser_state = MIME_STATE_HEADERS; + mime->flags &= ~MIME_PARSER_HAVE_CR; + mb_length = mime->cur_offset + - mb_offset + - mime->line_ndx; + if (mime->header_length) + /* this skips the preamble */ + { + /* RFC 1521 [Page 30]: + NOTE: The CRLF preceding the encapsulation + line is conceptually attached to the boundary + so that it is possible to have a part that + does not end with a CRLF (line break). Body + parts that must be considered to end with line + breaks, therefore, must have two CRLFs + preceding the encapsulation line, the first + of which is part of the preceding body part, + and the second of which is part of the + encapsulation boundary. */ + + if (mb_lines) + /* to prevent negative values in case of a + malformed message */ + mb_lines--; + + _mime_append_part (mime, NULL, + mb_offset, mb_length, + mb_lines); + } + + if ((&mime->cur_line[mime->line_ndx] - cp2 - 1 > blength + && memcmp (cp2 + blength + 2, "--", 2) == 0) + || (&mime->cur_line[mime->line_ndx] - cp2 - 1 == blength + && memcmp (cp2 + blength, "--", 2) == 0)) + { /* last boundary */ + mime->parser_state = MIME_STATE_BEGIN_LINE; + mime->header_length = 0; + } + else + mime->line_ndx = -1; /* headers parsing requires + empty line */ + } + else if (nbytes) + { + if (mime->header_length) + mb_lines++; + + mime->line_ndx = 0; + mime->cur_line[0] = *cp; /* stay in this state but + leave '\n' at begining */ + } + } + + if (nbytes == 0) + break; + if (*cp == '\n') { switch (mime->parser_state) @@ -308,68 +375,6 @@ _mime_parse_mpart_message (mu_mime_t mime) break; case MIME_STATE_SCAN_BOUNDARY: - cp2 = mime->cur_line[0] == '\n' - ? mime->cur_line + 1 : mime->cur_line; - if (mime->line_ndx >= blength) - { - if ((!strncmp (cp2, "--", 2) - && !mu_c_strncasecmp (cp2 + 2, mime->boundary, - blength)) - || !mu_c_strncasecmp (cp2, mime->boundary, blength)) - { - mime->parser_state = MIME_STATE_HEADERS; - mime->flags &= ~MIME_PARSER_HAVE_CR; - mb_length = mime->cur_offset - - mb_offset - - mime->line_ndx; - if (mime->header_length) - /* this skips the preamble */ - { - /* RFC 1521 [Page 30]: - NOTE: The CRLF preceding the encapsulation - line is conceptually attached to the boundary - so that it is possible to have a part that - does not end with a CRLF (line break). Body - parts that must be considered to end with line - breaks, therefore, must have two CRLFs - preceding the encapsulation line, the first - of which is part of the preceding body part, - and the second of which is part of the - encapsulation boundary. */ - - if (mb_lines) - /* to prevent negative values in case of a - malformed message */ - mb_lines--; - - _mime_append_part (mime, NULL, - mb_offset, mb_length, - mb_lines); - } - - if ((&mime->cur_line[mime->line_ndx] - cp2 - 1 > - blength - && !strncmp (cp2 + blength + 2, "--", 2)) - || (&mime->cur_line[mime->line_ndx] - cp2 - 1 == - blength - && !strncmp (cp2 + blength, "--", 2))) - { /* last boundary */ - mime->parser_state = MIME_STATE_BEGIN_LINE; - mime->header_length = 0; - } - else - mime->line_ndx = -1; /* headers parsing requires - empty line */ - break; - } - } - - if (mime->header_length) - mb_lines++; - - mime->line_ndx = 0; - mime->cur_line[0] = *cp; /* stay in this state but - leave '\n' at begining */ break; case MIME_STATE_HEADERS: @@ -385,6 +390,7 @@ _mime_parse_mpart_message (mu_mime_t mime) break; } } + mime->line_ndx++; if (mime->line_ndx >= mime->line_size) { diff --git a/testsuite/Makefile.am b/testsuite/Makefile.am index e0eeba031..42e73dd63 100644 --- a/testsuite/Makefile.am +++ b/testsuite/Makefile.am @@ -91,6 +91,7 @@ TESTSUITE_AT = \ lstuid02.at\ mbdel.at\ mime.at\ + mime01.at\ smtp-msg.at\ smtp-str.at\ ufms.at\ diff --git a/testsuite/mime.at b/testsuite/mime.at index 872002cf0..0afadec0d 100644 --- a/testsuite/mime.at +++ b/testsuite/mime.at @@ -18,16 +18,15 @@ AT_SETUP([mime]) # FIXME: Mimetest should probably be fixed to avoid the use of `tr' # and `sed' here. -AT_CHECK([mimetest -i 0 -p $abs_top_srcdir/testsuite/spool/mbox1 | dnl - tr '\t' ' ' | sed 's/ *$//'], +AT_CHECK([mimetest -i 0 -p $abs_top_srcdir/testsuite/spool/mbox1], [0], -[Message: 1 -From: Foo Bar <foobar@nonexistent.net> -Subject: Jabberwocky -Number of parts in message - 1 -Total message size - 1254/44 -Type of part 1 = -Message part size - 1254/44: 317/9, 937/35 +[Message:1 +From:Foo Bar <foobar@nonexistent.net> +Subject:Jabberwocky +Number of parts in message:1 +Total message size:1254/44 +Type of part 1: +Message part size:1254/44: 317/9, 937/35 Text Message Begin `Twas brillig, and the slithy toves @@ -67,13 +66,13 @@ And the mome raths outgrabe. End -Message: 2 -From: Bar <bar@dontmailme.org> -Subject: Re: Jabberwocky -Number of parts in message - 1 -Total message size - 534/13 -Type of part 1 = -Message part size - 534/13: 319/9, 215/4 +Message:2 +From:Bar <bar@dontmailme.org> +Subject:Re: Jabberwocky +Number of parts in message:1 +Total message size:534/13 +Type of part 1: +Message part size:534/13: 319/9, 215/4 Text Message Begin It seems very pretty, but it's *rather* hard to understand!' @@ -82,13 +81,13 @@ exactly know what they are! However, SOMEBODY killed SOMETHING: that's clear, at any rate... End -Message: 3 -From: Sergey Poznyakoff <gray@example.net> -Subject: Simple MIME -Number of parts in message - 2 -Total message size - 1569/42 -Type of part 1 = text/plain -Message part size - 364/13: 134/4, 230/9 +Message:3 +From:Sergey Poznyakoff <gray@example.net> +Subject:Simple MIME +Number of parts in message:2 +Total message size:1569/42 +Type of part 1:text/plain +Message part size:364/13: 134/4, 230/9 Text Message Begin How doth the little crocodile @@ -102,8 +101,8 @@ And welcome little fishes in With gently smiling jaws! End -Type of part 2 = application/octet-stream -Message part size - 638/11: 176/5, 462/6 +Type of part 2:application/octet-stream +Message part size:638/11: 176/5, 462/6 Attachment - saving [[msg.21]] Begin `You are old, Father William,' the young man said, @@ -118,13 +117,13 @@ Why, I do it again and again.' End -Message: 4 -From: Sergey Poznyakoff <gray@example.net> -Subject: Nested MIME -Number of parts in message - 2 -Total message size - 3399/84 -Type of part 1 = text/plain -Message part size - 489/14: 148/4, 341/10 +Message:4 +From:Sergey Poznyakoff <gray@example.net> +Subject:Nested MIME +Number of parts in message:2 +Total message size:3399/84 +Type of part 1:text/plain +Message part size:489/14: 148/4, 341/10 Text Message Begin `You are old, Father William,' the young man said, @@ -139,12 +138,14 @@ Why, I do it again and again.' End -Type of part 2 = multipart/mixed -Message part size - 2343/52: 107/3, 2236/49 -Encapsulated message : +Type of part 2:multipart/mixed +Message part size:2343/52: 107/3, 2236/49 +Encapsulated message: +From: +Subject: Begin -Type of part 1 = application/octet-stream -Message part size - 656/12: 177/5, 479/7 +Type of part 1:application/octet-stream +Message part size:656/12: 177/5, 479/7 Attachment - saving [[msg.22]] Begin `You are old,' said the youth, `as I mentioned before, @@ -158,12 +159,14 @@ By the use of this ointment--one shilling the box-- Allow me to sell you a couple?' End -Type of part 2 = multipart/mixed -Message part size - 1510/32: 107/3, 1403/29 -Encapsulated message : +Type of part 2:multipart/mixed +Message part size:1510/32: 107/3, 1403/29 +Encapsulated message: +From: +Subject: Begin -Type of part 1 = application/octet-stream -Message part size - 661/12: 178/5, 483/7 +Type of part 1:application/octet-stream +Message part size:661/12: 178/5, 483/7 Attachment - saving [[msg.23]] Begin `You are old,' said the youth, `and your jaws are too weak @@ -177,8 +180,8 @@ And the muscular strength, which it gave to my jaw, Has lasted the rest of my life.' End -Type of part 2 = application/octet-stream -Message part size - 672/12: 177/5, 495/7 +Type of part 2:application/octet-stream +Message part size:672/12: 177/5, 495/7 Attachment - saving [[msg.24]] Begin `You are old,' said the youth, `one would hardly suppose @@ -196,19 +199,19 @@ End End End -Message: 5 -From: Sergey Poznyakoff <gray@example.net> -Subject: Empty MIME Parts -Number of parts in message - 2 -Total message size - 857/27 -Type of part 1 = text/plain -Message part size - 136/4: 136/4, 0/0 +Message:5 +From:Sergey Poznyakoff <gray@example.net> +Subject:Empty MIME Parts +Number of parts in message:2 +Total message size:857/27 +Type of part 1:text/plain +Message part size:136/4: 136/4, 0/0 Text Message Begin End -Type of part 2 = text/plain -Message part size - 149/5: 148/4, 1/1 +Type of part 2:text/plain +Message part size:149/5: 148/4, 1/1 Text Message Begin diff --git a/testsuite/mime01.at b/testsuite/mime01.at new file mode 100644 index 000000000..f82a16de7 --- /dev/null +++ b/testsuite/mime01.at @@ -0,0 +1,130 @@ +# This file is part of GNU Mailutils. -*- Autotest -*- +# Copyright (C) 2017 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/>. + +AT_SETUP([mime - adjacent closing delimiters]) +AT_DATA([in.msg], +[From foo@example.com Wed Nov 22 16:55:56 2017 +MIME-Version: 1.0 +From: Foo Bar <foo@example.com> +Date: Wed, 22 Nov 2017 18:54:55 +0200 +Subject: MIME delimiter test +To: Gray <gray@example.org> +Content-Type: multipart/mixed; boundary="94eb2c190d42daa45d055e952d64" + +--94eb2c190d42daa45d055e952d64 +Content-Type: multipart/alternative; boundary="94eb2c190d42daa45a055e952d62" + +--94eb2c190d42daa45a055e952d62 +Content-Type: text/plain; charset="UTF-8" +Content-Transfer-Encoding: base64 + +SGllciBsaWVndCBlaW4gTWFubiBnYW56IG9ibmVnbGVpY2g7CkltIExlaWJlIGRpY2ssIGFuIFN1 +ZGVuIHJlaWNoLgpXaXIgaGFiZW4gaWhuIGluIGRhcyBHcmFiIGdlc3RlY2t0LCAgICAgSGVyZSBs +aWVzIGEgbWFuIHdpdGggc3VuZHJ5IGZsYXdzCldlaWwgZXMgdW5zIGR1bmt0IGVyIHNlaSB2ZXJy +ZWNrdC4gICAgICBBbmQgbnVtZXJvdXMgU2lucyB1cG9uIGhpcyBoZWFkOwogICAgICAgICAgICAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgV2UgYnVyaWVkIGhpbSB0b2RheSBiZWNhdXNlCiAg +ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBcyBmYXIgYXMgd2UgY2FuIHRl +bGwsIGhlJ3MgZGVhZC4KCiAgICAgICAgICAgICAgICAtLSBQRFEgQmFjaCdzIGVwaXRhcGgsIGFz +IHJlcXVlc3RlZCBieSBoaXMgY291c2luIEJldHR5CiAgICAgICAgICAgICAgICAgICBTdWUgQmFj +aCBhbmQgd3JpdHRlbiBieSB0aGUgbG9jYWwgZG9nZ2VyYWwgY2F0Y2hlcjsKICAgICAgICAgICAg +ICAgICAgICJUaGUgRGVmaW5pdGl2ZSBCaW9ncmFwaHkgb2YgUERRIEJhY2giLCBQZXRlciBTY2hp +Y2tlbGUK +--94eb2c190d42daa45a055e952d62 +Content-Type: text/html; charset="UTF-8" +Content-Transfer-Encoding: base64 + +PGh0bWw+Cjxib2R5Pgo8ZGl2Pgo8ZGl2PjxwcmU+SGllciBsaWVndCBlaW4gTWFubiBnYW56IG9i +bmVnbGVpY2g7CkltIExlaWJlIGRpY2ssIGFuIFN1ZGVuIHJlaWNoLjwvcHJlPgo8L2Rpdj4KPGRp +dj4KIDxkaXY+CiAgIFdpciBoYWJlbiBpaG4gaW4gZGFzIEdyYWIgZ2VzdGVja3QsCiAgIFdlaWwg +ZXMgdW5zIGR1bmt0IGVyIHNlaSB2ZXJyZWNrdC4KIDwvZGl2PgogPGRpdj4KICAgSGVyZSBsaWVz +IGEgbWFuIHdpdGggc3VuZHJ5IGZsYXdzCiAgIEFuZCBudW1lcm91cyBTaW5zIHVwb24gaGlzIGhl +YWQ7CiA8L2Rpdj4KPC9kaXY+CjxkaXY+CldlIGJ1cmllZCBoaW0gdG9kYXkgYmVjYXVzZQpBcyBm +YXIgYXMgd2UgY2FuIHRlbGwsIGhlJ3MgZGVhZC4KPC9kaXY+CjxibG9ja3F1b3RlPgotLSBQRFEg +QmFjaCdzIGVwaXRhcGgsIGFzIHJlcXVlc3RlZCBieSBoaXMgY291c2luIEJldHR5CiAgIFN1ZSBC +YWNoIGFuZCB3cml0dGVuIGJ5IHRoZSBsb2NhbCBkb2dnZXJhbCBjYXRjaGVyOwogICAiVGhlIERl +ZmluaXRpdmUgQmlvZ3JhcGh5IG9mIFBEUSBCYWNoIiwgUGV0ZXIgU2NoaWNrZWxlCjwvYmxvY2tx +dW90ZT4KPC9ib2R5Pgo8L2h0bWw+Cg== +--94eb2c190d42daa45a055e952d62-- +--94eb2c190d42daa45d055e952d64-- +]) + +AT_CHECK([mimetest -i 0 in.msg +], +[0], +[Message:1 +From:Foo Bar <foo@example.com> +Subject:MIME delimiter test +Number of parts in message:1 +Total message size:2189/42 +Type of part 1:multipart/alternative +Message part size:1907/32: 78/2, 1829/30 +Encapsulated message: +From: +Subject: +Begin +Type of part 1:text/plain +Message part size:855/13: 77/3, 778/10 +Text Message +Begin +Hier liegt ein Mann ganz obnegleich; +Im Leibe dick, an Suden reich. +Wir haben ihn in das Grab gesteckt, Here lies a man with sundry flaws +Weil es uns dunkt er sei verreckt. And numerous Sins upon his head; + We buried him today because + As far as we can tell, he's dead. + + -- PDQ Bach's epitaph, as requested by his cousin Betty + Sue Bach and written by the local doggeral catcher; + "The Definitive Biography of PDQ Bach", Peter Schickele + +End +Type of part 2:text/html +Message part size:878/13: 76/3, 802/10 +Text Message +Begin +<html> +<body> +<div> +<div><pre>Hier liegt ein Mann ganz obnegleich; +Im Leibe dick, an Suden reich.</pre> +</div> +<div> + <div> + Wir haben ihn in das Grab gesteckt, + Weil es uns dunkt er sei verreckt. + </div> + <div> + Here lies a man with sundry flaws + And numerous Sins upon his head; + </div> +</div> +<div> +We buried him today because +As far as we can tell, he's dead. +</div> +<blockquote> +-- PDQ Bach's epitaph, as requested by his cousin Betty + Sue Bach and written by the local doggeral catcher; + "The Definitive Biography of PDQ Bach", Peter Schickele +</blockquote> +</body> +</html> + +End + +End +]) +AT_CLEANUP diff --git a/testsuite/mimetest.c b/testsuite/mimetest.c index 0f8e593aa..1f5e11bc4 100644 --- a/testsuite/mimetest.c +++ b/testsuite/mimetest.c @@ -130,14 +130,14 @@ main (int argc, char **argv) from = ""; if (mu_header_sget_value (hdr, MU_HEADER_SUBJECT, &subject)) subject = ""; - printf ("Message: %lu\n", (unsigned long) i); - printf ("From: %s\n", from); - printf ("Subject: %s\n", subject); + printf ("Message:%lu\n", (unsigned long) i); + printf ("From:%s\n", from); + printf ("Subject:%s\n", subject); MU_ASSERT (mu_message_get_num_parts (msg, &nparts)); - printf ("Number of parts in message - %lu\n", + printf ("Number of parts in message:%lu\n", (unsigned long) nparts); - printf ("Total message size - %lu/%lu\n", + printf ("Total message size:%lu/%lu\n", (unsigned long) msize, (unsigned long) nlines); message_display_parts (msg, 0); } @@ -163,7 +163,7 @@ print_message_part_sizes (mu_message_t part, int indent) MU_ASSERT (mu_message_get_body (part, &body)); MU_ASSERT (mu_body_size (body, &bsize)); MU_ASSERT (mu_body_lines (body, &blines)); - printf ("%*.*sMessage part size - %lu/%lu: %lu/%lu, %lu/%lu\n", + printf ("%*.*sMessage part size:%lu/%lu: %lu/%lu, %lu/%lu\n", indent, indent, "", (unsigned long) msize, (unsigned long) mlines, (unsigned long) hsize, (unsigned long) hlines, @@ -214,7 +214,7 @@ message_display_parts (mu_message_t msg, int indent) mu_error ("Cannot extract content type field: %s", mu_strerror (status)); } - printf ("%*.*sType of part %d = %s\n", indent, indent, "", + printf ("%*.*sType of part %d:%s\n", indent, indent, "", j, mu_prstr (type)); print_message_part_sizes (part, indent); if (mu_header_sget_value (hdr, MU_HEADER_CONTENT_TRANSFER_ENCODING, @@ -233,8 +233,10 @@ message_display_parts (mu_message_t msg, int indent) from = ""; if (mu_header_sget_value (hdr, MU_HEADER_SUBJECT, &subject)) subject = ""; - printf ("%*.*sEncapsulated message : %s\t%s\n", - indent, indent, "", from, subject); + printf ("%*.*sEncapsulated message:\n", + indent, indent, ""); + printf ("%*.*sFrom:%s\n", indent, indent, "", from); + printf ("%*.*sSubject:%s\n", indent, indent, "", subject); printf ("%*.*sBegin\n", indent, indent, ""); message_display_parts (part, indent + indent_level); mu_message_destroy (&part, NULL); diff --git a/testsuite/testsuite.at b/testsuite/testsuite.at index addfed025..85d102e35 100644 --- a/testsuite/testsuite.at +++ b/testsuite/testsuite.at @@ -25,6 +25,7 @@ m4_include([lstuid02.at]) AT_BANNER(mimetest) m4_include([mime.at]) +m4_include([mime01.at]) AT_BANNER(Mailbox removal) m4_include([mbdel.at]) |