aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--widgets/account-wizard.go229
-rw-r--r--widgets/selector.go12
2 files changed, 152 insertions, 89 deletions
diff --git a/widgets/account-wizard.go b/widgets/account-wizard.go
index ffbdb28b..b4af40b2 100644
--- a/widgets/account-wizard.go
+++ b/widgets/account-wizard.go
@@ -18,6 +18,7 @@ import (
"git.sr.ht/~rjarry/aerc/config"
"git.sr.ht/~rjarry/aerc/lib/ui"
+ "git.sr.ht/~rjarry/aerc/log"
)
const (
@@ -27,12 +28,6 @@ const (
CONFIGURE_COMPLETE = iota
)
-const (
- SSL_TLS = iota
- STARTTLS = iota
- INSECURE = iota
-)
-
type AccountWizard struct {
aerc *Aerc
step int
@@ -42,21 +37,26 @@ type AccountWizard struct {
// CONFIGURE_BASICS
accountName *ui.TextInput
email *ui.TextInput
+ discovered map[string]string
fullName *ui.TextInput
basics []ui.Interactive
// CONFIGURE_SOURCE
+ sourceProtocol *Selector
+ sourceTransport *Selector
+
sourceUsername *ui.TextInput
sourcePassword *ui.TextInput
sourceServer *ui.TextInput
- sourceMode int
sourceStr *ui.Text
sourceUrl url.URL
source []ui.Interactive
// CONFIGURE_OUTGOING
+ outgoingProtocol *Selector
+ outgoingTransport *Selector
+
outgoingUsername *ui.TextInput
outgoingPassword *ui.TextInput
outgoingServer *ui.TextInput
- outgoingMode int
outgoingStr *ui.Text
outgoingUrl url.URL
outgoingCopyTo *ui.TextInput
@@ -86,6 +86,22 @@ after the setup.
aerc.AddDialog(warning)
}
+const (
+ // protocols
+ IMAP = "IMAP"
+ SMTP = "SMTP"
+ // transports
+ SSL_TLS = "SSL/TLS"
+ STARTTLS = "STARTTLS"
+ INSECURE = "Insecure"
+)
+
+var (
+ sources = []string{IMAP}
+ outgoings = []string{SMTP}
+ transports = []string{SSL_TLS, STARTTLS, INSECURE}
+)
+
func NewAccountWizard(aerc *Aerc) *AccountWizard {
wizard := &AccountWizard{
accountName: ui.NewTextInput("", config.Ui).Prompt("> "),
@@ -102,6 +118,11 @@ func NewAccountWizard(aerc *Aerc) *AccountWizard {
outgoingStr: ui.NewText("Connection URL: smtps://", config.Ui.GetStyle(config.STYLE_DEFAULT)),
outgoingUsername: ui.NewTextInput("", config.Ui).Prompt("> "),
outgoingCopyTo: ui.NewTextInput("", config.Ui).Prompt("> "),
+
+ sourceProtocol: NewSelector(sources, 0, config.Ui).Chooser(true),
+ sourceTransport: NewSelector(transports, 0, config.Ui).Chooser(true),
+ outgoingProtocol: NewSelector(outgoings, 0, config.Ui).Chooser(true),
+ outgoingTransport: NewSelector(transports, 0, config.Ui).Chooser(true),
}
// Autofill some stuff for the user
@@ -116,6 +137,11 @@ func NewAccountWizard(aerc *Aerc) *AccountWizard {
wizard.sourceUri()
wizard.outgoingUri()
})
+ wizard.sourceProtocol.OnSelect(func(option string) {
+ wizard.sourceServer.Set("")
+ wizard.autofill()
+ wizard.sourceUri()
+ })
wizard.sourceServer.OnChange(func(_ *ui.TextInput) {
wizard.sourceUri()
})
@@ -137,6 +163,9 @@ func NewAccountWizard(aerc *Aerc) *AccountWizard {
wizard.outgoingUri()
}
})
+ wizard.sourceTransport.OnSelect(func(option string) {
+ wizard.sourceUri()
+ })
var once sync.Once
wizard.sourcePassword.OnChange(func(_ *ui.TextInput) {
wizard.outgoingPassword.Set(wizard.sourcePassword.String())
@@ -150,6 +179,11 @@ func NewAccountWizard(aerc *Aerc) *AccountWizard {
})
}
})
+ wizard.outgoingProtocol.OnSelect(func(option string) {
+ wizard.outgoingServer.Set("")
+ wizard.autofill()
+ wizard.outgoingUri()
+ })
wizard.outgoingServer.OnChange(func(_ *ui.TextInput) {
wizard.outgoingUri()
})
@@ -164,6 +198,9 @@ func NewAccountWizard(aerc *Aerc) *AccountWizard {
}
wizard.outgoingUri()
})
+ wizard.outgoingTransport.OnSelect(func(option string) {
+ wizard.outgoingUri()
+ })
basics := ui.NewGrid().Rows([]ui.GridSpec{
{Strategy: ui.SIZE_EXACT, Size: ui.Const(8)}, // Introduction
@@ -211,26 +248,10 @@ func NewAccountWizard(aerc *Aerc) *AccountWizard {
At(8, 0)
selector := NewSelector([]string{"Next"}, 0, config.Ui).
OnChoose(func(option string) {
- email := wizard.email.String()
- if strings.ContainsRune(email, '@') {
- server := email[strings.IndexRune(email, '@')+1:]
- hostport, srv := getSRV(server, []string{"imaps", "imap"})
- if hostport != "" {
- wizard.sourceServer.Set(hostport)
- if srv == "imaps" {
- wizard.sourceMode = SSL_TLS
- } else {
- wizard.sourceMode = STARTTLS
- }
- wizard.sourceUri()
- }
- hostport, _ = getSRV(server, []string{"submission"})
- if hostport != "" {
- wizard.outgoingServer.Set(hostport)
- wizard.outgoingMode = STARTTLS
- wizard.outgoingUri()
- }
- }
+ wizard.discoverServices()
+ wizard.autofill()
+ wizard.sourceUri()
+ wizard.outgoingUri()
wizard.advance(option)
})
basics.AddChild(selector).At(9, 0)
@@ -288,22 +309,7 @@ func NewAccountWizard(aerc *Aerc) *AccountWizard {
ui.NewText("Connection mode",
config.Ui.GetStyle(config.STYLE_HEADER))).
At(10, 0)
- sourceMode := NewSelector([]string{
- "IMAP over SSL/TLS",
- "IMAP with STARTTLS",
- "Insecure IMAP",
- }, 0, config.Ui).Chooser(true).OnSelect(func(option string) {
- switch option {
- case "IMAP over SSL/TLS":
- wizard.sourceMode = SSL_TLS
- case "IMAP with STARTTLS":
- wizard.sourceMode = STARTTLS
- case "Insecure IMAP":
- wizard.sourceMode = INSECURE
- }
- wizard.sourceUri()
- })
- incoming.AddChild(sourceMode).At(11, 0)
+ incoming.AddChild(wizard.sourceTransport).At(11, 0)
selector = NewSelector([]string{"Previous", "Next"}, 1, config.Ui).
OnChoose(wizard.advance)
incoming.AddChild(ui.NewFill(' ', tcell.StyleDefault)).At(12, 0)
@@ -313,7 +319,8 @@ func NewAccountWizard(aerc *Aerc) *AccountWizard {
wizard.sourceUsername,
wizard.sourcePassword,
wizard.sourceServer,
- sourceMode, selector,
+ wizard.sourceTransport,
+ selector,
}
outgoing := ui.NewGrid().Rows([]ui.GridSpec{
@@ -366,25 +373,10 @@ func NewAccountWizard(aerc *Aerc) *AccountWizard {
outgoing.AddChild(ui.NewFill(' ', tcell.StyleDefault)).
At(9, 0)
outgoing.AddChild(
- ui.NewText("Connection mode",
+ ui.NewText("Transport security",
config.Ui.GetStyle(config.STYLE_HEADER))).
At(10, 0)
- outgoingMode := NewSelector([]string{
- "SMTP over SSL/TLS",
- "SMTP with STARTTLS",
- "Insecure SMTP",
- }, 0, config.Ui).Chooser(true).OnSelect(func(option string) {
- switch option {
- case "SMTP over SSL/TLS":
- wizard.outgoingMode = SSL_TLS
- case "SMTP with STARTTLS":
- wizard.outgoingMode = STARTTLS
- case "Insecure SMTP":
- wizard.outgoingMode = INSECURE
- }
- wizard.outgoingUri()
- })
- outgoing.AddChild(outgoingMode).At(11, 0)
+ outgoing.AddChild(wizard.outgoingTransport).At(11, 0)
selector = NewSelector([]string{"Previous", "Next"}, 1, config.Ui).
OnChoose(wizard.advance)
outgoing.AddChild(ui.NewFill(' ', tcell.StyleDefault)).At(12, 0)
@@ -399,7 +391,9 @@ func NewAccountWizard(aerc *Aerc) *AccountWizard {
wizard.outgoingUsername,
wizard.outgoingPassword,
wizard.outgoingServer,
- outgoingMode, wizard.outgoingCopyTo, selector,
+ wizard.outgoingTransport,
+ wizard.outgoingCopyTo,
+ selector,
}
complete := ui.NewGrid().Rows([]ui.GridSpec{
@@ -572,13 +566,15 @@ func (wizard *AccountWizard) sourceUri() url.URL {
user := wizard.sourceUsername.String()
pass := wizard.sourcePassword.String()
var scheme string
- switch wizard.sourceMode {
- case SSL_TLS:
- scheme = "imaps"
- case STARTTLS:
- scheme = "imap"
- case INSECURE:
- scheme = "imap+insecure"
+ if wizard.sourceProtocol.Selected() == IMAP {
+ switch wizard.sourceTransport.Selected() {
+ case STARTTLS:
+ scheme = "imap"
+ case INSECURE:
+ scheme = "imap+insecure"
+ default:
+ scheme = "imaps"
+ }
}
var (
userpass *url.Userinfo
@@ -612,13 +608,15 @@ func (wizard *AccountWizard) outgoingUri() url.URL {
user := wizard.outgoingUsername.String()
pass := wizard.outgoingPassword.String()
var scheme string
- switch wizard.outgoingMode {
- case SSL_TLS:
- scheme = "smtps"
- case STARTTLS:
- scheme = "smtp"
- case INSECURE:
- scheme = "smtp+insecure"
+ if wizard.outgoingProtocol.Selected() == SMTP {
+ switch wizard.outgoingTransport.Selected() {
+ case INSECURE:
+ scheme = "smtp+insecure"
+ case STARTTLS:
+ scheme = "smtp"
+ default:
+ scheme = "smtps"
+ }
}
var (
userpass *url.Userinfo
@@ -730,19 +728,72 @@ func (wizard *AccountWizard) Event(event tcell.Event) bool {
return false
}
-func getSRV(host string, services []string) (string, string) {
- var hostport, srv string
- for _, srv = range services {
- _, addrs, err := net.LookupSRV(srv, "tcp", host)
- if err != nil {
- continue
+func (wizard *AccountWizard) discoverServices() {
+ email := wizard.email.String()
+ if !strings.ContainsRune(email, '@') {
+ return
+ }
+ domain := email[strings.IndexRune(email, '@')+1:]
+ var wg sync.WaitGroup
+ type Service struct{ srv, hostport string }
+ services := make(chan Service)
+
+ for _, service := range []string{"imaps", "imap", "submission"} {
+ wg.Add(1)
+ go func(srv string) {
+ defer log.PanicHandler()
+ defer wg.Done()
+ _, addrs, err := net.LookupSRV(srv, "tcp", domain)
+ if err != nil {
+ log.Tracef("SRV lookup for _%s._tcp.%s failed: %s",
+ srv, domain, err)
+ } else if addrs[0].Target != "" && addrs[0].Port > 0 {
+ services <- Service{
+ srv: srv,
+ hostport: net.JoinHostPort(
+ strings.TrimSuffix(addrs[0].Target, "."),
+ strconv.Itoa(int(addrs[0].Port))),
+ }
+ }
+ }(service)
+ }
+ go func() {
+ defer log.PanicHandler()
+ wg.Wait()
+ close(services)
+ }()
+
+ wizard.discovered = make(map[string]string)
+ for s := range services {
+ wizard.discovered[s.srv] = s.hostport
+ }
+}
+
+func (wizard *AccountWizard) autofill() {
+ if wizard.sourceServer.String() == "" {
+ if wizard.sourceProtocol.Selected() == IMAP {
+ if s, ok := wizard.discovered["imaps"]; ok {
+ wizard.sourceServer.Set(s)
+ wizard.sourceTransport.Select(SSL_TLS)
+ } else if s, ok := wizard.discovered["imap"]; ok {
+ wizard.sourceServer.Set(s)
+ wizard.sourceTransport.Select(STARTTLS)
+ }
}
- if addrs[0].Target != "" && addrs[0].Port > 0 {
- hostport = net.JoinHostPort(
- strings.TrimSuffix(addrs[0].Target, "."),
- strconv.Itoa(int(addrs[0].Port)))
- break
+ }
+ if wizard.outgoingServer.String() == "" {
+ if wizard.outgoingProtocol.Selected() == SMTP {
+ if s, ok := wizard.discovered["submission"]; ok {
+ switch {
+ case strings.HasSuffix(s, ":587"):
+ wizard.outgoingTransport.Select(SSL_TLS)
+ case strings.HasSuffix(s, ":465"):
+ wizard.outgoingTransport.Select(STARTTLS)
+ default:
+ wizard.outgoingTransport.Select(INSECURE)
+ }
+ wizard.outgoingServer.Set(s)
+ }
}
}
- return hostport, srv
}
diff --git a/widgets/selector.go b/widgets/selector.go
index fb8c8094..00479d4f 100644
--- a/widgets/selector.go
+++ b/widgets/selector.go
@@ -122,6 +122,18 @@ func (sel *Selector) OnSelect(fn func(option string)) *Selector {
return sel
}
+func (sel *Selector) Select(option string) {
+ for i, opt := range sel.options {
+ if option == opt {
+ sel.focus = i
+ if sel.onSelect != nil {
+ sel.onSelect(opt)
+ }
+ break
+ }
+ }
+}
+
func (sel *Selector) Selected() string {
return sel.options[sel.focus]
}