diff options
author | Ben Burwell <ben@benburwell.com> | 2019-07-11 09:44:51 -0400 |
---|---|---|
committer | Drew DeVault <sir@cmpwn.com> | 2019-07-12 11:09:50 -0400 |
commit | 1b8b6e218c7a70cb61c5449a204e38738b7bd945 (patch) | |
tree | 505495696c83b407b4a9f3379b1d8d1050e970fa /worker/maildir/container.go | |
parent | d7cd35e72b81644774e5f1ab44ff8645e31aa510 (diff) | |
download | aerc-1b8b6e218c7a70cb61c5449a204e38738b7bd945.tar.gz |
Add maildir backend worker
Add the initial implementation of a backend for Maildir accounts. Much of the functionality required is implemented in the go-message and go-maildir libraries, so we use them as much as possible. The maildir worker hooks into a new maildir:// URL scheme in the accounts.conf file which points to a container of several maildir directories. From there, the OpenDirectory, FetchDirectoryContents, etc messages work on subdirectories. This is implemented as a Container struct which handles mapping between the symbolic email folder names and UIDs to the concrete directories and file names.
Diffstat (limited to 'worker/maildir/container.go')
-rw-r--r-- | worker/maildir/container.go | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/worker/maildir/container.go b/worker/maildir/container.go new file mode 100644 index 0000000..351afed --- /dev/null +++ b/worker/maildir/container.go @@ -0,0 +1,105 @@ +package maildir + +import ( + "fmt" + "io/ioutil" + "log" + "path/filepath" + "sort" + + "github.com/emersion/go-maildir" + + "git.sr.ht/~sircmpwn/aerc/lib/uidstore" +) + +// A Container is a directory which contains other directories which adhere to +// the Maildir spec +type Container struct { + dir string + log *log.Logger + uids *uidstore.Store +} + +// NewContainer creates a new container at the specified directory +// TODO: return an error if the provided directory is not accessible +func NewContainer(dir string, l *log.Logger) *Container { + return &Container{dir: dir, uids: uidstore.NewStore(), log: l} +} + +// ListFolders returns a list of maildir folders in the container +func (c *Container) ListFolders() ([]string, error) { + files, err := ioutil.ReadDir(c.dir) + if err != nil { + return nil, fmt.Errorf("error reading folders: %v", err) + } + dirnames := []string{} + for _, f := range files { + if f.IsDir() { + dirnames = append(dirnames, f.Name()) + } + } + return dirnames, nil +} + +// OpenDirectory opens an existing maildir in the container by name, moves new +// messages into cur, and registers the new keys in the UIDStore. +func (c *Container) OpenDirectory(name string) (maildir.Dir, error) { + dir := c.Dir(name) + keys, err := dir.Unseen() + if err != nil { + return dir, err + } + for _, key := range keys { + c.uids.GetOrInsert(key) + } + return dir, nil +} + +// Dir returns a maildir.Dir with the specified name inside the container +func (c *Container) Dir(name string) maildir.Dir { + return maildir.Dir(filepath.Join(c.dir, name)) +} + +// UIDs fetches the unique message identifiers for the maildir +func (c *Container) UIDs(d maildir.Dir) ([]uint32, error) { + keys, err := d.Keys() + if err != nil { + return nil, fmt.Errorf("could not get keys for %s: %v", d, err) + } + sort.Strings(keys) + var uids []uint32 + for _, key := range keys { + uids = append(uids, c.uids.GetOrInsert(key)) + } + return uids, nil +} + +// Message returns a Message struct for the given UID and maildir +func (c *Container) Message(d maildir.Dir, uid uint32) (*Message, error) { + if key, ok := c.uids.GetKey(uid); ok { + return &Message{ + dir: d, + uid: uid, + key: key, + }, nil + } + return nil, fmt.Errorf("could not find message with uid %d in maildir %s", + uid, d) +} + +// DeleteAll deletes a set of messages by UID and returns the subset of UIDs +// which were successfully deleted, stopping upon the first error. +func (c *Container) DeleteAll(d maildir.Dir, uids []uint32) ([]uint32, error) { + var success []uint32 + for _, uid := range uids { + msg, err := c.Message(d, uid) + if err != nil { + return success, err + } + if err := msg.Remove(); err != nil { + return success, err + } + success = append(success, uid) + } + return success, nil +} |