diff --git a/backend/jmap/jmap.go b/backend/jmap/jmap.go index 85181d84b7ee0cfce569b81157295145237383cf..6c2dd78eecc6bb2be32ccc7ab1487fb4edb9e33e 100644 --- a/backend/jmap/jmap.go +++ b/backend/jmap/jmap.go @@ -53,7 +53,7 @@ func New(account *config.Account) (*Provider, error) { SessionEndpoint: account.JMAPEndpoint, } - if account.AuthMethod == "oauth2" { + if account.AuthMethod == "oauth2" || account.AuthMethod == "token" || account.AuthMethod == "" { client.WithAccessToken(account.Password) } else { client.WithBasicAuth(account.Email, account.Password) diff --git a/fetcher/dispatch.go b/fetcher/dispatch.go index faafc7ef2e3407cc1c4a58a4de61421835f36aff..d1ab098eafd56f4f936b64f8b2a2815430e6cb32 100644 --- a/fetcher/dispatch.go +++ b/fetcher/dispatch.go @@ -2,15 +2,16 @@ package fetcher import ( "github.com/floatpane/matcha/backend" + _ "github.com/floatpane/matcha/backend/jmap" // register jmap backend _ "github.com/floatpane/matcha/backend/maildir" // register maildir backend "github.com/floatpane/matcha/config" ) // hasBackendProvider reports whether the account is served by a non-IMAP -// backend (currently only "maildir") and should be routed through the -// backend.Provider abstraction instead of the legacy IMAP code path. +// backend (currently only "maildir" and "jmap") and should be routed through +// the backend.Provider abstraction instead of the legacy IMAP code path. func hasBackendProvider(account *config.Account) bool { - return account != nil && account.Protocol == "maildir" + return account != nil && (account.Protocol == "maildir" || account.Protocol == "jmap") } // newBackendProvider builds the backend.Provider for the account. Callers diff --git a/tui/login.go b/tui/login.go index 2e3958e87c0b914cfbe017069ca118e57bc82fc1..e99122acc97d7eec2d6f3fc2832569591a31be1d 100644 --- a/tui/login.go +++ b/tui/login.go @@ -94,7 +94,7 @@ func NewLogin(hideTips bool) *Login { t.Placeholder = "Send As Email (optional From header override)" t.Prompt = "✉️ > " case inputAuthMethod: - t.Placeholder = "Auth Method (password or oauth2)" + t.Placeholder = "Auth Method (password, oauth2, or token)" t.Prompt = "🔐 > " case inputPassword: t.Placeholder = "Password / App Password" @@ -178,7 +178,7 @@ func (m *Login) visibleFields() []int { switch proto { case protocolJMAP: // JMAP: no provider selector, just endpoint + common fields - fields = append(fields, inputName, inputEmail, inputFetchEmail, inputSendAsEmail, inputCatchAll, inputPassword, inputJMAPEndpoint) + fields = append(fields, inputName, inputEmail, inputFetchEmail, inputSendAsEmail, inputCatchAll, inputAuthMethod, inputPassword, inputJMAPEndpoint) case protocolPOP3: // POP3: custom server fields + SMTP for sending fields = append(fields, inputName, inputEmail, inputFetchEmail, inputSendAsEmail, inputCatchAll, inputPassword, @@ -313,6 +313,13 @@ func (m *Login) updateFlags() { provider := m.inputs[inputProvider].Value() m.showCustom = provider == "custom" m.useOAuth2 = m.inputs[inputAuthMethod].Value() == "oauth2" + + authMethod := m.inputs[inputAuthMethod].Value() + if m.protocol() == protocolJMAP && (authMethod == "token" || authMethod == "") { + m.inputs[inputPassword].Placeholder = "API Token" + } else { + m.inputs[inputPassword].Placeholder = "Password / App Password" + } } // validPort parses a port string and returns the integer value if it is within @@ -335,13 +342,21 @@ func (m *Login) submitForm() func() tea.Msg { smtpPort := validPort(m.inputs[inputSMTPPort].Value(), 587) pop3Port := validPort(m.inputs[inputPOP3Port].Value(), 995) - authMethod := "password" - if m.useOAuth2 { + proto := m.protocol() + + var authMethod string + switch { + case proto == protocolJMAP: + authMethod = m.inputs[inputAuthMethod].Value() + if authMethod == "" { + authMethod = "token" + } + case m.useOAuth2: authMethod = "oauth2" + default: + authMethod = "password" } - proto := m.protocol() - insecure := m.inputs[inputInsecure].Value() == "true" catchAll := m.inputs[inputCatchAll].Value() == "true" @@ -414,6 +429,7 @@ func (m *Login) protocolFieldViews(proto string) []string { switch proto { case protocolJMAP: return append(common, + m.inputs[inputAuthMethod].View(), m.inputs[inputPassword].View(), "", listHeader.Render("JMAP Settings:"), @@ -500,7 +516,11 @@ func (m *Login) View() tea.View { case inputSendAsEmail: tip = "Optional From header override for outgoing email. Leave blank to send as the fetched address." case inputAuthMethod: - tip = "Type 'oauth2' for OAuth2 or 'password' for app password." + if m.protocol() == protocolJMAP { + tip = "Type 'token' for API token (Bearer auth, default) or 'password' for HTTP Basic auth." + } else { + tip = "Type 'oauth2' for OAuth2 or 'password' for app password." + } case inputPassword: tip = "Your password or an app-specific password if using 2FA." case inputIMAPServer: