diff options
Diffstat (limited to 'worker/jmap/connect.go')
-rw-r--r-- | worker/jmap/connect.go | 133 |
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 +} |