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 }