Convert from BoltDB to Maildir storage for emails
This commit is contained in:
@@ -2,42 +2,123 @@ package store
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/mail"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/luksen/maildir"
|
||||
|
||||
"ur.gs/crockery/internal/imap/uidlist"
|
||||
)
|
||||
|
||||
type MailboxInterface interface {
|
||||
CreateMailbox(*Mailbox) error
|
||||
FindMailbox(account Account, name string) (Mailbox, error)
|
||||
FindMailboxes(account Account) ([]Mailbox, error)
|
||||
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 Mailbox struct {
|
||||
ID uint64 `storm:"id,increment"`
|
||||
Account string `storm:"index"` // FK accounts.username
|
||||
Name string `storm:"index"`
|
||||
type Maildir struct {
|
||||
Account Account
|
||||
Name string
|
||||
|
||||
directory string
|
||||
|
||||
filesystem maildir.Dir
|
||||
uids *uidlist.List
|
||||
}
|
||||
|
||||
func (c *concrete) CreateMailbox(mailbox *Mailbox) error {
|
||||
return c.storm.Save(mailbox)
|
||||
func (m *Maildir) Rel() string {
|
||||
return filepath.Join(m.Account.Username, m.Name)
|
||||
}
|
||||
|
||||
func (c *concrete) FindMailbox(account Account, name string) (Mailbox, error) {
|
||||
// FIXME I don't know how to storm
|
||||
candidates, err := c.FindMailboxes(account)
|
||||
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 Mailbox{}, err
|
||||
return err
|
||||
}
|
||||
|
||||
for _, mbox := range candidates {
|
||||
if mbox.Name == name {
|
||||
return mbox, nil
|
||||
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 Mailbox{}, errors.New("not found")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *concrete) FindMailboxes(account Account) ([]Mailbox, error) {
|
||||
var out []Mailbox
|
||||
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)
|
||||
|
||||
return out, c.storm.Find("Account", account.Username, &out)
|
||||
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
|
||||
}
|
||||
|
Reference in New Issue
Block a user