mirror of
https://git.sr.ht/~rjarry/aerc
synced 2026-03-02 18:23:33 +01:00
186 lines
4.7 KiB
Go
186 lines
4.7 KiB
Go
package middleware
|
|
|
|
import (
|
|
"fmt"
|
|
"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) Unwrap() types.WorkerInteractor {
|
|
return f.WorkerInteractor
|
|
}
|
|
|
|
func (f *folderMapper) incoming(msg types.WorkerMessage, dir string) string {
|
|
f.Lock()
|
|
defer f.Unlock()
|
|
mapped, ok := f.table[dir]
|
|
if !ok {
|
|
return 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, error) {
|
|
f.Lock()
|
|
defer f.Unlock()
|
|
backend := createFolder(f.table, s)
|
|
if _, exists := f.table[s]; exists {
|
|
return s, fmt.Errorf("folder already exists: %s", s)
|
|
}
|
|
f.table[s] = backend
|
|
f.Tracef("create display folder '%s' as '%s'", s, backend)
|
|
return backend, nil
|
|
}
|
|
|
|
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:
|
|
var err error
|
|
msg.Directory, err = f.create(msg.Directory)
|
|
if err != nil {
|
|
f.Errorf("error creating new directory: %v", err)
|
|
}
|
|
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) {
|
|
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.CheckMailDirectories:
|
|
for i := range msg.Directories {
|
|
msg.Directories[i] = f.outgoing(msg, msg.Directories[i])
|
|
}
|
|
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)
|
|
case *types.MessagesMoved:
|
|
msg.Destination = f.outgoing(msg, msg.Destination)
|
|
case *types.MessagesCopied:
|
|
msg.Destination = f.outgoing(msg, msg.Destination)
|
|
case *types.RemoveDirectory:
|
|
msg.Directory = f.outgoing(msg, msg.Directory)
|
|
}
|
|
f.WorkerInteractor.PostMessage(msg)
|
|
}
|
|
|
|
// 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) {
|
|
term := strings.TrimPrefix(s, v)
|
|
if strings.Contains(k, "*") && !strict {
|
|
prefix := k
|
|
for strings.Contains(prefix, "**") {
|
|
prefix = strings.ReplaceAll(prefix, "**", "*")
|
|
}
|
|
s = strings.Replace(prefix, "*", term, 1)
|
|
} else {
|
|
s = k + term
|
|
}
|
|
}
|
|
}
|
|
return s
|
|
}
|
|
|
|
// createFolder reverses the mapping of a new folder name
|
|
func createFolder(table map[string]string, s string) string {
|
|
max, key := 0, ""
|
|
for k := range table {
|
|
if strings.HasPrefix(s, k) && len(k) > max {
|
|
max, key = len(k), k
|
|
}
|
|
}
|
|
if max > 0 && key != "" {
|
|
s = table[key] + strings.TrimPrefix(s, key)
|
|
}
|
|
return s
|
|
}
|