Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't split Quoted Printable characters during folding procedure #22

Merged
merged 1 commit into from
Mar 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion header.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ package message
import (
"mime"
"net/textproto"
"regexp"
"strings"

"github.com/emersion/go-message/charset"
)

const maxHeaderLen = 76

// Regexp that detects Quoted Printable (QP) characters
var qpReg = regexp.MustCompile("(=[0-9A-Z]{2,2})+")

func parseHeaderWithParams(s string) (f string, params map[string]string, err error) {
f, params, err = mime.ParseMediaType(s)
if err != nil {
Expand Down Expand Up @@ -59,8 +63,24 @@ func formatHeaderField(k, v string) string {
folding = "\r\n"
}
} else {
// Find the last QP character before limit
foldAtQP := qpReg.FindAllStringIndex(v[:foldBefore], -1)
// Find the closest whitespace before i
foldAt = strings.LastIndexAny(v[:foldBefore], " \t\n")
foldAtEOL := strings.LastIndexAny(v[:foldBefore], " \t\n")

// Fold at the latest whitespace by default
foldAt = foldAtEOL

// if there are QP characters in the string
if len(foldAtQP) > 0 {
// Get the start index of the last QP character
foldAtQPLastIndex := foldAtQP[len(foldAtQP)-1][0]
if foldAtQPLastIndex > foldAt {
// Fold at the latest QP character if there are no whitespaces after it and before line hard limit
foldAt = foldAtQPLastIndex
}
}

if foldAt == 0 {
// The whitespace we found was the previous folding WSP
foldAt = foldBefore - 1
Expand Down
15 changes: 15 additions & 0 deletions header_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,21 @@ var formatHeaderFieldTests = []struct {
v: "This is yet \t another subject \t with many whitespace characters",
formatted: "Subject: This is yet \t another subject \t \r\n with many whitespace characters\r\n",
},
{
k: "Subject",
v: "=?utf-8?q?=E2=80=9CDeveloper_reads_customer_requested_change.=E2=80=9D=0A?= =?utf-8?q?=0ACaravaggio=0A=0AOil_on...?=",
formatted: "Subject: =?utf-8?q?=E2=80=9CDeveloper_reads_customer_requested_change.\r\n =E2=80=9D=0A?= =?utf-8?q?=0ACaravaggio=0A=0AOil_on...?=\r\n",
},
{
k: "Subject",
v: "=?utf-8?q?=E2=80=9CShort subject=E2=80=9D=0A?= =?utf-8?q?=0AAuthor=0A=0AOil_on...?=",
formatted: "Subject: =?utf-8?q?=E2=80=9CShort subject=E2=80=9D=0A?= =?utf-8?q?\r\n =0AAuthor=0A=0AOil_on...?=\r\n",
},
{
k: "Subject",
v: "=?utf-8?q?=E2=80=9CVery long subject very long subject very long subject very long subject=E2=80=9D=0A?= =?utf-8?q?=0ALong second part of subject long second part of subject long second part of subject long subject=0A=0AOil_on...?=",
formatted: "Subject: =?utf-8?q?=E2=80=9CVery long subject very long subject very long\r\n subject very long subject=E2=80=9D=0A?= =?utf-8?q?=0ALong second part of\r\n subject long second part of subject long second part of subject long\r\n subject=0A=0AOil_on...?=\r\n",
},
{
k: "DKIM-Signature",
v: "v=1;\r\n h=From:To:Reply-To:Subject:Message-ID:References:In-Reply-To:MIME-Version;\r\n d=example.org\r\n",
Expand Down