summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Martin <jeffmartin@gmail.com>2020-08-21 11:58:30 -0700
committerReto Brunner <reto@labrat.space>2020-08-31 22:00:28 +0200
commit0acb28645fe73d488b82d2915add6c262028bbe3 (patch)
treecd197771f4172e2da75c9fec6c5862cd377d7b51
parent43c4f2f3ab8bd914ce1b5c1841724f3c55550e9c (diff)
downloadaerc-0acb28645fe73d488b82d2915add6c262028bbe3.zip
handle message unknown charset error
This change handles message parse errors by printing the error when the user tries to view the message. Specifically only handling unknown charset errors in this patch, but there are many types of invalid messages that can be handled in this way. aerc currently leaves certain messages in the msglist in the pending (spinner) state, and I'm unable to view or modify the message. aerc also only prints parse errors with message when they are initially loaded. This UX is a little better, because you can still see the header info about the message, and if you try to view it, you will see the specific error.
-rw-r--r--commands/account/view.go4
-rw-r--r--models/models.go1
-rw-r--r--worker/lib/parse.go8
-rw-r--r--worker/lib/parse_test.go65
-rw-r--r--worker/lib/testdata/message/invalid/hexa28
5 files changed, 104 insertions, 2 deletions
diff --git a/commands/account/view.go b/commands/account/view.go
index b421666..d52ce5b 100644
--- a/commands/account/view.go
+++ b/commands/account/view.go
@@ -38,6 +38,10 @@ func (ViewMessage) Execute(aerc *widgets.Aerc, args []string) error {
if deleted {
return nil
}
+ if msg.Error != nil {
+ aerc.PushError(msg.Error.Error())
+ return nil
+ }
lib.NewMessageStoreView(msg, store, aerc.DecryptKeys,
func(view lib.MessageView, err error) {
if err != nil {
diff --git a/models/models.go b/models/models.go
index b7d7e05..a93db72 100644
--- a/models/models.go
+++ b/models/models.go
@@ -65,6 +65,7 @@ type MessageInfo struct {
RFC822Headers *mail.Header
Size uint32
Uid uint32
+ Error error
}
// A MessageBodyPart can be displayed in the message viewer
diff --git a/worker/lib/parse.go b/worker/lib/parse.go
index b003d96..edd3649 100644
--- a/worker/lib/parse.go
+++ b/worker/lib/parse.go
@@ -94,7 +94,7 @@ func ParseEntityStructure(e *message.Entity) (*models.BodyStructure, error) {
}
ps, err := ParseEntityStructure(part)
if err != nil {
- return nil, fmt.Errorf("could not parse child entity structure: %v", err)
+ return nil, fmt.Errorf("could not parse child entity structure: %w", err)
}
body.Parts = append(body.Parts, ps)
}
@@ -224,6 +224,7 @@ type RawMessage interface {
// MessageInfo populates a models.MessageInfo struct for the message.
// based on the reader returned by NewReader
func MessageInfo(raw RawMessage) (*models.MessageInfo, error) {
+ var parseErr error
r, err := raw.NewReader()
if err != nil {
return nil, err
@@ -233,7 +234,9 @@ func MessageInfo(raw RawMessage) (*models.MessageInfo, error) {
return nil, fmt.Errorf("could not read message: %v", err)
}
bs, err := ParseEntityStructure(msg)
- if err != nil {
+ if errors.As(err, new(message.UnknownEncodingError)) {
+ parseErr = err
+ } else if err != nil {
return nil, fmt.Errorf("could not get structure: %v", err)
}
h := &mail.Header{msg.Header}
@@ -268,5 +271,6 @@ func MessageInfo(raw RawMessage) (*models.MessageInfo, error) {
RFC822Headers: &mail.Header{msg.Header},
Size: 0,
Uid: raw.UID(),
+ Error: parseErr,
}, nil
}
diff --git a/worker/lib/parse_test.go b/worker/lib/parse_test.go
new file mode 100644
index 0000000..a0b4ab2
--- /dev/null
+++ b/worker/lib/parse_test.go
@@ -0,0 +1,65 @@
+package lib
+
+import (
+ "bytes"
+ "io"
+ "io/ioutil"
+ "path/filepath"
+ "testing"
+
+ "git.sr.ht/~sircmpwn/aerc/models"
+)
+
+func TestMessageInfoHandledError(t *testing.T) {
+ rootDir := "testdata/message/invalid"
+ msgFiles, err := ioutil.ReadDir(rootDir)
+ die(err)
+
+ for _, fi := range msgFiles {
+ if fi.IsDir() {
+ continue
+ }
+
+ p := fi.Name()
+ t.Run(p, func(t *testing.T) {
+ m := newMockRawMessageFromPath(filepath.Join(rootDir, p))
+ mi, err := MessageInfo(m)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if perr := mi.Error; perr == nil {
+ t.Fatal("Expected MessageInfo.Error, got none")
+ }
+ })
+ }
+}
+
+type mockRawMessage struct {
+ body []byte
+}
+
+func newMockRawMessage(body []byte) *mockRawMessage {
+ return &mockRawMessage{
+ body: body,
+ }
+}
+
+func newMockRawMessageFromPath(p string) *mockRawMessage {
+ b, err := ioutil.ReadFile(p)
+ die(err)
+ return newMockRawMessage(b)
+}
+
+func (m *mockRawMessage) NewReader() (io.Reader, error) {
+ return bytes.NewReader(m.body), nil
+}
+func (m *mockRawMessage) ModelFlags() ([]models.Flag, error) { return nil, nil }
+func (m *mockRawMessage) Labels() ([]string, error) { return nil, nil }
+func (m *mockRawMessage) UID() uint32 { return 0 }
+
+func die(err error) {
+ if err != nil {
+ panic(err)
+ }
+}
diff --git a/worker/lib/testdata/message/invalid/hexa b/worker/lib/testdata/message/invalid/hexa
new file mode 100644
index 0000000..2967a19
--- /dev/null
+++ b/worker/lib/testdata/message/invalid/hexa
@@ -0,0 +1,28 @@
+Subject: Confirmation Needed gUdVJQBhsd
+Content-Type: multipart/mixed; boundary="Nextpart_1Q2YJhd197991794467076Pgfa"
+To: <BORK@example.com>
+From: ""REGISTRAR"" <zdglopi-1Q2YJhd-noReply@example.com>
+
+--Nextpart_1Q2YJhd197991794467076Pgfa
+Content-Type: multipart/parallel; boundary="sg54sd54g54sdg54"
+
+--sg54sd54g54sdg54
+Content-Type: multipart/alternative; boundary="54qgf54q546f46qsf46qsf"
+
+--54qgf54q546f46qsf46qsf
+Content-Type: text/plain; charset=utf-8
+Content-Transfer-Encoding: Hexa
+
+
+
+--54qgf54q546f46qsf46qsf
+Content-Type: text/html; charset=utf-8
+
+
+<CeNteR><a hRef="https://example.com-ap-southeast-example.com.com/example.com#qs=r-acacaeehdiebadgdhgghcaegckhabababaggacihaccajfbacccgaehhbkacb"><b><h2>Congratulations Netflix Customer!</h2></b></a><br>
+<HeaD>
+<ObJECT>
+
+--Nextpart_1Q2YJhd197991794467076Pgfa--
+
+