109 lines
2.2 KiB
Go
109 lines
2.2 KiB
Go
package store
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/mail"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
type Message struct {
|
|
Maildir Maildir // maildir.name
|
|
|
|
UID uint64
|
|
Key string
|
|
Data io.ReadCloser
|
|
hdrCache mail.Header
|
|
}
|
|
|
|
// TODO: the cache is probably fine
|
|
func (m *Message) Header() (mail.Header, error) {
|
|
if m.hdrCache != nil {
|
|
return m.hdrCache, nil
|
|
}
|
|
|
|
hdr, err := m.Maildir.Header(m.Key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
m.hdrCache = hdr
|
|
return hdr, nil
|
|
}
|
|
|
|
func (m *Message) Len() uint64 {
|
|
return 0 // FIXME
|
|
}
|
|
|
|
func (m *Message) HeaderString() (string, error) {
|
|
var sb strings.Builder
|
|
|
|
hdr, err := m.Header()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
for k, vs := range hdr {
|
|
for _, v := range vs {
|
|
fmt.Fprintf(&sb, "%s: %s\r\n", k, v)
|
|
}
|
|
}
|
|
return sb.String(), nil // FIXME
|
|
}
|
|
|
|
type MessageInterface interface {
|
|
CreateMessage(Message) error
|
|
}
|
|
|
|
// DeliverMessage takes the given message and delivers it to the correct maildir
|
|
// It does not call Close() on message.Data
|
|
func (c *concrete) CreateMessage(message Message) error {
|
|
// TODO: recover from panics, assure Abort() is called for them
|
|
maildir := message.Maildir
|
|
|
|
delivery, err := maildir.filesystem.NewDelivery()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := io.Copy(delivery, message.Data); err != nil {
|
|
delivery.Abort()
|
|
return err
|
|
}
|
|
|
|
if err := delivery.Close(); err != nil {
|
|
delivery.Abort()
|
|
return err
|
|
}
|
|
|
|
// FIXME: this moves files in the maildir before the dovecot-uidlist is
|
|
// updated. Not ideal.
|
|
// FIXME: we're not
|
|
keys, err := maildir.filesystem.Unseen()
|
|
if err != nil {
|
|
log.Printf("Failed moving messages from new/ to cur/: %v", err)
|
|
}
|
|
|
|
var filenames []string
|
|
for _, key := range keys {
|
|
filename, err := maildir.filesystem.Filename(key)
|
|
if err != nil {
|
|
log.Printf("Failed getting filename for unseen message %q: %v", key, err)
|
|
continue
|
|
}
|
|
filenames = append(filenames, filepath.Base(filename))
|
|
}
|
|
|
|
// Don't bubble the error up here as delivery has succeeded, IMAP just
|
|
// doesn't know it has. We don't want the client to attempt redelivery.
|
|
//
|
|
// FIXME: this is IMAP stuff that needs moving
|
|
if err := maildir.uids.Append(filenames...); err != nil {
|
|
log.Printf("Allocating UIDs for unseen messages failed: %v", err)
|
|
}
|
|
|
|
return nil
|
|
}
|