notmuch: make maildir store path configurable

Add the "maildir-store" account configuration option to select the
maildir store to associate with the notmuch database.

This also allows the previous changes to be backward compatible since
not specifying this option will make the backend behave the same as if
there were no changes.

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>
This commit is contained in:
Julian Pidancet 2022-10-26 22:29:05 +02:00 committed by Robin Jarry
parent c7bfe4e490
commit fbff8cf0ac
3 changed files with 78 additions and 34 deletions

View file

@ -66,12 +66,18 @@ This can for example be useful if you use an archive or spam tag.
Default: none Default: none
*maildir-store*
Path to the maildir store containing the message files backing the
notmuch database. This is often the same as the notmuch database path.
This is optional. If specified, it will be used by aerc to list
available folders and enable commands such as :delete and :archive.
Default: none
# USAGE # USAGE
Notmuch shows slightly different behavior than for example imap.++ Notmuch shows slightly different behavior than for example imap.++
Some commands are simply unsupported because they have no proper counterpart Some commands are slightly different in semantics and mentioned below:
in notmuch, like :delete and :archive.++
Others are slightly different in semantics and mentioned below:
*cf* <notmuch query> *cf* <notmuch query>
The change folder command allows for arbitrary notmuch queries. Performing a The change folder command allows for arbitrary notmuch queries. Performing a

View file

@ -20,19 +20,21 @@ func (w *worker) handleNotmuchEvent(et eventType) error {
} }
func (w *worker) handleUpdateDirCounts(ev eventType) error { func (w *worker) handleUpdateDirCounts(ev eventType) error {
folders, err := w.store.FolderMap() if w.store != nil {
if err != nil { folders, err := w.store.FolderMap()
logging.Errorf("failed listing directories: %v", err)
return err
}
for name := range folders {
query := fmt.Sprintf("folder:%s", strconv.Quote(name))
info, err := w.buildDirInfo(name, query, true)
if err != nil { if err != nil {
logging.Errorf("could not gather DirectoryInfo: %v", err) logging.Errorf("failed listing directories: %v", err)
continue return err
}
for name := range folders {
query := fmt.Sprintf("folder:%s", strconv.Quote(name))
info, err := w.buildDirInfo(name, query, true)
if err != nil {
logging.Errorf("could not gather DirectoryInfo: %v", err)
continue
}
w.w.PostMessage(info, nil)
} }
w.w.PostMessage(info, nil)
} }
for name, query := range w.nameQueryMap { for name, query := range w.nameQueryMap {

View file

@ -179,11 +179,19 @@ func (w *worker) handleConfigure(msg *types.Configure) error {
} }
excludedTags := w.loadExcludeTags(msg.Config) excludedTags := w.loadExcludeTags(msg.Config)
w.db = notmuch.NewDB(pathToDB, excludedTags) w.db = notmuch.NewDB(pathToDB, excludedTags)
store, err := lib.NewMaildirStore(pathToDB, false)
if err != nil { val, ok := msg.Config.Params["maildir-store"]
return fmt.Errorf("Cannot initialize maildir store: %w", err) if ok {
path, err := homedir.Expand(val)
if err != nil {
return err
}
store, err := lib.NewMaildirStore(path, false)
if err != nil {
return fmt.Errorf("Cannot initialize maildir store: %w", err)
}
w.store = store
} }
w.store = store
return nil return nil
} }
@ -207,19 +215,21 @@ func (w *worker) handleConnect(msg *types.Connect) error {
} }
func (w *worker) handleListDirectories(msg *types.ListDirectories) error { func (w *worker) handleListDirectories(msg *types.ListDirectories) error {
folders, err := w.store.FolderMap() if w.store != nil {
if err != nil { folders, err := w.store.FolderMap()
logging.Errorf("failed listing directories: %v", err) if err != nil {
return err logging.Errorf("failed listing directories: %v", err)
} return err
for name := range folders { }
w.w.PostMessage(&types.Directory{ for name := range folders {
Message: types.RespondTo(msg), w.w.PostMessage(&types.Directory{
Dir: &models.Directory{ Message: types.RespondTo(msg),
Name: name, Dir: &models.Directory{
Attributes: []string{}, Name: name,
}, Attributes: []string{},
}, nil) },
}, nil)
}
} }
for _, name := range w.queryMapOrder { for _, name := range w.queryMapOrder {
@ -287,9 +297,11 @@ func (w *worker) queryFromName(name string) (string, bool) {
// try the friendly name first, if that fails assume it's a query // try the friendly name first, if that fails assume it's a query
q, ok := w.nameQueryMap[name] q, ok := w.nameQueryMap[name]
if !ok { if !ok {
folders, _ := w.store.FolderMap() if w.store != nil {
if _, ok := folders[name]; ok { folders, _ := w.store.FolderMap()
return fmt.Sprintf("folder:%s", strconv.Quote(name)), true if _, ok := folders[name]; ok {
return fmt.Sprintf("folder:%s", strconv.Quote(name)), true
}
} }
return name, true return name, true
} }
@ -713,6 +725,10 @@ func (w *worker) handleCheckMail(msg *types.CheckMail) {
} }
func (w *worker) handleDeleteMessages(msg *types.DeleteMessages) error { func (w *worker) handleDeleteMessages(msg *types.DeleteMessages) error {
if w.store == nil {
return errUnsupported
}
var deleted []uint32 var deleted []uint32
// With notmuch, two identical files can be referenced under // With notmuch, two identical files can be referenced under
@ -753,6 +769,10 @@ func (w *worker) handleDeleteMessages(msg *types.DeleteMessages) error {
} }
func (w *worker) handleCopyMessages(msg *types.CopyMessages) error { func (w *worker) handleCopyMessages(msg *types.CopyMessages) error {
if w.store == nil {
return errUnsupported
}
// Only allow file to be copied to a maildir folder // Only allow file to be copied to a maildir folder
folders, _ := w.store.FolderMap() folders, _ := w.store.FolderMap()
dest, ok := folders[msg.Destination] dest, ok := folders[msg.Destination]
@ -781,6 +801,10 @@ func (w *worker) handleCopyMessages(msg *types.CopyMessages) error {
} }
func (w *worker) handleMoveMessages(msg *types.MoveMessages) error { func (w *worker) handleMoveMessages(msg *types.MoveMessages) error {
if w.store == nil {
return errUnsupported
}
var moved []uint32 var moved []uint32
// With notmuch, two identical files can be referenced under // With notmuch, two identical files can be referenced under
@ -824,6 +848,10 @@ func (w *worker) handleMoveMessages(msg *types.MoveMessages) error {
} }
func (w *worker) handleAppendMessage(msg *types.AppendMessage) error { func (w *worker) handleAppendMessage(msg *types.AppendMessage) error {
if w.store == nil {
return errUnsupported
}
// Only allow file to be created in a maildir folder // Only allow file to be created in a maildir folder
// since we are the "master" maildir process, we can modify the maildir directly // since we are the "master" maildir process, we can modify the maildir directly
folders, _ := w.store.FolderMap() folders, _ := w.store.FolderMap()
@ -859,6 +887,10 @@ func (w *worker) handleAppendMessage(msg *types.AppendMessage) error {
} }
func (w *worker) handleCreateDirectory(msg *types.CreateDirectory) error { func (w *worker) handleCreateDirectory(msg *types.CreateDirectory) error {
if w.store == nil {
return errUnsupported
}
dir := w.store.Dir(msg.Directory) dir := w.store.Dir(msg.Directory)
if err := dir.Init(); err != nil { if err := dir.Init(); err != nil {
logging.Errorf("could not create directory %s: %v", logging.Errorf("could not create directory %s: %v",
@ -870,6 +902,10 @@ func (w *worker) handleCreateDirectory(msg *types.CreateDirectory) error {
} }
func (w *worker) handleRemoveDirectory(msg *types.RemoveDirectory) error { func (w *worker) handleRemoveDirectory(msg *types.RemoveDirectory) error {
if w.store == nil {
return errUnsupported
}
dir := w.store.Dir(msg.Directory) dir := w.store.Dir(msg.Directory)
if err := os.RemoveAll(string(dir)); err != nil { if err := os.RemoveAll(string(dir)); err != nil {
logging.Errorf("could not remove directory %s: %v", logging.Errorf("could not remove directory %s: %v",