2022-07-11 20:11:18 +02:00
|
|
|
package mboxer
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
|
|
|
|
"git.sr.ht/~rjarry/aerc/models"
|
|
|
|
"git.sr.ht/~rjarry/aerc/worker/lib"
|
|
|
|
)
|
|
|
|
|
|
|
|
type mailboxContainer struct {
|
|
|
|
mailboxes map[string]*container
|
|
|
|
}
|
|
|
|
|
|
|
|
func (md *mailboxContainer) Names() []string {
|
|
|
|
files := make([]string, 0)
|
|
|
|
for file := range md.mailboxes {
|
|
|
|
files = append(files, file)
|
|
|
|
}
|
|
|
|
return files
|
|
|
|
}
|
|
|
|
|
|
|
|
func (md *mailboxContainer) Mailbox(f string) (*container, bool) {
|
|
|
|
mb, ok := md.mailboxes[f]
|
|
|
|
return mb, ok
|
|
|
|
}
|
|
|
|
|
|
|
|
func (md *mailboxContainer) Create(file string) *container {
|
|
|
|
md.mailboxes[file] = &container{filename: file}
|
|
|
|
return md.mailboxes[file]
|
|
|
|
}
|
|
|
|
|
|
|
|
func (md *mailboxContainer) Remove(file string) error {
|
|
|
|
delete(md.mailboxes, file)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (md *mailboxContainer) DirectoryInfo(file string) *models.DirectoryInfo {
|
|
|
|
var exists int
|
|
|
|
if md, ok := md.Mailbox(file); ok {
|
|
|
|
exists = len(md.Uids())
|
|
|
|
}
|
|
|
|
return &models.DirectoryInfo{
|
|
|
|
Name: file,
|
|
|
|
Flags: []string{},
|
|
|
|
ReadOnly: false,
|
|
|
|
Exists: exists,
|
|
|
|
Recent: 0,
|
|
|
|
Unseen: 0,
|
|
|
|
AccurateCounts: false,
|
|
|
|
Caps: &models.Capabilities{
|
|
|
|
Sort: true,
|
|
|
|
Thread: false,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (md *mailboxContainer) Copy(dest, src string, uids []uint32) error {
|
|
|
|
srcmbox, ok := md.Mailbox(src)
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("source %s not found", src)
|
|
|
|
}
|
|
|
|
destmbox, ok := md.Mailbox(dest)
|
|
|
|
if !ok {
|
|
|
|
return fmt.Errorf("destination %s not found", dest)
|
|
|
|
}
|
|
|
|
for _, uidSrc := range srcmbox.Uids() {
|
|
|
|
found := false
|
|
|
|
for _, uid := range uids {
|
|
|
|
if uid == uidSrc {
|
|
|
|
found = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if found {
|
|
|
|
msg, err := srcmbox.Message(uidSrc)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not get message with uid %d from folder %s", uidSrc, src)
|
|
|
|
}
|
|
|
|
r, err := msg.NewReader()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not get reader for message with uid %d", uidSrc)
|
|
|
|
}
|
|
|
|
flags, err := msg.ModelFlags()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not get flags for message with uid %d", uidSrc)
|
|
|
|
}
|
2022-07-29 22:31:54 +02:00
|
|
|
err = destmbox.Append(r, flags)
|
|
|
|
if err != nil {
|
2022-07-31 15:15:27 +02:00
|
|
|
return fmt.Errorf("could not append data to mbox: %w", err)
|
2022-07-29 22:31:54 +02:00
|
|
|
}
|
2022-07-11 20:11:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
md.mailboxes[dest] = destmbox
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type container struct {
|
|
|
|
filename string
|
|
|
|
messages []lib.RawMessage
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *container) Uids() []uint32 {
|
|
|
|
uids := make([]uint32, len(f.messages))
|
|
|
|
for i, m := range f.messages {
|
|
|
|
uids[i] = m.UID()
|
|
|
|
}
|
|
|
|
return uids
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *container) Message(uid uint32) (lib.RawMessage, error) {
|
|
|
|
for _, m := range f.messages {
|
|
|
|
if uid == m.UID() {
|
|
|
|
return m, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return &message{}, fmt.Errorf("uid [%d] not found", uid)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *container) Delete(uids []uint32) (deleted []uint32) {
|
|
|
|
newMessages := make([]lib.RawMessage, 0)
|
|
|
|
for _, m := range f.messages {
|
|
|
|
del := false
|
|
|
|
for _, uid := range uids {
|
|
|
|
if m.UID() == uid {
|
|
|
|
del = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if del {
|
|
|
|
deleted = append(deleted, m.UID())
|
|
|
|
} else {
|
|
|
|
newMessages = append(newMessages, m)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
f.messages = newMessages
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *container) newUid() (next uint32) {
|
|
|
|
for _, m := range f.messages {
|
|
|
|
if uid := m.UID(); uid > next {
|
|
|
|
next = uid
|
|
|
|
}
|
|
|
|
}
|
|
|
|
next++
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *container) Append(r io.Reader, flags []models.Flag) error {
|
2022-08-17 16:19:45 +02:00
|
|
|
data, err := io.ReadAll(r)
|
2022-07-11 20:11:18 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
f.messages = append(f.messages, &message{
|
|
|
|
uid: f.newUid(),
|
|
|
|
flags: flags,
|
|
|
|
content: data,
|
|
|
|
})
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// message implements the lib.RawMessage interface
|
|
|
|
type message struct {
|
|
|
|
uid uint32
|
|
|
|
flags []models.Flag
|
|
|
|
content []byte
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *message) NewReader() (io.ReadCloser, error) {
|
2022-08-17 16:19:45 +02:00
|
|
|
return io.NopCloser(bytes.NewReader(m.content)), nil
|
2022-07-11 20:11:18 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (m *message) ModelFlags() ([]models.Flag, error) {
|
|
|
|
return m.flags, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *message) Labels() ([]string, error) {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *message) UID() uint32 {
|
|
|
|
return m.uid
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *message) SetFlag(flag models.Flag, state bool) error {
|
|
|
|
flagSet := make(map[models.Flag]bool)
|
|
|
|
flags, err := m.ModelFlags()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
for _, f := range flags {
|
|
|
|
flagSet[f] = true
|
|
|
|
}
|
|
|
|
flagSet[flag] = state
|
|
|
|
newFlags := make([]models.Flag, 0)
|
|
|
|
for flag, isSet := range flagSet {
|
|
|
|
if isSet {
|
|
|
|
newFlags = append(newFlags, flag)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m.flags = newFlags
|
|
|
|
return nil
|
|
|
|
}
|