diff options
| author | Drew DeVault <sir@cmpwn.com> | 2019-03-20 23:23:38 -0400 | 
|---|---|---|
| committer | Drew DeVault <sir@cmpwn.com> | 2019-03-20 23:23:38 -0400 | 
| commit | 312a53e5ff721e0a29e34aaeceb0eece1203002d (patch) | |
| tree | fb0c5f30d89f904d5fad4a900c910a1dd1d891be | |
| parent | f3d3e0ed4f5dbf36b7a7c9762e6297083843f127 (diff) | |
Implement :delete-message
| -rw-r--r-- | commands/delete-message.go | 25 | ||||
| -rw-r--r-- | lib/msgstore.go | 29 | ||||
| -rw-r--r-- | widgets/account.go | 3 | ||||
| -rw-r--r-- | widgets/msglist.go | 20 | ||||
| -rw-r--r-- | worker/imap/fetch.go | 1 | ||||
| -rw-r--r-- | worker/imap/flags.go | 43 | ||||
| -rw-r--r-- | worker/imap/open.go | 1 | ||||
| -rw-r--r-- | worker/imap/worker.go | 6 | ||||
| -rw-r--r-- | worker/types/messages.go | 10 | 
9 files changed, 134 insertions, 4 deletions
diff --git a/commands/delete-message.go b/commands/delete-message.go new file mode 100644 index 0000000..be56dbb --- /dev/null +++ b/commands/delete-message.go @@ -0,0 +1,25 @@ +package commands + +import ( +	"errors" + +	"git.sr.ht/~sircmpwn/aerc2/widgets" +) + +func init() { +	Register("delete-message", DeleteMessage) +} + +func DeleteMessage(aerc *widgets.Aerc, args []string) error { +	if len(args) != 1 { +		return errors.New("Usage: :delete-message") +	} +	acct := aerc.SelectedAccount() +	if acct == nil { +		return errors.New("No account selected") +	} +	store := acct.Messages().Store() +	msg := acct.Messages().Selected() +	store.Delete([]uint32{msg.Uid}) +	return nil +} diff --git a/lib/msgstore.go b/lib/msgstore.go index d745093..6830f64 100644 --- a/lib/msgstore.go +++ b/lib/msgstore.go @@ -1,6 +1,8 @@  package lib  import ( +	"fmt" +  	"github.com/emersion/go-imap"  	"git.sr.ht/~sircmpwn/aerc2/worker/types" @@ -53,7 +55,6 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {  	case *types.DirectoryInfo:  		store.DirInfo = *msg  		update = true -		break  	case *types.DirectoryContents:  		newMap := make(map[uint32]*types.MessageInfo)  		for _, uid := range msg.Uids { @@ -66,7 +67,6 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {  		store.Messages = newMap  		store.Uids = msg.Uids  		update = true -		break  	case *types.MessageInfo:  		// TODO: merge message info into existing record, if applicable  		store.Messages[msg.Uid] = msg @@ -74,7 +74,22 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {  			delete(store.pendingHeaders, msg.Uid)  		}  		update = true -		break +	case *types.MessagesDeleted: +		toDelete := make(map[uint32]interface{}) +		for _, uid := range msg.Uids { +			toDelete[uid] = nil +			delete(store.Messages, uid) +		} +		uids := make([]uint32, len(store.Uids)-len(msg.Uids)) +		j := 0 +		for i, uid := range store.Uids { +			if _, deleted := toDelete[uid]; !deleted { +				uids[j] = store.Uids[i] +				j += 1 +			} +		} +		store.Uids = uids +		update = true  	}  	if update && store.onUpdate != nil {  		store.onUpdate(store) @@ -84,3 +99,11 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {  func (store *MessageStore) OnUpdate(fn func(store *MessageStore)) {  	store.onUpdate = fn  } + +func (store *MessageStore) Delete(uids []uint32) { +	var set imap.SeqSet +	for _, uid := range uids { +		set.AddNum(uid) +	} +	store.worker.PostAction(&types.DeleteMessages{Uids: set}, nil) +} diff --git a/widgets/account.go b/widgets/account.go index 8a3b989..f42ff6c 100644 --- a/widgets/account.go +++ b/widgets/account.go @@ -176,6 +176,9 @@ func (acct *AccountView) onMessage(msg types.WorkerMessage) {  	case *types.MessageInfo:  		store := acct.msgStores[acct.dirlist.selected]  		store.Update(msg) +	case *types.MessagesDeleted: +		store := acct.msgStores[acct.dirlist.selected] +		store.Update(msg)  	case *types.Error:  		acct.logger.Printf("%v", msg.Error)  		acct.host.SetStatus(fmt.Sprintf("%v", msg.Error)). diff --git a/widgets/msglist.go b/widgets/msglist.go index ab25847..ac941c8 100644 --- a/widgets/msglist.go +++ b/widgets/msglist.go @@ -8,6 +8,7 @@ import (  	"git.sr.ht/~sircmpwn/aerc2/config"  	"git.sr.ht/~sircmpwn/aerc2/lib"  	"git.sr.ht/~sircmpwn/aerc2/lib/ui" +	"git.sr.ht/~sircmpwn/aerc2/worker/types"  )  type MessageList struct { @@ -98,6 +99,16 @@ func (ml *MessageList) Height() int {  	return ml.height  } +func (ml *MessageList) storeUpdate(store *lib.MessageStore) { +	if ml.store != store { +		return +	} +	for ml.selected >= len(ml.store.Uids) { +		ml.Prev() +	} +	ml.Invalidate() +} +  func (ml *MessageList) SetStore(store *lib.MessageStore) {  	if ml.store == store {  		ml.scroll = 0 @@ -106,12 +117,21 @@ func (ml *MessageList) SetStore(store *lib.MessageStore) {  	ml.store = store  	if store != nil {  		ml.spinner.Stop() +		ml.store.OnUpdate(ml.storeUpdate)  	} else {  		ml.spinner.Start()  	}  	ml.Invalidate()  } +func (ml *MessageList) Store() *lib.MessageStore { +	return ml.store +} + +func (ml *MessageList) Selected() *types.MessageInfo { +	return ml.store.Messages[ml.store.Uids[len(ml.store.Uids)-ml.selected-1]] +} +  func (ml *MessageList) Select(index int) {  	ml.selected = index  	for ; ml.selected < 0; ml.selected = len(ml.store.Uids) + ml.selected { diff --git a/worker/imap/fetch.go b/worker/imap/fetch.go index 383a8a8..489dbe4 100644 --- a/worker/imap/fetch.go +++ b/worker/imap/fetch.go @@ -25,6 +25,7 @@ func (imapw *IMAPWorker) handleFetchMessageHeaders(  		}()  		go func() {  			for msg := range messages { +				imapw.seqMap[msg.SeqNum-1] = msg.Uid  				imapw.worker.PostMessage(&types.MessageInfo{  					Envelope:     msg.Envelope,  					Flags:        msg.Flags, diff --git a/worker/imap/flags.go b/worker/imap/flags.go new file mode 100644 index 0000000..cb9b3b1 --- /dev/null +++ b/worker/imap/flags.go @@ -0,0 +1,43 @@ +package imap + +import ( +	"github.com/emersion/go-imap" + +	"git.sr.ht/~sircmpwn/aerc2/worker/types" +) + +func (imapw *IMAPWorker) handleDeleteMessages(msg *types.DeleteMessages) { +	item := imap.FormatFlagsOp(imap.AddFlags, true) +	flags := []interface{}{imap.DeletedFlag} +	if err := imapw.client.UidStore(&msg.Uids, item, flags, nil); err != nil { +		imapw.worker.PostMessage(&types.Error{ +			Message: types.RespondTo(msg), +			Error:   err, +		}, nil) +		return +	} +	var deleted []uint32 +	ch := make(chan uint32) +	done := make(chan interface{}) +	go func() { +		for seqNum := range ch { +			i := seqNum - 1 +			deleted = append(deleted, imapw.seqMap[i]) +			imapw.seqMap = append(imapw.seqMap[:i], imapw.seqMap[i+1:]...) +		} +		done <- nil +	}() +	if err := imapw.client.Expunge(ch); err != nil { +		imapw.worker.PostMessage(&types.Error{ +			Message: types.RespondTo(msg), +			Error:   err, +		}, nil) +	} else { +		<-done +		imapw.worker.PostMessage(&types.MessagesDeleted{ +			Message: types.RespondTo(msg), +			Uids:    deleted, +		}, nil) +		imapw.worker.PostMessage(&types.Done{types.RespondTo(msg)}, nil) +	} +} diff --git a/worker/imap/open.go b/worker/imap/open.go index 87c4fb3..3705bc0 100644 --- a/worker/imap/open.go +++ b/worker/imap/open.go @@ -39,6 +39,7 @@ func (imapw *IMAPWorker) handleFetchDirectoryContents(  			}, nil)  		} else {  			imapw.worker.Logger.Printf("Found %d UIDs", len(uids)) +			imapw.seqMap = make([]uint32, len(uids))  			imapw.worker.PostMessage(&types.DirectoryContents{  				Message: types.RespondTo(msg),  				Uids:    uids, diff --git a/worker/imap/worker.go b/worker/imap/worker.go index 1646165..ea7f317 100644 --- a/worker/imap/worker.go +++ b/worker/imap/worker.go @@ -33,12 +33,14 @@ type IMAPWorker struct {  	selected imap.MailboxStatus  	updates  chan client.Update  	worker   *types.Worker +	// Map of sequence numbers to UIDs, index 0 is seq number 1 +	seqMap []uint32  }  func NewIMAPWorker(worker *types.Worker) *IMAPWorker {  	return &IMAPWorker{ -		worker:  worker,  		updates: make(chan client.Update, 50), +		worker:  worker,  	}  } @@ -156,6 +158,8 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error {  		w.handleFetchDirectoryContents(msg)  	case *types.FetchMessageHeaders:  		w.handleFetchMessageHeaders(msg) +	case *types.DeleteMessages: +		w.handleDeleteMessages(msg)  	default:  		return errUnsupported  	} diff --git a/worker/types/messages.go b/worker/types/messages.go index 3f1a39f..ff2c36b 100644 --- a/worker/types/messages.go +++ b/worker/types/messages.go @@ -86,6 +86,11 @@ type FetchMessageBodies struct {  	Uids imap.SeqSet  } +type DeleteMessages struct { +	Message +	Uids imap.SeqSet +} +  // Messages  type CertificateApprovalRequest struct { @@ -122,3 +127,8 @@ type MessageInfo struct {  	Size         uint32  	Uid          uint32  } + +type MessagesDeleted struct { +	Message +	Uids []uint32 +}  | 
