package imap import ( "bufio" "fmt" "net/url" "os" "strconv" "strings" "time" "git.sr.ht/~rjarry/aerc/worker/lib" "git.sr.ht/~rjarry/aerc/worker/middleware" "git.sr.ht/~rjarry/aerc/worker/types" "github.com/mitchellh/go-homedir" "golang.org/x/oauth2" ) func (w *IMAPWorker) handleConfigure(msg *types.Configure) error { w.config.name = msg.Config.Name 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 } if strings.HasSuffix(w.config.scheme, "+xoauth2") { w.config.scheme = strings.TrimSuffix(w.config.scheme, "+xoauth2") w.config.xoauth2.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.xoauth2.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.headers = msg.Config.Headers w.config.headersExclude = msg.Config.HeadersExclude w.config.idle_timeout = 10 * time.Second w.config.idle_debounce = 10 * time.Millisecond w.config.connection_timeout = 30 * time.Second w.config.keepalive_period = 0 * time.Second w.config.keepalive_probes = 3 w.config.keepalive_interval = 3 w.config.reconnect_maxwait = 30 * time.Second w.config.cacheEnabled = false w.config.cacheMaxAge = 30 * 24 * time.Hour // 30 days 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: %w", value, err) } w.config.idle_timeout = val case "idle-debounce": val, err := time.ParseDuration(value) if err != nil || val < 0 { return fmt.Errorf( "invalid idle-debounce value %v: %w", value, err) } w.config.idle_debounce = val case "reconnect-maxwait": val, err := time.ParseDuration(value) if err != nil || val < 0 { return fmt.Errorf( "invalid reconnect-maxwait value %v: %w", value, err) } w.config.reconnect_maxwait = val case "connection-timeout": val, err := time.ParseDuration(value) if err != nil || val < 0 { return fmt.Errorf( "invalid connection-timeout value %v: %w", 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: %w", 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: %w", 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: %w", value, err) } w.config.keepalive_interval = int(val.Seconds()) case "cache-headers": cache, err := strconv.ParseBool(value) if err != nil { // Return an error here because the user tried to set header // caching, and we want them to know they didn't set it right - // one way or the other return fmt.Errorf("invalid cache-headers value %v: %w", value, err) } w.config.cacheEnabled = cache case "cache-max-age": val, err := time.ParseDuration(value) if err != nil || val < 0 { return fmt.Errorf("invalid cache-max-age value %v: %w", value, err) } w.config.cacheMaxAge = val case "use-gmail-ext": val, err := strconv.ParseBool(value) if err != nil { return fmt.Errorf("invalid use-gmail-ext value %v: %w", value, err) } w.config.useXGMEXT = val } } if w.config.cacheEnabled { w.initCacheDb(msg.Config.Name) } w.idler = newIdler(w.config, w.worker) w.observer = newObserver(w.config, w.worker) if name, ok := msg.Config.Params["folder-map"]; ok { file, err := homedir.Expand(name) if err != nil { return err } f, err := os.Open(file) if err != nil { return err } defer f.Close() fmap, order, err := lib.ParseFolderMap(bufio.NewReader(f)) if err != nil { return err } w.worker = middleware.NewFolderMapper(w.worker, fmap, order) } return nil }