Add types.Mail

This commit is contained in:
Neil Alexander
2021-07-09 22:25:10 +01:00
parent d290ec1c22
commit a0c2c595f0
4 changed files with 49 additions and 30 deletions

View File

@@ -11,6 +11,7 @@ import (
"github.com/emersion/go-imap" "github.com/emersion/go-imap"
"github.com/emersion/go-imap/backend/backendutil" "github.com/emersion/go-imap/backend/backendutil"
"github.com/emersion/go-message/textproto" "github.com/emersion/go-message/textproto"
"github.com/neilalexander/yggmail/internal/storage/types"
) )
type Mailbox struct { type Mailbox struct {
@@ -115,17 +116,17 @@ func (mbox *Mailbox) ListMessages(uid bool, seqSet *imap.SeqSet, items []imap.Fe
} }
for _, id := range ids { for _, id := range ids {
mseq, mid, body, seen, answered, flagged, deleted, datetime, err := mbox.backend.Storage.MailSelect(mbox.name, int(id)) mseq, mail, err := mbox.backend.Storage.MailSelect(mbox.name, int(id))
if err != nil { if err != nil {
continue continue
} }
fetched := imap.NewMessage(uint32(id), items) fetched := imap.NewMessage(uint32(id), items)
fetched.SeqNum = uint32(mseq) fetched.SeqNum = uint32(mseq)
fetched.Uid = uint32(mid) fetched.Uid = uint32(mail.ID)
get := func() (io.Reader, textproto.Header, error) { get := func() (io.Reader, textproto.Header, error) {
bodyreader := bufio.NewReader(bytes.NewReader(body)) bodyreader := bufio.NewReader(bytes.NewReader(mail.Mail))
hdr, err := textproto.ReadHeader(bodyreader) hdr, err := textproto.ReadHeader(bodyreader)
if err != nil { if err != nil {
return nil, textproto.Header{}, fmt.Errorf("textproto.ReadHeader: %w", err) return nil, textproto.Header{}, fmt.Errorf("textproto.ReadHeader: %w", err)
@@ -155,24 +156,24 @@ func (mbox *Mailbox) ListMessages(uid bool, seqSet *imap.SeqSet, items []imap.Fe
case imap.FetchFlags: case imap.FetchFlags:
fetched.Flags = []string{} fetched.Flags = []string{}
if seen { if mail.Seen {
fetched.Flags = append(fetched.Flags, "\\Seen") fetched.Flags = append(fetched.Flags, "\\Seen")
} }
if answered { if mail.Answered {
fetched.Flags = append(fetched.Flags, "\\Answered") fetched.Flags = append(fetched.Flags, "\\Answered")
} }
if flagged { if mail.Flagged {
fetched.Flags = append(fetched.Flags, "\\Flagged") fetched.Flags = append(fetched.Flags, "\\Flagged")
} }
if deleted { if mail.Deleted {
fetched.Flags = append(fetched.Flags, "\\Deleted") fetched.Flags = append(fetched.Flags, "\\Deleted")
} }
case imap.FetchInternalDate: case imap.FetchInternalDate:
fetched.InternalDate = datetime fetched.InternalDate = mail.Date
case imap.FetchRFC822Size: case imap.FetchRFC822Size:
fetched.Size = uint32(len(body)) fetched.Size = uint32(len(mail.Mail))
case imap.FetchUid: case imap.FetchUid:
fetched.Uid = uint32(id) fetched.Uid = uint32(id)
@@ -241,11 +242,10 @@ func (mbox *Mailbox) UpdateMessagesFlags(uid bool, seqSet *imap.SeqSet, op imap.
} }
for _, id := range ids { for _, id := range ids {
var seen, answered, flagged, deleted bool var mail *types.Mail
var mid int
if op != imap.SetFlags { if op != imap.SetFlags {
var err error var err error
_, mid, _, seen, answered, flagged, deleted, _, err = mbox.backend.Storage.MailSelect(mbox.name, int(id)) _, mail, err = mbox.backend.Storage.MailSelect(mbox.name, int(id))
if err != nil { if err != nil {
return fmt.Errorf("mbox.backend.Storage.MailSelect: %w", err) return fmt.Errorf("mbox.backend.Storage.MailSelect: %w", err)
} }
@@ -253,18 +253,19 @@ func (mbox *Mailbox) UpdateMessagesFlags(uid bool, seqSet *imap.SeqSet, op imap.
for _, flag := range flags { for _, flag := range flags {
switch flag { switch flag {
case "\\Seen": case "\\Seen":
seen = op != imap.RemoveFlags mail.Seen = op != imap.RemoveFlags
case "\\Answered": case "\\Answered":
answered = op != imap.RemoveFlags mail.Answered = op != imap.RemoveFlags
case "\\Flagged": case "\\Flagged":
flagged = op != imap.RemoveFlags mail.Flagged = op != imap.RemoveFlags
case "\\Deleted": case "\\Deleted":
deleted = op != imap.RemoveFlags mail.Deleted = op != imap.RemoveFlags
} }
} }
if err := mbox.backend.Storage.MailUpdateFlags( if err := mbox.backend.Storage.MailUpdateFlags(
mbox.name, int(mid), seen, answered, flagged, deleted, mbox.name, int(mail.ID), mail.Seen,
mail.Answered, mail.Flagged, mail.Deleted,
); err != nil { ); err != nil {
return err return err
} }
@@ -283,15 +284,17 @@ func (mbox *Mailbox) CopyMessages(uid bool, seqSet *imap.SeqSet, destName string
} }
for _, id := range ids { for _, id := range ids {
_, _, body, seen, answered, flagged, deleted, _, err := mbox.backend.Storage.MailSelect(mbox.name, int(id)) _, mail, err := mbox.backend.Storage.MailSelect(mbox.name, int(id))
if err != nil { if err != nil {
return fmt.Errorf("mbox.backend.Storage.MailSelect: %w", err) return fmt.Errorf("mbox.backend.Storage.MailSelect: %w", err)
} }
pid, err := mbox.backend.Storage.MailCreate(destName, body) pid, err := mbox.backend.Storage.MailCreate(destName, mail.Mail)
if err != nil { if err != nil {
return fmt.Errorf("mbox.backend.Storage.MailCreate: %w", err) return fmt.Errorf("mbox.backend.Storage.MailCreate: %w", err)
} }
if err = mbox.backend.Storage.MailUpdateFlags(mbox.name, pid, seen, answered, flagged, deleted); err != nil { if err = mbox.backend.Storage.MailUpdateFlags(
mbox.name, pid, mail.Seen, mail.Answered, mail.Flagged, mail.Deleted,
); err != nil {
return fmt.Errorf("mbox.backend.Storage.MailUpdateFlags: %w", err) return fmt.Errorf("mbox.backend.Storage.MailUpdateFlags: %w", err)
} }
} }

View File

@@ -4,6 +4,8 @@ import (
"database/sql" "database/sql"
"fmt" "fmt"
"time" "time"
"github.com/neilalexander/yggmail/internal/storage/types"
) )
type TableMails struct { type TableMails struct {
@@ -35,7 +37,6 @@ const mailsSchema = `
FOREIGN KEY (mailbox) REFERENCES mailboxes(mailbox) ON DELETE CASCADE ON UPDATE CASCADE FOREIGN KEY (mailbox) REFERENCES mailboxes(mailbox) ON DELETE CASCADE ON UPDATE CASCADE
); );
DROP VIEW IF EXISTS inboxes;
CREATE VIEW IF NOT EXISTS inboxes AS SELECT * FROM ( CREATE VIEW IF NOT EXISTS inboxes AS SELECT * FROM (
SELECT ROW_NUMBER() OVER (PARTITION BY mailbox) AS seq, * FROM mails SELECT ROW_NUMBER() OVER (PARTITION BY mailbox) AS seq, * FROM mails
) )
@@ -160,13 +161,14 @@ func (t *TableMails) MailCreate(mailbox string, data []byte) (int, error) {
return id, err return id, err
} }
func (t *TableMails) MailSelect(mailbox string, id int) (int, int, []byte, bool, bool, bool, bool, time.Time, error) { func (t *TableMails) MailSelect(mailbox string, id int) (int, *types.Mail, error) {
var data []byte var seq int
var seen, answered, flagged, deleted bool mail := &types.Mail{}
var ts int64 err := t.selectMail.QueryRow(mailbox, id).Scan(
var seq, pid int &seq, &mail.ID, &mail.Mail, &mail.Date,
err := t.selectMail.QueryRow(mailbox, id).Scan(&seq, &pid, &data, &ts, &seen, &answered, &flagged, &deleted) &mail.Seen, &mail.Answered, &mail.Flagged, &mail.Deleted,
return seq, pid, data, seen, answered, flagged, deleted, time.Unix(ts, 0), err )
return seq, mail, err
} }
func (t *TableMails) MailSearch(mailbox string) ([]uint32, error) { func (t *TableMails) MailSearch(mailbox string) ([]uint32, error) {

View File

@@ -1,6 +1,6 @@
package storage package storage
import "time" import "github.com/neilalexander/yggmail/internal/storage/types"
type Storage interface { type Storage interface {
ConfigGet(key string) (string, error) ConfigGet(key string) (string, error)
@@ -19,7 +19,7 @@ type Storage interface {
MailboxSubscribe(name string, subscribed bool) error MailboxSubscribe(name string, subscribed bool) error
MailCreate(mailbox string, data []byte) (int, error) MailCreate(mailbox string, data []byte) (int, error)
MailSelect(mailbox string, id int) (int, int, []byte, bool, bool, bool, bool, time.Time, error) MailSelect(mailbox string, id int) (int, *types.Mail, error)
MailSearch(mailbox string) ([]uint32, error) MailSearch(mailbox string) ([]uint32, error)
MailUpdateFlags(mailbox string, id int, seen, answered, flagged, deleted bool) error MailUpdateFlags(mailbox string, id int, seen, answered, flagged, deleted bool) error
MailDelete(mailbox, id string) error MailDelete(mailbox, id string) error

View File

@@ -0,0 +1,14 @@
package types
import "time"
type Mail struct {
Mailbox string
ID int
Mail []byte
Date time.Time
Seen bool
Answered bool
Flagged bool
Deleted bool
}