244 lines
4.2 KiB
Go
244 lines
4.2 KiB
Go
package memory
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"time"
|
|
|
|
"github.com/emersion/go-imap"
|
|
"github.com/emersion/go-imap/backend"
|
|
"github.com/emersion/go-imap/backend/backendutil"
|
|
)
|
|
|
|
var Delimiter = "/"
|
|
|
|
type Mailbox struct {
|
|
Subscribed bool
|
|
Messages []*Message
|
|
|
|
name string
|
|
user *User
|
|
}
|
|
|
|
func (mbox *Mailbox) Name() string {
|
|
return mbox.name
|
|
}
|
|
|
|
func (mbox *Mailbox) Info() (*imap.MailboxInfo, error) {
|
|
info := &imap.MailboxInfo{
|
|
Delimiter: Delimiter,
|
|
Name: mbox.name,
|
|
}
|
|
return info, nil
|
|
}
|
|
|
|
func (mbox *Mailbox) uidNext() uint32 {
|
|
var uid uint32
|
|
for _, msg := range mbox.Messages {
|
|
if msg.Uid > uid {
|
|
uid = msg.Uid
|
|
}
|
|
}
|
|
uid++
|
|
return uid
|
|
}
|
|
|
|
func (mbox *Mailbox) flags() []string {
|
|
flagsMap := make(map[string]bool)
|
|
for _, msg := range mbox.Messages {
|
|
for _, f := range msg.Flags {
|
|
if !flagsMap[f] {
|
|
flagsMap[f] = true
|
|
}
|
|
}
|
|
}
|
|
|
|
var flags []string
|
|
for f := range flagsMap {
|
|
flags = append(flags, f)
|
|
}
|
|
return flags
|
|
}
|
|
|
|
func (mbox *Mailbox) unseenSeqNum() uint32 {
|
|
for i, msg := range mbox.Messages {
|
|
seqNum := uint32(i + 1)
|
|
|
|
seen := false
|
|
for _, flag := range msg.Flags {
|
|
if flag == imap.SeenFlag {
|
|
seen = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !seen {
|
|
return seqNum
|
|
}
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func (mbox *Mailbox) Status(items []imap.StatusItem) (*imap.MailboxStatus, error) {
|
|
status := imap.NewMailboxStatus(mbox.name, items)
|
|
status.Flags = mbox.flags()
|
|
status.PermanentFlags = []string{"\\*"}
|
|
status.UnseenSeqNum = mbox.unseenSeqNum()
|
|
|
|
for _, name := range items {
|
|
switch name {
|
|
case imap.StatusMessages:
|
|
status.Messages = uint32(len(mbox.Messages))
|
|
case imap.StatusUidNext:
|
|
status.UidNext = mbox.uidNext()
|
|
case imap.StatusUidValidity:
|
|
status.UidValidity = 1
|
|
case imap.StatusRecent:
|
|
status.Recent = 0 // TODO
|
|
case imap.StatusUnseen:
|
|
status.Unseen = 0 // TODO
|
|
}
|
|
}
|
|
|
|
return status, nil
|
|
}
|
|
|
|
func (mbox *Mailbox) SetSubscribed(subscribed bool) error {
|
|
mbox.Subscribed = subscribed
|
|
return nil
|
|
}
|
|
|
|
func (mbox *Mailbox) Check() error {
|
|
return nil
|
|
}
|
|
|
|
func (mbox *Mailbox) ListMessages(uid bool, seqSet *imap.SeqSet, items []imap.FetchItem, ch chan<- *imap.Message) error {
|
|
defer close(ch)
|
|
|
|
for i, msg := range mbox.Messages {
|
|
seqNum := uint32(i + 1)
|
|
|
|
var id uint32
|
|
if uid {
|
|
id = msg.Uid
|
|
} else {
|
|
id = seqNum
|
|
}
|
|
if !seqSet.Contains(id) {
|
|
continue
|
|
}
|
|
|
|
m, err := msg.Fetch(seqNum, items)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
ch <- m
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (mbox *Mailbox) SearchMessages(uid bool, criteria *imap.SearchCriteria) ([]uint32, error) {
|
|
var ids []uint32
|
|
for i, msg := range mbox.Messages {
|
|
seqNum := uint32(i + 1)
|
|
|
|
ok, err := msg.Match(seqNum, criteria)
|
|
if err != nil || !ok {
|
|
continue
|
|
}
|
|
|
|
var id uint32
|
|
if uid {
|
|
id = msg.Uid
|
|
} else {
|
|
id = seqNum
|
|
}
|
|
ids = append(ids, id)
|
|
}
|
|
return ids, nil
|
|
}
|
|
|
|
func (mbox *Mailbox) CreateMessage(flags []string, date time.Time, body imap.Literal) error {
|
|
if date.IsZero() {
|
|
date = time.Now()
|
|
}
|
|
|
|
b, err := ioutil.ReadAll(body)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
mbox.Messages = append(mbox.Messages, &Message{
|
|
Uid: mbox.uidNext(),
|
|
Date: date,
|
|
Size: uint32(len(b)),
|
|
Flags: flags,
|
|
Body: b,
|
|
})
|
|
return nil
|
|
}
|
|
|
|
func (mbox *Mailbox) UpdateMessagesFlags(uid bool, seqset *imap.SeqSet, op imap.FlagsOp, flags []string) error {
|
|
for i, msg := range mbox.Messages {
|
|
var id uint32
|
|
if uid {
|
|
id = msg.Uid
|
|
} else {
|
|
id = uint32(i + 1)
|
|
}
|
|
if !seqset.Contains(id) {
|
|
continue
|
|
}
|
|
|
|
msg.Flags = backendutil.UpdateFlags(msg.Flags, op, flags)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (mbox *Mailbox) CopyMessages(uid bool, seqset *imap.SeqSet, destName string) error {
|
|
dest, ok := mbox.user.mailboxes[destName]
|
|
if !ok {
|
|
return backend.ErrNoSuchMailbox
|
|
}
|
|
|
|
for i, msg := range mbox.Messages {
|
|
var id uint32
|
|
if uid {
|
|
id = msg.Uid
|
|
} else {
|
|
id = uint32(i + 1)
|
|
}
|
|
if !seqset.Contains(id) {
|
|
continue
|
|
}
|
|
|
|
msgCopy := *msg
|
|
msgCopy.Uid = dest.uidNext()
|
|
dest.Messages = append(dest.Messages, &msgCopy)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (mbox *Mailbox) Expunge() error {
|
|
for i := len(mbox.Messages) - 1; i >= 0; i-- {
|
|
msg := mbox.Messages[i]
|
|
|
|
deleted := false
|
|
for _, flag := range msg.Flags {
|
|
if flag == imap.DeletedFlag {
|
|
deleted = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if deleted {
|
|
mbox.Messages = append(mbox.Messages[:i], mbox.Messages[i+1:]...)
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|