diff --git a/etc/swaks-tests/utf8-subject.raw b/etc/swaks-tests/utf8-subject.raw index 689e655..24d7094 100644 --- a/etc/swaks-tests/utf8-subject.raw +++ b/etc/swaks-tests/utf8-subject.raw @@ -1,6 +1,8 @@ Date: %DATE% -To: %TO_ADDRESS% -From: %FROM_ADDRESS% +To: %TO_ADDRESS%, + =?utf-8?B?VGVzdCBvZiDIh8myyqLIr8ihyarJtMqb?= +From: =?utf-8?q?X-=C3=A4=C3=A9=C3=9F_Y-=C3=A4=C3=A9=C3=9F?= + Subject: =?utf-8?B?VGVzdCBvZiDIh8myyqLIr8ihyarJtMqb?= Thread-Topic: =?utf-8?B?VGVzdCBvZiDIh8myyqLIr8ihyarJtMqb?= Thread-Index: Ac6+4nH7mOymA+1JRQyk2LQPe1bEcw== diff --git a/pkg/rest/apiv1_controller.go b/pkg/rest/apiv1_controller.go index d9795eb..09ff079 100644 --- a/pkg/rest/apiv1_controller.go +++ b/pkg/rest/apiv1_controller.go @@ -33,7 +33,7 @@ func MailboxListV1(w http.ResponseWriter, req *http.Request, ctx *web.Context) ( jmessages[i] = &model.JSONMessageHeaderV1{ Mailbox: name, ID: msg.ID, - From: msg.From.String(), + From: stringutil.StringAddress(msg.From), To: stringutil.StringAddressList(msg.To), Subject: msg.Subject, Date: msg.Date, @@ -79,7 +79,7 @@ func MailboxShowV1(w http.ResponseWriter, req *http.Request, ctx *web.Context) ( &model.JSONMessageV1{ Mailbox: name, ID: msg.ID, - From: msg.From.String(), + From: stringutil.StringAddress(msg.From), To: stringutil.StringAddressList(msg.To), Subject: msg.Subject, Date: msg.Date, diff --git a/pkg/server/web/helpers.go b/pkg/server/web/helpers.go index ea32cb2..838950f 100644 --- a/pkg/server/web/helpers.go +++ b/pkg/server/web/helpers.go @@ -8,11 +8,13 @@ import ( "strings" "time" + "github.com/jhillyerd/inbucket/pkg/stringutil" "github.com/rs/zerolog/log" ) // TemplateFuncs declares functions made available to all templates (including partials) var TemplateFuncs = template.FuncMap{ + "address": stringutil.StringAddress, "friendlyTime": FriendlyTime, "reverse": Reverse, "stringsJoin": strings.Join, diff --git a/pkg/stringutil/utils.go b/pkg/stringutil/utils.go index afde694..cae5fbd 100644 --- a/pkg/stringutil/utils.go +++ b/pkg/stringutil/utils.go @@ -19,13 +19,28 @@ func HashMailboxName(mailbox string) string { return fmt.Sprintf("%x", h.Sum(nil)) } -// StringAddressList converts a list of addresses to a list of strings +// StringAddress converts an Address to a UTF-8 string. +func StringAddress(a *mail.Address) string { + b := &strings.Builder{} + if a != nil { + if a.Name != "" { + b.WriteString(a.Name) + b.WriteRune(' ') + } + if a.Address != "" { + b.WriteRune('<') + b.WriteString(a.Address) + b.WriteRune('>') + } + } + return b.String() +} + +// StringAddressList converts a list of addresses to a list of UTF-8 strings. func StringAddressList(addrs []*mail.Address) []string { s := make([]string, len(addrs)) for i, a := range addrs { - if a != nil { - s[i] = a.String() - } + s[i] = StringAddress(a) } return s } diff --git a/pkg/stringutil/utils_test.go b/pkg/stringutil/utils_test.go index 8c0b7bd..4bc3cc7 100644 --- a/pkg/stringutil/utils_test.go +++ b/pkg/stringutil/utils_test.go @@ -17,10 +17,14 @@ func TestHashMailboxName(t *testing.T) { func TestStringAddressList(t *testing.T) { input := []*mail.Address{ - {Name: "Fred B. Fish", Address: "fred@fish.org"}, + {Name: "Fred ß. Fish", Address: "fred@fish.org"}, {Name: "User", Address: "user@domain.org"}, + {Address: "a@b.com"}, } - want := []string{`"Fred B. Fish" `, `"User" `} + want := []string{ + `Fred ß. Fish `, + `User `, + ``} output := stringutil.StringAddressList(input) if len(output) != len(want) { t.Fatalf("Got %v strings, want: %v", len(output), len(want)) diff --git a/pkg/test/integration_test.go b/pkg/test/integration_test.go index 3dbca28..9d0963a 100644 --- a/pkg/test/integration_test.go +++ b/pkg/test/integration_test.go @@ -44,6 +44,7 @@ func TestSuite(t *testing.T) { }{ {"basic", testBasic}, {"fullname", testFullname}, + {"encodedHeader", testEncodedHeader}, } for _, tc := range testCases { t.Run(tc.name, tc.test) @@ -59,13 +60,13 @@ func testBasic(t *testing.T) { to := []string{"recipient@inbucket.org"} input := readTestData("basic.txt") - // Send mail + // Send mail. err = smtpclient.SendMail(smtpHost, nil, from, to, input) if err != nil { t.Fatal(err) } - // Confirm receipt + // Confirm receipt. msg, err := client.GetMessage("recipient", "latest") if err != nil { t.Fatal(err) @@ -88,13 +89,13 @@ func testFullname(t *testing.T) { to := []string{"recipient@inbucket.org"} input := readTestData("fullname.txt") - // Send mail + // Send mail. err = smtpclient.SendMail(smtpHost, nil, from, to, input) if err != nil { t.Fatal(err) } - // Confirm receipt + // Confirm receipt. msg, err := client.GetMessage("recipient", "latest") if err != nil { t.Fatal(err) @@ -108,6 +109,35 @@ func testFullname(t *testing.T) { goldiff.File(t, got, "testdata", "fullname.golden") } +func testEncodedHeader(t *testing.T) { + client, err := client.New(restBaseURL) + if err != nil { + t.Fatal(err) + } + from := "fromuser@inbucket.org" + to := []string{"recipient@inbucket.org"} + input := readTestData("encodedheader.txt") + + // Send mail. + err = smtpclient.SendMail(smtpHost, nil, from, to, input) + if err != nil { + t.Fatal(err) + } + + // Confirm receipt. + msg, err := client.GetMessage("recipient", "latest") + if err != nil { + t.Fatal(err) + } + if msg == nil { + t.Errorf("Got nil message, wanted non-nil message.") + } + + // Compare to golden. + got := formatMessage(msg) + goldiff.File(t, got, "testdata", "encodedheader.golden") +} + func formatMessage(m *client.Message) []byte { b := &bytes.Buffer{} fmt.Fprintf(b, "Mailbox: %v\n", m.Mailbox) diff --git a/pkg/test/testdata/encodedheader.golden b/pkg/test/testdata/encodedheader.golden new file mode 100644 index 0000000..af11c2a --- /dev/null +++ b/pkg/test/testdata/encodedheader.golden @@ -0,0 +1,12 @@ +Mailbox: recipient +From: X-äéß Y-äéß +To: [Test of ȇɲʢȯȡɪɴʛ ] +Subject: Test of ȇɲʢȯȡɪɴʛ +Size: 351 + +BODY TEXT: +Basic message. + + +BODY HTML: + diff --git a/pkg/test/testdata/encodedheader.txt b/pkg/test/testdata/encodedheader.txt new file mode 100644 index 0000000..8855f72 --- /dev/null +++ b/pkg/test/testdata/encodedheader.txt @@ -0,0 +1,5 @@ +From: =?utf-8?q?X-=C3=A4=C3=A9=C3=9F_Y-=C3=A4=C3=A9=C3=9F?= +To: =?utf-8?B?VGVzdCBvZiDIh8myyqLIr8ihyarJtMqb?= +Subject: =?utf-8?b?VGVzdCBvZiDIh8myyqLIr8ihyarJtMqb?= + +Basic message. diff --git a/pkg/test/testdata/fullname.golden b/pkg/test/testdata/fullname.golden index e42108f..b40a967 100644 --- a/pkg/test/testdata/fullname.golden +++ b/pkg/test/testdata/fullname.golden @@ -1,6 +1,6 @@ Mailbox: recipient -From: "From User" -To: ["Rec I. Pient" ] +From: From User +To: [Rec I. Pient ] Subject: basic subject Size: 246 diff --git a/ui/templates/mailbox/_show.html b/ui/templates/mailbox/_show.html index 49621f0..227ec1f 100644 --- a/ui/templates/mailbox/_show.html +++ b/ui/templates/mailbox/_show.html @@ -51,12 +51,12 @@
From:
-
{{.message.From}}
+
{{.message.From | address}}
To:
{{range $i, $addr := .message.To}} {{- if $i}},{{end}} - {{$addr -}} + {{$addr | address -}} {{end}}
Date: