about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2019-03-14 21:51:29 -0400
committerDrew DeVault <sir@cmpwn.com>2019-03-14 21:51:29 -0400
commit11f0a7267fd1a9d1c6dd55e1dc044b8ed639bbc0 (patch)
tree80e2456edadfdcd7c6a8e02ab4830c1139816174
parent0f8b7a1203309ebec0dc78baf3f195671eadac2d (diff)
downloadaerc-11f0a7267fd1a9d1c6dd55e1dc044b8ed639bbc0.tar.gz
Implement message store side of message fetching
-rw-r--r--widgets/account.go4
-rw-r--r--widgets/msglist.go62
-rw-r--r--worker/imap/open.go9
-rw-r--r--worker/types/messages.go4
4 files changed, 58 insertions, 21 deletions
diff --git a/widgets/account.go b/widgets/account.go
index 8857535..5747f4b 100644
--- a/widgets/account.go
+++ b/widgets/account.go
@@ -58,7 +58,7 @@ func NewAccountView(conf *config.AccountConfig,
 	dirlist := NewDirectoryList(conf, logger, worker)
 	grid.AddChild(ui.NewBordered(dirlist, ui.BORDER_RIGHT)).Span(2, 1)
 
-	msglist := NewMessageList(logger, worker)
+	msglist := NewMessageList(logger)
 	grid.AddChild(msglist).At(0, 1)
 
 	acct := &AccountView{
@@ -183,7 +183,7 @@ func (acct *AccountView) onMessage(msg types.WorkerMessage) {
 		if store, ok := acct.msgStores[msg.Name]; ok {
 			store.Update(msg)
 		} else {
-			acct.msgStores[msg.Name] = NewMessageStore(msg)
+			acct.msgStores[msg.Name] = NewMessageStore(acct.worker, msg)
 		}
 	case *types.DirectoryContents:
 		store := acct.msgStores[acct.dirlist.selected]
diff --git a/widgets/msglist.go b/widgets/msglist.go
index 8e3c2eb..fef396b 100644
--- a/widgets/msglist.go
+++ b/widgets/msglist.go
@@ -3,6 +3,7 @@ package widgets
 import (
 	"log"
 
+	"github.com/emersion/go-imap"
 	"github.com/gdamore/tcell"
 
 	"git.sr.ht/~sircmpwn/aerc2/config"
@@ -12,20 +13,52 @@ import (
 
 type MessageStore struct {
 	DirInfo  types.DirectoryInfo
-	Messages map[uint64]*types.MessageInfo
+	Messages map[uint32]*types.MessageInfo
+	// Map of uids we've asked the worker to fetch
+	onUpdate       func(store *MessageStore)
+	pendingBodies  map[uint32]interface{}
+	pendingHeaders map[uint32]interface{}
+	worker         *types.Worker
 }
 
-func NewMessageStore(dirInfo *types.DirectoryInfo) *MessageStore {
-	return &MessageStore{DirInfo: *dirInfo}
+func NewMessageStore(worker *types.Worker,
+	dirInfo *types.DirectoryInfo) *MessageStore {
+
+	return &MessageStore{
+		DirInfo: *dirInfo,
+
+		pendingBodies:  make(map[uint32]interface{}),
+		pendingHeaders: make(map[uint32]interface{}),
+		worker:         worker,
+	}
+}
+
+func (store *MessageStore) FetchHeaders(uids []uint32) {
+	// TODO: this could be optimized by pre-allocating toFetch and trimming it
+	// at the end. In practice we expect to get most messages back in one frame.
+	var toFetch imap.SeqSet
+	for _, uid := range uids {
+		if _, ok := store.pendingHeaders[uid]; !ok {
+			toFetch.AddNum(uint32(uid))
+			store.pendingHeaders[uid] = nil
+		}
+	}
+	if !toFetch.Empty() {
+		store.worker.PostAction(&types.FetchMessageHeaders{
+			Uids: toFetch,
+		}, nil)
+	}
 }
 
 func (store *MessageStore) Update(msg types.WorkerMessage) {
+	update := false
 	switch msg := msg.(type) {
 	case *types.DirectoryInfo:
 		store.DirInfo = *msg
+		update = true
 		break
 	case *types.DirectoryContents:
-		newMap := make(map[uint64]*types.MessageInfo)
+		newMap := make(map[uint32]*types.MessageInfo)
 		for _, uid := range msg.Uids {
 			if msg, ok := store.Messages[uid]; ok {
 				newMap[uid] = msg
@@ -34,11 +67,23 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
 			}
 		}
 		store.Messages = newMap
+		update = true
 		break
 	case *types.MessageInfo:
 		store.Messages[msg.Uid] = msg
+		if _, ok := store.pendingHeaders[msg.Uid]; msg.Envelope != nil && ok {
+			delete(store.pendingHeaders, msg.Uid)
+		}
+		update = true
 		break
 	}
+	if update && store.onUpdate != nil {
+		store.onUpdate(store)
+	}
+}
+
+func (store *MessageStore) OnUpdate(fn func(store *MessageStore)) {
+	store.onUpdate = fn
 }
 
 type MessageList struct {
@@ -47,15 +92,13 @@ type MessageList struct {
 	onInvalidate func(d ui.Drawable)
 	spinner      *Spinner
 	store        *MessageStore
-	worker       *types.Worker
 }
 
 // TODO: fish in config
-func NewMessageList(logger *log.Logger, worker *types.Worker) *MessageList {
+func NewMessageList(logger *log.Logger) *MessageList {
 	ml := &MessageList{
 		logger:  logger,
 		spinner: NewSpinner(),
-		worker:  worker,
 	}
 	ml.spinner.OnInvalidate(func(_ ui.Drawable) {
 		ml.Invalidate()
@@ -84,7 +127,7 @@ func (ml *MessageList) Draw(ctx *ui.Context) {
 	}
 
 	var (
-		needsHeaders []uint64
+		needsHeaders []uint32
 		row          int = 0
 	)
 
@@ -102,12 +145,11 @@ func (ml *MessageList) Draw(ctx *ui.Context) {
 	}
 
 	if len(needsHeaders) != 0 {
+		ml.store.FetchHeaders(needsHeaders)
 		ml.spinner.Start()
 	} else {
 		ml.spinner.Stop()
 	}
-
-	// TODO: Fetch these messages
 }
 
 func (ml *MessageList) SetStore(store *MessageStore) {
diff --git a/worker/imap/open.go b/worker/imap/open.go
index 0f25c5e..87c4fb3 100644
--- a/worker/imap/open.go
+++ b/worker/imap/open.go
@@ -29,7 +29,7 @@ func (imapw *IMAPWorker) handleFetchDirectoryContents(
 	go func() {
 		seqSet := &imap.SeqSet{}
 		seqSet.AddRange(1, imapw.selected.Messages)
-		uid32, err := imapw.client.UidSearch(&imap.SearchCriteria{
+		uids, err := imapw.client.UidSearch(&imap.SearchCriteria{
 			SeqNum: seqSet,
 		})
 		if err != nil {
@@ -38,12 +38,7 @@ func (imapw *IMAPWorker) handleFetchDirectoryContents(
 				Error:   err,
 			}, nil)
 		} else {
-			imapw.worker.Logger.Printf("Found %d UIDs", len(uid32))
-			var uids []uint64
-			for _, uid := range uid32 {
-				uids = append(uids,
-					(uint64(imapw.selected.UidValidity)<<32)|uint64(uid))
-			}
+			imapw.worker.Logger.Printf("Found %d UIDs", len(uids))
 			imapw.worker.PostMessage(&types.DirectoryContents{
 				Message: types.RespondTo(msg),
 				Uids:    uids,
diff --git a/worker/types/messages.go b/worker/types/messages.go
index d44624d..3f1a39f 100644
--- a/worker/types/messages.go
+++ b/worker/types/messages.go
@@ -110,7 +110,7 @@ type DirectoryInfo struct {
 
 type DirectoryContents struct {
 	Message
-	Uids []uint64
+	Uids []uint32
 }
 
 type MessageInfo struct {
@@ -120,5 +120,5 @@ type MessageInfo struct {
 	InternalDate time.Time
 	Mail         *mail.Message
 	Size         uint32
-	Uid          uint64
+	Uid          uint32
 }