diff options
author | Julian Pidancet <julian.pidancet@oracle.com> | 2022-10-26 22:29:04 +0200 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2022-10-27 21:45:24 +0200 |
commit | c7bfe4e490fb1fcf779edceb23c96301eb763b47 (patch) | |
tree | 27de60f42275414bb392a853166714d1c6b24672 /worker/notmuch/message.go | |
parent | ea10b329ddd18573fdb066a1a3293c839d839fbd (diff) | |
download | aerc-c7bfe4e490fb1fcf779edceb23c96301eb763b47.tar.gz |
notmuch: add maildir support
By associating the notmuch database with a maildir store, we can add the
Copy/Move/Delete operations on messages to the notmuch backend.
This change assumes that the notmuch database location is also the root
of the maildir store.
In a previous change, we added the ability to dynamically add and remove
message files to the notmuch DB. This change uses this facility to
synchronize the database with the filesystem operations on maildir
files.
While it's still possible to use the query-map file to create virtual
folders from notmuch search queries, the sidebar is now loaded with the
folders found in the maildir store.
With notmuch, two identical but distinct message files can be indexed in
the database with the same key. This change takes extra care of only
deleting or removing message files from the maildir corresponding to the
folder that is currently selected (if any).
Implements: https://todo.sr.ht/~rjarry/aerc/88
Fixes: https://todo.sr.ht/~rjarry/aerc/73
Signed-off-by: Julian Pidancet <julian.pidancet@oracle.com>
Acked-by: Robin Jarry <robin@jarry.cc>
Acked-by: Tim Culverhouse <tim@timculverhouse.com>
Diffstat (limited to 'worker/notmuch/message.go')
-rw-r--r-- | worker/notmuch/message.go | 109 |
1 files changed, 109 insertions, 0 deletions
diff --git a/worker/notmuch/message.go b/worker/notmuch/message.go index 59367fd1..8f8deffd 100644 --- a/worker/notmuch/message.go +++ b/worker/notmuch/message.go @@ -7,6 +7,10 @@ import ( "fmt" "io" "os" + "path/filepath" + "strings" + + "github.com/emersion/go-maildir" "git.sr.ht/~rjarry/aerc/models" "git.sr.ht/~rjarry/aerc/worker/lib" @@ -175,3 +179,108 @@ func (m *Message) RemoveTag(tag string) error { func (m *Message) ModifyTags(add, remove []string) error { return m.db.MsgModifyTags(m.key, add, remove) } + +func (m *Message) Remove(dir maildir.Dir) error { + filenames, err := m.db.MsgFilenames(m.key) + if err != nil { + return err + } + for _, filename := range filenames { + if dirContains(dir, filename) { + err := m.db.DeleteMessage(filename) + if err != nil { + return err + } + + if err := os.Remove(filename); err != nil { + return err + } + + return nil + } + } + + return fmt.Errorf("no matching message file found in %s", string(dir)) +} + +func (m *Message) Copy(target maildir.Dir) error { + filename, err := m.Filename() + if err != nil { + return err + } + + source, key := parseFilename(filename) + if key == "" { + return fmt.Errorf("failed to parse message filename: %s", filename) + } + + newKey, err := source.Copy(target, key) + if err != nil { + return err + } + newFilename, err := target.Filename(newKey) + if err != nil { + return err + } + _, err = m.db.IndexFile(newFilename) + return err +} + +func (m *Message) Move(srcDir, destDir maildir.Dir) error { + var src string + + filenames, err := m.db.MsgFilenames(m.key) + if err != nil { + return err + } + for _, filename := range filenames { + if dirContains(srcDir, filename) { + src = filename + break + } + } + + if src == "" { + return fmt.Errorf("no matching message file found in %s", string(srcDir)) + } + + // Remove encoded UID information from the key to prevent sync issues + name := lib.StripUIDFromMessageFilename(filepath.Base(src)) + dest := filepath.Join(string(destDir), "cur", name) + + if err := m.db.DeleteMessage(src); err != nil { + return err + } + + if err := os.Rename(src, dest); err != nil { + return err + } + + _, err = m.db.IndexFile(dest) + return err +} + +func parseFilename(filename string) (maildir.Dir, string) { + base := filepath.Base(filename) + dir := filepath.Dir(filename) + dir, curdir := filepath.Split(dir) + if curdir != "cur" { + return "", "" + } + split := strings.Split(base, ":") + if len(split) < 2 { + return maildir.Dir(dir), "" + } + key := split[0] + return maildir.Dir(dir), key +} + +func dirContains(dir maildir.Dir, filename string) bool { + for _, sub := range []string{"cur", "new"} { + match, _ := filepath.Match(filepath.Join(string(dir), sub, "*"), filename) + if match { + return true + } + } + return false +} |