mirror of
https://git.sr.ht/~rjarry/aerc
synced 2026-10-29 12:15:10 +01:00
Add a Uid field to Directory and DirectoryInfo that stores a unique identifier which changes when the directory contents become invalid. For IMAP, this is the UIDVALIDITY value; other backends leave it empty. Fetch UIDVALIDITY during directory listing when LIST-STATUS is available, otherwise fetch it during CheckMail status queries. Include the validity in Directory messages sent to the UI. Refactor handleListDirectories to collect all mailboxes and statuses before sending Directory messages, allowing the validity to be included from the status response. Signed-off-by: Robin Jarry <robin@jarry.cc> Reviewed-by: Simon Martin <simon@nasilyan.com>
92 lines
2.4 KiB
Go
92 lines
2.4 KiB
Go
package imap
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"git.sr.ht/~rjarry/aerc/models"
|
|
"git.sr.ht/~rjarry/aerc/worker/types"
|
|
"github.com/emersion/go-imap"
|
|
)
|
|
|
|
func (w *IMAPWorker) handleCheckMailMessage(msg *types.CheckMail) error {
|
|
items := []imap.StatusItem{
|
|
imap.StatusMessages,
|
|
imap.StatusRecent,
|
|
imap.StatusUnseen,
|
|
imap.StatusUidNext,
|
|
imap.StatusUidValidity,
|
|
}
|
|
var (
|
|
statuses []*imap.MailboxStatus
|
|
err error
|
|
remaining []string
|
|
)
|
|
switch {
|
|
case w.liststatus:
|
|
w.worker.Tracef("Checking mail with LIST-STATUS")
|
|
ref := ""
|
|
if len(msg.Directories) == 1 {
|
|
// If checking a single directory, restrict the ListStatus to it.
|
|
ref = msg.Directories[0]
|
|
}
|
|
statuses, err = w.client.liststatus.ListStatus(ref, "*", items, nil)
|
|
if err == nil && len(statuses) == 0 && len(msg.Directories) == 1 {
|
|
// For providers such as Zoho, we might get an empty list and
|
|
// no error when ref contains the name of a single directory.
|
|
// Workaround this bug by retrying with "".
|
|
statuses, err = w.client.liststatus.ListStatus("", "*", items, nil)
|
|
}
|
|
if err != nil {
|
|
return err
|
|
}
|
|
default:
|
|
for _, dir := range msg.Directories {
|
|
if len(w.worker.Actions()) > 0 {
|
|
remaining = append(remaining, dir)
|
|
continue
|
|
}
|
|
w.worker.Tracef("Getting status of directory %s", dir)
|
|
status, err := w.client.Status(dir, items)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
statuses = append(statuses, status)
|
|
}
|
|
}
|
|
for _, status := range statuses {
|
|
refetch := false
|
|
if status.Name == w.selected.Name {
|
|
if status.UidNext != w.selected.UidNext {
|
|
refetch = true
|
|
} else if status.Messages != w.selected.Messages {
|
|
// Some providers (e.g. O365 upon new mail) might report the
|
|
// same UIDNEXT even though the contents of the folder has
|
|
// changed. So force a refetch if the server reports a
|
|
// number of messages different from what we currently have.
|
|
refetch = true
|
|
}
|
|
w.selected = status
|
|
}
|
|
info := &models.DirectoryInfo{
|
|
Name: status.Name,
|
|
Exists: int(status.Messages),
|
|
Recent: int(status.Recent),
|
|
Unseen: int(status.Unseen),
|
|
}
|
|
if status.UidValidity != 0 {
|
|
info.Uid = fmt.Sprintf("%d", status.UidValidity)
|
|
}
|
|
w.worker.PostMessage(&types.DirectoryInfo{
|
|
Info: info,
|
|
Refetch: refetch,
|
|
}, nil)
|
|
}
|
|
if len(remaining) > 0 {
|
|
w.worker.PostMessage(&types.CheckMailDirectories{
|
|
Message: types.RespondTo(msg),
|
|
Directories: remaining,
|
|
}, nil)
|
|
}
|
|
return nil
|
|
}
|