~sircmpwn/aerc

b3896476a0e6978c0d7f6fedfb64588934a78f1e — Drew DeVault 2 years ago 289e3b0
Fetch valid UIDs from server after opening dir
6 files changed, 141 insertions(+), 100 deletions(-)

M widgets/account.go
A widgets/msglist.go
M worker/imap/open.go
M worker/imap/worker.go
D worker/messages.go
M worker/types/messages.go
M widgets/account.go => widgets/account.go +29 -6
@@ 21,6 21,7 @@ type AccountView struct {
	interactive  ui.Interactive
	onInvalidate func(d ui.Drawable)
	runCmd       func(cmd string) error
	msgStores    map[string]*MessageStore
	statusline   *StatusLine
	statusbar    *ui.Stack
	worker       *types.Worker


@@ 64,9 65,10 @@ func NewAccountView(conf *config.AccountConfig,
		dirlist:    dirlist,
		grid:       grid,
		logger:     logger,
		msgStores:  make(map[string]*MessageStore),
		runCmd:     runCmd,
		statusline: statusline,
		statusbar:  statusbar,
		statusline: statusline,
		worker:     worker,
	}



@@ 157,10 159,6 @@ func (acct *AccountView) connected(msg types.WorkerMessage) {
			Message:  types.RespondTo(msg),
			Approved: true,
		}, acct.connected)
	case *types.Error:
		acct.logger.Printf("%v", msg.Error)
		acct.statusline.Set(fmt.Sprintf("%v", msg.Error)).
			Color(tcell.ColorRed, tcell.ColorDefault)
	}
}



@@ 169,5 167,30 @@ func (acct *AccountView) Directories() *DirectoryList {
}

func (acct *AccountView) onMessage(msg types.WorkerMessage) {
	// TODO
	switch msg := msg.(type) {
	case *types.Done:
		switch msg.InResponseTo().(type) {
		case *types.OpenDirectory:
			acct.worker.PostAction(&types.FetchDirectoryContents{},
				func(msg types.WorkerMessage) {
					// TODO: Do we care
				})
		}
	case *types.DirectoryInfo:
		if store, ok := acct.msgStores[msg.Name]; ok {
			store.Update(msg)
		} else {
			acct.msgStores[msg.Name] = NewMessageStore(msg)
		}
	case *types.DirectoryContents:
		store := acct.msgStores[acct.dirlist.selected]
		store.Update(msg)
	case *types.MessageInfo:
		store := acct.msgStores[acct.dirlist.selected]
		store.Update(msg)
	case *types.Error:
		acct.logger.Printf("%v", msg.Error)
		acct.statusline.Set(fmt.Sprintf("%v", msg.Error)).
			Color(tcell.ColorRed, tcell.ColorDefault)
	}
}

A widgets/msglist.go => widgets/msglist.go +36 -0
@@ 0,0 1,36 @@
package widgets

import (
	"git.sr.ht/~sircmpwn/aerc2/worker/types"
)

type MessageStore struct {
	DirInfo  types.DirectoryInfo
	Messages map[uint64]*types.MessageInfo
}

func NewMessageStore(dirInfo *types.DirectoryInfo) *MessageStore {
	return &MessageStore{DirInfo: *dirInfo}
}

func (store *MessageStore) Update(msg types.WorkerMessage) {
	switch msg := msg.(type) {
	case *types.DirectoryInfo:
		store.DirInfo = *msg
		break
	case *types.DirectoryContents:
		newMap := make(map[uint64]*types.MessageInfo)
		for _, uid := range msg.Uids {
			if msg, ok := store.Messages[uid]; ok {
				newMap[uid] = msg
			} else {
				newMap[uid] = nil
			}
		}
		store.Messages = newMap
		break
	case *types.MessageInfo:
		store.Messages[msg.Uid] = msg
		break
	}
}

M worker/imap/open.go => worker/imap/open.go +34 -0
@@ 1,6 1,8 @@
package imap

import (
	"github.com/emersion/go-imap"

	"git.sr.ht/~sircmpwn/aerc2/worker/types"
)



@@ 18,3 20,35 @@ func (imapw *IMAPWorker) handleOpenDirectory(msg *types.OpenDirectory) {
		}
	}()
}

func (imapw *IMAPWorker) handleFetchDirectoryContents(
	msg *types.FetchDirectoryContents) {

	imapw.worker.Logger.Printf("Fetching UID list")

	go func() {
		seqSet := &imap.SeqSet{}
		seqSet.AddRange(1, imapw.selected.Messages)
		uid32, err := imapw.client.UidSearch(&imap.SearchCriteria{
			SeqNum: seqSet,
		})
		if err != nil {
			imapw.worker.PostMessage(&types.Error{
				Message: types.RespondTo(msg),
				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.PostMessage(&types.DirectoryContents{
				Message: types.RespondTo(msg),
				Uids:    uids,
			}, nil)
			imapw.worker.PostMessage(&types.Done{types.RespondTo(msg)}, nil)
		}
	}()
}

M worker/imap/worker.go => worker/imap/worker.go +9 -3
@@ 29,9 29,10 @@ type IMAPWorker struct {
		user     *url.Userinfo
	}

	worker  *types.Worker
	client  *imapClient
	updates chan client.Update
	client   *imapClient
	selected imap.MailboxStatus
	updates  chan client.Update
	worker   *types.Worker
}

func NewIMAPWorker(worker *types.Worker) *IMAPWorker {


@@ 151,6 152,8 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error {
		w.handleListDirectories(msg)
	case *types.OpenDirectory:
		w.handleOpenDirectory(msg)
	case *types.FetchDirectoryContents:
		w.handleFetchDirectoryContents(msg)
	default:
		return errUnsupported
	}


@@ 162,6 165,9 @@ func (w *IMAPWorker) handleImapUpdate(update client.Update) {
	switch update := update.(type) {
	case *client.MailboxUpdate:
		status := update.Mailbox
		if w.selected.Name == status.Name {
			w.selected = *status
		}
		w.worker.PostMessage(&types.DirectoryInfo{
			Flags:    status.Flags,
			Name:     status.Name,

D worker/messages.go => worker/messages.go +0 -91
@@ 1,91 0,0 @@
package worker

import (
	"crypto/x509"

	"git.sr.ht/~sircmpwn/aerc2/config"
)

type WorkerMessage interface {
	InResponseTo() WorkerMessage
}

type Message struct {
	inResponseTo WorkerMessage
}

func RespondTo(msg WorkerMessage) Message {
	return Message{
		inResponseTo: msg,
	}
}

func (m Message) InResponseTo() WorkerMessage {
	return m.inResponseTo
}

// Meta-messages

type Done struct {
	Message
}

type Error struct {
	Message
	Error error
}

type Unsupported struct {
	Message
}

// Actions

type ApproveCertificate struct {
	Message
	Approved bool
}

type Configure struct {
	Message
	Config *config.AccountConfig
}

type Connect struct {
	Message
}

type Disconnect struct {
	Message
}

type ListDirectories struct {
	Message
}

type OpenDirectory struct {
	Message
	Directory string
}

// Messages

type CertificateApprovalRequest struct {
	Message
	CertPool *x509.CertPool
}

type Directory struct {
	Message
	Attributes []string
	Name       string
}

type DirectoryInfo struct {
	Message
	Flags    []string
	Name     string
	ReadOnly bool

	Exists, Recent, Unseen int
}

M worker/types/messages.go => worker/types/messages.go +33 -0
@@ 2,6 2,10 @@ package types

import (
	"crypto/x509"
	"net/mail"
	"time"

	"github.com/emersion/go-imap"

	"git.sr.ht/~sircmpwn/aerc2/config"
)


@@ 68,6 72,20 @@ type OpenDirectory struct {
	Directory string
}

type FetchDirectoryContents struct {
	Message
}

type FetchMessageHeaders struct {
	Message
	Uids imap.SeqSet
}

type FetchMessageBodies struct {
	Message
	Uids imap.SeqSet
}

// Messages

type CertificateApprovalRequest struct {


@@ 89,3 107,18 @@ type DirectoryInfo struct {

	Exists, Recent, Unseen int
}

type DirectoryContents struct {
	Message
	Uids []uint64
}

type MessageInfo struct {
	Message
	Envelope     *imap.Envelope
	Flags        []string
	InternalDate time.Time
	Mail         *mail.Message
	Size         uint32
	Uid          uint64
}