~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] maildir: track the recent flag correctly

Details
Message ID
<20200913084240.1688298-1-reto@labrat.space>
DKIM signature
pass
Download raw message
Patch: +55 -31
In the maildir worker we manually need to track the Recent flag in order for the
notification command etc to work.

Push that responsibility to the container, we must make sure to manually add the
flag though if one grabs the message info.
---
 worker/maildir/container.go | 40 ++++++++++++++++++++++++--------
 worker/maildir/worker.go    | 46 +++++++++++++++++++------------------
 2 files changed, 55 insertions(+), 31 deletions(-)

diff --git a/worker/maildir/container.go b/worker/maildir/container.go
index 14815c9..1bdc4e7 100644
--- a/worker/maildir/container.go
+++ b/worker/maildir/container.go
@@ -15,9 +15,10 @@ import (
// A Container is a directory which contains other directories which adhere to
// the Maildir spec
type Container struct {
	dir  string
	log  *log.Logger
	uids *uidstore.Store
	dir        string
	log        *log.Logger
	uids       *uidstore.Store
	recentUIDS map[uint32]struct{} // used to set the recent flag
}

// NewContainer creates a new container at the specified directory
@@ -34,7 +35,8 @@ func NewContainer(dir string, l *log.Logger) (*Container, error) {
	if !s.IsDir() {
		return nil, fmt.Errorf("Given maildir '%s' not a directory", dir)
	}
	return &Container{dir: dir, uids: uidstore.NewStore(), log: l}, nil
	return &Container{dir: dir, uids: uidstore.NewStore(), log: l,
		recentUIDS: make(map[uint32]struct{})}, nil
}

// ListFolders returns a list of maildir folders in the container
@@ -72,17 +74,26 @@ func (c *Container) ListFolders() ([]string, error) {
	return folders, err
}

// SyncNewMail adds emails from new to cur, tracking them
func (c *Container) SyncNewMail(dir maildir.Dir) error {
	keys, err := dir.Unseen()
	if err != nil {
		return err
	}
	for _, key := range keys {
		uid := c.uids.GetOrInsert(key)
		c.recentUIDS[uid] = struct{}{}
	}
	return nil
}

// OpenDirectory opens an existing maildir in the container by name, moves new
// messages into cur, and registers the new keys in the UIDStore.
func (c *Container) OpenDirectory(name string) (maildir.Dir, error) {
	dir := c.Dir(name)
	keys, err := dir.Unseen()
	if err != nil {
	if err := c.SyncNewMail(dir); err != nil {
		return dir, err
	}
	for _, key := range keys {
		c.uids.GetOrInsert(key)
	}
	return dir, nil
}

@@ -91,6 +102,17 @@ func (c *Container) Dir(name string) maildir.Dir {
	return maildir.Dir(filepath.Join(c.dir, name))
}

// IsRecent returns if a uid has the Recent flag set
func (c *Container) IsRecent(uid uint32) bool {
	_, ok := c.recentUIDS[uid]
	return ok
}

// ClearRecentFlag removes the Recent flag from the message with the given uid
func (c *Container) ClearRecentFlag(uid uint32) {
	delete(c.recentUIDS, uid)
}

// UIDs fetches the unique message identifiers for the maildir
func (c *Container) UIDs(d maildir.Dir) ([]uint32, error) {
	keys, err := d.Keys()
diff --git a/worker/maildir/worker.go b/worker/maildir/worker.go
index 4a7ae51..cf08e70 100644
--- a/worker/maildir/worker.go
+++ b/worker/maildir/worker.go
@@ -79,11 +79,12 @@ func (w *Worker) handleFSEvent(ev fsnotify.Event) {
	if w.selected == nil {
		return
	}
	newUnseen, err := w.selected.Unseen()
	err := w.c.SyncNewMail(*w.selected)
	if err != nil {
		w.worker.Logger.Printf("could not move new to cur : %v", err)
		return
	}

	uids, err := w.c.UIDs(*w.selected)
	if err != nil {
		w.worker.Logger.Printf("could not scan UIDs: %v", err)
@@ -98,7 +99,6 @@ func (w *Worker) handleFSEvent(ev fsnotify.Event) {
		Uids: sortedUids,
	}, nil)
	dirInfo := w.getDirectoryInfo(w.selectedName)
	dirInfo.Recent = len(newUnseen)
	w.worker.PostMessage(&types.DirectoryInfo{
		Info: dirInfo,
	}, nil)
@@ -138,12 +138,6 @@ func (w *Worker) getDirectoryInfo(name string) *models.DirectoryInfo {
		return dirInfo
	}

	recent, err := dir.UnseenCount()
	if err != nil {
		w.worker.Logger.Printf("could not get unseen count: %v", err)
	}
	dirInfo.Recent = recent

	for _, uid := range uids {
		message, err := w.c.Message(dir, uid)
		if err != nil {
@@ -164,9 +158,12 @@ func (w *Worker) getDirectoryInfo(name string) *models.DirectoryInfo {
		if !seen {
			dirInfo.Unseen++
		}
		if w.c.IsRecent(uid) {
			dirInfo.Recent++
		}
	}
	dirInfo.Unseen += dirInfo.Recent
	dirInfo.Exists = len(uids) + recent
	dirInfo.Exists = len(uids) + dirInfo.Recent
	return dirInfo
}

@@ -334,12 +331,7 @@ func (w *Worker) sort(uids []uint32, criteria []*types.SortCriterion) ([]uint32,
	}
	var msgInfos []*models.MessageInfo
	for _, uid := range uids {
		m, err := w.c.Message(*w.selected, uid)
		if err != nil {
			w.worker.Logger.Printf("could not get message: %v", err)
			continue
		}
		info, err := m.MessageInfo()
		info, err := w.msgInfoFromUid(uid)
		if err != nil {
			w.worker.Logger.Printf("could not get message info: %v", err)
			continue
@@ -377,13 +369,7 @@ func (w *Worker) handleRemoveDirectory(msg *types.RemoveDirectory) error {
func (w *Worker) handleFetchMessageHeaders(
	msg *types.FetchMessageHeaders) 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
		}
		info, err := m.MessageInfo()
		info, err := w.msgInfoFromUid(uid)
		if err != nil {
			w.worker.Logger.Printf("could not get message info: %v", err)
			w.err(msg, err)
@@ -393,6 +379,7 @@ func (w *Worker) handleFetchMessageHeaders(
			Message: types.RespondTo(msg),
			Info:    info,
		}, nil)
		w.c.ClearRecentFlag(uid)
	}
	return nil
}
@@ -590,3 +577,18 @@ func (w *Worker) handleSearchDirectory(msg *types.SearchDirectory) error {
	}, nil)
	return nil
}

func (w *Worker) msgInfoFromUid(uid uint32) (*models.MessageInfo, error) {
	m, err := w.c.Message(*w.selected, uid)
	if err != nil {
		return nil, err
	}
	info, err := m.MessageInfo()
	if err != nil {
		return nil, err
	}
	if w.c.IsRecent(uid) {
		info.Flags = append(info.Flags, models.RecentFlag)
	}
	return info, nil
}
-- 
2.28.0
Review patch Export thread (mbox)