diff --git a/internal/imap/mailbox_message.go b/internal/imap/mailbox_message.go index de41b4d6..bf6f2894 100644 --- a/internal/imap/mailbox_message.go +++ b/internal/imap/mailbox_message.go @@ -67,13 +67,7 @@ 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() - buf := new(bytes.Buffer) - - if _, err := buf.ReadFrom(body); err != nil { - return err - } - - m, _, readers, err := message.Parse(buf.Bytes(), "", "") + m, _, _, readers, err := message.Parse(body, "", "") if err != nil { return err } diff --git a/internal/smtp/user.go b/internal/smtp/user.go index 67f105ee..ae14f30f 100644 --- a/internal/smtp/user.go +++ b/internal/smtp/user.go @@ -20,7 +20,6 @@ package smtp import ( - "bytes" "encoding/base64" "io" "mime" @@ -183,18 +182,7 @@ func (su *smtpUser) Send(from string, to []string, messageReader io.Reader) (err attachedPublicKeyName = "publickey - " + kr.GetIdentities()[0].Name } - buf := new(bytes.Buffer) - - if _, err = buf.ReadFrom(messageReader); err != nil { - return - } - - // HELP: Can we trust the mail client's 7bit filter? - // Might want to check here that it truly is 7bit clean. - // If it's not we need to use the message parser's writer ability (already has 7bit filter). - mimeBody := buf.String() - - message, plainBody, attReaders, err := message.Parse(buf.Bytes(), attachedPublicKey, attachedPublicKeyName) + message, mimeBody, plainBody, attReaders, err := message.Parse(messageReader, attachedPublicKey, attachedPublicKeyName) if err != nil { return } diff --git a/pkg/message/parser.go b/pkg/message/parser.go index de7e1792..e992da11 100644 --- a/pkg/message/parser.go +++ b/pkg/message/parser.go @@ -34,8 +34,8 @@ import ( "github.com/jaytaylor/html2text" ) -func Parse(b []byte, key, keyName string) (m *pmapi.Message, plainBody string, attReaders []io.Reader, err error) { - p, err := parser.New(b) +func Parse(r io.Reader, key, keyName string) (m *pmapi.Message, mimeBody, plainBody string, attReaders []io.Reader, err error) { + p, err := parser.New(r) if err != nil { return } @@ -68,7 +68,13 @@ func Parse(b []byte, key, keyName string) (m *pmapi.Message, plainBody string, a return } - return m, plainBody, attReaders, nil + mimeBodyBuffer := new(bytes.Buffer) + + if err = p.NewWriter().Write(mimeBodyBuffer); err != nil { + return + } + + return m, mimeBodyBuffer.String(), plainBody, attReaders, nil } func convertForeignEncodings(p *parser.Parser) error { diff --git a/pkg/message/parser/parser.go b/pkg/message/parser/parser.go index eebb78c4..41790cdd 100644 --- a/pkg/message/parser/parser.go +++ b/pkg/message/parser/parser.go @@ -18,7 +18,6 @@ package parser import ( - "bytes" "io" "io/ioutil" @@ -30,10 +29,10 @@ type Parser struct { root *Part } -func New(b []byte) (*Parser, error) { +func New(r io.Reader) (*Parser, error) { p := new(Parser) - entity, err := message.Read(bytes.NewReader(b)) + entity, err := message.Read(r) if err != nil && !message.IsUnknownCharset(err) { return nil, err } diff --git a/pkg/message/parser/parser_test.go b/pkg/message/parser/parser_test.go index 4b8d7c4e..3d1ec04e 100644 --- a/pkg/message/parser/parser_test.go +++ b/pkg/message/parser/parser_test.go @@ -18,7 +18,6 @@ package parser import ( - "bytes" "io" "io/ioutil" "os" @@ -29,15 +28,7 @@ import ( ) func newTestParser(t *testing.T, msg string) *Parser { - r := f(msg) - - buf := new(bytes.Buffer) - - if _, err := buf.ReadFrom(r); err != nil { - panic(err) - } - - p, err := New(buf.Bytes()) + p, err := New(f(msg)) require.NoError(t, err) return p diff --git a/pkg/message/parser_test.go b/pkg/message/parser_test.go index 6f2d161b..dd4ccac4 100644 --- a/pkg/message/parser_test.go +++ b/pkg/message/parser_test.go @@ -18,7 +18,6 @@ package message import ( - "bytes" "image/png" "io" "io/ioutil" @@ -34,7 +33,7 @@ import ( func TestParseTextPlain(t *testing.T) { f := f("text_plain.eml") - m, plainBody, attReaders, err := Parse(f, "", "") + m, _, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) @@ -49,7 +48,7 @@ func TestParseTextPlain(t *testing.T) { func TestParseTextPlainUTF8(t *testing.T) { f := f("text_plain_utf8.eml") - m, plainBody, attReaders, err := Parse(f, "", "") + m, _, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) @@ -64,7 +63,7 @@ func TestParseTextPlainUTF8(t *testing.T) { func TestParseTextPlainLatin1(t *testing.T) { f := f("text_plain_latin1.eml") - m, plainBody, attReaders, err := Parse(f, "", "") + m, _, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) @@ -79,7 +78,7 @@ func TestParseTextPlainLatin1(t *testing.T) { func TestParseTextPlainUnknownCharsetIsActuallyLatin1(t *testing.T) { f := f("text_plain_unknown_latin1.eml") - m, plainBody, attReaders, err := Parse(f, "", "") + m, _, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) @@ -94,7 +93,7 @@ func TestParseTextPlainUnknownCharsetIsActuallyLatin1(t *testing.T) { func TestParseTextPlainUnknownCharsetIsActuallyLatin2(t *testing.T) { f := f("text_plain_unknown_latin2.eml") - m, plainBody, attReaders, err := Parse(f, "", "") + m, _, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) @@ -115,7 +114,7 @@ func TestParseTextPlainUnknownCharsetIsActuallyLatin2(t *testing.T) { func TestParseTextPlainAlready7Bit(t *testing.T) { f := f("text_plain_7bit.eml") - m, plainBody, attReaders, err := Parse(f, "", "") + m, _, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) @@ -130,7 +129,7 @@ func TestParseTextPlainAlready7Bit(t *testing.T) { func TestParseTextPlainWithOctetAttachment(t *testing.T) { f := f("text_plain_octet_attachment.eml") - m, plainBody, attReaders, err := Parse(f, "", "") + m, _, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) @@ -146,7 +145,7 @@ func TestParseTextPlainWithOctetAttachment(t *testing.T) { func TestParseTextPlainWithOctetAttachmentGoodFilename(t *testing.T) { f := f("text_plain_octet_attachment_good_2231_filename.eml") - m, plainBody, attReaders, err := Parse(f, "", "") + m, _, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) @@ -163,7 +162,7 @@ func TestParseTextPlainWithOctetAttachmentGoodFilename(t *testing.T) { func TestParseTextPlainWithOctetAttachmentBadFilename(t *testing.T) { f := f("text_plain_octet_attachment_bad_2231_filename.eml") - m, plainBody, attReaders, err := Parse(f, "", "") + m, _, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) @@ -180,7 +179,7 @@ func TestParseTextPlainWithOctetAttachmentBadFilename(t *testing.T) { func TestParseTextPlainWithPlainAttachment(t *testing.T) { f := f("text_plain_plain_attachment.eml") - m, plainBody, attReaders, err := Parse(f, "", "") + m, _, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) @@ -196,7 +195,7 @@ func TestParseTextPlainWithPlainAttachment(t *testing.T) { func TestParseTextPlainWithImageInline(t *testing.T) { f := f("text_plain_image_inline.eml") - m, plainBody, attReaders, err := Parse(f, "", "") + m, _, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) @@ -216,7 +215,7 @@ func TestParseTextPlainWithImageInline(t *testing.T) { func TestParseWithMultipleTextParts(t *testing.T) { f := f("multiple_text_parts.eml") - m, plainBody, attReaders, err := Parse(f, "", "") + m, _, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) @@ -231,7 +230,7 @@ func TestParseWithMultipleTextParts(t *testing.T) { func TestParseTextHTML(t *testing.T) { f := f("text_html.eml") - m, plainBody, attReaders, err := Parse(f, "", "") + m, _, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) @@ -246,7 +245,7 @@ func TestParseTextHTML(t *testing.T) { func TestParseTextHTMLAlready7Bit(t *testing.T) { f := f("text_html_7bit.eml") - m, plainBody, attReaders, err := Parse(f, "", "") + m, _, plainBody, attReaders, err := Parse(f, "", "") assert.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) @@ -261,7 +260,7 @@ func TestParseTextHTMLAlready7Bit(t *testing.T) { func TestParseTextHTMLWithOctetAttachment(t *testing.T) { f := f("text_html_octet_attachment.eml") - m, plainBody, attReaders, err := Parse(f, "", "") + m, _, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) @@ -277,7 +276,7 @@ func TestParseTextHTMLWithOctetAttachment(t *testing.T) { func TestParseTextHTMLWithPlainAttachment(t *testing.T) { f := f("text_html_plain_attachment.eml") - m, plainBody, attReaders, err := Parse(f, "", "") + m, _, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) @@ -294,7 +293,7 @@ func TestParseTextHTMLWithPlainAttachment(t *testing.T) { func TestParseTextHTMLWithImageInline(t *testing.T) { f := f("text_html_image_inline.eml") - m, plainBody, attReaders, err := Parse(f, "", "") + m, _, plainBody, attReaders, err := Parse(f, "", "") assert.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) @@ -315,7 +314,7 @@ func TestParseWithAttachedPublicKey(t *testing.T) { f := f("text_plain.eml") // BAD: Public Key is not attached unless Content-Type is specified (not required)! - m, 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()) @@ -331,7 +330,7 @@ func TestParseWithAttachedPublicKey(t *testing.T) { func TestParseTextHTMLWithEmbeddedForeignEncoding(t *testing.T) { f := f("text_html_embedded_foreign_encoding.eml") - m, plainBody, attReaders, err := Parse(f, "", "") + m, _, plainBody, attReaders, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"Sender" `, m.Sender.String()) @@ -347,7 +346,7 @@ func TestParseTextHTMLWithEmbeddedForeignEncoding(t *testing.T) { func TestParseMultipartAlternative(t *testing.T) { f := f("multipart_alternative.eml") - m, plainBody, _, err := Parse(f, "", "") + m, _, plainBody, _, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"schizofrenic" `, m.Sender.String()) @@ -369,7 +368,7 @@ func TestParseMultipartAlternative(t *testing.T) { func TestParseMultipartAlternativeNested(t *testing.T) { f := f("multipart_alternative_nested.eml") - m, plainBody, _, err := Parse(f, "", "") + m, _, plainBody, _, err := Parse(f, "", "") require.NoError(t, err) assert.Equal(t, `"schizofrenic" `, m.Sender.String()) @@ -388,17 +387,13 @@ func TestParseMultipartAlternativeNested(t *testing.T) { assert.Equal(t, "*multipart 2.1*\n\n", plainBody) } -func f(filename string) []byte { +func f(filename string) io.Reader { f, err := os.Open(filepath.Join("testdata", filename)) if err != nil { panic(err) } - buf := new(bytes.Buffer) - - _, _ = buf.ReadFrom(f) - - return buf.Bytes() + return f } func readerToString(r io.Reader) string {