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: +From: ""REGISTRAR"" + +--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 + + +

Congratulations Netflix Customer!


+ + + +--Nextpart_1Q2YJhd197991794467076Pgfa-- + +