package store import ( "fmt" "io" "log" "net/mail" "path/filepath" "strings" ) type Message struct { Maildir Maildir // maildir.name UID uint64 SeqNum 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 }