diff --git a/internal/imap/mailbox_message.go b/internal/imap/mailbox_message.go index 730f7079..de41b4d6 100644 --- a/internal/imap/mailbox_message.go +++ b/internal/imap/mailbox_message.go @@ -37,7 +37,6 @@ import ( "github.com/ProtonMail/proton-bridge/pkg/pmapi" "github.com/emersion/go-imap" "github.com/hashicorp/go-multierror" - enmime "github.com/jhillyerd/enmime" "github.com/pkg/errors" openpgperrors "golang.org/x/crypto/openpgp/errors" ) @@ -68,7 +67,13 @@ func (im *imapMailbox) CreateMessage(flags []string, date time.Time, body imap.L // Called from go-imap in goroutines - we need to handle panics for each function. defer im.panicHandler.HandlePanic() - m, _, _, readers, err := message.Parse(body, "", "") + buf := new(bytes.Buffer) + + if _, err := buf.ReadFrom(body); err != nil { + return err + } + + m, _, readers, err := message.Parse(buf.Bytes(), "", "") if err != nil { return err } @@ -446,17 +451,6 @@ func (im *imapMailbox) writeMessageBody(w io.Writer, m *pmapi.Message) (err erro return } -func (im *imapMailbox) writeAndParseMIMEBody(m *pmapi.Message) (mime *enmime.Envelope, err error) { //nolint[unused] - b := &bytes.Buffer{} - if err = im.writeMessageBody(b, m); err != nil { - return - } - - mime, err = enmime.ReadEnvelope(b) - - return -} - func (im *imapMailbox) writeAttachmentBody(w io.Writer, m *pmapi.Message, att *pmapi.Attachment) (err error) { // Retrieve encrypted attachment. r, err := im.user.client().GetAttachment(att.ID) diff --git a/internal/smtp/user.go b/internal/smtp/user.go index ae14f30f..dac6ef6c 100644 --- a/internal/smtp/user.go +++ b/internal/smtp/user.go @@ -20,6 +20,7 @@ package smtp import ( + "bytes" "encoding/base64" "io" "mime" @@ -182,7 +183,15 @@ func (su *smtpUser) Send(from string, to []string, messageReader io.Reader) (err attachedPublicKeyName = "publickey - " + kr.GetIdentities()[0].Name } - message, mimeBody, plainBody, attReaders, err := message.Parse(messageReader, attachedPublicKey, attachedPublicKeyName) + buf := new(bytes.Buffer) + + if _, err = buf.ReadFrom(messageReader); err != nil { + return + } + + mimeBody := buf.String() + + message, plainBody, attReaders, err := message.Parse(buf.Bytes(), attachedPublicKey, attachedPublicKeyName) if err != nil { return } diff --git a/pkg/message/parser.go b/pkg/message/parser.go index d52b83cf..d6e35be1 100644 --- a/pkg/message/parser.go +++ b/pkg/message/parser.go @@ -34,12 +34,22 @@ import ( "github.com/jaytaylor/html2text" ) -func Parse(r io.Reader, key, keyName string) (m *pmapi.Message, mimeMessage, plainBody string, attReaders []io.Reader, err error) { - p, err := parser.New(r) +func Parse(b []byte, key, keyName string) (m *pmapi.Message, plainBody string, attReaders []io.Reader, err error) { + p, err := parser.New(b) if err != nil { return } + if err = convertForeignEncodings(p); err != nil { + return + } + + if key != "" { + if err = attachPublicKey(p.Root(), key, keyName); err != nil { + return + } + } + m = pmapi.NewMessage() if err = parseMessageHeader(m, p.Root().Header); err != nil { @@ -58,15 +68,14 @@ func Parse(r io.Reader, key, keyName string) (m *pmapi.Message, mimeMessage, pla return } - if key != "" { - attachPublicKey(p.Root(), key, keyName) - } + return m, plainBody, attReaders, nil +} - if mimeMessage, err = writeMIMEMessage(p); err != nil { - return - } - - return m, mimeMessage, plainBody, attReaders, nil +func convertForeignEncodings(p *parser.Parser) error { + // HELP: Is it correct to only do this to text types? + return p.NewWalker().RegisterContentTypeHandler("text/.*", func(p *parser.Part) error { + return p.ConvertToUTF8() + }).Walk() } func collectAttachments(p *parser.Parser) ([]*pmapi.Attachment, []io.Reader, error) { @@ -171,9 +180,27 @@ func collectBodyParts(p *parser.Parser, preferredContentType string) (parser.Par return bestChoice(childParts, preferredContentType), nil }). RegisterRule("text/plain", func(p *parser.Part, visit parser.Visit) (interface{}, error) { + disp, _, err := p.Header.ContentDisposition() + if err != nil { + disp = "" + } + + if disp == "attachment" { + return parser.Parts{}, nil + } + return parser.Parts{p}, nil }). RegisterRule("text/html", func(p *parser.Part, visit parser.Visit) (interface{}, error) { + disp, _, err := p.Header.ContentDisposition() + if err != nil { + disp = "" + } + + if disp == "attachment" { + return parser.Parts{}, nil + } + return parser.Parts{p}, nil }) @@ -280,17 +307,7 @@ func getPlainBody(part *parser.Part) []byte { } } -func writeMIMEMessage(p *parser.Parser) (string, error) { - buf := new(bytes.Buffer) - - if err := p.NewWriter().Write(buf); err != nil { - return "", err - } - - return buf.String(), nil -} - -func attachPublicKey(p *parser.Part, key, keyName string) { +func attachPublicKey(p *parser.Part, key, keyName string) error { h := message.Header{} h.Set("Content-Type", fmt.Sprintf(`application/pgp-key; name="%v"`, keyName)) @@ -299,20 +316,24 @@ func attachPublicKey(p *parser.Part, key, keyName string) { body := new(bytes.Buffer) - textwrapper.NewRFC822(body).Write([]byte(key)) + if _, err := textwrapper.NewRFC822(body).Write([]byte(key)); err != nil { + return err + } p.AddChild(&parser.Part{ Header: h, Body: body.Bytes(), }) + + return nil } -func parseMessageHeader(m *pmapi.Message, h message.Header) error { +// NOTE: We should use our own ParseAddressList here. +func parseMessageHeader(m *pmapi.Message, h message.Header) error { // nolint[funlen] mimeHeader, err := toMailHeader(h) if err != nil { return err } - m.Header = mimeHeader fields := h.Fields() @@ -401,6 +422,10 @@ func parseAttachment(h message.Header) (*pmapi.Attachment, error) { } } else { att.Name = dispParams["filename"] + + if att.Name == "" { + att.Name = "attachment.bin" + } } att.ContentID = strings.Trim(h.Get("Content-Id"), " <>") diff --git a/pkg/message/parser/handler.go b/pkg/message/parser/handler.go index 9d14bd19..f9e26438 100644 --- a/pkg/message/parser/handler.go +++ b/pkg/message/parser/handler.go @@ -1,3 +1,20 @@ +// Copyright (c) 2020 Proton Technologies AG +// +// This file is part of ProtonMail Bridge. +// +// ProtonMail Bridge 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 of the License, or +// (at your option) any later version. +// +// ProtonMail Bridge 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 ProtonMail Bridge. If not, see . + package parser import "regexp" diff --git a/pkg/message/parser/parser.go b/pkg/message/parser/parser.go index b5a78af8..eebb78c4 100644 --- a/pkg/message/parser/parser.go +++ b/pkg/message/parser/parser.go @@ -1,11 +1,28 @@ +// Copyright (c) 2020 Proton Technologies AG +// +// This file is part of ProtonMail Bridge. +// +// ProtonMail Bridge 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 of the License, or +// (at your option) any later version. +// +// ProtonMail Bridge 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 ProtonMail Bridge. If not, see . + package parser import ( + "bytes" "io" "io/ioutil" "github.com/emersion/go-message" - "github.com/sirupsen/logrus" ) type Parser struct { @@ -13,10 +30,10 @@ type Parser struct { root *Part } -func New(r io.Reader) (*Parser, error) { +func New(b []byte) (*Parser, error) { p := new(Parser) - entity, err := message.Read(r) + entity, err := message.Read(bytes.NewReader(b)) if err != nil && !message.IsUnknownCharset(err) { return nil, err } @@ -70,12 +87,6 @@ func (p *Parser) endPart() { } else { p.root = part } - - if !part.isUTF8() { - if err := part.convertToUTF8(); err != nil { - logrus.WithError(err).Error("failed to convert part to utf-8") - } - } } func (p *Parser) top() *Part { diff --git a/pkg/message/parser/parser_test.go b/pkg/message/parser/parser_test.go index 94a907f1..4b8d7c4e 100644 --- a/pkg/message/parser/parser_test.go +++ b/pkg/message/parser/parser_test.go @@ -1,49 +1,48 @@ +// Copyright (c) 2020 Proton Technologies AG +// +// This file is part of ProtonMail Bridge. +// +// ProtonMail Bridge 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 of the License, or +// (at your option) any later version. +// +// ProtonMail Bridge 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 ProtonMail Bridge. If not, see . + package parser import ( + "bytes" "io" "io/ioutil" "os" "path/filepath" "testing" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func newTestParser(t *testing.T, msg string) *Parser { r := f(msg) - p, err := New(r) + buf := new(bytes.Buffer) + + if _, err := buf.ReadFrom(r); err != nil { + panic(err) + } + + p, err := New(buf.Bytes()) require.NoError(t, err) return p } -func TestParserSpecifiedLatin1Charset(t *testing.T) { - p := newTestParser(t, "text_plain_latin1.eml") - - checkBodies(t, p, "ééééééé") -} - -func TestParserUnspecifiedLatin1Charset(t *testing.T) { - p := newTestParser(t, "text_plain_unknown_latin1.eml") - - checkBodies(t, p, "ééééééé") -} - -func TestParserSpecifiedLatin2Charset(t *testing.T) { - p := newTestParser(t, "text_plain_latin2.eml") - - checkBodies(t, p, "řšřšřš") -} - -func TestParserEmbeddedLatin2Charset(t *testing.T) { - p := newTestParser(t, "text_html_embedded_latin2_encoding.eml") - - checkBodies(t, p, `latin2 řšřš`) -} - func f(filename string) io.ReadCloser { f, err := os.Open(filepath.Join("testdata", filename)) @@ -62,21 +61,3 @@ func s(filename string) string { return string(b) } - -func checkBodies(t *testing.T, p *Parser, wantBodies ...string) { - var partBodies, expectedBodies [][]byte - - require.NoError(t, p.NewWalker().RegisterDefaultHandler(func(p *Part) (err error) { - if p.Body != nil { - partBodies = append(partBodies, p.Body) - } - - return - }).Walk()) - - for _, body := range wantBodies { - expectedBodies = append(expectedBodies, []byte(body)) - } - - assert.ElementsMatch(t, expectedBodies, partBodies) -} diff --git a/pkg/message/parser/part.go b/pkg/message/parser/part.go index 5b161920..7b6debe5 100644 --- a/pkg/message/parser/part.go +++ b/pkg/message/parser/part.go @@ -1,3 +1,20 @@ +// Copyright (c) 2020 Proton Technologies AG +// +// This file is part of ProtonMail Bridge. +// +// ProtonMail Bridge 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 of the License, or +// (at your option) any later version. +// +// ProtonMail Bridge 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 ProtonMail Bridge. If not, see . + package parser import ( @@ -34,11 +51,11 @@ func (p *Part) AddChild(child *Part) { p.children = append(p.children, child) } -func (p *Part) isUTF8() bool { - return utf8.Valid(p.Body) -} +func (p *Part) ConvertToUTF8() error { + if utf8.Valid(p.Body) { + return nil + } -func (p *Part) convertToUTF8() error { t, params, err := p.Header.ContentType() if err != nil { return err @@ -57,7 +74,7 @@ func (p *Part) convertToUTF8() error { return err } - // TODO: Is this okay? What about when the charset is embedded in structured text type eg html/xml? + // HELP: Is this okay? What about when the charset is embedded in structured text type eg html/xml? params["charset"] = "utf-8" p.Header.SetContentType(t, params) diff --git a/pkg/message/parser/part_test.go b/pkg/message/parser/part_test.go index 5fd62c17..4d925b25 100644 --- a/pkg/message/parser/part_test.go +++ b/pkg/message/parser/part_test.go @@ -1,3 +1,20 @@ +// Copyright (c) 2020 Proton Technologies AG +// +// This file is part of ProtonMail Bridge. +// +// ProtonMail Bridge 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 of the License, or +// (at your option) any later version. +// +// ProtonMail Bridge 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 ProtonMail Bridge. If not, see . + package parser import ( diff --git a/pkg/message/parser/testdata/text_html_embedded_latin2_encoding.eml b/pkg/message/parser/testdata/text_html_embedded_latin2_encoding.eml deleted file mode 100644 index 3bba7086..00000000 --- a/pkg/message/parser/testdata/text_html_embedded_latin2_encoding.eml +++ /dev/null @@ -1,5 +0,0 @@ -From: Sender -To: Receiver -Content-Type: text/html - -latin2 ø¹ø¹ \ No newline at end of file diff --git a/pkg/message/parser/testdata/text_plain_latin1.eml b/pkg/message/parser/testdata/text_plain_latin1.eml deleted file mode 100644 index dd8f88e0..00000000 --- a/pkg/message/parser/testdata/text_plain_latin1.eml +++ /dev/null @@ -1,5 +0,0 @@ -From: Sender -To: Receiver -Content-Type: text/plain; charset=ISO-8859-1 - -ééééééé \ No newline at end of file diff --git a/pkg/message/parser/testdata/text_plain_latin2.eml b/pkg/message/parser/testdata/text_plain_latin2.eml deleted file mode 100644 index 950991bd..00000000 --- a/pkg/message/parser/testdata/text_plain_latin2.eml +++ /dev/null @@ -1,5 +0,0 @@ -From: Sender -To: Receiver -Content-Type: text/plain; charset=ISO-8859-2 - -ø¹ø¹ø¹ \ No newline at end of file diff --git a/pkg/message/parser/testdata/text_plain_unknown_latin1.eml b/pkg/message/parser/testdata/text_plain_unknown_latin1.eml deleted file mode 100644 index 2e1aa2cd..00000000 --- a/pkg/message/parser/testdata/text_plain_unknown_latin1.eml +++ /dev/null @@ -1,5 +0,0 @@ -From: Sender -To: Receiver -Content-Type: text/plain - -ééééééé \ No newline at end of file diff --git a/pkg/message/parser/testdata/text_plain_unknown_latin2.eml b/pkg/message/parser/testdata/text_plain_unknown_latin2.eml deleted file mode 100644 index 549a48a9..00000000 --- a/pkg/message/parser/testdata/text_plain_unknown_latin2.eml +++ /dev/null @@ -1,5 +0,0 @@ -From: Sender -To: Receiver -Content-Type: text/plain - -ø¹ø¹ø¹ \ No newline at end of file diff --git a/pkg/message/parser/visitor.go b/pkg/message/parser/visitor.go index a20d74dd..6b58f20b 100644 --- a/pkg/message/parser/visitor.go +++ b/pkg/message/parser/visitor.go @@ -1,3 +1,20 @@ +// Copyright (c) 2020 Proton Technologies AG +// +// This file is part of ProtonMail Bridge. +// +// ProtonMail Bridge 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 of the License, or +// (at your option) any later version. +// +// ProtonMail Bridge 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 ProtonMail Bridge. If not, see . + package parser import "regexp" diff --git a/pkg/message/parser/walker.go b/pkg/message/parser/walker.go index 3db04b9d..589d44b7 100644 --- a/pkg/message/parser/walker.go +++ b/pkg/message/parser/walker.go @@ -1,3 +1,20 @@ +// Copyright (c) 2020 Proton Technologies AG +// +// This file is part of ProtonMail Bridge. +// +// ProtonMail Bridge 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 of the License, or +// (at your option) any later version. +// +// ProtonMail Bridge 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 ProtonMail Bridge. If not, see . + package parser type Walker struct { diff --git a/pkg/message/parser/walker_test.go b/pkg/message/parser/walker_test.go index d13bea80..42a69292 100644 --- a/pkg/message/parser/walker_test.go +++ b/pkg/message/parser/walker_test.go @@ -1,3 +1,20 @@ +// Copyright (c) 2020 Proton Technologies AG +// +// This file is part of ProtonMail Bridge. +// +// ProtonMail Bridge 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 of the License, or +// (at your option) any later version. +// +// ProtonMail Bridge 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 ProtonMail Bridge. If not, see . + package parser import ( diff --git a/pkg/message/parser/writer.go b/pkg/message/parser/writer.go index 90994c8c..a6dfade5 100644 --- a/pkg/message/parser/writer.go +++ b/pkg/message/parser/writer.go @@ -1,3 +1,20 @@ +// Copyright (c) 2020 Proton Technologies AG +// +// This file is part of ProtonMail Bridge. +// +// ProtonMail Bridge 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 of the License, or +// (at your option) any later version. +// +// ProtonMail Bridge 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 ProtonMail Bridge. If not, see . + package parser import ( diff --git a/pkg/message/parser/writer_test.go b/pkg/message/parser/writer_test.go index 16ef0dfd..e8e8ce8d 100644 --- a/pkg/message/parser/writer_test.go +++ b/pkg/message/parser/writer_test.go @@ -1,3 +1,20 @@ +// Copyright (c) 2020 Proton Technologies AG +// +// This file is part of ProtonMail Bridge. +// +// ProtonMail Bridge 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 of the License, or +// (at your option) any later version. +// +// ProtonMail Bridge 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 ProtonMail Bridge. If not, see . + package parser import ( diff --git a/pkg/message/parser_test.go b/pkg/message/parser_test.go index d4418703..6f2d161b 100644 --- a/pkg/message/parser_test.go +++ b/pkg/message/parser_test.go @@ -18,10 +18,10 @@ package message import ( + "bytes" "image/png" "io" "io/ioutil" - "math/rand" "os" "path/filepath" "testing" @@ -31,48 +31,16 @@ import ( "golang.org/x/text/encoding/charmap" ) -func f(filename string) io.ReadCloser { - f, err := os.Open(filepath.Join("testdata", filename)) - - if err != nil { - panic(err) - } - - return f -} - -func s(filename string) string { - b, err := ioutil.ReadAll(f(filename)) - - if err != nil { - panic(err) - } - - return string(b) -} - -func readerToString(r io.Reader) string { - b, err := ioutil.ReadAll(r) - - if err != nil { - panic(err) - } - - return string(b) -} - func TestParseTextPlain(t *testing.T) { f := f("text_plain.eml") - defer func() { _ = f.Close() }() - m, mimeMessage, plainBody, attReaders, err := Parse(f, "", "") + m, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) assert.Equal(t, `"Receiver" `, m.ToList[0].String()) assert.Equal(t, "body", m.Body) - assert.Equal(t, s("text_plain.mime"), mimeMessage) assert.Equal(t, "body", plainBody) assert.Len(t, attReaders, 0) @@ -80,16 +48,14 @@ func TestParseTextPlain(t *testing.T) { func TestParseTextPlainUTF8(t *testing.T) { f := f("text_plain_utf8.eml") - defer func() { _ = f.Close() }() - m, mimeMessage, plainBody, attReaders, err := Parse(f, "", "") + m, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) assert.Equal(t, `"Receiver" `, m.ToList[0].String()) assert.Equal(t, "body", m.Body) - assert.Equal(t, s("text_plain_utf8.mime"), mimeMessage) assert.Equal(t, "body", plainBody) assert.Len(t, attReaders, 0) @@ -97,16 +63,14 @@ func TestParseTextPlainUTF8(t *testing.T) { func TestParseTextPlainLatin1(t *testing.T) { f := f("text_plain_latin1.eml") - defer func() { _ = f.Close() }() - m, mimeMessage, plainBody, attReaders, err := Parse(f, "", "") + m, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) assert.Equal(t, `"Receiver" `, m.ToList[0].String()) assert.Equal(t, "ééééééé", m.Body) - assert.Equal(t, s("text_plain_latin1.mime"), mimeMessage) assert.Equal(t, "ééééééé", plainBody) assert.Len(t, attReaders, 0) @@ -114,16 +78,14 @@ func TestParseTextPlainLatin1(t *testing.T) { func TestParseTextPlainUnknownCharsetIsActuallyLatin1(t *testing.T) { f := f("text_plain_unknown_latin1.eml") - defer func() { _ = f.Close() }() - m, mimeMessage, plainBody, attReaders, err := Parse(f, "", "") + m, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) assert.Equal(t, `"Receiver" `, m.ToList[0].String()) assert.Equal(t, "ééééééé", m.Body) - assert.Equal(t, s("text_plain_unknown_latin1.mime"), mimeMessage) assert.Equal(t, "ééééééé", plainBody) assert.Len(t, attReaders, 0) @@ -131,9 +93,8 @@ func TestParseTextPlainUnknownCharsetIsActuallyLatin1(t *testing.T) { func TestParseTextPlainUnknownCharsetIsActuallyLatin2(t *testing.T) { f := f("text_plain_unknown_latin2.eml") - defer func() { _ = f.Close() }() - m, mimeMessage, plainBody, attReaders, err := Parse(f, "", "") + m, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) @@ -146,7 +107,6 @@ func TestParseTextPlainUnknownCharsetIsActuallyLatin2(t *testing.T) { assert.NotEqual(t, []byte("řšřšřš"), expect) assert.Equal(t, string(expect), m.Body) - assert.Equal(t, s("text_plain_unknown_latin2.mime"), mimeMessage) assert.Equal(t, string(expect), plainBody) assert.Len(t, attReaders, 0) @@ -154,16 +114,14 @@ func TestParseTextPlainUnknownCharsetIsActuallyLatin2(t *testing.T) { func TestParseTextPlainAlready7Bit(t *testing.T) { f := f("text_plain_7bit.eml") - defer func() { _ = f.Close() }() - m, mimeMessage, plainBody, attReaders, err := Parse(f, "", "") + m, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) assert.Equal(t, `"Receiver" `, m.ToList[0].String()) assert.Equal(t, "body", m.Body) - assert.Equal(t, s("text_plain_7bit.mime"), mimeMessage) assert.Equal(t, "body", plainBody) assert.Len(t, attReaders, 0) @@ -171,16 +129,14 @@ func TestParseTextPlainAlready7Bit(t *testing.T) { func TestParseTextPlainWithOctetAttachment(t *testing.T) { f := f("text_plain_octet_attachment.eml") - defer func() { _ = f.Close() }() - m, mimeMessage, plainBody, attReaders, err := Parse(f, "", "") + m, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) assert.Equal(t, `"Receiver" `, m.ToList[0].String()) assert.Equal(t, "body", m.Body) - assert.Equal(t, s("text_plain_octet_attachment.mime"), mimeMessage) assert.Equal(t, "body", plainBody) require.Len(t, attReaders, 1) @@ -189,16 +145,14 @@ func TestParseTextPlainWithOctetAttachment(t *testing.T) { func TestParseTextPlainWithOctetAttachmentGoodFilename(t *testing.T) { f := f("text_plain_octet_attachment_good_2231_filename.eml") - defer func() { _ = f.Close() }() - m, mimeMessage, plainBody, attReaders, err := Parse(f, "", "") + m, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) assert.Equal(t, `"Receiver" `, m.ToList[0].String()) assert.Equal(t, "body", m.Body) - assert.Equal(t, s("text_plain_octet_attachment_good_2231_filename.mime"), mimeMessage) assert.Equal(t, "body", plainBody) assert.Len(t, attReaders, 1) @@ -208,16 +162,14 @@ func TestParseTextPlainWithOctetAttachmentGoodFilename(t *testing.T) { func TestParseTextPlainWithOctetAttachmentBadFilename(t *testing.T) { f := f("text_plain_octet_attachment_bad_2231_filename.eml") - defer func() { _ = f.Close() }() - m, mimeMessage, plainBody, attReaders, err := Parse(f, "", "") + m, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) assert.Equal(t, `"Receiver" `, m.ToList[0].String()) assert.Equal(t, "body", m.Body) - assert.Equal(t, s("text_plain_octet_attachment_bad_2231_filename.mime"), mimeMessage) assert.Equal(t, "body", plainBody) assert.Len(t, attReaders, 1) @@ -227,16 +179,14 @@ func TestParseTextPlainWithOctetAttachmentBadFilename(t *testing.T) { func TestParseTextPlainWithPlainAttachment(t *testing.T) { f := f("text_plain_plain_attachment.eml") - defer func() { _ = f.Close() }() - m, mimeMessage, plainBody, attReaders, err := Parse(f, "", "") + m, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) assert.Equal(t, `"Receiver" `, m.ToList[0].String()) assert.Equal(t, "body", m.Body) - assert.Equal(t, s("text_plain_plain_attachment.mime"), mimeMessage) assert.Equal(t, "body", plainBody) require.Len(t, attReaders, 1) @@ -245,16 +195,14 @@ func TestParseTextPlainWithPlainAttachment(t *testing.T) { func TestParseTextPlainWithImageInline(t *testing.T) { f := f("text_plain_image_inline.eml") - defer func() { _ = f.Close() }() - m, mimeMessage, plainBody, attReaders, err := Parse(f, "", "") + m, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) assert.Equal(t, `"Receiver" `, m.ToList[0].String()) assert.Equal(t, "body", m.Body) - assert.Equal(t, s("text_plain_image_inline.mime"), mimeMessage) assert.Equal(t, "body", plainBody) // The inline image is an 8x8 mic-dropping gopher. @@ -267,73 +215,59 @@ func TestParseTextPlainWithImageInline(t *testing.T) { func TestParseWithMultipleTextParts(t *testing.T) { f := f("multiple_text_parts.eml") - defer func() { _ = f.Close() }() - m, mimeMessage, plainBody, attReaders, err := Parse(f, "", "") + m, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) assert.Equal(t, `"Receiver" `, m.ToList[0].String()) assert.Equal(t, "body\nsome other part of the message", m.Body) - assert.Equal(t, s("multiple_text_parts.mime"), mimeMessage) assert.Equal(t, "body\nsome other part of the message", plainBody) assert.Len(t, attReaders, 0) } func TestParseTextHTML(t *testing.T) { - rand.Seed(0) - f := f("text_html.eml") - defer func() { _ = f.Close() }() - m, mimeMessage, plainBody, attReaders, err := Parse(f, "", "") + m, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) assert.Equal(t, `"Receiver" `, m.ToList[0].String()) - assert.Equal(t, "This is body of HTML mail without attachment", m.Body) - assert.Equal(t, s("text_html.mime"), mimeMessage) + assert.Equal(t, "This is body of HTML mail without attachment", m.Body) assert.Equal(t, "This is body of *HTML mail* without attachment", plainBody) assert.Len(t, attReaders, 0) } func TestParseTextHTMLAlready7Bit(t *testing.T) { - rand.Seed(0) - f := f("text_html_7bit.eml") - defer func() { _ = f.Close() }() - m, mimeMessage, plainBody, attReaders, err := Parse(f, "", "") + m, plainBody, attReaders, err := Parse(f, "", "") assert.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) assert.Equal(t, `"Receiver" `, m.ToList[0].String()) - assert.Equal(t, "This is body of HTML mail without attachment", m.Body) - assert.Equal(t, s("text_html_7bit.mime"), mimeMessage) + assert.Equal(t, "This is body of HTML mail without attachment", m.Body) assert.Equal(t, "This is body of *HTML mail* without attachment", plainBody) assert.Len(t, attReaders, 0) } func TestParseTextHTMLWithOctetAttachment(t *testing.T) { - rand.Seed(0) - f := f("text_html_octet_attachment.eml") - defer func() { _ = f.Close() }() - m, mimeMessage, plainBody, attReaders, err := Parse(f, "", "") + m, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) assert.Equal(t, `"Receiver" `, m.ToList[0].String()) - assert.Equal(t, "This is body of HTML mail with attachment", m.Body) - assert.Equal(t, s("text_html_octet_attachment.mime"), mimeMessage) + assert.Equal(t, "This is body of HTML mail with attachment", m.Body) assert.Equal(t, "This is body of *HTML mail* with attachment", plainBody) require.Len(t, attReaders, 1) @@ -341,20 +275,16 @@ func TestParseTextHTMLWithOctetAttachment(t *testing.T) { } func TestParseTextHTMLWithPlainAttachment(t *testing.T) { - rand.Seed(0) - f := f("text_html_plain_attachment.eml") - defer func() { _ = f.Close() }() - m, mimeMessage, plainBody, attReaders, err := Parse(f, "", "") + m, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) assert.Equal(t, `"Receiver" `, m.ToList[0].String()) // BAD: plainBody should not be empty! - assert.Equal(t, "This is body of HTML mail with attachment", m.Body) - assert.Equal(t, s("text_html_plain_attachment.mime"), mimeMessage) + assert.Equal(t, "This is body of HTML mail with attachment", m.Body) assert.Equal(t, "This is body of *HTML mail* with attachment", plainBody) require.Len(t, attReaders, 1) @@ -362,19 +292,15 @@ func TestParseTextHTMLWithPlainAttachment(t *testing.T) { } func TestParseTextHTMLWithImageInline(t *testing.T) { - rand.Seed(0) - f := f("text_html_image_inline.eml") - defer func() { _ = f.Close() }() - m, mimeMessage, plainBody, attReaders, err := Parse(f, "", "") + m, plainBody, attReaders, err := Parse(f, "", "") assert.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) assert.Equal(t, `"Receiver" `, m.ToList[0].String()) - assert.Equal(t, "This is body of HTML mail with attachment", m.Body) - assert.Equal(t, s("text_html_image_inline.mime"), mimeMessage) + assert.Equal(t, "This is body of HTML mail with attachment", m.Body) assert.Equal(t, "This is body of *HTML mail* with attachment", plainBody) // The inline image is an 8x8 mic-dropping gopher. @@ -387,30 +313,25 @@ func TestParseTextHTMLWithImageInline(t *testing.T) { func TestParseWithAttachedPublicKey(t *testing.T) { f := f("text_plain.eml") - defer func() { _ = f.Close() }() // BAD: Public Key is not attached unless Content-Type is specified (not required)! - m, mimeMessage, plainBody, attReaders, err := Parse(f, "publickey", "publickeyname") + m, plainBody, attReaders, err := Parse(f, "publickey", "publickeyname") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) assert.Equal(t, `"Receiver" `, m.ToList[0].String()) assert.Equal(t, "body", m.Body) - assert.Equal(t, s("text_plain_pubkey.mime"), mimeMessage) assert.Equal(t, "body", plainBody) - // BAD: Public key not available as an attachment! + // HELP: Should public key be available as an attachment? In previous parser it wasn't... require.Len(t, attReaders, 1) } func TestParseTextHTMLWithEmbeddedForeignEncoding(t *testing.T) { - rand.Seed(0) - f := f("text_html_embedded_foreign_encoding.eml") - defer func() { _ = f.Close() }() - m, mimeMessage, plainBody, attReaders, err := Parse(f, "", "") + m, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) @@ -418,19 +339,15 @@ func TestParseTextHTMLWithEmbeddedForeignEncoding(t *testing.T) { // BAD: Bridge does not detect the charset specified in the tag of the html. assert.Equal(t, `latin2 řšřš`, m.Body) - assert.Equal(t, s("text_html_embedded_foreign_encoding.mime"), mimeMessage) assert.Equal(t, `latin2 řšřš`, plainBody) assert.Len(t, attReaders, 0) } func TestParseMultipartAlternative(t *testing.T) { - rand.Seed(0) - f := f("multipart_alternative.eml") - defer func() { _ = f.Close() }() - m, _, plainBody, _, err := Parse(f, "", "") + m, plainBody, _, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"schizofrenic" `, m.Sender.String()) @@ -450,12 +367,9 @@ func TestParseMultipartAlternative(t *testing.T) { } func TestParseMultipartAlternativeNested(t *testing.T) { - rand.Seed(0) - f := f("multipart_alternative_nested.eml") - defer func() { _ = f.Close() }() - m, _, plainBody, _, err := Parse(f, "", "") + m, plainBody, _, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"schizofrenic" `, m.Sender.String()) @@ -473,3 +387,26 @@ func TestParseMultipartAlternativeNested(t *testing.T) { assert.Equal(t, "*multipart 2.1*\n\n", plainBody) } + +func f(filename string) []byte { + f, err := os.Open(filepath.Join("testdata", filename)) + if err != nil { + panic(err) + } + + buf := new(bytes.Buffer) + + _, _ = buf.ReadFrom(f) + + return buf.Bytes() +} + +func readerToString(r io.Reader) string { + b, err := ioutil.ReadAll(r) + + if err != nil { + panic(err) + } + + return string(b) +} diff --git a/pkg/message/section_test.go b/pkg/message/section_test.go index d1073caa..21b59719 100644 --- a/pkg/message/section_test.go +++ b/pkg/message/section_test.go @@ -28,7 +28,13 @@ import ( "github.com/stretchr/testify/require" ) +var enableDebug = false // nolint[global] + func debug(msg string, v ...interface{}) { + if !enableDebug { + return + } + _, file, line, _ := runtime.Caller(1) fmt.Printf("%s:%d: \033[2;33m"+msg+"\033[0;39m\n", append([]interface{}{filepath.Base(file), line}, v...)...) } diff --git a/pkg/message/testdata/multipart_alternative.eml b/pkg/message/testdata/multipart_alternative.eml index 2910c009..93438a34 100644 --- a/pkg/message/testdata/multipart_alternative.eml +++ b/pkg/message/testdata/multipart_alternative.eml @@ -27,4 +27,4 @@ Content-Transfer-Encoding: 7bit ---------------22BC647264E52252E386881A-- +--------------22BC647264E52252E386881A-- \ No newline at end of file diff --git a/pkg/message/testdata/multiple_text_parts.mime b/pkg/message/testdata/multiple_text_parts.mime deleted file mode 100644 index e0d5d19d..00000000 --- a/pkg/message/testdata/multiple_text_parts.mime +++ /dev/null @@ -1,17 +0,0 @@ -Content-Type: multipart/mixed; boundary=longrandomstring -From: Sender -To: Receiver - - -This is a multi-part message in MIME format. ---longrandomstring -Content-Transfer-Encoding: quoted-printable - -body - ---longrandomstring -Content-Transfer-Encoding: quoted-printable - -some other part of the message ---longrandomstring-- -. diff --git a/pkg/message/testdata/text_html.mime b/pkg/message/testdata/text_html.mime deleted file mode 100644 index 07786fd0..00000000 --- a/pkg/message/testdata/text_html.mime +++ /dev/null @@ -1,19 +0,0 @@ -Content-Type: multipart/alternative; boundary="0194fdc2fa2ffcc041d3ff12045b73c86e4ff95ff662a5eee82abdf44a2d" -From: Sender -To: Receiver - - -This is a multi-part message in MIME format. ---0194fdc2fa2ffcc041d3ff12045b73c86e4ff95ff662a5eee82abdf44a2d -Content-Transfer-Encoding: quoted-printable -Content-Type: text/html - -This is body of HTML mail without attachment ---0194fdc2fa2ffcc041d3ff12045b73c86e4ff95ff662a5eee82abdf44a2d -Content-Transfer-Encoding: quoted-printable -Content-Type: text/plain - -This is body of *HTML mail* without attachment ---0194fdc2fa2ffcc041d3ff12045b73c86e4ff95ff662a5eee82abdf44a2d-- -. diff --git a/pkg/message/testdata/text_html_7bit.mime b/pkg/message/testdata/text_html_7bit.mime deleted file mode 100644 index 3e12d832..00000000 --- a/pkg/message/testdata/text_html_7bit.mime +++ /dev/null @@ -1,19 +0,0 @@ -Content-Transfer-Encoding: 7bit -Content-Type: multipart/alternative; boundary="0194fdc2fa2ffcc041d3ff12045b73c86e4ff95ff662a5eee82abdf44a2d" -From: Sender -To: Receiver - - -This is a multi-part message in MIME format. ---0194fdc2fa2ffcc041d3ff12045b73c86e4ff95ff662a5eee82abdf44a2d -Content-Transfer-Encoding: 7bit -Content-Type: text/html - -This is body of HTML mail without attachment ---0194fdc2fa2ffcc041d3ff12045b73c86e4ff95ff662a5eee82abdf44a2d -Content-Transfer-Encoding: 7bit -Content-Type: text/plain - -This is body of *HTML mail* without attachment ---0194fdc2fa2ffcc041d3ff12045b73c86e4ff95ff662a5eee82abdf44a2d-- -. diff --git a/pkg/message/testdata/text_html_embedded_foreign_encoding.eml b/pkg/message/testdata/text_html_embedded_foreign_encoding.eml index 2fcd12d2..3bba7086 100644 --- a/pkg/message/testdata/text_html_embedded_foreign_encoding.eml +++ b/pkg/message/testdata/text_html_embedded_foreign_encoding.eml @@ -2,4 +2,4 @@ From: Sender To: Receiver Content-Type: text/html -latin2 ø¹ø¹ +latin2 ø¹ø¹ \ No newline at end of file diff --git a/pkg/message/testdata/text_html_image_inline.mime b/pkg/message/testdata/text_html_image_inline.mime deleted file mode 100644 index 88f021ad..00000000 --- a/pkg/message/testdata/text_html_image_inline.mime +++ /dev/null @@ -1,52 +0,0 @@ -Content-Type: multipart/mixed; boundary=longrandomstring -From: Sender -To: Receiver - - -This is a multi-part message in MIME format. ---longrandomstring -Content-Type: multipart/alternative; boundary="0194fdc2fa2ffcc041d3ff12045b73c86e4ff95ff662a5eee82abdf44a2d" - - -This is a multi-part message in MIME format. ---0194fdc2fa2ffcc041d3ff12045b73c86e4ff95ff662a5eee82abdf44a2d -Content-Transfer-Encoding: quoted-printable -Content-Type: text/html - -This is body of HTML mail with attachment ---0194fdc2fa2ffcc041d3ff12045b73c86e4ff95ff662a5eee82abdf44a2d -Content-Transfer-Encoding: quoted-printable -Content-Type: text/plain - -This is body of *HTML mail* with attachment ---0194fdc2fa2ffcc041d3ff12045b73c86e4ff95ff662a5eee82abdf44a2d-- -. - ---longrandomstring -Content-Disposition: inline -Content-Transfer-Encoding: base64 -Content-Type: image/png - -iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAABGdBTUEAALGPC/xhBQAAACBjSFJ -NAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAhGVYSWZNTQAqAAAACAAFAR -IAAwAAAAEAAQAAARoABQAAAAEAAABKARsABQAAAAEAAABSASgAAwAAAAEAAgAAh2kABAAAAAEAA -ABaAAAAAAAAASwAAAABAAABLAAAAAEAA6ABAAMAAAABAAEAAKACAAQAAAABAAAACKADAAQAAAAB -AAAACAAAAAAAXWZ6AAAACXBIWXMAAC4jAAAuIwF4pT92AAACZmlUWHRYTUw6Y29tLmFkb2JlLnh -tcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIE -NvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5O -TkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91 -dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4 -wLyIKICAgICAgICAgICAgeG1sbnM6ZXhpZj0iaHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC -8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgI -CAgICA8dGlmZjpSZXNvbHV0aW9uVW5pdD4yPC90aWZmOlJlc29sdXRpb25Vbml0PgogICAgICAg -ICA8ZXhpZjpDb2xvclNwYWNlPjE8L2V4aWY6Q29sb3JTcGFjZT4KICAgICAgICAgPGV4aWY6UGl -4ZWxYRGltZW5zaW9uPjE2PC9leGlmOlBpeGVsWERpbWVuc2lvbj4KICAgICAgICAgPGV4aWY6UG -l4ZWxZRGltZW5zaW9uPjE2PC9leGlmOlBpeGVsWURpbWVuc2lvbj4KICAgICAgPC9yZGY6RGVzY -3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CgZBD4sAAAEISURBVBgZY2CAAO5F -x07Zz96xZ0Pn4lXqIKGGhgYmsFTHvAWdW6/dvnb89Yf/B5+9/r/y9IXzbVPahCH6/jMysfAJygo -JC2r++/T619Mb139J8HIb8Gs5hYMUzJ+/gJ1Jmo9H6c+L5wz3bt5iEeLmYOHn42fQ4vyacqGNQS -0xMfEHc7Cvl6CYho4rh5jUPyYefqafLKyMbH9+/d28/dFfdWtfDaZvTy7Zvv72nYGZkeEvw98/f -5j//2P4yCvxq/nU7zVs//8yM2gzMMitOnnu5cUff/8ff/v5/5Xf///vuHBhJcSRDAws9aEMr38c -W7XjNgvzexZ2rn9vbjx/IXl/M9iLM2fOZAUAKCZv7dU+UgAAAAAASUVORK5CYII= ---longrandomstring-- -. diff --git a/pkg/message/testdata/text_html_octet_attachment.mime b/pkg/message/testdata/text_html_octet_attachment.mime deleted file mode 100644 index 9767f58d..00000000 --- a/pkg/message/testdata/text_html_octet_attachment.mime +++ /dev/null @@ -1,31 +0,0 @@ -Content-Type: multipart/mixed; boundary=longrandomstring -From: Sender -To: Receiver - - -This is a multi-part message in MIME format. ---longrandomstring -Content-Type: multipart/alternative; boundary="0194fdc2fa2ffcc041d3ff12045b73c86e4ff95ff662a5eee82abdf44a2d" - - -This is a multi-part message in MIME format. ---0194fdc2fa2ffcc041d3ff12045b73c86e4ff95ff662a5eee82abdf44a2d -Content-Transfer-Encoding: quoted-printable -Content-Type: text/html - -This is body of HTML mail with attachment ---0194fdc2fa2ffcc041d3ff12045b73c86e4ff95ff662a5eee82abdf44a2d -Content-Transfer-Encoding: quoted-printable -Content-Type: text/plain - -This is body of *HTML mail* with attachment ---0194fdc2fa2ffcc041d3ff12045b73c86e4ff95ff662a5eee82abdf44a2d-- -. - ---longrandomstring -Content-Transfer-Encoding: base64 -Content-Type: application/octet-stream - -aWYgeW91IGFyZSByZWFkaW5nIHRoaXMsIGhpIQ== ---longrandomstring-- -. diff --git a/pkg/message/testdata/text_plain.mime b/pkg/message/testdata/text_plain.mime deleted file mode 100644 index 11e2fd1c..00000000 --- a/pkg/message/testdata/text_plain.mime +++ /dev/null @@ -1,5 +0,0 @@ -Content-Transfer-Encoding: quoted-printable -From: Sender -To: Receiver - -body \ No newline at end of file diff --git a/pkg/message/testdata/text_plain_7bit.mime b/pkg/message/testdata/text_plain_7bit.mime deleted file mode 100644 index 8d8e4d94..00000000 --- a/pkg/message/testdata/text_plain_7bit.mime +++ /dev/null @@ -1,5 +0,0 @@ -Content-Transfer-Encoding: 7bit -From: Sender -To: Receiver - -body \ No newline at end of file diff --git a/pkg/message/testdata/text_plain_image_inline.mime b/pkg/message/testdata/text_plain_image_inline.mime deleted file mode 100644 index 0aa46109..00000000 --- a/pkg/message/testdata/text_plain_image_inline.mime +++ /dev/null @@ -1,38 +0,0 @@ -Content-Type: multipart/related; boundary=longrandomstring -From: Sender -To: Receiver - - -This is a multi-part message in MIME format. ---longrandomstring -Content-Transfer-Encoding: quoted-printable - -body ---longrandomstring -Content-Disposition: inline -Content-Transfer-Encoding: base64 -Content-Type: image/png - -iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAABGdBTUEAALGPC/xhBQAAACBjSFJ -NAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAhGVYSWZNTQAqAAAACAAFAR -IAAwAAAAEAAQAAARoABQAAAAEAAABKARsABQAAAAEAAABSASgAAwAAAAEAAgAAh2kABAAAAAEAA -ABaAAAAAAAAASwAAAABAAABLAAAAAEAA6ABAAMAAAABAAEAAKACAAQAAAABAAAACKADAAQAAAAB -AAAACAAAAAAAXWZ6AAAACXBIWXMAAC4jAAAuIwF4pT92AAACZmlUWHRYTUw6Y29tLmFkb2JlLnh -tcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIE -NvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5O -TkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91 -dD0iIgogICAgICAgICAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4 -wLyIKICAgICAgICAgICAgeG1sbnM6ZXhpZj0iaHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC -8iPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgI -CAgICA8dGlmZjpSZXNvbHV0aW9uVW5pdD4yPC90aWZmOlJlc29sdXRpb25Vbml0PgogICAgICAg -ICA8ZXhpZjpDb2xvclNwYWNlPjE8L2V4aWY6Q29sb3JTcGFjZT4KICAgICAgICAgPGV4aWY6UGl -4ZWxYRGltZW5zaW9uPjE2PC9leGlmOlBpeGVsWERpbWVuc2lvbj4KICAgICAgICAgPGV4aWY6UG -l4ZWxZRGltZW5zaW9uPjE2PC9leGlmOlBpeGVsWURpbWVuc2lvbj4KICAgICAgPC9yZGY6RGVzY -3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CgZBD4sAAAEISURBVBgZY2CAAO5F -x07Zz96xZ0Pn4lXqIKGGhgYmsFTHvAWdW6/dvnb89Yf/B5+9/r/y9IXzbVPahCH6/jMysfAJygo -JC2r++/T619Mb139J8HIb8Gs5hYMUzJ+/gJ1Jmo9H6c+L5wz3bt5iEeLmYOHn42fQ4vyacqGNQS -0xMfEHc7Cvl6CYho4rh5jUPyYefqafLKyMbH9+/d28/dFfdWtfDaZvTy7Zvv72nYGZkeEvw98/f -5j//2P4yCvxq/nU7zVs//8yM2gzMMitOnnu5cUff/8ff/v5/5Xf///vuHBhJcSRDAws9aEMr38c -W7XjNgvzexZ2rn9vbjx/IXl/M9iLM2fOZAUAKCZv7dU+UgAAAAAASUVORK5CYII= ---longrandomstring-- -. diff --git a/pkg/message/testdata/text_plain_latin1.mime b/pkg/message/testdata/text_plain_latin1.mime deleted file mode 100644 index bec9ec97..00000000 --- a/pkg/message/testdata/text_plain_latin1.mime +++ /dev/null @@ -1,6 +0,0 @@ -Content-Transfer-Encoding: quoted-printable -Content-Type: text/plain; charset=ISO-8859-1 -From: Sender -To: Receiver - -=E9=E9=E9=E9=E9=E9=E9 \ No newline at end of file diff --git a/pkg/message/testdata/text_plain_octet_attachment.mime b/pkg/message/testdata/text_plain_octet_attachment.mime deleted file mode 100644 index f78b3ec9..00000000 --- a/pkg/message/testdata/text_plain_octet_attachment.mime +++ /dev/null @@ -1,17 +0,0 @@ -Content-Type: multipart/mixed; boundary=longrandomstring -From: Sender -To: Receiver - - -This is a multi-part message in MIME format. ---longrandomstring -Content-Transfer-Encoding: quoted-printable - -body ---longrandomstring -Content-Transfer-Encoding: base64 -Content-Type: application/octet-stream - -aWYgeW91IGFyZSByZWFkaW5nIHRoaXMsIGhpIQ== ---longrandomstring-- -. diff --git a/pkg/message/testdata/text_plain_octet_attachment_bad_2231_filename.mime b/pkg/message/testdata/text_plain_octet_attachment_bad_2231_filename.mime deleted file mode 100644 index 15a1193f..00000000 --- a/pkg/message/testdata/text_plain_octet_attachment_bad_2231_filename.mime +++ /dev/null @@ -1,18 +0,0 @@ -Content-Type: multipart/mixed; boundary=longrandomstring -From: Sender -To: Receiver - - -This is a multi-part message in MIME format. ---longrandomstring -Content-Transfer-Encoding: quoted-printable - -body ---longrandomstring -Content-Disposition: attachment; filename*=utf-8'%F0%9F%98%81%F0%9F%98%82.txt -Content-Transfer-Encoding: base64 -Content-Type: application/octet-stream - -aWYgeW91IGFyZSByZWFkaW5nIHRoaXMsIGhpIQ== ---longrandomstring-- -. diff --git a/pkg/message/testdata/text_plain_octet_attachment_good_2231_filename.mime b/pkg/message/testdata/text_plain_octet_attachment_good_2231_filename.mime deleted file mode 100644 index bec75a51..00000000 --- a/pkg/message/testdata/text_plain_octet_attachment_good_2231_filename.mime +++ /dev/null @@ -1,18 +0,0 @@ -Content-Type: multipart/mixed; boundary=longrandomstring -From: Sender -To: Receiver - - -This is a multi-part message in MIME format. ---longrandomstring -Content-Transfer-Encoding: quoted-printable - -body ---longrandomstring -Content-Disposition: attachment; filename*=utf-8''%F0%9F%98%81%F0%9F%98%82.txt -Content-Transfer-Encoding: base64 -Content-Type: application/octet-stream - -aWYgeW91IGFyZSByZWFkaW5nIHRoaXMsIGhpIQ== ---longrandomstring-- -. diff --git a/pkg/message/testdata/text_plain_plain_attachment.mime b/pkg/message/testdata/text_plain_plain_attachment.mime deleted file mode 100644 index c45b3cc4..00000000 --- a/pkg/message/testdata/text_plain_plain_attachment.mime +++ /dev/null @@ -1,17 +0,0 @@ -Content-Type: multipart/mixed; boundary=longrandomstring -From: Sender -To: Receiver - - -This is a multi-part message in MIME format. ---longrandomstring -Content-Transfer-Encoding: quoted-printable - -body ---longrandomstring -Content-Disposition: attachment -Content-Transfer-Encoding: quoted-printable - -attachment ---longrandomstring-- -. diff --git a/pkg/message/testdata/text_plain_unknown_latin1.mime b/pkg/message/testdata/text_plain_unknown_latin1.mime deleted file mode 100644 index c12ccbee..00000000 --- a/pkg/message/testdata/text_plain_unknown_latin1.mime +++ /dev/null @@ -1,6 +0,0 @@ -Content-Transfer-Encoding: quoted-printable -Content-Type: text/plain -From: Sender -To: Receiver - -=E9=E9=E9=E9=E9=E9=E9 \ No newline at end of file diff --git a/pkg/message/testdata/text_plain_unknown_latin2.mime b/pkg/message/testdata/text_plain_unknown_latin2.mime deleted file mode 100644 index 060ea378..00000000 --- a/pkg/message/testdata/text_plain_unknown_latin2.mime +++ /dev/null @@ -1,6 +0,0 @@ -Content-Transfer-Encoding: quoted-printable -Content-Type: text/plain -From: Sender -To: Receiver - -=F8=B9=F8=B9=F8=B9 \ No newline at end of file diff --git a/pkg/message/testdata/text_plain_utf8.mime b/pkg/message/testdata/text_plain_utf8.mime deleted file mode 100644 index 083cdc48..00000000 --- a/pkg/message/testdata/text_plain_utf8.mime +++ /dev/null @@ -1,6 +0,0 @@ -Content-Transfer-Encoding: quoted-printable -Content-Type: text/plain; charset=utf-8 -From: Sender -To: Receiver - -body \ No newline at end of file diff --git a/pkg/mime/encoding.go b/pkg/mime/encoding.go index ad522465..54903223 100644 --- a/pkg/mime/encoding.go +++ b/pkg/mime/encoding.go @@ -21,13 +21,10 @@ import ( "fmt" "io" "mime" - "mime/quotedprintable" "regexp" "strings" "unicode/utf8" - "encoding/base64" - "github.com/pkg/errors" "github.com/sirupsen/logrus" "golang.org/x/net/html/charset" @@ -246,19 +243,6 @@ func DecodeCharset(original []byte, contentType string) ([]byte, error) { return decoded, nil } -// DecodeContentEncoding wraps the reader with decoder based on content encoding. -func DecodeContentEncoding(r io.Reader, contentEncoding string) (d io.Reader) { - switch strings.ToLower(contentEncoding) { - case "quoted-printable": - d = quotedprintable.NewReader(r) - case "base64": - d = base64.NewDecoder(base64.StdEncoding, r) - case "7bit", "8bit", "binary", "": // Nothing to do - d = r - } - return -} - // ParseMediaType from MIME doesn't support RFC2231 for non asci / utf8 encodings so we have to pre-parse it. func ParseMediaType(v string) (mediatype string, params map[string]string, err error) { v, _ = changeEncodingAndKeepLastParamDefinition(v)