aboutsummaryrefslogtreecommitdiff
path: root/worker/imap
diff options
context:
space:
mode:
authoremersion <contact@emersion.fr>2018-01-14 11:30:11 +0100
committerDrew DeVault <sir@cmpwn.com>2018-01-14 10:26:38 -0500
commit1710c9054898e820700d673e21e7c7a90a3f67b1 (patch)
treeca0c18c038b43ec9b456088d90e4dffa7c1210e8 /worker/imap
parent4074445cbb45dc6ec132e67b7eac9f32dcfd53de (diff)
Connect to IMAP server, login and idle
Diffstat (limited to 'worker/imap')
-rw-r--r--worker/imap/worker.go122
1 files changed, 111 insertions, 11 deletions
diff --git a/worker/imap/worker.go b/worker/imap/worker.go
index 080927d..6971f8c 100644
--- a/worker/imap/worker.go
+++ b/worker/imap/worker.go
@@ -1,20 +1,43 @@
package imap
import (
- "time"
+ "fmt"
+ "net/url"
+ "strings"
"git.sr.ht/~sircmpwn/aerc2/worker/types"
+ "github.com/emersion/go-imap"
+ "github.com/emersion/go-imap/client"
+ "github.com/emersion/go-imap-idle"
)
+var errUnsupported = fmt.Errorf("unsupported command")
+
+type imapClient struct {
+ *client.Client
+ *idle.IdleClient
+}
+
type IMAPWorker struct {
messages chan types.WorkerMessage
actions chan types.WorkerMessage
+
+ config struct {
+ scheme string
+ insecure bool
+ addr string
+ user *url.Userinfo
+ }
+
+ client *imapClient
+ updates chan client.Update
}
func NewIMAPWorker() *IMAPWorker {
return &IMAPWorker{
messages: make(chan types.WorkerMessage, 50),
actions: make(chan types.WorkerMessage, 50),
+ updates: make(chan client.Update, 50),
}
}
@@ -26,27 +49,104 @@ func (w *IMAPWorker) PostAction(msg types.WorkerMessage) {
w.actions <- msg
}
-func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) {
+func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error {
switch msg := msg.(type) {
case types.Ping:
- w.messages <- types.Ack{
- Message: types.RespondTo(msg),
+ // No-op
+ case types.Configure:
+ u, err := url.Parse(msg.Config.Source)
+ if err != nil {
+ return err
}
- default:
- w.messages <- types.Unsupported{
- Message: types.RespondTo(msg),
+
+ 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
+ }
+
+ w.config.addr = u.Host
+ if !strings.ContainsRune(w.config.addr, ':') {
+ w.config.addr += ":" + u.Scheme
}
+
+ w.config.scheme = u.Scheme
+ w.config.user = u.User
+ case types.Connect:
+ // TODO: populate TLS config
+
+ var (
+ c *client.Client
+ err error
+ )
+ switch w.config.scheme {
+ case "imap":
+ c, err = client.Dial(w.config.addr)
+ if err != nil {
+ return err
+ }
+
+ if !w.config.insecure {
+ if err := c.StartTLS(nil); err != nil {
+ return err
+ }
+ }
+ case "imaps":
+ c, err = client.DialTLS(w.config.addr, nil)
+ if err != nil {
+ return err
+ }
+ default:
+ return fmt.Errorf("Unknown IMAP scheme %s", w.config.scheme)
+ }
+
+ if w.config.user != nil {
+ username := w.config.user.Username()
+ password, hasPassword := w.config.user.Password()
+ if !hasPassword {
+ // TODO: ask password
+ }
+ if err := c.Login(username, password); err != nil {
+ return err
+ }
+ }
+
+ if _, err := c.Select(imap.InboxName, false); err != nil {
+ return err
+ }
+
+ c.Updates = w.updates
+ w.client = &imapClient{c, idle.NewClient(c)}
+
+ // TODO: don't idle right away
+ go w.client.IdleWithFallback(nil, 0)
+ default:
+ return errUnsupported
}
+ return nil
}
func (w *IMAPWorker) Run() {
- // TODO: IMAP shit
for {
select {
case msg := <-w.actions:
- w.handleMessage(msg)
- default:
- time.Sleep(100 * time.Millisecond)
+ fmt.Printf("<= %T\n", msg)
+ if err := w.handleMessage(msg); err == errUnsupported {
+ w.messages <- types.Unsupported{
+ Message: types.RespondTo(msg),
+ }
+ } else if err != nil {
+ w.messages <- types.Error{
+ Message: types.RespondTo(msg),
+ Error: err,
+ }
+ } else {
+ w.messages <- types.Ack{
+ Message: types.RespondTo(msg),
+ }
+ }
+ case update := <-w.updates:
+ fmt.Printf("<= %T\n", update)
}
}
}