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 }