backends: send MessageInfoError on header fetching error

When an error is encountered fetching a header, the backends respond
with a type.Error worker message. On receipt of this message, the UI
deletes all pending headers. The headers are all requested again as they
remain on the screen, resulting in an infinite request loop - and an
infinite logging loop. The user only ever sees the spinner unless they
check the logs.

A previous commit intended to fix this, however it introduced a
regression where any message that was part of the fetch request would
also be marked as erroneous. This commit is reverted with commit
2aad2fea7d36 ("msgstore: revert 9fdc7acf5b48").

Send an erroneous message info message from the backend when an error is
encountered for a specific UID.

Fixes: 01f80721e2 ("msgstore: post MessageInfo on erroneous fetch")
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
This commit is contained in:
Tim Culverhouse 2022-09-21 11:44:12 -05:00 committed by Robin Jarry
parent a9af5635bc
commit e7a51f5524
5 changed files with 20 additions and 8 deletions

View file

@ -50,10 +50,7 @@ func (imapw *IMAPWorker) handleFetchMessageHeaders(
if err != nil { if err != nil {
logging.Errorf( logging.Errorf(
"message %d: could not read header: %v", _msg.Uid, err) "message %d: could not read header: %v", _msg.Uid, err)
imapw.worker.PostMessage(&types.Error{ imapw.worker.PostMessageInfoError(msg, _msg.Uid, err)
Message: types.RespondTo(msg),
Error: err,
}, nil)
return nil return nil
} }
header := &mail.Header{Header: message.Header{Header: textprotoHeader}} header := &mail.Header{Header: message.Header{Header: textprotoHeader}}

View file

@ -479,7 +479,7 @@ func (w *Worker) handleFetchMessageHeaders(
info, err := w.msgInfoFromUid(uid) info, err := w.msgInfoFromUid(uid)
if err != nil { if err != nil {
logging.Errorf("could not get message info: %w", err) logging.Errorf("could not get message info: %w", err)
w.err(msg, err) w.worker.PostMessageInfoError(msg, uid, err)
continue continue
} }
w.worker.PostMessage(&types.MessageInfo{ w.worker.PostMessage(&types.MessageInfo{

View file

@ -152,7 +152,7 @@ func (w *mboxWorker) handleMessage(msg types.WorkerMessage) error {
} }
msgInfo, err := lib.MessageInfo(m) msgInfo, err := lib.MessageInfo(m)
if err != nil { if err != nil {
reterr = err w.worker.PostMessageInfoError(msg, uid, err)
break break
} else { } else {
w.worker.PostMessage(&types.MessageInfo{ w.worker.PostMessage(&types.MessageInfo{

View file

@ -315,13 +315,13 @@ func (w *worker) handleFetchMessageHeaders(
m, err := w.msgFromUid(uid) m, err := w.msgFromUid(uid)
if err != nil { if err != nil {
logging.Errorf("could not get message: %w", err) logging.Errorf("could not get message: %w", err)
w.err(msg, err) w.w.PostMessageInfoError(msg, uid, err)
continue continue
} }
err = w.emitMessageInfo(m, msg) err = w.emitMessageInfo(m, msg)
if err != nil { if err != nil {
logging.Errorf("could not emit message info: %w", err) logging.Errorf("could not emit message info: %w", err)
w.err(msg, err) w.w.PostMessageInfoError(msg, uid, err)
continue continue
} }
} }

View file

@ -4,6 +4,7 @@ import (
"sync/atomic" "sync/atomic"
"git.sr.ht/~rjarry/aerc/logging" "git.sr.ht/~rjarry/aerc/logging"
"git.sr.ht/~rjarry/aerc/models"
) )
var lastId int64 = 1 // access via atomic var lastId int64 = 1 // access via atomic
@ -104,3 +105,17 @@ func (worker *Worker) ProcessAction(msg WorkerMessage) WorkerMessage {
} }
return msg return msg
} }
// PostMessageInfoError posts a MessageInfo message to the worker when an
// error was encountered fetching the message header
func (worker *Worker) PostMessageInfoError(msg WorkerMessage, uid uint32, err error) {
worker.PostMessage(&MessageInfo{
Info: &models.MessageInfo{
Envelope: &models.Envelope{},
Flags: []models.Flag{models.SeenFlag},
Uid: uid,
Error: err,
},
Message: RespondTo(msg),
}, nil)
}