aboutsummaryrefslogtreecommitdiffstats
path: root/worker/jmap/connect.go
diff options
context:
space:
mode:
Diffstat (limited to 'worker/jmap/connect.go')
-rw-r--r--worker/jmap/connect.go133
1 files changed, 133 insertions, 0 deletions
diff --git a/worker/jmap/connect.go b/worker/jmap/connect.go
new file mode 100644
index 00000000..affa9474
--- /dev/null
+++ b/worker/jmap/connect.go
@@ -0,0 +1,133 @@
+package jmap
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/url"
+ "strings"
+ "sync/atomic"
+
+ "git.sr.ht/~rjarry/aerc/worker/types"
+ "git.sr.ht/~rockorager/go-jmap"
+ "git.sr.ht/~rockorager/go-jmap/mail"
+ "git.sr.ht/~rockorager/go-jmap/mail/identity"
+)
+
+func (w *JMAPWorker) handleConnect(msg *types.Connect) error {
+ client := &jmap.Client{SessionEndpoint: w.config.endpoint}
+
+ if w.config.oauth {
+ pass, _ := w.config.user.Password()
+ client.WithAccessToken(pass)
+ } else {
+ user := w.config.user.Username()
+ pass, _ := w.config.user.Password()
+ client.WithBasicAuth(user, pass)
+ }
+
+ if session, err := w.cache.GetSession(); err != nil {
+ if err := client.Authenticate(); err != nil {
+ return err
+ }
+ if err := w.cache.PutSession(client.Session); err != nil {
+ w.w.Warnf("PutSession: %s", err)
+ }
+ } else {
+ client.Session = session
+ }
+
+ switch {
+ case client == nil:
+ fallthrough
+ case client.Session == nil:
+ fallthrough
+ case client.Session.PrimaryAccounts == nil:
+ break
+ default:
+ w.accountId = client.Session.PrimaryAccounts[mail.URI]
+ }
+
+ w.client = client
+
+ return w.GetIdentities()
+}
+
+func (w *JMAPWorker) GetIdentities() error {
+ u, err := url.Parse(w.config.account.Outgoing.Value)
+ if err != nil {
+ return fmt.Errorf("GetIdentities: %w", err)
+ }
+ if !strings.HasPrefix(u.Scheme, "jmap") {
+ // no need for identities
+ return nil
+ }
+
+ var req jmap.Request
+
+ req.Invoke(&identity.Get{Account: w.accountId})
+ resp, err := w.Do(&req)
+ if err != nil {
+ return err
+ }
+ for _, inv := range resp.Responses {
+ switch r := inv.Args.(type) {
+ case *identity.GetResponse:
+ for _, ident := range r.List {
+ w.identities[ident.Email] = ident
+ }
+ case *jmap.MethodError:
+ return wrapMethodError(r)
+ }
+ }
+
+ return nil
+}
+
+var seqnum uint64
+
+func (w *JMAPWorker) Do(req *jmap.Request) (*jmap.Response, error) {
+ seq := atomic.AddUint64(&seqnum, 1)
+ body, _ := json.Marshal(req.Calls)
+ w.w.Debugf(">%d> POST %s", seq, body)
+ resp, err := w.client.Do(req)
+ if err == nil {
+ w.w.Debugf("<%d< done", seq)
+ } else {
+ w.w.Debugf("<%d< %s", seq, err)
+ }
+ return resp, err
+}
+
+func (w *JMAPWorker) Download(blobID jmap.ID) (io.ReadCloser, error) {
+ seq := atomic.AddUint64(&seqnum, 1)
+ replacer := strings.NewReplacer(
+ "{accountId}", string(w.accountId),
+ "{blobId}", string(blobID),
+ "{type}", "application/octet-stream",
+ "{name}", "filename",
+ )
+ url := replacer.Replace(w.client.Session.DownloadURL)
+ w.w.Debugf(">%d> GET %s", seq, url)
+ rd, err := w.client.Download(w.accountId, blobID)
+ if err == nil {
+ w.w.Debugf("<%d< 200 OK", seq)
+ } else {
+ w.w.Debugf("<%d< %s", seq, err)
+ }
+ return rd, err
+}
+
+func (w *JMAPWorker) Upload(reader io.Reader) (*jmap.UploadResponse, error) {
+ seq := atomic.AddUint64(&seqnum, 1)
+ url := strings.ReplaceAll(w.client.Session.UploadURL,
+ "{accountId}", string(w.accountId))
+ w.w.Debugf(">%d> POST %s", seq, url)
+ resp, err := w.client.Upload(w.accountId, reader)
+ if err == nil {
+ w.w.Debugf("<%d< 200 OK", seq)
+ } else {
+ w.w.Debugf("<%d< %s", seq, err)
+ }
+ return resp, err
+}