From 4d75137b20664cbdf90159c78d1fbf78779f3416 Mon Sep 17 00:00:00 2001 From: Koni Marti Date: Sat, 30 Apr 2022 01:08:54 +0200 Subject: [PATCH] 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 Acked-by: Robin Jarry --- worker/imap/configure.go | 99 ++++++++++++++++++++++++++++++++ worker/imap/worker.go | 121 ++++++++------------------------------- 2 files changed, 123 insertions(+), 97 deletions(-) create mode 100644 worker/imap/configure.go diff --git a/worker/imap/configure.go b/worker/imap/configure.go new file mode 100644 index 0000000..ac1d606 --- /dev/null +++ b/worker/imap/configure.go @@ -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 +} diff --git a/worker/imap/worker.go b/worker/imap/worker.go index cc9434f..ad08333 100644 --- a/worker/imap/worker.go +++ b/worker/imap/worker.go @@ -6,15 +6,12 @@ import ( "math" "net" "net/url" - "strconv" - "strings" "time" "github.com/emersion/go-imap" sortthread "github.com/emersion/go-imap-sortthread" "github.com/emersion/go-imap/client" "github.com/pkg/errors" - "golang.org/x/oauth2" "git.sr.ht/~rjarry/aerc/lib" "git.sr.ht/~rjarry/aerc/logging" @@ -28,7 +25,11 @@ func init() { 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 { *client.Client @@ -36,20 +37,23 @@ type imapClient struct { sort *sortthread.SortClient } +type imapConfig struct { + scheme string + insecure bool + addr string + user *url.Userinfo + folders []string + oauthBearer lib.OAuthBearer + idle_timeout time.Duration + // tcp connection parameters + connection_timeout time.Duration + keepalive_period time.Duration + keepalive_probes int + keepalive_interval int +} + type IMAPWorker struct { - config struct { - scheme string - insecure bool - addr string - user *url.Userinfo - folders []string - oauthBearer lib.OAuthBearer - // tcp connection parameters - connection_timeout time.Duration - keepalive_period time.Duration - keepalive_probes int - keepalive_interval int - } + config imapConfig client *imapClient idleStop chan struct{} @@ -103,91 +107,14 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error { case *types.Unsupported: // No-op case *types.Configure: - u, err := url.Parse(msg.Config.Source) - 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()) - } - } + reterr = w.handleConfigure(msg) case *types.Connect: if w.client != nil && w.client.State() == imap.SelectedState { if !w.autoReconnect { w.autoReconnect = true checkConn(0) } - reterr = fmt.Errorf("Already connected") + reterr = errAlreadyConnected break } @@ -233,7 +160,7 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error { w.autoReconnect = false w.stopConnectionObserver() if w.client == nil || w.client.State() != imap.SelectedState { - reterr = fmt.Errorf("Not connected") + reterr = errNotConnected break }