From 12269c757d9ffcf93ba23a39c8e12cd222c5ae82 Mon Sep 17 00:00:00 2001 From: Ben Burwell Date: Sat, 12 Oct 2019 22:17:29 -0400 Subject: Add threading support for maildir --- worker/maildir/container.go | 46 +++++++++++++++++++++++++++++++++++++++++++++ worker/maildir/message.go | 17 +++++++++++++++++ worker/maildir/worker.go | 15 +++++++++++++++ 3 files changed, 78 insertions(+) diff --git a/worker/maildir/container.go b/worker/maildir/container.go index 85e892a..a7acfb7 100644 --- a/worker/maildir/container.go +++ b/worker/maildir/container.go @@ -10,6 +10,7 @@ import ( "github.com/emersion/go-maildir" "git.sr.ht/~sircmpwn/aerc/lib/uidstore" + "git.sr.ht/~sircmpwn/aerc/worker/types" ) // A Container is a directory which contains other directories which adhere to @@ -123,3 +124,48 @@ func (c *Container) copyMessage( _, err := src.Copy(dest, key) return err } + +func (c *Container) ScanThreads(d maildir.Dir) ([]*types.Thread, error) { + uids, err := c.UIDs(d) + if err != nil { + return nil, err + } + + // a map from message-id to the Thread that represents it + threads := make(map[string]*types.Thread) + + for _, uid := range uids { + m, err := c.Message(d, uid) + if err != nil { + return nil, err + } + hs, err := m.Headers() + if err != nil { + return nil, err + } + msgID, err := hs.Text("message-id") + if err != nil { + return nil, err + } + irt, err := hs.Text("in-reply-to") + if err != nil { + return nil, err + } + + t := &types.Thread{Uid: uid} + threads[msgID] = t + + if p, ok := threads[irt]; ok { + p.Children = append(p.Children, t) + t.Parent = p + } + } + + var threadSlice []*types.Thread + for _, t := range threads { + if t.Parent == nil { + threadSlice = append(threadSlice, t) + } + } + return threadSlice, nil +} diff --git a/worker/maildir/message.go b/worker/maildir/message.go index dc5646b..283a3cd 100644 --- a/worker/maildir/message.go +++ b/worker/maildir/message.go @@ -1,6 +1,7 @@ package maildir import ( + "bufio" "bytes" "fmt" "io" @@ -8,6 +9,7 @@ import ( "github.com/emersion/go-maildir" "github.com/emersion/go-message" + "github.com/emersion/go-message/textproto" "git.sr.ht/~sircmpwn/aerc/models" "git.sr.ht/~sircmpwn/aerc/worker/lib" @@ -119,3 +121,18 @@ func translateFlags(maildirFlags []maildir.Flag) []models.Flag { func (m Message) UID() uint32 { return m.uid } + +func (m Message) Headers() (*message.Header, error) { + f, err := m.dir.Open(m.key) + if err != nil { + return nil, err + } + defer f.Close() + br := bufio.NewReader(f) + h, err := textproto.ReadHeader(br) + if err != nil { + return nil, err + } + mh := message.Header{h} + return &mh, nil +} diff --git a/worker/maildir/worker.go b/worker/maildir/worker.go index 1df4e09..7bd7cbd 100644 --- a/worker/maildir/worker.go +++ b/worker/maildir/worker.go @@ -170,6 +170,8 @@ func (w *Worker) handleMessage(msg types.WorkerMessage) error { return w.handleOpenDirectory(msg) case *types.FetchDirectoryContents: return w.handleFetchDirectoryContents(msg) + case *types.FetchDirectoryThreaded: + return w.handleDirectoryThreaded(msg) case *types.CreateDirectory: return w.handleCreateDirectory(msg) case *types.FetchMessageHeaders: @@ -291,6 +293,19 @@ func (w *Worker) handleFetchDirectoryContents( return nil } +func (w *Worker) handleDirectoryThreaded(msg *types.FetchDirectoryThreaded) error { + threads, err := w.c.ScanThreads(*w.selected) + if err != nil { + w.worker.Logger.Printf("error scanning threads: %v", err) + return err + } + w.worker.PostMessage(&types.DirectoryThreaded{ + Message: types.RespondTo(msg), + Threads: threads, + }, nil) + return nil +} + func (w *Worker) sort(uids []uint32, criteria []*types.SortCriterion) ([]uint32, error) { if len(criteria) == 0 { return uids, nil -- cgit v1.2.3