~sircmpwn/aerc

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch

[PATCH v2] Set AnsweredFlag on successful reply

Details
Message ID
<20200525145948.282179-1-sri@vathsan.com>
DKIM signature
pass
Download raw message
Patch: +179 -0
---
Rebased as requested.

 commands/compose/send.go  |  2 ++
 commands/msg/reply.go     |  4 ++++
 lib/msgstore.go           |  9 +++++++++
 widgets/compose.go        |  9 +++++++++
 worker/imap/flags.go      | 32 ++++++++++++++++++++++++++++++++
 worker/imap/worker.go     |  2 ++
 worker/maildir/message.go | 20 ++++++++++++++++++++
 worker/maildir/worker.go  | 35 +++++++++++++++++++++++++++++++++++
 worker/notmuch/message.go | 33 +++++++++++++++++++++++++++++++++
 worker/notmuch/worker.go  | 27 +++++++++++++++++++++++++++
 worker/types/messages.go  |  6 ++++++
 11 files changed, 179 insertions(+)

diff --git a/commands/compose/send.go b/commands/compose/send.go
index 36b9fd81bc9c..59ae5d0bdb2c 100644
--- a/commands/compose/send.go
+++ b/commands/compose/send.go
@@ -244,6 +244,7 @@ func (Send) Execute(aerc *widgets.Aerc, args []string) error {
				case *types.Done:
					aerc.PushStatus("Message sent.", 10*time.Second)
					r.Close()
					composer.SetSent()
					composer.Close()
				case *types.Error:
					aerc.PushError(" " + msg.Error.Error())
@@ -256,6 +257,7 @@ func (Send) Execute(aerc *widgets.Aerc, args []string) error {
			w.Close()
		} else {
			aerc.PushStatus("Message sent.", 10*time.Second)
			composer.SetSent()
			composer.Close()
		}
	}()
diff --git a/commands/msg/reply.go b/commands/msg/reply.go
index 8e0feef97802..28ce245d5e15 100644
--- a/commands/msg/reply.go
+++ b/commands/msg/reply.go
@@ -157,6 +157,10 @@ func (reply) Execute(aerc *widgets.Aerc, args []string) error {
			tab.Content.Invalidate()
		})

		composer.OnClose(func(c *widgets.Composer) {
			store.Answered([]uint32{msg.Uid}, c.Sent(), nil)
		})

		return nil
	}

diff --git a/lib/msgstore.go b/lib/msgstore.go
index 7dc26898af6d..86215a720be0 100644
--- a/lib/msgstore.go
+++ b/lib/msgstore.go
@@ -342,6 +342,15 @@ func (store *MessageStore) Read(uids []uint32, read bool,
	}, cb)
}

func (store *MessageStore) Answered(uids []uint32, answered bool,
	cb func(msg types.WorkerMessage)) {

	store.worker.PostAction(&types.AnsweredMessages{
		Answered: answered,
		Uids:     uids,
	}, cb)
}

func (store *MessageStore) Uids() []uint32 {
	if store.filter {
		return store.results
diff --git a/widgets/compose.go b/widgets/compose.go
index 42819411424c..01b8dd80b799 100644
--- a/widgets/compose.go
+++ b/widgets/compose.go
@@ -52,6 +52,7 @@ type Composer struct {
	layout    HeaderLayout
	focusable []ui.MouseableDrawableInteractive
	focused   int
	sent      bool

	onClose []func(ti *Composer)

@@ -163,6 +164,14 @@ func buildComposeHeader(conf *config.AercConfig, cmpl *completer.Completer,
	return layout, editors, focusable
}

func (c *Composer) SetSent() {
	c.sent = true
}

func (c *Composer) Sent() bool {
	return c.sent
}

// Note: this does not reload the editor. You must call this before the first
// Draw() call.
func (c *Composer) SetContents(reader io.Reader) *Composer {
diff --git a/worker/imap/flags.go b/worker/imap/flags.go
index 17c9393cfa61..262508669b93 100644
--- a/worker/imap/flags.go
+++ b/worker/imap/flags.go
@@ -44,6 +44,38 @@ func (imapw *IMAPWorker) handleDeleteMessages(msg *types.DeleteMessages) {
	}
}

func (imapw *IMAPWorker) handleAnsweredMessages(msg *types.AnsweredMessages) {
	item := imap.FormatFlagsOp(imap.AddFlags, true)
	flags := []interface{}{imap.AnsweredFlag}
	if !msg.Answered {
		item = imap.FormatFlagsOp(imap.RemoveFlags, true)
		flags = []interface{}{imap.AnsweredFlag}
	}
	uids := toSeqSet(msg.Uids)
	emitErr := func(err error) {
		imapw.worker.PostMessage(&types.Error{
			Message: types.RespondTo(msg),
			Error:   err,
		}, nil)
	}
	if err := imapw.client.UidStore(uids, item, flags, nil); err != nil {
		emitErr(err)
		return
	}
	imapw.worker.PostAction(&types.FetchMessageHeaders{
		Uids: msg.Uids,
	}, func(_msg types.WorkerMessage) {
		switch m := _msg.(type) {
		case *types.Error:
			err := fmt.Errorf("handleAnsweredMessages: %v", m.Error)
			imapw.worker.Logger.Printf("could not fetch headers: %s", err)
			emitErr(err)
		case *types.Done:
			imapw.worker.PostMessage(&types.Done{types.RespondTo(msg)}, nil)
		}
	})
}

func (imapw *IMAPWorker) handleReadMessages(msg *types.ReadMessages) {
	item := imap.FormatFlagsOp(imap.AddFlags, true)
	flags := []interface{}{imap.SeenFlag}
diff --git a/worker/imap/worker.go b/worker/imap/worker.go
index 45a226904929..a43ac49efdac 100644
--- a/worker/imap/worker.go
+++ b/worker/imap/worker.go
@@ -175,6 +175,8 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error {
		w.handleDeleteMessages(msg)
	case *types.ReadMessages:
		w.handleReadMessages(msg)
	case *types.AnsweredMessages:
		w.handleAnsweredMessages(msg)
	case *types.CopyMessages:
		w.handleCopyMessages(msg)
	case *types.AppendMessage:
diff --git a/worker/maildir/message.go b/worker/maildir/message.go
index 9d622b45fb55..5c6c9307d945 100644
--- a/worker/maildir/message.go
+++ b/worker/maildir/message.go
@@ -53,6 +53,26 @@ func (m Message) SetFlags(flags []maildir.Flag) error {
	return m.dir.SetFlags(m.key, flags)
}

// MarkReplied either adds or removes the maildir.FlagReplied flag from the
// message.
func (m Message) MarkReplied(answered bool) error {
	flags, err := m.Flags()
	if err != nil {
		return fmt.Errorf("could not read previous flags: %v", err)
	}
	if answered {
		flags = append(flags, maildir.FlagReplied)
		return m.SetFlags(flags)
	}
	var newFlags []maildir.Flag
	for _, flag := range flags {
		if flag != maildir.FlagReplied {
			newFlags = append(newFlags, flag)
		}
	}
	return m.SetFlags(newFlags)
}

// MarkRead either adds or removes the maildir.FlagSeen flag from the message.
func (m Message) MarkRead(seen bool) error {
	flags, err := m.Flags()
diff --git a/worker/maildir/worker.go b/worker/maildir/worker.go
index dbdb92523eb4..f14672e5a819 100644
--- a/worker/maildir/worker.go
+++ b/worker/maildir/worker.go
@@ -195,6 +195,8 @@ func (w *Worker) handleMessage(msg types.WorkerMessage) error {
		return w.handleDeleteMessages(msg)
	case *types.ReadMessages:
		return w.handleReadMessages(msg)
	case *types.AnsweredMessages:
		return w.handleAnsweredMessages(msg)
	case *types.CopyMessages:
		return w.handleCopyMessages(msg)
	case *types.AppendMessage:
@@ -438,6 +440,39 @@ func (w *Worker) handleDeleteMessages(msg *types.DeleteMessages) error {
	return nil
}

func (w *Worker) handleAnsweredMessages(msg *types.AnsweredMessages) error {
	for _, uid := range msg.Uids {
		m, err := w.c.Message(*w.selected, uid)
		if err != nil {
			w.worker.Logger.Printf("could not get message: %v", err)
			w.err(msg, err)
			continue
		}
		if err := m.MarkReplied(msg.Answered); err != nil {
			w.worker.Logger.Printf(
				"could not mark message as answered: %v", err)
			w.err(msg, err)
			continue
		}
		info, err := m.MessageInfo()
		if err != nil {
			w.worker.Logger.Printf("could not get message info: %v", err)
			w.err(msg, err)
			continue
		}

		w.worker.PostMessage(&types.MessageInfo{
			Message: types.RespondTo(msg),
			Info:    info,
		}, nil)

		w.worker.PostMessage(&types.DirectoryInfo{
			Info: w.getDirectoryInfo(w.selectedName),
		}, nil)
	}
	return nil
}

func (w *Worker) handleReadMessages(msg *types.ReadMessages) error {
	for _, uid := range msg.Uids {
		m, err := w.c.Message(*w.selected, uid)
diff --git a/worker/notmuch/message.go b/worker/notmuch/message.go
index ec1adb9ba6ef..3fd2fb62ade2 100644
--- a/worker/notmuch/message.go
+++ b/worker/notmuch/message.go
@@ -64,6 +64,39 @@ func (m *Message) NewBodyPartReader(requestedParts []int) (io.Reader, error) {
	return lib.FetchEntityPartReader(msg, requestedParts)
}

// MarkAnswered either adds or removes the "replied" tag from the message.
func (m *Message) MarkAnswered(answered bool) error {
	haveReplied := false
	tags, err := m.Tags()
	if err != nil {
		return err
	}
	for _, t := range tags {
		if t == "replied" {
			haveReplied = true
			break
		}
	}
	if haveReplied == answered {
		// we already have the desired state
		return nil
	}

	if haveAnswered {
		err := m.RemoveTag("replied")
		if err != nil {
			return err
		}
		return nil
	}

	err = m.AddTag("replied")
	if err != nil {
		return err
	}
	return nil
}

// MarkRead either adds or removes the maildir.FlagSeen flag from the message.
func (m *Message) MarkRead(seen bool) error {
	haveUnread := false
diff --git a/worker/notmuch/worker.go b/worker/notmuch/worker.go
index 9929648da734..b22626981068 100644
--- a/worker/notmuch/worker.go
+++ b/worker/notmuch/worker.go
@@ -363,6 +363,33 @@ func (w *worker) handleFetchFullMessages(msg *types.FetchFullMessages) error {
	return nil
}

func (w *worker) handleAnsweredMessages(msg *types.AnsweredMessages) error {
	for _, uid := range msg.Uids {
		m, err := w.msgFromUid(uid)
		if err != nil {
			w.w.Logger.Printf("could not get message: %v", err)
			w.err(msg, err)
			continue
		}
		if err := m.MarkAnswered(msg.Answered); err != nil {
			w.w.Logger.Printf("could not mark message as answered: %v", err)
			w.err(msg, err)
			continue
		}
		err = w.emitMessageInfo(m, msg)
		if err != nil {
			w.w.Logger.Printf(err.Error())
			w.err(msg, err)
			continue
		}
	}
	if err := w.emitDirectoryInfo(w.currentQueryName); err != nil {
		w.w.Logger.Printf(err.Error())
	}
	w.done(msg)
	return nil
}

func (w *worker) handleReadMessages(msg *types.ReadMessages) error {
	for _, uid := range msg.Uids {
		m, err := w.msgFromUid(uid)
diff --git a/worker/types/messages.go b/worker/types/messages.go
index f1ef36ea52a4..475a7aa32bd8 100644
--- a/worker/types/messages.go
+++ b/worker/types/messages.go
@@ -120,6 +120,12 @@ type ReadMessages struct {
	Uids []uint32
}

type AnsweredMessages struct {
	Message
	Answered bool
	Uids     []uint32
}

type CopyMessages struct {
	Message
	Destination string
-- 
2.26.2
Review patch Export thread (mbox)