mirror of
https://git.sr.ht/~rjarry/aerc
synced 2026-04-09 02:14:55 +02:00
Move the Gmail X-GM-EXT-1 extension handling from the middleware layer directly into the IMAP worker. This simplifies the architecture by removing the gmailWorker middleware wrapper and its associated locking. The XGMExtClient is now a field of the IMAP client struct, initialized alongside other extension clients. Gmail-specific search and filter operations are handled by dedicated methods in xgmext.go that are called directly from the message handlers when the extension is available. Rename xgmext types to be exported (XGMExtClient, ThreadIDSearch, RawSearch) and simplify their methods to work with uint32 UIDs directly, avoiding unnecessary type conversions. Signed-off-by: Robin Jarry <robin@jarry.cc> Reviewed-by: Simon Martin <simon@nasilyan.com>
90 lines
2 KiB
Go
90 lines
2 KiB
Go
package xgmext
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/emersion/go-imap"
|
|
"github.com/emersion/go-imap/client"
|
|
"github.com/emersion/go-imap/commands"
|
|
"github.com/emersion/go-imap/responses"
|
|
|
|
"git.sr.ht/~rjarry/aerc/lib/log"
|
|
)
|
|
|
|
// XGMExtClient is a client for the X-GM-EXT-1 Gmail extension.
|
|
type XGMExtClient struct {
|
|
c *client.Client
|
|
}
|
|
|
|
func NewXGMExtClient(c *client.Client) *XGMExtClient {
|
|
return &XGMExtClient{c: c}
|
|
}
|
|
|
|
func (x *XGMExtClient) FetchEntireThreads(requested []uint32) ([]uint32, error) {
|
|
threadIds, err := x.fetchThreadIds(requested)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to fetch thread IDs: %w", err)
|
|
}
|
|
if len(threadIds) == 0 {
|
|
return nil, errors.New("no thread IDs provided")
|
|
}
|
|
uids, err := x.runSearch(NewThreadIDSearch(threadIds))
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to search for thread IDs: %w", err)
|
|
}
|
|
return uids, nil
|
|
}
|
|
|
|
func (x *XGMExtClient) fetchThreadIds(uids []uint32) ([]string, error) {
|
|
messages := make(chan *imap.Message)
|
|
done := make(chan error)
|
|
|
|
thriditem := imap.FetchItem("X-GM-THRID")
|
|
items := []imap.FetchItem{thriditem}
|
|
|
|
m := make(map[string]struct{}, len(uids))
|
|
go func() {
|
|
defer log.PanicHandler()
|
|
for msg := range messages {
|
|
if msg == nil {
|
|
continue
|
|
}
|
|
item, ok := msg.Items[thriditem].(string)
|
|
if ok {
|
|
m[item] = struct{}{}
|
|
}
|
|
}
|
|
done <- nil
|
|
}()
|
|
|
|
var set imap.SeqSet
|
|
for _, uid := range uids {
|
|
set.AddNum(uid)
|
|
}
|
|
err := x.c.UidFetch(&set, items, messages)
|
|
<-done
|
|
|
|
thrid := make([]string, 0, len(m))
|
|
for id := range m {
|
|
thrid = append(thrid, id)
|
|
}
|
|
return thrid, err
|
|
}
|
|
|
|
func (x *XGMExtClient) RawSearch(rawSearch string) ([]uint32, error) {
|
|
return x.runSearch(NewRawSearch(rawSearch))
|
|
}
|
|
|
|
func (x *XGMExtClient) runSearch(cmd imap.Commander) ([]uint32, error) {
|
|
if x.c.State() != imap.SelectedState {
|
|
return nil, errors.New("no mailbox selected")
|
|
}
|
|
cmd = &commands.Uid{Cmd: cmd}
|
|
res := new(responses.Search)
|
|
status, err := x.c.Execute(cmd, res)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("imap execute failed: %w", err)
|
|
}
|
|
return res.Ids, status.Err()
|
|
}
|