imap: extract imap config and configure handling

Extract the imap config and move the configure part out of the message
handler.

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
This commit is contained in:
Koni Marti 2022-04-30 01:08:54 +02:00 committed by Robin Jarry
parent a1b75a99bd
commit 4d75137b20
2 changed files with 123 additions and 97 deletions

99
worker/imap/configure.go Normal file
View file

@ -0,0 +1,99 @@
package imap
import (
"fmt"
"net/url"
"strconv"
"strings"
"time"
"git.sr.ht/~rjarry/aerc/worker/types"
"golang.org/x/oauth2"
)
func (w *IMAPWorker) handleConfigure(msg *types.Configure) error {
u, err := url.Parse(msg.Config.Source)
if err != nil {
return err
}
w.config.scheme = u.Scheme
if strings.HasSuffix(w.config.scheme, "+insecure") {
w.config.scheme = strings.TrimSuffix(w.config.scheme, "+insecure")
w.config.insecure = true
}
if strings.HasSuffix(w.config.scheme, "+oauthbearer") {
w.config.scheme = strings.TrimSuffix(w.config.scheme, "+oauthbearer")
w.config.oauthBearer.Enabled = true
q := u.Query()
oauth2 := &oauth2.Config{}
if q.Get("token_endpoint") != "" {
oauth2.ClientID = q.Get("client_id")
oauth2.ClientSecret = q.Get("client_secret")
oauth2.Scopes = []string{q.Get("scope")}
oauth2.Endpoint.TokenURL = q.Get("token_endpoint")
}
w.config.oauthBearer.OAuth2 = oauth2
}
w.config.addr = u.Host
if !strings.ContainsRune(w.config.addr, ':') {
w.config.addr += ":" + w.config.scheme
}
w.config.user = u.User
w.config.folders = msg.Config.Folders
w.config.idle_timeout = 10 * time.Second
w.config.connection_timeout = 30 * time.Second
w.config.keepalive_period = 0 * time.Second
w.config.keepalive_probes = 3
w.config.keepalive_interval = 3
for key, value := range msg.Config.Params {
switch key {
case "idle-timeout":
val, err := time.ParseDuration(value)
if err != nil || val < 0 {
return fmt.Errorf(
"invalid idle-timeout value %v: %v",
value, err)
}
w.config.idle_timeout = val
case "connection-timeout":
val, err := time.ParseDuration(value)
if err != nil || val < 0 {
return fmt.Errorf(
"invalid connection-timeout value %v: %v",
value, err)
}
w.config.connection_timeout = val
case "keepalive-period":
val, err := time.ParseDuration(value)
if err != nil || val < 0 {
return fmt.Errorf(
"invalid keepalive-period value %v: %v",
value, err)
}
w.config.keepalive_period = val
case "keepalive-probes":
val, err := strconv.Atoi(value)
if err != nil || val < 0 {
return fmt.Errorf(
"invalid keepalive-probes value %v: %v",
value, err)
}
w.config.keepalive_probes = val
case "keepalive-interval":
val, err := time.ParseDuration(value)
if err != nil || val < 0 {
return fmt.Errorf(
"invalid keepalive-interval value %v: %v",
value, err)
}
w.config.keepalive_interval = int(val.Seconds())
}
}
return nil
}

View file

@ -6,15 +6,12 @@ import (
"math" "math"
"net" "net"
"net/url" "net/url"
"strconv"
"strings"
"time" "time"
"github.com/emersion/go-imap" "github.com/emersion/go-imap"
sortthread "github.com/emersion/go-imap-sortthread" sortthread "github.com/emersion/go-imap-sortthread"
"github.com/emersion/go-imap/client" "github.com/emersion/go-imap/client"
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/oauth2"
"git.sr.ht/~rjarry/aerc/lib" "git.sr.ht/~rjarry/aerc/lib"
"git.sr.ht/~rjarry/aerc/logging" "git.sr.ht/~rjarry/aerc/logging"
@ -28,7 +25,11 @@ func init() {
handlers.RegisterWorkerFactory("imaps", NewIMAPWorker) handlers.RegisterWorkerFactory("imaps", NewIMAPWorker)
} }
var errUnsupported = fmt.Errorf("unsupported command") var (
errUnsupported = fmt.Errorf("unsupported command")
errNotConnected = fmt.Errorf("not connected")
errAlreadyConnected = fmt.Errorf("already connected")
)
type imapClient struct { type imapClient struct {
*client.Client *client.Client
@ -36,14 +37,14 @@ type imapClient struct {
sort *sortthread.SortClient sort *sortthread.SortClient
} }
type IMAPWorker struct { type imapConfig struct {
config struct {
scheme string scheme string
insecure bool insecure bool
addr string addr string
user *url.Userinfo user *url.Userinfo
folders []string folders []string
oauthBearer lib.OAuthBearer oauthBearer lib.OAuthBearer
idle_timeout time.Duration
// tcp connection parameters // tcp connection parameters
connection_timeout time.Duration connection_timeout time.Duration
keepalive_period time.Duration keepalive_period time.Duration
@ -51,6 +52,9 @@ type IMAPWorker struct {
keepalive_interval int keepalive_interval int
} }
type IMAPWorker struct {
config imapConfig
client *imapClient client *imapClient
idleStop chan struct{} idleStop chan struct{}
idleDone chan error idleDone chan error
@ -103,91 +107,14 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error {
case *types.Unsupported: case *types.Unsupported:
// No-op // No-op
case *types.Configure: case *types.Configure:
u, err := url.Parse(msg.Config.Source) reterr = w.handleConfigure(msg)
if err != nil {
reterr = err
break
}
w.config.scheme = u.Scheme
if strings.HasSuffix(w.config.scheme, "+insecure") {
w.config.scheme = strings.TrimSuffix(w.config.scheme, "+insecure")
w.config.insecure = true
}
if strings.HasSuffix(w.config.scheme, "+oauthbearer") {
w.config.scheme = strings.TrimSuffix(w.config.scheme, "+oauthbearer")
w.config.oauthBearer.Enabled = true
q := u.Query()
oauth2 := &oauth2.Config{}
if q.Get("token_endpoint") != "" {
oauth2.ClientID = q.Get("client_id")
oauth2.ClientSecret = q.Get("client_secret")
oauth2.Scopes = []string{q.Get("scope")}
oauth2.Endpoint.TokenURL = q.Get("token_endpoint")
}
w.config.oauthBearer.OAuth2 = oauth2
}
w.config.addr = u.Host
if !strings.ContainsRune(w.config.addr, ':') {
w.config.addr += ":" + w.config.scheme
}
w.config.user = u.User
w.config.folders = msg.Config.Folders
w.config.connection_timeout = 30 * time.Second
w.config.keepalive_period = 0 * time.Second
w.config.keepalive_probes = 3
w.config.keepalive_interval = 3
for key, value := range msg.Config.Params {
switch key {
case "connection-timeout":
val, err := time.ParseDuration(value)
if err != nil || val < 0 {
reterr = fmt.Errorf(
"invalid connection-timeout value %v: %v",
value, err)
break
}
w.config.connection_timeout = val
case "keepalive-period":
val, err := time.ParseDuration(value)
if err != nil || val < 0 {
reterr = fmt.Errorf(
"invalid keepalive-period value %v: %v",
value, err)
break
}
w.config.keepalive_period = val
case "keepalive-probes":
val, err := strconv.Atoi(value)
if err != nil || val < 0 {
reterr = fmt.Errorf(
"invalid keepalive-probes value %v: %v",
value, err)
break
}
w.config.keepalive_probes = val
case "keepalive-interval":
val, err := time.ParseDuration(value)
if err != nil || val < 0 {
reterr = fmt.Errorf(
"invalid keepalive-interval value %v: %v",
value, err)
break
}
w.config.keepalive_interval = int(val.Seconds())
}
}
case *types.Connect: case *types.Connect:
if w.client != nil && w.client.State() == imap.SelectedState { if w.client != nil && w.client.State() == imap.SelectedState {
if !w.autoReconnect { if !w.autoReconnect {
w.autoReconnect = true w.autoReconnect = true
checkConn(0) checkConn(0)
} }
reterr = fmt.Errorf("Already connected") reterr = errAlreadyConnected
break break
} }
@ -233,7 +160,7 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error {
w.autoReconnect = false w.autoReconnect = false
w.stopConnectionObserver() w.stopConnectionObserver()
if w.client == nil || w.client.State() != imap.SelectedState { if w.client == nil || w.client.State() != imap.SelectedState {
reterr = fmt.Errorf("Not connected") reterr = errNotConnected
break break
} }