From 40f5d435e5f92abc8b64dae1c029f67d620db1f2 Mon Sep 17 00:00:00 2001 From: René 'Necoro' Neumann Date: Sun, 19 Apr 2020 17:53:12 +0200 Subject: Started IMAP connection --- go.mod | 1 + go.sum | 10 ++++ internal/imap/imap.go | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++ main.go | 15 ++++++ 4 files changed, 152 insertions(+) create mode 100644 internal/imap/imap.go diff --git a/go.mod b/go.mod index c2ce27b..2c62fda 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.14 require ( github.com/PuerkitoBio/goquery v1.5.1 // indirect + github.com/emersion/go-imap v1.0.4 github.com/mmcdole/gofeed v1.0.0-beta2.0.20200331235650-4298e4366be3 golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e // indirect golang.org/x/text v0.3.2 // indirect diff --git a/go.sum b/go.sum index 15457f3..42a9933 100644 --- a/go.sum +++ b/go.sum @@ -5,16 +5,26 @@ github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9Pq github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo= github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/codegangsta/cli v1.20.0/go.mod h1:/qJNoX69yVSKu5o4jLyXAENLRyk1uhi7zkbQ3slBdOA= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/emersion/go-imap v1.0.4 h1:uiCAIHM6Z5Jwkma1zdNDWWXxSCqb+/xHBkHflD7XBro= +github.com/emersion/go-imap v1.0.4/go.mod h1:yKASt+C3ZiDAiCSssxg9caIckWF/JG7ZQTO7GAmvicU= +github.com/emersion/go-message v0.11.1/go.mod h1:C4jnca5HOTo4bGN9YdqNQM9sITuT3Y0K6bSUw9RklvY= +github.com/emersion/go-sasl v0.0.0-20191210011802-430746ea8b9b h1:uhWtEWBHgop1rqEk2klKaxPAkVDCXexai6hSuRQ7Nvs= +github.com/emersion/go-sasl v0.0.0-20191210011802-430746ea8b9b/go.mod h1:G/dpzLu16WtQpBfQ/z3LYiYJn3ZhKSGWn83fyoyQe/k= +github.com/emersion/go-textwrapper v0.0.0-20160606182133-d0e65e56babe/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U= +github.com/martinlindhe/base36 v1.0.0/go.mod h1:+AtEs8xrBpCeYgSLoY/aJ6Wf37jtBuR0s35750M27+8= github.com/mmcdole/gofeed v1.0.0-beta2.0.20200331235650-4298e4366be3 h1:Wy+ed15cpwtLcJYNiO4Z0wmjZHpNj4q0RsGbsoxWSMA= github.com/mmcdole/gofeed v1.0.0-beta2.0.20200331235650-4298e4366be3/go.mod h1:tkVcyzS3qVMlQrQxJoEH1hkTiuo9a8emDzkMi7TZBu0= github.com/mmcdole/goxpp v0.0.0-20181012175147-0068e33feabf h1:sWGE2v+hO0Nd4yFU/S/mDBM5plIU8v/Qhfz41hkDIAI= github.com/mmcdole/goxpp v0.0.0-20181012175147-0068e33feabf/go.mod h1:pasqhqstspkosTneA62Nc+2p9SOBBYAPbnmRRWPQ0V8= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/internal/imap/imap.go b/internal/imap/imap.go new file mode 100644 index 0000000..18039d3 --- /dev/null +++ b/internal/imap/imap.go @@ -0,0 +1,126 @@ +package imap + +import ( + "fmt" + "net/url" + + "github.com/emersion/go-imap" + imapClient "github.com/emersion/go-imap/client" + + "github.com/Necoro/feed2imap-go/internal/log" +) + +const ( + imapsPort = "993" + imapPort = "143" +) + +type Client struct { + c *imapClient.Client + host string +} + +func forceTLS(url *url.URL) bool { + return url.Scheme == "imaps" || url.Port() == imapsPort +} + +func setDefaultScheme(url *url.URL) { + switch url.Scheme { + case "imap", "imaps": + return + default: + oldScheme := url.Scheme + if url.Port() == imapsPort { + url.Scheme = "imaps" + } else { + url.Scheme = "imap" + } + + if oldScheme != "" { + log.Warnf("Unknown scheme '%s', defaulting to '%s'", oldScheme, url.Scheme) + } + } +} + +func setDefaultPort(url *url.URL) { + if url.Port() == "" { + var port string + if url.Scheme == "imaps" { + port = imapsPort + } else { + port = imapPort + } + url.Host += ":" + port + } +} + +func sanitizeUrl(url *url.URL) { + setDefaultScheme(url) + setDefaultPort(url) +} + +func (client *Client) Disconnect() { + if client != nil { + connected := (client.c.State() & imap.ConnectedState) != 0 + _ = client.c.Logout() + + if connected { + log.Print("Disconnected from ", client.host) + } + } +} + +func Connect(url *url.URL) (*Client, error) { + var c *imapClient.Client + var err error + + sanitizeUrl(url) + + forceTls := forceTLS(url) + + if forceTls { + c, err = imapClient.DialTLS(url.Host, nil) + if err != nil { + return nil, fmt.Errorf("connecting (TLS) to %s: %w", url.Host, err) + } + log.Print("Connected to ", url.Host, " (TLS)") + } else { + c, err = imapClient.Dial(url.Host) + if err != nil { + return nil, fmt.Errorf("connecting to %s: %w", url.Host, err) + } + } + + var client = Client{c, url.Host} + + defer func() { + if err != nil { + client.Disconnect() + } + }() + + if !forceTls { + var hasStartTls bool // explicit to avoid shadowing err + + hasStartTls, err = c.SupportStartTLS() + if err != nil { + return nil, fmt.Errorf("checking for starttls for %s: %w", url.Host, err) + } + + if hasStartTls { + if err = c.StartTLS(nil); err != nil { + return nil, fmt.Errorf("enabling starttls for %s: %w", url.Host, err) + } + + log.Print("Connected to ", url.Host, " (STARTTLS)") + } + log.Print("Connected to ", url.Host, " (Plain)") + } + + pwd, _ := url.User.Password() + if err = c.Login(url.User.Username(), pwd); err != nil { + return nil, fmt.Errorf("login to %s: %w", url.Host, err) + } + + return &client, nil +} diff --git a/main.go b/main.go index bbea985..f90cc50 100644 --- a/main.go +++ b/main.go @@ -2,9 +2,12 @@ package main import ( "flag" + "fmt" + "net/url" "os" "github.com/Necoro/feed2imap-go/internal/config" + "github.com/Necoro/feed2imap-go/internal/imap" "github.com/Necoro/feed2imap-go/internal/log" "github.com/Necoro/feed2imap-go/internal/parse" ) @@ -26,6 +29,18 @@ func run() error { parse.Parse(cfg.Feeds) + imapUrl, err := url.Parse(cfg.GlobalConfig["target"].(string)) + if err != nil { + return fmt.Errorf("parsing 'target': %w", err) + } + + c, err := imap.Connect(imapUrl) + if err != nil { + return err + } + + defer c.Disconnect() + return nil } -- cgit v1.2.3-54-g00ecf