Hi there,

Quoting RFC 3501 sec. 7.4.2 “FETCH Response” (data item BODYSTRUCTURE):

    “A body type of type MESSAGE and subtype RFC822 contains,
     immediately after the basic fields, the envelope structure, body
     structure, and size in text lines of the encapsulated message.”

According the ABNF (RFC 3501 sec. 9) the envelope structure is that of
the ENVELOPE FETCH data item, and the env-{from,sender,reply-to,to,cc,
bcc} fields are non-space-separated address lists:

    body-type-msg = media-message SP body-fields SP envelope SP body SP 
body-fld-lines
    envelope      = "(" env-from SP … SP env-to SP … ")"
    env-from      = "(" 1*address ")" / nil
    env-to        = "(" 1*address ")" / nil

While this is indeed the case for ‘FETCH … (ENVELOPE)’, for ‘FETCH …
(BODY)’ dovecot 2.2.25 adds a space between addresses of an address list
of the envelope structure of an encapsulated MESSAGE/RFC822 message.

See the attached patch to ‘src/lib-imap/test-imap-bodystructure.c’,
which currently (2.2.25) fails as follows

    test-imap-bodystructure.c:122: Assert failed: strcmp(str_c(str), 
testmsg_body) == 0
    test-imap-bodystructure.c:129: Assert failed: strcmp(str_c(str), 
testmsg_bodystructure) == 0
    imap bodystructure parser ............................................ : 
FAILED

because the ‘env-to’ field of the envelope structure of the encapsulated
MESSAGE/RFC822 message is printed as

    ((NIL NIL "sub-to1" "domain.org") (NIL NIL "sub-to2" "domain.org"))

while it should be

    ((NIL NIL "sub-to1" "domain.org")(NIL NIL "sub-to2" "domain.org"))

After a quick look at the source, this seems to be due to
src/lib-imap/imap-bodystructure.c:imap_write_list, which always
separates list items with spaces.  In the case of an envelope, only the
top-level list should be space-separated.  Indeed, not adding a space
between items of type IMAP_ARG_LIST in the recursive call makes the test
pass again.

Cheers,
-- 
Guilhem.
--- a/src/lib-imap/test-imap-bodystructure.c
+++ b/src/lib-imap/test-imap-bodystructure.c
@@ -31,6 +31,7 @@ static const char testmsg[] =
 "Content-Type: message/rfc822\n"
 "\n"
 "From: s...@domain.org\n"
+"To: sub-...@domain.org, sub-...@domain.org\n"
 "Date: Sun, 12 Aug 2012 12:34:56 +0300\n"
 "Subject: submsg\n"
 "Content-Type: multipart/alternative; boundary=\"sub1\"\n"
@@ -55,10 +56,10 @@ static const char testmsg[] =
 "Root MIME epilogue\n";
 
 static const char testmsg_bodystructure[] =
-"(\"text\" \"x-myown\" (\"charset\" \"us-ascii\" \"foo\" \"quoted\\\"string\") \"<f...@example.com>\" \"hellodescription\" \"7bit\" 7 1 \"Q2hlY2sgSW50ZWdyaXR5IQ==\" (\"inline\" (\"foo\" \"bar\")) (\"en\" \"fi\" \"se\") \"http://example.com/test.txt\";)(\"message\" \"rfc822\" NIL NIL NIL \"7bit\" 368 (\"Sun, 12 Aug 2012 12:34:56 +0300\" \"submsg\" ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub\" \"domain.org\")) NIL NIL NIL NIL NIL) ((\"text\" \"html\" (\"charset\" \"us-ascii\") NIL NIL \"8bit\" 20 1 NIL NIL NIL NIL)(\"text\" \"plain\" (\"charset\" \"us-ascii\") NIL NIL \"7bit\" 21 1 NIL NIL NIL NIL) \"alternative\" (\"boundary\" \"sub1\") NIL NIL NIL) 20 NIL NIL NIL NIL) \"mixed\" (\"boundary\" \"foo bar\") NIL NIL NIL";
+"(\"text\" \"x-myown\" (\"charset\" \"us-ascii\" \"foo\" \"quoted\\\"string\") \"<f...@example.com>\" \"hellodescription\" \"7bit\" 7 1 \"Q2hlY2sgSW50ZWdyaXR5IQ==\" (\"inline\" (\"foo\" \"bar\")) (\"en\" \"fi\" \"se\") \"http://example.com/test.txt\";)(\"message\" \"rfc822\" NIL NIL NIL \"7bit\" 412 (\"Sun, 12 Aug 2012 12:34:56 +0300\" \"submsg\" ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub-to1\" \"domain.org\")(NIL NIL \"sub-to2\" \"domain.org\")) NIL NIL NIL NIL) ((\"text\" \"html\" (\"charset\" \"us-ascii\") NIL NIL \"8bit\" 20 1 NIL NIL NIL NIL)(\"text\" \"plain\" (\"charset\" \"us-ascii\") NIL NIL \"7bit\" 21 1 NIL NIL NIL NIL) \"alternative\" (\"boundary\" \"sub1\") NIL NIL NIL) 21 NIL NIL NIL NIL) \"mixed\" (\"boundary\" \"foo bar\") NIL NIL NIL";
 
 static const char testmsg_body[] =
-"(\"text\" \"x-myown\" (\"charset\" \"us-ascii\" \"foo\" \"quoted\\\"string\") \"<f...@example.com>\" \"hellodescription\" \"7bit\" 7 1)(\"message\" \"rfc822\" NIL NIL NIL \"7bit\" 368 (\"Sun, 12 Aug 2012 12:34:56 +0300\" \"submsg\" ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub\" \"domain.org\")) NIL NIL NIL NIL NIL) ((\"text\" \"html\" (\"charset\" \"us-ascii\") NIL NIL \"8bit\" 20 1)(\"text\" \"plain\" (\"charset\" \"us-ascii\") NIL NIL \"7bit\" 21 1) \"alternative\") 20) \"mixed\"";
+"(\"text\" \"x-myown\" (\"charset\" \"us-ascii\" \"foo\" \"quoted\\\"string\") \"<f...@example.com>\" \"hellodescription\" \"7bit\" 7 1)(\"message\" \"rfc822\" NIL NIL NIL \"7bit\" 412 (\"Sun, 12 Aug 2012 12:34:56 +0300\" \"submsg\" ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub\" \"domain.org\")) ((NIL NIL \"sub-to1\" \"domain.org\")(NIL NIL \"sub-to2\" \"domain.org\")) NIL NIL NIL NIL) ((\"text\" \"html\" (\"charset\" \"us-ascii\") NIL NIL \"8bit\" 20 1)(\"text\" \"plain\" (\"charset\" \"us-ascii\") NIL NIL \"7bit\" 21 1) \"alternative\") 21) \"mixed\"";
 
 static struct message_part *msg_parse(pool_t pool, bool parse_bodystructure)
 {

Attachment: signature.asc
Description: PGP signature

Reply via email to