1
0
Fork 0
mirror of https://git.sr.ht/~rjarry/aerc synced 2025-07-06 19:30:22 +02:00
aerc/lib/autoconfig/autoconfig.go
Moritz Poldrack 932d9a44d5 autoconfig: fix spelling
This commit fixes a critical bug found by the CI where import was
allegedly misspelled

Signed-off-by: Moritz Poldrack <git@moritz.sh>
Acked-by: Robin Jarry <robin@jarry.cc>
2025-02-19 12:01:18 +01:00

177 lines
5.1 KiB
Go

// Package autoconfig provides a somewhat smart way of automatically
// determining the mailservers for a given address.
//
// It works by first checking for a Thunderbird autoconfiguration, and if not
// found checking common names (imap|smtp|mail).example.com and performing a TCP
// Ping on their ports.
//
// The first part is described here: https://wiki.mozilla.org/Thunderbird:Autoconfiguration
package autoconfig
import (
"context"
"encoding/xml"
"fmt"
"net/http"
"net/url"
"strconv"
"strings"
"git.sr.ht/~rjarry/aerc/lib/log"
)
// getFromAutoconfig retrieves the config from the provider using a Mozilla
// Thunderbird autoconfig service
func getFromAutoconfig(ctx context.Context, localpart, domain string, result chan<- *Config) {
defer log.PanicHandler()
defer close(result)
res := make(chan *Config, 1)
go func(res chan *Config) {
defer log.PanicHandler()
defer close(res)
var addresses []*url.URL
u, err := url.Parse(fmt.Sprintf(
"https://autoconfig.%s/mail/config-v1.1.xml?emailaddress=%s",
domain, url.QueryEscape(localpart+"@"+domain)))
if err == nil {
addresses = append(addresses, u)
}
u, err = url.Parse(fmt.Sprintf(
"https://%s/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress=%s",
domain, url.QueryEscape(localpart+"@"+domain)))
if err == nil {
addresses = append(addresses, u)
}
log.Debugf("checking for autoconfig files at %v", addresses)
cc := new(ClientConfig)
for _, u := range addresses {
response, err := httpGet(u.String())
if err != nil {
continue
}
err = xml.NewDecoder(response.Body).Decode(cc)
if err != nil {
continue
}
// IMAP sanity check
var incoming *IncomingServer
for i := range cc.EmailProvider.IncomingServer {
if strings.ToLower(cc.EmailProvider.IncomingServer[i].Type) != "imap" {
continue
}
incoming = &cc.EmailProvider.IncomingServer[i]
break
}
if incoming == nil {
// no imap server found
continue
}
var incomingPort int
if incomingPort, err = strconv.Atoi(incoming.Port); err != nil {
continue
}
inenc := EncryptionSTARTTLS
switch strings.ToLower(incoming.SocketType) {
case "plain":
inenc = EncryptionInsecure
case "ssl":
inenc = EncryptionTLS
}
if strings.ToLower(incoming.Username) == "%emailaddress%" {
incoming.Username = localpart + "@" + domain
}
var outport int
if outport, err = strconv.Atoi(cc.EmailProvider.OutgoingServer.Port); err != nil {
continue
}
outenc := EncryptionSTARTTLS
switch strings.ToLower(cc.EmailProvider.OutgoingServer.SocketType) {
case "plain":
outenc = EncryptionInsecure
case "ssl":
outenc = EncryptionTLS
}
if strings.ToLower(cc.EmailProvider.OutgoingServer.Username) == "%emailaddress%" {
cc.EmailProvider.OutgoingServer.Username = localpart + "@" + domain
}
log.Debugf("found HTTP-based autoconfig at %s", u)
res <- &Config{
Found: ProtocolIMAP,
IMAP: Credentials{
Encryption: inenc,
Address: incoming.Hostname,
Port: incomingPort,
Username: incoming.Username,
},
SMTP: Credentials{
Encryption: outenc,
Address: cc.EmailProvider.OutgoingServer.Hostname,
Port: outport,
Username: cc.EmailProvider.OutgoingServer.Username,
},
}
return
}
}(res)
select {
case r, isValue := <-res:
if isValue {
result <- r
}
case <-ctx.Done():
}
}
var httpGet = http.Get
///////////////////////////////////////////////////////////////////////////////
// Autogenerated struct… you probably don't want to touch this. //
///////////////////////////////////////////////////////////////////////////////
type ClientConfig struct {
XMLName xml.Name `xml:"clientConfig"`
Text string `xml:",chardata"`
Version string `xml:"version,attr"`
EmailProvider EmailProvider `xml:"emailProvider"`
}
type EmailProvider struct {
Text string `xml:",chardata"`
ID string `xml:"id,attr"`
Domain []string `xml:"domain"`
IncomingServer []IncomingServer `xml:"incomingServer"`
OutgoingServer OutgoingServer `xml:"outgoingServer"`
}
type IncomingServer struct {
Text string `xml:",chardata"`
// can only be "imap" or "pop3", only imap is supported by aerc
Type string `xml:"type,attr"`
Hostname string `xml:"hostname"`
Port string `xml:"port"`
SocketType string `xml:"socketType"`
Username string `xml:"username"`
Authentication string `xml:"authentication"`
Password string `xml:"password"`
}
type OutgoingServer struct {
Text string `xml:",chardata"`
Type string `xml:"type,attr"`
Hostname string `xml:"hostname"`
Port string `xml:"port"`
SocketType string `xml:"socketType"`
Username string `xml:"username"`
Authentication string `xml:"authentication"`
Restriction string `xml:"restriction"`
AddThisServer string `xml:"addThisServer"`
UseGlobalPreferredServer string `xml:"useGlobalPreferredServer"`
Password string `xml:"password"`
}