about summary refs log tree commit diff stats
path: root/worker/imap
diff options
context:
space:
mode:
authorReto Brunner <reto@labrat.space>2020-09-12 15:05:02 +0200
committerReto Brunner <reto@labrat.space>2020-10-11 09:18:45 +0200
commitb6bcf89784605aa8baa982677de9d8d8ddbaa404 (patch)
tree532a17d2c5fbf67b1576ca718596e271b631b384 /worker/imap
parentd8a75a5159eb9bf18e629be0598aaef5f90da7e4 (diff)
downloadaerc-b6bcf89784605aa8baa982677de9d8d8ddbaa404.tar.gz
imap: add sort support
Diffstat (limited to 'worker/imap')
-rw-r--r--worker/imap/open.go49
-rw-r--r--worker/imap/worker.go4
2 files changed, 50 insertions, 3 deletions
diff --git a/worker/imap/open.go b/worker/imap/open.go
index 0602a7f..891b8a2 100644
--- a/worker/imap/open.go
+++ b/worker/imap/open.go
@@ -2,6 +2,7 @@ package imap
 
 import (
 	"github.com/emersion/go-imap"
+	sortthread "github.com/emersion/go-imap-sortthread"
 
 	"git.sr.ht/~sircmpwn/aerc/worker/types"
 )
@@ -30,9 +31,29 @@ func (imapw *IMAPWorker) handleFetchDirectoryContents(
 
 	seqSet := &imap.SeqSet{}
 	seqSet.AddRange(1, imapw.selected.Messages)
-	uids, err := imapw.client.UidSearch(&imap.SearchCriteria{
+
+	searchCriteria := &imap.SearchCriteria{
 		SeqNum: seqSet,
-	})
+	}
+	sortCriteria := translateSortCriterions(msg.SortCriteria)
+
+	var uids []uint32
+
+	// If the server supports the SORT extension, do the sorting server side
+	ok, err := imapw.client.sort.SupportSort()
+	if err == nil && ok && len(sortCriteria) > 0 {
+		uids, err = imapw.client.sort.UidSort(sortCriteria, searchCriteria)
+		// copy in reverse as msgList displays backwards
+		for i, j := 0, len(uids)-1; i < j; i, j = i+1, j-1 {
+			uids[i], uids[j] = uids[j], uids[i]
+		}
+	} else {
+		if err != nil {
+			// Non fatal, but we do want to print to get some debug info
+			imapw.worker.Logger.Printf("can't check for SORT support: %v", err)
+		}
+		uids, err = imapw.client.UidSearch(searchCriteria)
+	}
 	if err != nil {
 		imapw.worker.PostMessage(&types.Error{
 			Message: types.RespondTo(msg),
@@ -50,3 +71,27 @@ func (imapw *IMAPWorker) handleFetchDirectoryContents(
 		imapw.worker.PostMessage(&types.Done{types.RespondTo(msg)}, nil)
 	}
 }
+
+type sortFieldMapT map[types.SortField]sortthread.SortField
+
+// caution, incomplete mapping
+var sortFieldMap sortFieldMapT = sortFieldMapT{
+	types.SortArrival: sortthread.SortArrival,
+	types.SortCc:      sortthread.SortCc,
+	types.SortDate:    sortthread.SortDate,
+	types.SortFrom:    sortthread.SortFrom,
+	types.SortSize:    sortthread.SortSize,
+	types.SortSubject: sortthread.SortSubject,
+	types.SortTo:      sortthread.SortTo,
+}
+
+func translateSortCriterions(
+	cs []*types.SortCriterion) []sortthread.SortCriterion {
+	result := make([]sortthread.SortCriterion, 0, len(cs))
+	for _, c := range cs {
+		if f, ok := sortFieldMap[c.Field]; ok {
+			result = append(result, sortthread.SortCriterion{f, c.Reverse})
+		}
+	}
+	return result
+}
diff --git a/worker/imap/worker.go b/worker/imap/worker.go
index c016af6..dab0afb 100644
--- a/worker/imap/worker.go
+++ b/worker/imap/worker.go
@@ -8,6 +8,7 @@ import (
 
 	"github.com/emersion/go-imap"
 	idle "github.com/emersion/go-imap-idle"
+	sortthread "github.com/emersion/go-imap-sortthread"
 	"github.com/emersion/go-imap/client"
 	"golang.org/x/oauth2"
 
@@ -27,6 +28,7 @@ var errUnsupported = fmt.Errorf("unsupported command")
 type imapClient struct {
 	*client.Client
 	idle *idle.IdleClient
+	sort *sortthread.SortClient
 }
 
 type IMAPWorker struct {
@@ -155,7 +157,7 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error {
 		}
 
 		c.Updates = w.updates
-		w.client = &imapClient{c, idle.NewClient(c)}
+		w.client = &imapClient{c, idle.NewClient(c), sortthread.NewSortClient(c)}
 		w.worker.PostMessage(&types.Done{types.RespondTo(msg)}, nil)
 	case *types.ListDirectories:
 		w.handleListDirectories(msg)