From 8a6f96f9f2015258175ef8a1d185642f8fe4a84e Mon Sep 17 00:00:00 2001 From: Romain Le Jeune Date: Fri, 29 Sep 2023 07:08:10 +0000 Subject: [PATCH] fix(GODT-2965): fix multipart/mixed testdata + structure parsing steps related to this. --- tests/features/imap/message/import.feature | 78 +++++++++++++--------- tests/types_test.go | 41 +++++++----- 2 files changed, 74 insertions(+), 45 deletions(-) diff --git a/tests/features/imap/message/import.feature b/tests/features/imap/message/import.feature index fb0c4046..377cbaa7 100644 --- a/tests/features/imap/message/import.feature +++ b/tests/features/imap/message/import.feature @@ -322,11 +322,21 @@ Feature: IMAP import messages Content-Type: multipart/mixed; boundary="boundary" Received: by 2002:0:0:0:0:0:0:0 with SMTP id 0123456789abcdef; Wed, 30 Dec 2020 01:23:45 0000 + --boundary + This is a multi-part message in MIME format. + --boundary Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit + Hello + + --boundary + Content-Type: text/html; charset=utf-8 + Content-Transfer-Encoding: 7bit + +

HELLO

--boundary Content-Type: message/rfc822; name="embedded.eml" @@ -345,33 +355,41 @@ Feature: IMAP import messages """ Then it succeeds -# And IMAP client "1" eventually sees the following message in "INBOX" with this structure: -# """ -# { -# "from": "Foo ", -# "date": "01 Jan 80 00:00 +0000", -# "to": "Bridge Test ", -# "subject": "Embedded message", -# "body-contains": "Hello", -# "content": { -# "content-type": "multipart/mixed", -# "body-contains": "This is a multi-part message in MIME format.", -# "sections":[ -# { -# "content-type": "text/plain", -# "content-type-charset": "utf-8", -# "transfer-encoding": "7bit", -# "body-is": "" -# }, -# { -# "content-type": "message/rfc822", -# "content-type-name": "embedded.eml", -# "transfer-encoding": "7bit", -# "content-disposition": "attachment", -# "content-disposition-filename": "embedded.eml", -# "body-is": "From: Bar \n\rTo: Bridge Test \n\rSubject: (No Subject)\n\rContent-Type: text/plain; charset=utf-8\n\rContent-Transfer-Encoding: quoted-printable\n\r\n\rhello" -# } -# ] -# } -# } -# """ + And IMAP client "1" eventually sees the following message in "INBOX" with this structure: + """ + { + "from": "Foo ", + "date": "01 Jan 80 00:00 +0000", + "to": "Bridge Test ", + "subject": "Embedded message", + "body-contains": "Hello", + "content": { + "content-type": "multipart/mixed", + "sections":[ + { + "body-is": "This is a multi-part message in MIME format." + }, + { + "content-type": "text/plain", + "content-type-charset": "utf-8", + "transfer-encoding": "7bit", + "body-is": "Hello" + }, + { + "content-type": "text/html", + "content-type-charset": "utf-8", + "transfer-encoding": "7bit", + "body-contains": "HELLO" + }, + { + "content-type": "message/rfc822", + "content-type-name": "embedded.eml", + "transfer-encoding": "7bit", + "content-disposition": "attachment", + "content-disposition-filename": "embedded.eml", + "body-is": "From: Bar \nTo: Bridge Test \nSubject: (No Subject)\nContent-Type: text/plain; charset=utf-8\nContent-Transfer-Encoding: quoted-printable\n\nhello" + } + ] + } + } + """ diff --git a/tests/types_test.go b/tests/types_test.go index f7d4526d..78eb7b97 100644 --- a/tests/types_test.go +++ b/tests/types_test.go @@ -207,9 +207,12 @@ func newMessageStructFromIMAP(msg *imap.Message) MessageStruct { panic(err) } var body string - if m.MIMEType == rfc822.TextPlain { + switch { + case m.MIMEType == rfc822.TextPlain: body = strings.TrimSpace(string(m.PlainBody)) - } else { + case m.MIMEType == rfc822.MultipartMixed: + _, body, _ = strings.Cut(string(m.MIMEBody), "\r\n\r\n") + default: body = strings.TrimSpace(string(m.RichBody)) } @@ -221,7 +224,7 @@ func newMessageStructFromIMAP(msg *imap.Message) MessageStruct { CC: formatAddressList(msg.Envelope.Cc), BCC: formatAddressList(msg.Envelope.Bcc), - Content: parseMessageSection(literal, body), + Content: parseMessageSection([]byte(strings.TrimSpace(string(literal))), strings.TrimSpace(body)), } return message } @@ -262,20 +265,30 @@ func parseMessageSection(literal []byte, body string) MessageSection { for id, value := range contentDisposition { if id == 0 { msgSect.ContentDisposition = strings.TrimSpace(string(value)) + continue } param := bytes.Split(value, []byte("=")) if strings.TrimSpace(string(param[0])) == "filename" && len(param) >= 2 { - filename := strings.TrimPrefix(string(value), "filename=") + _, filename, _ := strings.Cut(string(value), "filename=") + filename = strings.Trim(filename, "\"") msgSect.ContentDispositionFilename = strings.TrimSpace(filename) } } if msgSect.ContentTypeBoundary != "" { - sections := bytes.Split([]byte(msgSect.BodyIs), []byte("--"+msgSect.ContentTypeBoundary)) + sections := bytes.Split(literal, []byte("--"+msgSect.ContentTypeBoundary)) // Remove last element that will be the -- from finale boundary sections = sections[:len(sections)-1] + sections = sections[1:] for _, v := range sections { - msgSect.Sections = append(msgSect.Sections, parseMessageSection(v, string(v))) + str := strings.TrimSpace(string(v)) + _, sectionBody, found := strings.Cut(str, "\r\n\r\n") + if !found { + if _, sectionBody, found = strings.Cut(str, "\n\n"); !found { + sectionBody = str + } + } + msgSect.Sections = append(msgSect.Sections, parseMessageSection([]byte(str), strings.TrimSpace(sectionBody))) } } return msgSect @@ -367,18 +380,20 @@ func matchContent(have MessageSection, want MessageSection) bool { if want.TransferEncoding != "" && want.TransferEncoding != have.TransferEncoding { return false } - if want.BodyContains != "" && strings.Contains(have.BodyIs, want.BodyContains) { + if want.BodyContains != "" && !strings.Contains(strings.TrimSpace(have.BodyIs), strings.TrimSpace(want.BodyContains)) { return false } - if want.BodyIs != "" && want.BodyIs != have.BodyIs { + if want.BodyIs != "" && strings.TrimSpace(have.BodyIs) != strings.TrimSpace(want.BodyIs) { return false } - for _, section := range want.Sections { - if !matchContent(have, section) { + if len(have.Sections) != len(want.Sections) { + return false + } + for i, section := range want.Sections { + if !matchContent(have.Sections[i], section) { return false } } - return true } @@ -536,7 +551,3 @@ type Contact struct { Sign string `bdd:"signature"` Encrypt string `bdd:"encryption"` } - -func FullAddress(addr *imap.Address) string { - return addr.PersonalName + " <" + addr.MailboxName + "@" + addr.HostName + ">" -}