From c9392c7eb1f174668076670cd17072cecf0e2127 Mon Sep 17 00:00:00 2001 From: James Hillyerd Date: Tue, 1 Oct 2013 14:01:08 -0700 Subject: [PATCH] Wired character-set decoding into From and Subject - Removed extra message object from ReadBody() return type - We now use enmime's GetHeader() when building the GOB, this will get us alternate character set decoding for the From and Subject headers. - Added a swaks test with a utf-8 subject line --- .goxc.json | 2 +- smtpd/datastore.go | 2 +- smtpd/filestore.go | 22 +++++++-------- swaks-tests/run-tests.sh | 3 ++ swaks-tests/utf8-subject.txt | 53 ++++++++++++++++++++++++++++++++++++ web/mailbox_controller.go | 8 +++--- 6 files changed, 72 insertions(+), 18 deletions(-) create mode 100644 swaks-tests/utf8-subject.txt diff --git a/.goxc.json b/.goxc.json index 3495d30..918a9bb 100644 --- a/.goxc.json +++ b/.goxc.json @@ -6,7 +6,7 @@ "Resources": { "Include": "README*,LICENSE*,bin,etc,themes" }, - "PackageVersion": "0.1", + "PackageVersion": "20131001", "PrereleaseInfo": "snapshot", "FormatVersion": "0.8" } diff --git a/smtpd/datastore.go b/smtpd/datastore.go index 40a2b12..7ae989d 100644 --- a/smtpd/datastore.go +++ b/smtpd/datastore.go @@ -26,7 +26,7 @@ type Message interface { Subject() string RawReader() (reader io.ReadCloser, err error) ReadHeader() (msg *mail.Message, err error) - ReadBody() (msg *mail.Message, body *enmime.MIMEBody, err error) + ReadBody() (body *enmime.MIMEBody, err error) ReadRaw() (raw *string, err error) Append(data []byte) error Close() error diff --git a/smtpd/filestore.go b/smtpd/filestore.go index 40c45f8..72b3037 100644 --- a/smtpd/filestore.go +++ b/smtpd/filestore.go @@ -246,25 +246,23 @@ func (m *FileMessage) ReadHeader() (msg *mail.Message, err error) { return msg, err } -// ReadBody opens the .raw portion of a Message and returns a MIMEBody object, along -// with a free mail.Message containing the Headers, since we had to make one of those -// anyway. -func (m *FileMessage) ReadBody() (msg *mail.Message, body *enmime.MIMEBody, err error) { +// ReadBody opens the .raw portion of a Message and returns a MIMEBody object +func (m *FileMessage) ReadBody() (body *enmime.MIMEBody, err error) { file, err := os.Open(m.rawPath()) defer file.Close() if err != nil { - return nil, nil, err + return nil, err } reader := bufio.NewReader(file) - msg, err = mail.ReadMessage(reader) + msg, err := mail.ReadMessage(reader) if err != nil { - return nil, nil, err + return nil, err } mime, err := enmime.ParseMIMEBody(msg) if err != nil { - return nil, nil, err + return nil, err } - return msg, mime, err + return mime, err } // RawReader opens the .raw portion of a Message as an io.ReadCloser @@ -365,14 +363,14 @@ func (m *FileMessage) createGob() error { writer := bufio.NewWriter(file) // Fetch headers - msg, err := m.ReadHeader() + body, err := m.ReadBody() if err != nil { return err } // Only public fields are stored in gob - m.Ffrom = msg.Header.Get("From") - m.Fsubject = msg.Header.Get("Subject") + m.Ffrom = body.GetHeader("From") + m.Fsubject = body.GetHeader("Subject") // Write & flush enc := gob.NewEncoder(writer) diff --git a/swaks-tests/run-tests.sh b/swaks-tests/run-tests.sh index 3b134e9..b89ec0e 100755 --- a/swaks-tests/run-tests.sh +++ b/swaks-tests/run-tests.sh @@ -11,3 +11,6 @@ swaks $* --h-Subject: "Swaks HTML" --data html.raw # Attachment test swaks $* --h-Subject: "Swaks Attachment" --attach-type image/png --attach favicon.png --body text.txt + +# Encoded subject line test +swaks $* --data utf8-subject.txt diff --git a/swaks-tests/utf8-subject.txt b/swaks-tests/utf8-subject.txt new file mode 100644 index 0000000..689e655 --- /dev/null +++ b/swaks-tests/utf8-subject.txt @@ -0,0 +1,53 @@ +Date: %DATE% +To: %TO_ADDRESS% +From: %FROM_ADDRESS% +Subject: =?utf-8?B?VGVzdCBvZiDIh8myyqLIr8ihyarJtMqb?= +Thread-Topic: =?utf-8?B?VGVzdCBvZiDIh8myyqLIr8ihyarJtMqb?= +Thread-Index: Ac6+4nH7mOymA+1JRQyk2LQPe1bEcw== +Accept-Language: en-US +Content-Language: en-US +X-MS-Has-Attach: +X-MS-TNEF-Correlator: +Content-Type: multipart/alternative; + boundary="_000_8D08CB465951804FA4DBB0C8B35CB0FAC1DF557EONERDEXCH03onen_" +MIME-Version: 1.0 + +--_000_8D08CB465951804FA4DBB0C8B35CB0FAC1DF557EONERDEXCH03onen_ +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: base64 + +VGVzdGluZyBzdWJqZWN0IGxpbmUgZW5jb2RpbmcNCg0K + +--_000_8D08CB465951804FA4DBB0C8B35CB0FAC1DF557EONERDEXCH03onen_ +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: base64 + +PGh0bWw+DQo8aGVhZD4NCjxtZXRhIGh0dHAtZXF1aXY9IkNvbnRlbnQtVHlwZSIgY29udGVudD0i +dGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04Ij4NCjxtZXRhIG5hbWU9IkdlbmVyYXRvciIgY29udGVu +dD0iTWljcm9zb2Z0IFdvcmQgMTQgKGZpbHRlcmVkIG1lZGl1bSkiPg0KPHN0eWxlPjwhLS0NCi8q +IEZvbnQgRGVmaW5pdGlvbnMgKi8NCkBmb250LWZhY2UNCgl7Zm9udC1mYW1pbHk6Q2FsaWJyaTsN +CglwYW5vc2UtMToyIDE1IDUgMiAyIDIgNCAzIDIgNDt9DQovKiBTdHlsZSBEZWZpbml0aW9ucyAq +Lw0KcC5Nc29Ob3JtYWwsIGxpLk1zb05vcm1hbCwgZGl2Lk1zb05vcm1hbA0KCXttYXJnaW46MGlu +Ow0KCW1hcmdpbi1ib3R0b206LjAwMDFwdDsNCglmb250LXNpemU6MTEuMHB0Ow0KCWZvbnQtZmFt +aWx5OiJDYWxpYnJpIiwic2Fucy1zZXJpZiI7fQ0KYTpsaW5rLCBzcGFuLk1zb0h5cGVybGluaw0K +CXttc28tc3R5bGUtcHJpb3JpdHk6OTk7DQoJY29sb3I6Ymx1ZTsNCgl0ZXh0LWRlY29yYXRpb246 +dW5kZXJsaW5lO30NCmE6dmlzaXRlZCwgc3Bhbi5Nc29IeXBlcmxpbmtGb2xsb3dlZA0KCXttc28t +c3R5bGUtcHJpb3JpdHk6OTk7DQoJY29sb3I6cHVycGxlOw0KCXRleHQtZGVjb3JhdGlvbjp1bmRl +cmxpbmU7fQ0Kc3Bhbi5FbWFpbFN0eWxlMTcNCgl7bXNvLXN0eWxlLXR5cGU6cGVyc29uYWwtY29t +cG9zZTsNCglmb250LWZhbWlseToiQ2FsaWJyaSIsInNhbnMtc2VyaWYiOw0KCWNvbG9yOndpbmRv +d3RleHQ7fQ0KLk1zb0NocERlZmF1bHQNCgl7bXNvLXN0eWxlLXR5cGU6ZXhwb3J0LW9ubHk7DQoJ +Zm9udC1mYW1pbHk6IkNhbGlicmkiLCJzYW5zLXNlcmlmIjt9DQpAcGFnZSBXb3JkU2VjdGlvbjEN +Cgl7c2l6ZTo4LjVpbiAxMS4waW47DQoJbWFyZ2luOjEuMGluIDEuMGluIDEuMGluIDEuMGluO30N +CmRpdi5Xb3JkU2VjdGlvbjENCgl7cGFnZTpXb3JkU2VjdGlvbjE7fQ0KLS0+PC9zdHlsZT48IS0t +W2lmIGd0ZSBtc28gOV0+PHhtbD4NCjxvOnNoYXBlZGVmYXVsdHMgdjpleHQ9ImVkaXQiIHNwaWRt +YXg9IjEwMjYiIC8+DQo8L3htbD48IVtlbmRpZl0tLT48IS0tW2lmIGd0ZSBtc28gOV0+PHhtbD4N +CjxvOnNoYXBlbGF5b3V0IHY6ZXh0PSJlZGl0Ij4NCjxvOmlkbWFwIHY6ZXh0PSJlZGl0IiBkYXRh +PSIxIiAvPg0KPC9vOnNoYXBlbGF5b3V0PjwveG1sPjwhW2VuZGlmXS0tPg0KPC9oZWFkPg0KPGJv +ZHkgbGFuZz0iRU4tVVMiIGxpbms9ImJsdWUiIHZsaW5rPSJwdXJwbGUiPg0KPGRpdiBjbGFzcz0i +V29yZFNlY3Rpb24xIj4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPlRlc3Rpbmcgc3ViamVjdCBsaW5l +IGVuY29kaW5nPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTo4LjBwdDtmb250LWZhbWlseTomcXVvdDtB +cmlhbCZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7Ij48bzpwPjwvbzpwPjwvc3Bhbj48L3A+ +DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48bzpwPiZuYnNwOzwvbzpwPjwvcD4NCjwvZGl2Pg0KPC9i +b2R5Pg0KPC9odG1sPg0K + +--_000_8D08CB465951804FA4DBB0C8B35CB0FAC1DF557EONERDEXCH03onen_-- diff --git a/web/mailbox_controller.go b/web/mailbox_controller.go index 4decc23..ef9866b 100644 --- a/web/mailbox_controller.go +++ b/web/mailbox_controller.go @@ -57,7 +57,7 @@ func MailboxShow(w http.ResponseWriter, req *http.Request, ctx *Context) (err er if err != nil { return fmt.Errorf("GetMessage() failed: %v", err) } - _, mime, err := message.ReadBody() + mime, err := message.ReadBody() if err != nil { return fmt.Errorf("ReadBody() failed: %v", err) } @@ -87,7 +87,7 @@ func MailboxHtml(w http.ResponseWriter, req *http.Request, ctx *Context) (err er if err != nil { return err } - _, mime, err := message.ReadBody() + mime, err := message.ReadBody() if err != nil { return err } @@ -144,7 +144,7 @@ func MailboxDownloadAttach(w http.ResponseWriter, req *http.Request, ctx *Contex if err != nil { return err } - _, body, err := message.ReadBody() + body, err := message.ReadBody() if err != nil { return err } @@ -181,7 +181,7 @@ func MailboxViewAttach(w http.ResponseWriter, req *http.Request, ctx *Context) ( if err != nil { return err } - _, body, err := message.ReadBody() + body, err := message.ReadBody() if err != nil { return err }