about summary refs log tree commit diff stats
path: root/worker/imap
diff options
context:
space:
mode:
Diffstat (limited to 'worker/imap')
-rw-r--r--worker/imap/open.go63
-rw-r--r--worker/imap/worker.go7
2 files changed, 68 insertions, 2 deletions
diff --git a/worker/imap/open.go b/worker/imap/open.go
index 4b4e943..2849573 100644
--- a/worker/imap/open.go
+++ b/worker/imap/open.go
@@ -1,6 +1,8 @@
 package imap
 
 import (
+	"sort"
+
 	"github.com/emersion/go-imap"
 	sortthread "github.com/emersion/go-imap-sortthread"
 
@@ -92,3 +94,64 @@ func translateSortCriterions(
 	}
 	return result
 }
+
+func (imapw *IMAPWorker) handleDirectoryThreaded(
+	msg *types.FetchDirectoryThreaded) {
+	imapw.worker.Logger.Printf("Fetching threaded UID list")
+
+	seqSet := &imap.SeqSet{}
+	seqSet.AddRange(1, imapw.selected.Messages)
+	threads, err := imapw.client.thread.UidThread(sortthread.References,
+		&imap.SearchCriteria{SeqNum: seqSet})
+	if err != nil {
+		imapw.worker.PostMessage(&types.Error{
+			Message: types.RespondTo(msg),
+			Error:   err,
+		}, nil)
+	} else {
+		aercThreads, count := convertThreads(threads, nil)
+		sort.Sort(types.ByUID(aercThreads))
+		imapw.worker.Logger.Printf("Found %d threaded messages", count)
+		imapw.seqMap = make([]uint32, count)
+		imapw.worker.PostMessage(&types.DirectoryThreaded{
+			Message: types.RespondTo(msg),
+			Threads: aercThreads,
+		}, nil)
+		imapw.worker.PostMessage(&types.Done{types.RespondTo(msg)}, nil)
+	}
+}
+
+func convertThreads(threads []*sortthread.Thread, parent *types.Thread) ([]*types.Thread, int) {
+	if threads == nil {
+		return nil, 0
+	}
+	conv := make([]*types.Thread, len(threads))
+	count := 0
+
+	for i := 0; i < len(threads); i++ {
+		t := threads[i]
+		conv[i] = &types.Thread{
+			Uid: t.Id,
+		}
+
+		// Set the first child node
+		children, childCount := convertThreads(t.Children, conv[i])
+		if len(children) > 0 {
+			conv[i].FirstChild = children[0]
+		}
+
+		// Set the parent node
+		if parent != nil {
+			conv[i].Parent = parent
+
+			// elements of threads are siblings
+			if i > 0 {
+				conv[i].PrevSibling = conv[i-1]
+				conv[i-1].NextSibling = conv[i]
+			}
+		}
+
+		count += childCount + 1
+	}
+	return conv, count
+}
diff --git a/worker/imap/worker.go b/worker/imap/worker.go
index cd52536..2c0e6a6 100644
--- a/worker/imap/worker.go
+++ b/worker/imap/worker.go
@@ -26,7 +26,8 @@ var errUnsupported = fmt.Errorf("unsupported command")
 
 type imapClient struct {
 	*client.Client
-	sort *sortthread.SortClient
+	thread *sortthread.ThreadClient
+	sort   *sortthread.SortClient
 }
 
 type IMAPWorker struct {
@@ -158,7 +159,7 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error {
 		}
 
 		c.Updates = w.updates
-		w.client = &imapClient{c, sortthread.NewSortClient(c)}
+		w.client = &imapClient{c, sortthread.NewThreadClient(c), sortthread.NewSortClient(c)}
 		w.worker.PostMessage(&types.Done{types.RespondTo(msg)}, nil)
 	case *types.Disconnect:
 		if w.client == nil {
@@ -175,6 +176,8 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error {
 		w.handleOpenDirectory(msg)
 	case *types.FetchDirectoryContents:
 		w.handleFetchDirectoryContents(msg)
+	case *types.FetchDirectoryThreaded:
+		w.handleDirectoryThreaded(msg)
 	case *types.CreateDirectory:
 		w.handleCreateDirectory(msg)
 	case *types.RemoveDirectory: