add JMAP functionality
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
package jmap
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// sessionCapability is one entry under the Session object's "capabilities" (account-
|
||||
// independent) or an account's own "accountCapabilities" — both are just
|
||||
// urn -> settings-object maps, an empty object being valid when a capability has no
|
||||
// extra settings to advertise (RFC 8620 §2).
|
||||
type sessionCapability = map[string]any
|
||||
|
||||
type sessionAccount struct {
|
||||
Name string `json:"name"`
|
||||
IsPersonal bool `json:"isPersonal"`
|
||||
IsReadOnly bool `json:"isReadOnly"`
|
||||
AccountCapabilities map[string]sessionCapability `json:"accountCapabilities"`
|
||||
}
|
||||
|
||||
type sessionResponse struct {
|
||||
Capabilities map[string]sessionCapability `json:"capabilities"`
|
||||
Accounts map[string]sessionAccount `json:"accounts"`
|
||||
PrimaryAccounts map[string]string `json:"primaryAccounts"`
|
||||
Username string `json:"username"`
|
||||
APIURL string `json:"apiUrl"`
|
||||
DownloadURL string `json:"downloadUrl"`
|
||||
UploadURL string `json:"uploadUrl"`
|
||||
EventSourceURL string `json:"eventSourceUrl"`
|
||||
State string `json:"state"`
|
||||
}
|
||||
|
||||
const (
|
||||
capCore = "urn:ietf:params:jmap:core"
|
||||
capMail = "urn:ietf:params:jmap:mail"
|
||||
capSubmission = "urn:ietf:params:jmap:submission"
|
||||
)
|
||||
|
||||
// handleSession serves the RFC 8620 §2 Session resource — the entry point a JMAP
|
||||
// client fetches once (and re-fetches on the Basic realm challenge/whenever the
|
||||
// server's "state" changes) to discover every other endpoint URL and this account's
|
||||
// capabilities.
|
||||
func (b *Backend) handleSession(w http.ResponseWriter, r *http.Request) {
|
||||
mbox := mailboxFromContext(r)
|
||||
accountID := strconv.FormatInt(mbox.ID, 10)
|
||||
|
||||
maxSize := b.Cfg.Section("Mailstore").Key("max_message_bytes").MustInt64(25 * 1024 * 1024)
|
||||
|
||||
resp := sessionResponse{
|
||||
Capabilities: map[string]sessionCapability{
|
||||
capCore: {
|
||||
"maxSizeUpload": maxSize,
|
||||
"maxConcurrentUpload": 4,
|
||||
"maxSizeRequest": maxSize,
|
||||
"maxConcurrentRequests": 4,
|
||||
"maxCallsInRequest": 32,
|
||||
"maxObjectsInGet": 500,
|
||||
"maxObjectsInSet": 500,
|
||||
"collationAlgorithms": []string{},
|
||||
},
|
||||
capMail: {},
|
||||
capSubmission: {},
|
||||
},
|
||||
Accounts: map[string]sessionAccount{
|
||||
accountID: {
|
||||
Name: mbox.Email,
|
||||
IsPersonal: true,
|
||||
IsReadOnly: false,
|
||||
AccountCapabilities: map[string]sessionCapability{
|
||||
capCore: {}, capMail: {}, capSubmission: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
PrimaryAccounts: map[string]string{
|
||||
capMail: accountID,
|
||||
capSubmission: accountID,
|
||||
},
|
||||
Username: mbox.Email,
|
||||
APIURL: "/jmap/api",
|
||||
DownloadURL: "/jmap/download/{accountId}/{blobId}/{name}?type={type}",
|
||||
UploadURL: "/jmap/upload/{accountId}",
|
||||
EventSourceURL: "/jmap/eventsource?types={types}&closeafter={closeafter}&ping={ping}",
|
||||
}
|
||||
state, err := b.DB.MessagesState(mbox.ID)
|
||||
if err != nil {
|
||||
http.Error(w, "internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
resp.State = state
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(resp)
|
||||
}
|
||||
Reference in New Issue
Block a user