aboutsummaryrefslogtreecommitdiffstats
path: root/worker/maildir/container.go
diff options
context:
space:
mode:
authorAdnan Maolood <me@adnano.co>2022-07-04 15:21:48 -0400
committerRobin Jarry <robin@jarry.cc>2022-07-10 20:34:47 +0200
commitc5daf434604f6b282d95ec6e5220c64988b476d9 (patch)
tree96c94e300dd0a43cf803c4581a94790b1ecc69f4 /worker/maildir/container.go
parent4d3156ddf1599b0d647c488f92b1a9ea4d74de7e (diff)
downloadaerc-c5daf434604f6b282d95ec6e5220c64988b476d9.tar.gz
worker/maildir: implement Maildir++ support
See https://www.courier-mta.org/maildir.html#maildircontents Signed-off-by: Adnan Maolood <me@adnano.co> Acked-by: Koni Marti <koni.marti@gmail.com>
Diffstat (limited to 'worker/maildir/container.go')
-rw-r--r--worker/maildir/container.go33
1 files changed, 30 insertions, 3 deletions
diff --git a/worker/maildir/container.go b/worker/maildir/container.go
index 6f7d74a8..fb0b1902 100644
--- a/worker/maildir/container.go
+++ b/worker/maildir/container.go
@@ -6,6 +6,7 @@ import (
"os"
"path/filepath"
"sort"
+ "strings"
"github.com/emersion/go-maildir"
@@ -19,10 +20,11 @@ type Container struct {
log *log.Logger
uids *uidstore.Store
recentUIDS map[uint32]struct{} // used to set the recent flag
+ maildirpp bool // whether to use Maildir++ directory layout
}
// NewContainer creates a new container at the specified directory
-func NewContainer(dir string, l *log.Logger) (*Container, error) {
+func NewContainer(dir string, l *log.Logger, maildirpp bool) (*Container, error) {
f, err := os.Open(dir)
if err != nil {
return nil, err
@@ -36,16 +38,19 @@ func NewContainer(dir string, l *log.Logger) (*Container, error) {
return nil, fmt.Errorf("Given maildir '%s' not a directory", dir)
}
return &Container{dir: dir, uids: uidstore.NewStore(), log: l,
- recentUIDS: make(map[uint32]struct{})}, nil
+ recentUIDS: make(map[uint32]struct{}), maildirpp: maildirpp}, nil
}
// ListFolders returns a list of maildir folders in the container
func (c *Container) ListFolders() ([]string, error) {
folders := []string{}
+ if c.maildirpp {
+ // In Maildir++ layout, INBOX is the root folder
+ folders = append(folders, "INBOX")
+ }
err := filepath.Walk(c.dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return fmt.Errorf("Invalid path '%s': error: %v", path, err)
-
}
if !info.IsDir() {
return nil
@@ -68,6 +73,21 @@ func (c *Container) ListFolders() ([]string, error) {
return nil
}
+ if c.maildirpp {
+ // In Maildir++ layout, mailboxes are stored in a single directory
+ // and prefixed with a dot, and subfolders are separated by dots.
+ if !strings.HasPrefix(dirPath, ".") {
+ return filepath.SkipDir
+ }
+ dirPath = strings.TrimPrefix(dirPath, ".")
+ dirPath = strings.Replace(dirPath, ".", "/", -1)
+ folders = append(folders, dirPath)
+
+ // Since all mailboxes are stored in a single directory, don't
+ // recurse into subdirectories
+ return filepath.SkipDir
+ }
+
folders = append(folders, dirPath)
return nil
})
@@ -99,6 +119,13 @@ func (c *Container) OpenDirectory(name string) (maildir.Dir, error) {
// Dir returns a maildir.Dir with the specified name inside the container
func (c *Container) Dir(name string) maildir.Dir {
+ if c.maildirpp {
+ // Use Maildir++ layout
+ if name == "INBOX" {
+ return maildir.Dir(c.dir)
+ }
+ return maildir.Dir(filepath.Join(c.dir, "."+strings.Replace(name, "/", ".", -1)))
+ }
return maildir.Dir(filepath.Join(c.dir, name))
}