aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Burwell <ben@benburwell.com>2019-07-07 22:43:56 -0400
committerDrew DeVault <sir@cmpwn.com>2019-07-08 16:06:23 -0400
commitcce7cb48081ca090ac2d3a0e781dfbc25d581946 (patch)
tree0709eff3daf75ac975bc9e12f068d7951aeaefe6
parentc79577d37675c8d9ed3355c532a215377e76d3b2 (diff)
downloadaerc-cce7cb48081ca090ac2d3a0e781dfbc25d581946.tar.gz
Factor UI models out of the worker message package
Before, the information needed to display different parts of the UI was tightly coupled to the specific messages being sent back and forth to the backend worker. Separating out a models package allows us to be more specific about exactly what a backend is able to and required to provide for the UI.
-rw-r--r--lib/indexformat.go4
-rw-r--r--lib/msgstore.go37
-rw-r--r--models/models.go52
-rw-r--r--widgets/account.go9
-rw-r--r--widgets/dirlist.go2
-rw-r--r--widgets/msglist.go4
-rw-r--r--widgets/msgviewer.go16
-rw-r--r--widgets/providesmessage.go4
-rw-r--r--worker/imap/fetch.go41
-rw-r--r--worker/imap/list.go9
-rw-r--r--worker/imap/worker.go29
-rw-r--r--worker/types/messages.go25
12 files changed, 146 insertions, 86 deletions
diff --git a/lib/indexformat.go b/lib/indexformat.go
index 9e7a8058..43d2ef83 100644
--- a/lib/indexformat.go
+++ b/lib/indexformat.go
@@ -9,11 +9,11 @@ import (
"github.com/emersion/go-imap"
"git.sr.ht/~sircmpwn/aerc/config"
- "git.sr.ht/~sircmpwn/aerc/worker/types"
+ "git.sr.ht/~sircmpwn/aerc/models"
)
func ParseIndexFormat(conf *config.AercConfig, number int,
- msg *types.MessageInfo) (string, []interface{}, error) {
+ msg *models.MessageInfo) (string, []interface{}, error) {
format := conf.Ui.IndexFormat
retval := make([]byte, 0, len(format))
diff --git a/lib/msgstore.go b/lib/msgstore.go
index 09cf31fd..77160ae1 100644
--- a/lib/msgstore.go
+++ b/lib/msgstore.go
@@ -6,14 +6,15 @@ import (
"github.com/emersion/go-imap"
+ "git.sr.ht/~sircmpwn/aerc/models"
"git.sr.ht/~sircmpwn/aerc/worker/types"
)
// Accesses to fields must be guarded by MessageStore.Lock/Unlock
type MessageStore struct {
Deleted map[uint32]interface{}
- DirInfo types.DirectoryInfo
- Messages map[uint32]*types.MessageInfo
+ DirInfo models.DirectoryInfo
+ Messages map[uint32]*models.MessageInfo
// Ordered list of known UIDs
Uids []uint32
@@ -33,7 +34,7 @@ type MessageStore struct {
}
func NewMessageStore(worker *types.Worker,
- dirInfo *types.DirectoryInfo) *MessageStore {
+ dirInfo *models.DirectoryInfo) *MessageStore {
return &MessageStore{
Deleted: make(map[uint32]interface{}),
@@ -106,11 +107,11 @@ func (store *MessageStore) FetchBodyPart(
if !ok {
return
}
- cb(msg.Reader)
+ cb(msg.Part.Reader)
})
}
-func merge(to *types.MessageInfo, from *types.MessageInfo) {
+func merge(to *models.MessageInfo, from *models.MessageInfo) {
if from.BodyStructure != nil {
to.BodyStructure = from.BodyStructure
}
@@ -131,11 +132,11 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
update := false
switch msg := msg.(type) {
case *types.DirectoryInfo:
- store.DirInfo = *msg
+ store.DirInfo = *msg.Info
store.worker.PostAction(&types.FetchDirectoryContents{}, nil)
update = true
case *types.DirectoryContents:
- newMap := make(map[uint32]*types.MessageInfo)
+ newMap := make(map[uint32]*models.MessageInfo)
for _, uid := range msg.Uids {
if msg, ok := store.Messages[uid]; ok {
newMap[uid] = msg
@@ -147,14 +148,14 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
store.Uids = msg.Uids
update = true
case *types.MessageInfo:
- if existing, ok := store.Messages[msg.Uid]; ok && existing != nil {
- merge(existing, msg)
+ if existing, ok := store.Messages[msg.Info.Uid]; ok && existing != nil {
+ merge(existing, msg.Info)
} else {
- store.Messages[msg.Uid] = msg
+ store.Messages[msg.Info.Uid] = msg.Info
}
- if _, ok := store.pendingHeaders[msg.Uid]; msg.Envelope != nil && ok {
- delete(store.pendingHeaders, msg.Uid)
- if cbs, ok := store.headerCallbacks[msg.Uid]; ok {
+ if _, ok := store.pendingHeaders[msg.Info.Uid]; msg.Info.Envelope != nil && ok {
+ delete(store.pendingHeaders, msg.Info.Uid)
+ if cbs, ok := store.headerCallbacks[msg.Info.Uid]; ok {
for _, cb := range cbs {
cb(msg)
}
@@ -162,11 +163,11 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
}
update = true
case *types.FullMessage:
- if _, ok := store.pendingBodies[msg.Uid]; ok {
- delete(store.pendingBodies, msg.Uid)
- if cbs, ok := store.bodyCallbacks[msg.Uid]; ok {
+ if _, ok := store.pendingBodies[msg.Content.Uid]; ok {
+ delete(store.pendingBodies, msg.Content.Uid)
+ if cbs, ok := store.bodyCallbacks[msg.Content.Uid]; ok {
for _, cb := range cbs {
- cb(msg.Reader)
+ cb(msg.Content.Reader)
}
}
}
@@ -283,7 +284,7 @@ func (store *MessageStore) Read(uids []uint32, read bool,
}, cb)
}
-func (store *MessageStore) Selected() *types.MessageInfo {
+func (store *MessageStore) Selected() *models.MessageInfo {
return store.Messages[store.Uids[len(store.Uids)-store.selected-1]]
}
diff --git a/models/models.go b/models/models.go
new file mode 100644
index 00000000..cff05b1e
--- /dev/null
+++ b/models/models.go
@@ -0,0 +1,52 @@
+package models
+
+import (
+ "io"
+ "time"
+
+ "github.com/emersion/go-imap"
+ "github.com/emersion/go-message/mail"
+)
+
+type Directory struct {
+ Name string
+ Attributes []string
+}
+
+type DirectoryInfo struct {
+ Name string
+ Flags []string
+ ReadOnly bool
+
+ // The total number of messages in this mailbox.
+ Exists int
+
+ // The number of messages not seen since the last time the mailbox was opened.
+ Recent int
+
+ // The number of unread messages
+ Unseen int
+}
+
+// A MessageInfo holds information about the structure of a message
+type MessageInfo struct {
+ BodyStructure *imap.BodyStructure
+ Envelope *imap.Envelope
+ Flags []string
+ InternalDate time.Time
+ RFC822Headers *mail.Header
+ Size uint32
+ Uid uint32
+}
+
+// A MessageBodyPart can be displayed in the message viewer
+type MessageBodyPart struct {
+ Reader io.Reader
+ Uid uint32
+}
+
+// A FullMessage is the entire message
+type FullMessage struct {
+ Reader io.Reader
+ Uid uint32
+}
diff --git a/widgets/account.go b/widgets/account.go
index 0948c5c6..e08a2537 100644
--- a/widgets/account.go
+++ b/widgets/account.go
@@ -9,6 +9,7 @@ import (
"git.sr.ht/~sircmpwn/aerc/config"
"git.sr.ht/~sircmpwn/aerc/lib"
"git.sr.ht/~sircmpwn/aerc/lib/ui"
+ "git.sr.ht/~sircmpwn/aerc/models"
"git.sr.ht/~sircmpwn/aerc/worker"
"git.sr.ht/~sircmpwn/aerc/worker/types"
)
@@ -169,7 +170,7 @@ func (acct *AccountView) SelectedAccount() *AccountView {
return acct
}
-func (acct *AccountView) SelectedMessage() *types.MessageInfo {
+func (acct *AccountView) SelectedMessage() *models.MessageInfo {
return acct.msglist.Selected()
}
@@ -195,11 +196,11 @@ func (acct *AccountView) onMessage(msg types.WorkerMessage) {
acct.dirlist.UpdateList(nil)
}
case *types.DirectoryInfo:
- if store, ok := acct.msgStores[msg.Name]; ok {
+ if store, ok := acct.msgStores[msg.Info.Name]; ok {
store.Update(msg)
} else {
- store = lib.NewMessageStore(acct.worker, msg)
- acct.msgStores[msg.Name] = store
+ store = lib.NewMessageStore(acct.worker, msg.Info)
+ acct.msgStores[msg.Info.Name] = store
store.OnUpdate(func(_ *lib.MessageStore) {
store.OnUpdate(nil)
acct.msglist.SetStore(store)
diff --git a/widgets/dirlist.go b/widgets/dirlist.go
index 4dc8fd2c..c5e4a0c0 100644
--- a/widgets/dirlist.go
+++ b/widgets/dirlist.go
@@ -55,7 +55,7 @@ func (dirlist *DirectoryList) UpdateList(done func(dirs []string)) {
switch msg := msg.(type) {
case *types.Directory:
- dirs = append(dirs, msg.Name)
+ dirs = append(dirs, msg.Dir.Name)
case *types.Done:
sort.Strings(dirs)
dirlist.store.Update(dirs)
diff --git a/widgets/msglist.go b/widgets/msglist.go
index 211cbcea..70514789 100644
--- a/widgets/msglist.go
+++ b/widgets/msglist.go
@@ -11,7 +11,7 @@ import (
"git.sr.ht/~sircmpwn/aerc/config"
"git.sr.ht/~sircmpwn/aerc/lib"
"git.sr.ht/~sircmpwn/aerc/lib/ui"
- "git.sr.ht/~sircmpwn/aerc/worker/types"
+ "git.sr.ht/~sircmpwn/aerc/models"
)
type MessageList struct {
@@ -176,7 +176,7 @@ func (ml *MessageList) Empty() bool {
return store == nil || len(store.Uids) == 0
}
-func (ml *MessageList) Selected() *types.MessageInfo {
+func (ml *MessageList) Selected() *models.MessageInfo {
store := ml.Store()
return store.Messages[store.Uids[len(store.Uids)-ml.store.SelectedIndex()-1]]
}
diff --git a/widgets/msgviewer.go b/widgets/msgviewer.go
index b0ae79ed..6a645f9a 100644
--- a/widgets/msgviewer.go
+++ b/widgets/msgviewer.go
@@ -20,7 +20,7 @@ import (
"git.sr.ht/~sircmpwn/aerc/config"
"git.sr.ht/~sircmpwn/aerc/lib"
"git.sr.ht/~sircmpwn/aerc/lib/ui"
- "git.sr.ht/~sircmpwn/aerc/worker/types"
+ "git.sr.ht/~sircmpwn/aerc/models"
)
var ansi = regexp.MustCompile("^\x1B\\[[0-?]*[ -/]*[@-~]")
@@ -31,7 +31,7 @@ type MessageViewer struct {
conf *config.AercConfig
err error
grid *ui.Grid
- msg *types.MessageInfo
+ msg *models.MessageInfo
switcher *PartSwitcher
store *lib.MessageStore
}
@@ -44,7 +44,7 @@ type PartSwitcher struct {
}
func NewMessageViewer(acct *AccountView, conf *config.AercConfig,
- store *lib.MessageStore, msg *types.MessageInfo) *MessageViewer {
+ store *lib.MessageStore, msg *models.MessageInfo) *MessageViewer {
grid := ui.NewGrid().Rows([]ui.GridSpec{
{ui.SIZE_EXACT, 4}, // TODO: Based on number of header rows
@@ -112,7 +112,7 @@ handle_error:
}
func enumerateParts(conf *config.AercConfig, store *lib.MessageStore,
- msg *types.MessageInfo, body *imap.BodyStructure,
+ msg *models.MessageInfo, body *imap.BodyStructure,
showHeaders bool, index []int) ([]*PartViewer, error) {
var parts []*PartViewer
@@ -140,7 +140,7 @@ func enumerateParts(conf *config.AercConfig, store *lib.MessageStore,
}
func createSwitcher(switcher *PartSwitcher, conf *config.AercConfig,
- store *lib.MessageStore, msg *types.MessageInfo, showHeaders bool) error {
+ store *lib.MessageStore, msg *models.MessageInfo, showHeaders bool) error {
var err error
switcher.showHeaders = showHeaders
@@ -212,7 +212,7 @@ func (mv *MessageViewer) SelectedAccount() *AccountView {
return mv.acct
}
-func (mv *MessageViewer) SelectedMessage() *types.MessageInfo {
+func (mv *MessageViewer) SelectedMessage() *models.MessageInfo {
return mv.msg
}
@@ -321,7 +321,7 @@ type PartViewer struct {
fetched bool
filter *exec.Cmd
index []int
- msg *types.MessageInfo
+ msg *models.MessageInfo
pager *exec.Cmd
pagerin io.WriteCloser
part *imap.BodyStructure
@@ -333,7 +333,7 @@ type PartViewer struct {
}
func NewPartViewer(conf *config.AercConfig,
- store *lib.MessageStore, msg *types.MessageInfo,
+ store *lib.MessageStore, msg *models.MessageInfo,
part *imap.BodyStructure, showHeaders bool,
index []int) (*PartViewer, error) {
diff --git a/widgets/providesmessage.go b/widgets/providesmessage.go
index 4b716371..d8b1e771 100644
--- a/widgets/providesmessage.go
+++ b/widgets/providesmessage.go
@@ -5,7 +5,7 @@ import (
"git.sr.ht/~sircmpwn/aerc/lib"
"git.sr.ht/~sircmpwn/aerc/lib/ui"
- "git.sr.ht/~sircmpwn/aerc/worker/types"
+ "git.sr.ht/~sircmpwn/aerc/models"
)
type PartInfo struct {
@@ -19,6 +19,6 @@ type ProvidesMessage interface {
ui.Drawable
Store() *lib.MessageStore
SelectedAccount() *AccountView
- SelectedMessage() *types.MessageInfo
+ SelectedMessage() *models.MessageInfo
SelectedMessagePart() *PartInfo
}
diff --git a/worker/imap/fetch.go b/worker/imap/fetch.go
index 7d1bfcf1..d5bb9aaf 100644
--- a/worker/imap/fetch.go
+++ b/worker/imap/fetch.go
@@ -8,6 +8,7 @@ import (
"github.com/emersion/go-message/mail"
"github.com/emersion/go-message/textproto"
+ "git.sr.ht/~sircmpwn/aerc/models"
"git.sr.ht/~sircmpwn/aerc/worker/types"
)
@@ -82,39 +83,49 @@ func (imapw *IMAPWorker) handleFetchMessages(
header = &mail.Header{message.Header{textprotoHeader}}
}
imapw.worker.PostMessage(&types.MessageInfo{
- Message: types.RespondTo(msg),
- BodyStructure: _msg.BodyStructure,
- Envelope: _msg.Envelope,
- Flags: _msg.Flags,
- InternalDate: _msg.InternalDate,
- RFC822Headers: header,
- Uid: _msg.Uid,
+ Message: types.RespondTo(msg),
+ Info: &models.MessageInfo{
+ BodyStructure: _msg.BodyStructure,
+ Envelope: _msg.Envelope,
+ Flags: _msg.Flags,
+ InternalDate: _msg.InternalDate,
+ RFC822Headers: header,
+ Uid: _msg.Uid,
+ },
}, nil)
case *types.FetchFullMessages:
reader := _msg.GetBody(section)
imapw.worker.PostMessage(&types.FullMessage{
Message: types.RespondTo(msg),
- Reader: reader,
- Uid: _msg.Uid,
+ Content: &models.FullMessage{
+ Reader: reader,
+ Uid: _msg.Uid,
+ },
}, nil)
// Update flags (to mark message as read)
imapw.worker.PostMessage(&types.MessageInfo{
Message: types.RespondTo(msg),
- Flags: _msg.Flags,
- Uid: _msg.Uid,
+ Info: &models.MessageInfo{
+ Flags: _msg.Flags,
+ Uid: _msg.Uid,
+ },
}, nil)
case *types.FetchMessageBodyPart:
reader := _msg.GetBody(section)
imapw.worker.PostMessage(&types.MessageBodyPart{
Message: types.RespondTo(msg),
- Reader: reader,
- Uid: _msg.Uid,
+ Part: &models.MessageBodyPart{
+ Reader: reader,
+ Uid: _msg.Uid,
+ },
}, nil)
// Update flags (to mark message as read)
imapw.worker.PostMessage(&types.MessageInfo{
Message: types.RespondTo(msg),
- Flags: _msg.Flags,
- Uid: _msg.Uid,
+ Info: &models.MessageInfo{
+ Flags: _msg.Flags,
+ Uid: _msg.Uid,
+ },
}, nil)
}
}
diff --git a/worker/imap/list.go b/worker/imap/list.go
index 708e70fd..42be50e4 100644
--- a/worker/imap/list.go
+++ b/worker/imap/list.go
@@ -3,6 +3,7 @@ package imap
import (
"github.com/emersion/go-imap"
+ "git.sr.ht/~sircmpwn/aerc/models"
"git.sr.ht/~sircmpwn/aerc/worker/types"
)
@@ -18,9 +19,11 @@ func (imapw *IMAPWorker) handleListDirectories(msg *types.ListDirectories) {
continue
}
imapw.worker.PostMessage(&types.Directory{
- Message: types.RespondTo(msg),
- Name: mbox.Name,
- Attributes: mbox.Attributes,
+ Message: types.RespondTo(msg),
+ Dir: &models.Directory{
+ Name: mbox.Name,
+ Attributes: mbox.Attributes,
+ },
}, nil)
}
done <- nil
diff --git a/worker/imap/worker.go b/worker/imap/worker.go
index 5005620f..9ddaa47e 100644
--- a/worker/imap/worker.go
+++ b/worker/imap/worker.go
@@ -10,6 +10,7 @@ import (
idle "github.com/emersion/go-imap-idle"
"github.com/emersion/go-imap/client"
+ "git.sr.ht/~sircmpwn/aerc/models"
"git.sr.ht/~sircmpwn/aerc/worker/types"
)
@@ -169,13 +170,15 @@ func (w *IMAPWorker) handleImapUpdate(update client.Update) {
w.selected = *status
}
w.worker.PostMessage(&types.DirectoryInfo{
- Flags: status.Flags,
- Name: status.Name,
- ReadOnly: status.ReadOnly,
-
- Exists: int(status.Messages),
- Recent: int(status.Recent),
- Unseen: int(status.Unseen),
+ Info: &models.DirectoryInfo{
+ Flags: status.Flags,
+ Name: status.Name,
+ ReadOnly: status.ReadOnly,
+
+ Exists: int(status.Messages),
+ Recent: int(status.Recent),
+ Unseen: int(status.Unseen),
+ },
}, nil)
case *client.MessageUpdate:
msg := update.Message
@@ -183,11 +186,13 @@ func (w *IMAPWorker) handleImapUpdate(update client.Update) {
msg.Uid = w.seqMap[msg.SeqNum-1]
}
w.worker.PostMessage(&types.MessageInfo{
- BodyStructure: msg.BodyStructure,
- Envelope: msg.Envelope,
- Flags: msg.Flags,
- InternalDate: msg.InternalDate,
- Uid: msg.Uid,
+ Info: &models.MessageInfo{
+ BodyStructure: msg.BodyStructure,
+ Envelope: msg.Envelope,
+ Flags: msg.Flags,
+ InternalDate: msg.InternalDate,
+ Uid: msg.Uid,
+ },
}, nil)
case *client.ExpungeUpdate:
i := update.SeqNum - 1
diff --git a/worker/types/messages.go b/worker/types/messages.go
index d9e911f1..bb2505a3 100644
--- a/worker/types/messages.go
+++ b/worker/types/messages.go
@@ -5,9 +5,9 @@ import (
"time"
"github.com/emersion/go-imap"
- "github.com/emersion/go-message/mail"
"git.sr.ht/~sircmpwn/aerc/config"
+ "git.sr.ht/~sircmpwn/aerc/models"
)
type WorkerMessage interface {
@@ -139,17 +139,12 @@ type AppendMessage struct {
type Directory struct {
Message
- Attributes []string
- Name string
+ Dir *models.Directory
}
type DirectoryInfo struct {
Message
- Flags []string
- Name string
- ReadOnly bool
-
- Exists, Recent, Unseen int
+ Info *models.DirectoryInfo
}
type DirectoryContents struct {
@@ -164,25 +159,17 @@ type SearchResults struct {
type MessageInfo struct {
Message
- BodyStructure *imap.BodyStructure
- Envelope *imap.Envelope
- Flags []string
- InternalDate time.Time
- RFC822Headers *mail.Header
- Size uint32
- Uid uint32
+ Info *models.MessageInfo
}
type FullMessage struct {
Message
- Reader io.Reader
- Uid uint32
+ Content *models.FullMessage
}
type MessageBodyPart struct {
Message
- Reader io.Reader
- Uid uint32
+ Part *models.MessageBodyPart
}
type MessagesDeleted struct {