aboutsummaryrefslogtreecommitdiffstats
path: root/worker
diff options
context:
space:
mode:
authorKoni Marti <koni.marti@gmail.com>2023-06-21 22:13:02 +0200
committerRobin Jarry <robin@jarry.cc>2023-06-22 10:55:25 +0200
commit0f37a0ce2cdc07a090e33bbe53b1b67081cce741 (patch)
treedad23eb0ade656b2bd7f1054f2ae9f3ccdf5c70d /worker
parent697b56b6d3071aab78a3b81114ba39618b59848f (diff)
downloadaerc-0f37a0ce2cdc07a090e33bbe53b1b67081cce741.tar.gz
worker: implement folder-map middleware
Implement a folder-map middleware that will translate the folder names between the ui and the backend according to a provided key-value map. Fixes: https://todo.sr.ht/~rjarry/aerc/175 Signed-off-by: Koni Marti <koni.marti@gmail.com> Tested-by: Bence Ferdinandy <bence@ferdinandy.com> Signed-off-by: Robin Jarry <robin@jarry.cc>
Diffstat (limited to 'worker')
-rw-r--r--worker/middleware/foldermapper.go152
1 files changed, 152 insertions, 0 deletions
diff --git a/worker/middleware/foldermapper.go b/worker/middleware/foldermapper.go
new file mode 100644
index 00000000..c78833a2
--- /dev/null
+++ b/worker/middleware/foldermapper.go
@@ -0,0 +1,152 @@
+package middleware
+
+import (
+ "strings"
+ "sync"
+
+ "git.sr.ht/~rjarry/aerc/worker/types"
+)
+
+type folderMapper struct {
+ sync.Mutex
+ types.WorkerInteractor
+ fm folderMap
+ table map[string]string
+}
+
+func NewFolderMapper(base types.WorkerInteractor, mapping map[string]string,
+ order []string,
+) types.WorkerInteractor {
+ base.Infof("loading worker middleware: foldermapper")
+ return &folderMapper{
+ WorkerInteractor: base,
+ fm: folderMap{mapping, order},
+ table: make(map[string]string),
+ }
+}
+
+func (f *folderMapper) incoming(msg types.WorkerMessage, dir string) string {
+ f.Lock()
+ defer f.Unlock()
+ mapped := f.table[dir]
+ return mapped
+}
+
+func (f *folderMapper) outgoing(msg types.WorkerMessage, dir string) string {
+ f.Lock()
+ defer f.Unlock()
+ for k, v := range f.table {
+ if v == dir {
+ mapped := k
+ return mapped
+ }
+ }
+ return dir
+}
+
+func (f *folderMapper) store(s string) {
+ f.Lock()
+ defer f.Unlock()
+ display := f.fm.Apply(s)
+ f.table[display] = s
+ f.Tracef("store display folder '%s' to '%s'", display, s)
+}
+
+func (f *folderMapper) create(s string) string {
+ f.Lock()
+ defer f.Unlock()
+ backend := f.fm.Create(s)
+ f.table[s] = backend
+ f.Tracef("create display folder '%s' as '%s'", s, backend)
+ return backend
+}
+
+func (f *folderMapper) ProcessAction(msg types.WorkerMessage) types.WorkerMessage {
+ switch msg := msg.(type) {
+ case *types.CheckMail:
+ for i := range msg.Directories {
+ msg.Directories[i] = f.incoming(msg, msg.Directories[i])
+ }
+ case *types.CopyMessages:
+ msg.Destination = f.incoming(msg, msg.Destination)
+ case *types.AppendMessage:
+ msg.Destination = f.incoming(msg, msg.Destination)
+ case *types.MoveMessages:
+ msg.Destination = f.incoming(msg, msg.Destination)
+ case *types.CreateDirectory:
+ msg.Directory = f.create(msg.Directory)
+ case *types.RemoveDirectory:
+ msg.Directory = f.incoming(msg, msg.Directory)
+ case *types.OpenDirectory:
+ msg.Directory = f.incoming(msg, msg.Directory)
+ }
+
+ return f.WorkerInteractor.ProcessAction(msg)
+}
+
+func (f *folderMapper) PostMessage(msg types.WorkerMessage, cb func(m types.WorkerMessage)) {
+ switch msg := msg.(type) {
+ case *types.Done:
+ switch msg := msg.InResponseTo().(type) {
+ case *types.CheckMail:
+ for i := range msg.Directories {
+ msg.Directories[i] = f.outgoing(msg, msg.Directories[i])
+ }
+ case *types.CopyMessages:
+ msg.Destination = f.outgoing(msg, msg.Destination)
+ case *types.AppendMessage:
+ msg.Destination = f.outgoing(msg, msg.Destination)
+ case *types.MoveMessages:
+ msg.Destination = f.outgoing(msg, msg.Destination)
+ case *types.CreateDirectory:
+ msg.Directory = f.outgoing(msg, msg.Directory)
+ case *types.RemoveDirectory:
+ msg.Directory = f.outgoing(msg, msg.Directory)
+ case *types.OpenDirectory:
+ msg.Directory = f.outgoing(msg, msg.Directory)
+ }
+ case *types.Directory:
+ f.store(msg.Dir.Name)
+ msg.Dir.Name = f.outgoing(msg, msg.Dir.Name)
+ case *types.DirectoryInfo:
+ msg.Info.Name = f.outgoing(msg, msg.Info.Name)
+ }
+ f.WorkerInteractor.PostMessage(msg, cb)
+}
+
+// folderMap contains the mapping between the ui and backend folder names
+type folderMap struct {
+ mapping map[string]string
+ order []string
+}
+
+// Apply applies the mapping from the folder map to the backend folder
+func (f *folderMap) Apply(s string) string {
+ for _, k := range f.order {
+ v := f.mapping[k]
+ strict := true
+ if strings.HasSuffix(v, "*") {
+ v = strings.TrimSuffix(v, "*")
+ strict = false
+ }
+ if (strings.HasPrefix(s, v) && !strict) || (s == v && strict) {
+ s = k + strings.TrimPrefix(s, v)
+ }
+ }
+ return s
+}
+
+// Create reverses the mapping of a new folder name
+func (f *folderMap) Create(s string) string {
+ max, key := 0, ""
+ for k := range f.mapping {
+ if strings.HasPrefix(s, k) && len(k) > max {
+ max, key = len(k), k
+ }
+ }
+ if max > 0 && key != "" {
+ s = strings.TrimSuffix(f.mapping[key], "*") +
+ strings.TrimPrefix(s, key)
+ }
+ return s
+}