notmuch: move new maildir files to cur upon opening a folder

By default "notmuch new" will index files in place and won't move new
files from the new/ directory to cur/ because it assumes that is the
job of the email client.
During normal operation, once moved by the client, the "notmuch new"
command will "fix" the database by detecting file renames.
This workflow is a problem because we need to move the new/ files to
cur/, otherwise the maildir lib will not work properly, but at the same
time we cannot afford the notmuch database to be out of sync with the
location of message files on disk, because we rely on it for listing
folders, displaying emails, ect...

This change uses a trick that request notmuch to synchronize message
tags to maildir flags, that will effectively rename new files and cause
them to be moved into the cur/ directory.

Signed-off-by: Julian Pidancet <julian.pidancet@oracle.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Acked-by: Tim Culverhouse <tim@timculverhouse.com>
This commit is contained in:
Julian Pidancet 2022-10-26 22:29:10 +02:00 committed by Robin Jarry
parent 81440e79ad
commit f20933f512
1 changed files with 39 additions and 1 deletions

View File

@ -281,8 +281,12 @@ func (w *worker) handleOpenDirectory(msg *types.OpenDirectory) error {
q := ""
if w.store != nil {
folders, _ := w.store.FolderMap()
if _, ok := folders[msg.Directory]; ok {
dir, ok := folders[msg.Directory]
if ok {
q = fmt.Sprintf("folder:%s", strconv.Quote(msg.Directory))
if err := w.processNewMaildirFiles(string(dir)); err != nil {
return err
}
}
}
if q == "" {
@ -901,3 +905,37 @@ func (w *worker) handleRemoveDirectory(msg *types.RemoveDirectory) error {
w.done(msg)
return nil
}
// This is a hack that calls MsgModifyTags with an empty list of tags to
// apply on new messages causing notmuch to rename files and effectively
// move them into the cur/ dir.
func (w *worker) processNewMaildirFiles(dir string) error {
f, err := os.Open(filepath.Join(dir, "new"))
if err != nil {
return err
}
defer f.Close()
names, err := f.Readdirnames(0)
if err != nil {
return err
}
for _, n := range names {
if n[0] == '.' {
continue
}
key, err := w.db.MsgIDFromFilename(filepath.Join(dir, "new", n))
if err != nil {
// Message is not yet indexed, leave it alone
continue
}
// Force message to move from new/ to cur/
err = w.db.MsgModifyTags(key, nil, nil)
if err != nil {
logging.Errorf("MsgModifyTags failed: %v", err)
}
}
return nil
}