From 2040fc1885ca4b4bea07d91e9fc6a0aaebfe7133 Mon Sep 17 00:00:00 2001 From: Moritz Poldrack Date: Tue, 9 May 2023 17:19:42 +0200 Subject: imap: use delimiter from server To accommodate servers that use a delimiter other than "/" ("." being a common alternative), the delimiter is fetched from the server when connecting. Signed-off-by: Moritz Poldrack Acked-by: Robin Jarry --- CHANGELOG.md | 1 + widgets/dirlist.go | 3 +-- widgets/dirtree.go | 20 +++++++++----------- worker/imap/connect.go | 11 +++++++++++ worker/imap/worker.go | 18 +++++++++++++----- worker/maildir/worker.go | 7 +++++++ worker/mbox/worker.go | 4 ++++ worker/notmuch/worker.go | 7 +++++++ worker/types/worker.go | 5 +++++ 9 files changed, 58 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53208c19..95043c45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Colorize can style diff chunk function names with `diff_chunk_func`. - Warn before sending emails with an empty subject with `empty-subject-warning` in `aerc.conf`. +- IMAP now uses the delimiter advertised by the server ## [0.15.2](https://git.sr.ht/~rjarry/aerc/refs/0.15.2) - 2023-05-11 diff --git a/widgets/dirlist.go b/widgets/dirlist.go index da2fa69a..6a10c99a 100644 --- a/widgets/dirlist.go +++ b/widgets/dirlist.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "math" - "os" "regexp" "sort" "time" @@ -79,7 +78,7 @@ func NewDirectoryList(acctConf *config.AccountConfig, dirlist.spinner.Start() if uiConf.DirListTree { - return NewDirectoryTree(dirlist, string(os.PathSeparator)) + return NewDirectoryTree(dirlist) } return dirlist diff --git a/widgets/dirtree.go b/widgets/dirtree.go index 41477c5f..c11a1fd0 100644 --- a/widgets/dirtree.go +++ b/widgets/dirtree.go @@ -22,16 +22,14 @@ type DirectoryTree struct { listIdx int list []*types.Thread - pathSeparator string - treeDirs []string + treeDirs []string } -func NewDirectoryTree(dirlist *DirectoryList, pathSeparator string) DirectoryLister { +func NewDirectoryTree(dirlist *DirectoryList) DirectoryLister { dt := &DirectoryTree{ DirectoryList: dirlist, listIdx: -1, list: make([]*types.Thread, 0), - pathSeparator: pathSeparator, } return dt } @@ -274,7 +272,7 @@ func (dt *DirectoryTree) countVisible(list []*types.Thread) (n int) { } func (dt *DirectoryTree) displayText(node *types.Thread) string { - elems := strings.Split(dt.treeDirs[getAnyUid(node)], dt.pathSeparator) + elems := strings.Split(dt.treeDirs[getAnyUid(node)], dt.DirectoryList.worker.PathSeparator()) return fmt.Sprintf("%s%s%s", threadPrefix(node, false, false), getFlag(node), elems[countLevels(node)]) } @@ -301,12 +299,12 @@ func (dt *DirectoryTree) hiddenDirectories() map[string]bool { hidden := make(map[string]bool, 0) for _, node := range dt.list { if node.Hidden && node.FirstChild != nil { - elems := strings.Split(dt.treeDirs[getAnyUid(node)], dt.pathSeparator) + elems := strings.Split(dt.treeDirs[getAnyUid(node)], dt.DirectoryList.worker.PathSeparator()) if levels := countLevels(node); levels < len(elems) { if node.FirstChild != nil && (levels+1) < len(elems) { levels += 1 } - if dirStr := strings.Join(elems[:levels], dt.pathSeparator); dirStr != "" { + if dirStr := strings.Join(elems[:levels], dt.DirectoryList.worker.PathSeparator()); dirStr != "" { hidden[dirStr] = true } } @@ -317,12 +315,12 @@ func (dt *DirectoryTree) hiddenDirectories() map[string]bool { func (dt *DirectoryTree) setHiddenDirectories(hiddenDirs map[string]bool) { for _, node := range dt.list { - elems := strings.Split(dt.treeDirs[getAnyUid(node)], dt.pathSeparator) + elems := strings.Split(dt.treeDirs[getAnyUid(node)], dt.DirectoryList.worker.PathSeparator()) if levels := countLevels(node); levels < len(elems) { if node.FirstChild != nil && (levels+1) < len(elems) { levels += 1 } - strDir := strings.Join(elems[:levels], dt.pathSeparator) + strDir := strings.Join(elems[:levels], dt.DirectoryList.worker.PathSeparator()) if hidden, ok := hiddenDirs[strDir]; hidden && ok { node.Hidden = true } @@ -340,7 +338,7 @@ func (dt *DirectoryTree) buildTree() { sTree := make([][]string, 0) for i, dir := range dt.dirs { - elems := strings.Split(dir, dt.pathSeparator) + elems := strings.Split(dir, dt.DirectoryList.worker.PathSeparator()) if len(elems) == 0 { continue } @@ -364,7 +362,7 @@ func (dt *DirectoryTree) buildTree() { // folders-sort if dt.DirectoryList.acctConf.EnableFoldersSort { toStr := func(t *types.Thread) string { - if elems := strings.Split(dt.treeDirs[getAnyUid(t)], dt.pathSeparator); len(elems) > 0 { + if elems := strings.Split(dt.treeDirs[getAnyUid(t)], dt.DirectoryList.worker.PathSeparator()); len(elems) > 0 { return elems[0] } return "" diff --git a/worker/imap/connect.go b/worker/imap/connect.go index 6f341753..f0ed8043 100644 --- a/worker/imap/connect.go +++ b/worker/imap/connect.go @@ -94,6 +94,17 @@ func (w *IMAPWorker) connect() (*client.Client, error) { return nil, err } + info := make(chan *imap.MailboxInfo, 1) + if err := c.List("", "", info); err != nil { + return nil, fmt.Errorf("failed to retrieve delimiter: %w", err) + } + mailboxinfo := <-info + w.delimiter = mailboxinfo.Delimiter + if w.delimiter == "" { + // just in case some implementation does not follow standards + w.delimiter = "/" + } + return c, nil } diff --git a/worker/imap/worker.go b/worker/imap/worker.go index 1f61f458..f9a722e6 100644 --- a/worker/imap/worker.go +++ b/worker/imap/worker.go @@ -61,11 +61,12 @@ type imapConfig struct { type IMAPWorker struct { config imapConfig - client *imapClient - selected *imap.MailboxStatus - updates chan client.Update - worker *types.Worker - seqMap SeqMap + client *imapClient + selected *imap.MailboxStatus + updates chan client.Update + worker *types.Worker + seqMap SeqMap + delimiter string idler *idler observer *observer @@ -311,3 +312,10 @@ func (w *IMAPWorker) Run() { func (w *IMAPWorker) Capabilities() *models.Capabilities { return w.caps } + +func (w *IMAPWorker) PathSeparator() string { + if w.delimiter == "" { + return "/" + } + return w.delimiter +} diff --git a/worker/maildir/worker.go b/worker/maildir/worker.go index ba72432c..b222aab8 100644 --- a/worker/maildir/worker.go +++ b/worker/maildir/worker.go @@ -108,6 +108,13 @@ func (w *Worker) Capabilities() *models.Capabilities { return w.capabilities } +func (w *Worker) PathSeparator() string { + if w.maildirpp { + return "." + } + return string(os.PathSeparator) +} + func (w *Worker) handleAction(action types.WorkerMessage) { msg := w.worker.ProcessAction(action) switch msg := msg.(type) { diff --git a/worker/mbox/worker.go b/worker/mbox/worker.go index fbdbec36..47713048 100644 --- a/worker/mbox/worker.go +++ b/worker/mbox/worker.go @@ -383,6 +383,10 @@ func (w *mboxWorker) Capabilities() *models.Capabilities { return w.capabilities } +func (w *mboxWorker) PathSeparator() string { + return "/" +} + func filterUids(folder *container, uids []uint32, args []string) ([]uint32, error) { criteria, err := lib.GetSearchCriteria(args) if err != nil { diff --git a/worker/notmuch/worker.go b/worker/notmuch/worker.go index 6b1b64d9..d5c012ad 100644 --- a/worker/notmuch/worker.go +++ b/worker/notmuch/worker.go @@ -109,6 +109,13 @@ func (w *worker) Capabilities() *models.Capabilities { return w.capabilities } +func (w *worker) PathSeparator() string { + // make it configurable? + // You can use those in query maps to force a tree + // Might be nice to be configurable? I see some notmuch people namespace with "::" + return "/" +} + func (w *worker) done(msg types.WorkerMessage) { w.w.PostMessage(&types.Done{Message: types.RespondTo(msg)}, nil) } diff --git a/worker/types/worker.go b/worker/types/worker.go index 55e00faf..7033bf77 100644 --- a/worker/types/worker.go +++ b/worker/types/worker.go @@ -15,6 +15,7 @@ var lastId int64 = 1 // access via atomic type Backend interface { Run() Capabilities() *models.Capabilities + PathSeparator() string } type Worker struct { @@ -179,3 +180,7 @@ func (worker *Worker) PostMessageInfoError(msg WorkerMessage, uid uint32, err er Message: RespondTo(msg), }, nil) } + +func (worker *Worker) PathSeparator() string { + return worker.Backend.PathSeparator() +} -- cgit v1.2.3-54-g00ecf