Files
crockery/internal/store/maildir.go

125 lines
2.5 KiB
Go
Raw Normal View History

package store
import (
"errors"
"net/mail"
"os"
"path/filepath"
"github.com/luksen/maildir"
"ur.gs/crockery/internal/imap/uidlist"
)
type MaildirInterface interface {
CreateMaildir(*Maildir) error
FindMaildir(account Account, name string) (Maildir, error)
FindMaildirs(account Account) ([]Maildir, error)
FindMessagesInRange(m Maildir, start, end uint64) ([]Message, error)
}
type Maildir struct {
Account Account
Name string
directory string
filesystem maildir.Dir
uids *uidlist.List
}
func (m *Maildir) Rel() string {
return filepath.Join(m.Account.Username, m.Name)
}
func (m *Maildir) Directory() string {
return m.directory
}
func (m *Maildir) Header(key string) (mail.Header, error) {
return m.filesystem.Header(key)
}
func (c *concrete) CreateMaildir(m *Maildir) error {
if m.directory == "" {
m.directory = c.buildMaildirPath(m.Account, m.Name)
}
if string(m.filesystem) == "" {
m.filesystem = maildir.Dir(m.directory)
}
err := m.filesystem.Create()
if err != nil {
return err
}
if m.uids == nil {
uids, err := uidlist.Create(m.directory)
if err != nil {
// FIXME: this leaves a dangling Maildir
return err
}
m.uids = uids
}
return nil
}
func (c *concrete) FindMaildir(account Account, name string) (Maildir, error) {
// FIXME: multiple IMAP sessions get different Maildir instances, so breaking
// any hope at locking (sigh)
m := Maildir{
Account: account,
Name: name,
directory: c.buildMaildirPath(account, name),
}
m.filesystem = maildir.Dir(m.directory)
if _, err := os.Stat(m.Directory()); os.IsNotExist(err) {
return Maildir{}, errors.New("not found")
}
uids, err := uidlist.Open(m.directory)
if err != nil {
return Maildir{}, err
}
m.uids = uids
return m, nil
}
func (c *concrete) FindMaildirs(account Account) ([]Maildir, error) {
// TODO: iterate through the maildir looking for submaildirs
defaultMaildir, err := c.FindMaildir(account, "")
if err != nil {
return nil, err
}
return []Maildir{defaultMaildir}, nil
}
func (c *concrete) buildMaildirPath(account Account, parts ...string) string {
bits := append([]string{BuildMailboxesPath(c.home), account.Username}, parts...)
return filepath.Join(bits...)
}
func (c *concrete) FindMessagesInRange(m Maildir, start, end uint64) ([]Message, error) {
var out []Message
entries := m.uids.EntriesInRange(start, end)
for _, entry := range entries {
msg := Message{
UID: entry.UID,
Maildir: m,
Key: entry.Key(),
}
out = append(out, msg)
}
return out, nil
}