From e41ed82cf3dbb4a1152a562ab754a9dc4a6c57b3 Mon Sep 17 00:00:00 2001 From: Robin Jarry Date: Mon, 1 Nov 2021 21:38:26 +0100 Subject: [PATCH] imap: add manual {dis,}connect support Signed-off-by: Robin Jarry --- commands/account/connection.go | 37 +++++++++++++++++++++ widgets/account.go | 59 ++++++++++++++++++---------------- worker/imap/worker.go | 16 +++++++-- 3 files changed, 82 insertions(+), 30 deletions(-) create mode 100644 commands/account/connection.go diff --git a/commands/account/connection.go b/commands/account/connection.go new file mode 100644 index 0000000..a87993b --- /dev/null +++ b/commands/account/connection.go @@ -0,0 +1,37 @@ +package account + +import ( + "errors" + + "git.sr.ht/~rjarry/aerc/widgets" + "git.sr.ht/~rjarry/aerc/worker/types" +) + +type Connection struct{} + +func init() { + register(Connection{}) +} + +func (Connection) Aliases() []string { + return []string{"connect", "disconnect"} +} + +func (Connection) Complete(aerc *widgets.Aerc, args []string) []string { + return nil +} + +func (Connection) Execute(aerc *widgets.Aerc, args []string) error { + acct := aerc.SelectedAccount() + if acct == nil { + return errors.New("No account selected") + } + if args[0] == "connect" { + acct.Worker().PostAction(&types.Connect{}, nil) + acct.SetStatus("Connecting...") + } else { + acct.Worker().PostAction(&types.Disconnect{}, nil) + acct.SetStatus("Disconnecting...") + } + return nil +} diff --git a/widgets/account.go b/widgets/account.go index 891278a..2f126a3 100644 --- a/widgets/account.go +++ b/widgets/account.go @@ -85,7 +85,7 @@ func NewAccountView(aerc *Aerc, conf *config.AercConfig, acct *config.AccountCon go worker.Backend.Run() worker.PostAction(&types.Configure{Config: acct}, nil) - worker.PostAction(&types.Connect{}, view.connected) + worker.PostAction(&types.Connect{}, nil) host.SetStatus("Connecting...") return view, nil @@ -105,6 +105,10 @@ func (acct *AccountView) Tick() bool { } } +func (acct *AccountView) SetStatus(msg string) { + acct.host.SetStatus(msg) +} + func (acct *AccountView) AccountConfig() *config.AccountConfig { return acct.acct } @@ -147,33 +151,6 @@ func (acct *AccountView) Focus(focus bool) { // TODO: Unfocus children I guess } -func (acct *AccountView) connected(msg types.WorkerMessage) { - switch msg.(type) { - case *types.Done: - acct.host.SetStatus("Listing mailboxes...") - acct.logger.Println("Listing mailboxes...") - acct.dirlist.UpdateList(func(dirs []string) { - var dir string - for _, _dir := range dirs { - if _dir == acct.acct.Default { - dir = _dir - break - } - } - if dir == "" && len(dirs) > 0 { - dir = dirs[0] - } - if dir != "" { - acct.dirlist.Select(dir) - } - - acct.msglist.SetInitDone() - acct.logger.Println("Connected.") - acct.host.SetStatus("Connected.") - }) - } -} - func (acct *AccountView) Directories() *DirectoryList { return acct.dirlist } @@ -225,6 +202,32 @@ func (acct *AccountView) onMessage(msg types.WorkerMessage) { switch msg := msg.(type) { case *types.Done: switch msg.InResponseTo().(type) { + case *types.Connect: + acct.host.SetStatus("Listing mailboxes...") + acct.logger.Println("Listing mailboxes...") + acct.dirlist.UpdateList(func(dirs []string) { + var dir string + for _, _dir := range dirs { + if _dir == acct.acct.Default { + dir = _dir + break + } + } + if dir == "" && len(dirs) > 0 { + dir = dirs[0] + } + if dir != "" { + acct.dirlist.Select(dir) + } + acct.msglist.SetInitDone() + acct.logger.Println("Connected.") + acct.host.SetStatus("Connected.") + }) + case *types.Disconnect: + acct.dirlist.UpdateList(nil) + acct.msglist.SetStore(nil) + acct.logger.Println("Disconnected.") + acct.host.SetStatus("Disconnected.") case *types.OpenDirectory: if store, ok := acct.dirlist.SelectedMsgStore(); ok { // If we've opened this dir before, we can re-render it from diff --git a/worker/imap/worker.go b/worker/imap/worker.go index 82b81bd..cd52536 100644 --- a/worker/imap/worker.go +++ b/worker/imap/worker.go @@ -59,7 +59,7 @@ func NewIMAPWorker(worker *types.Worker) (types.Backend, error) { } func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error { - if w.idleStop != nil { + if w.client != nil && w.client.State() == imap.SelectedState { close(w.idleStop) if err := <-w.idleDone; err != nil { w.worker.PostMessage(&types.Error{Error: err}, nil) @@ -110,6 +110,9 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error { c *client.Client err error ) + if w.client != nil { + return fmt.Errorf("Already connected") + } switch w.config.scheme { case "imap": c, err = client.Dial(w.config.addr) @@ -157,6 +160,15 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error { c.Updates = w.updates w.client = &imapClient{c, sortthread.NewSortClient(c)} w.worker.PostMessage(&types.Done{types.RespondTo(msg)}, nil) + case *types.Disconnect: + if w.client == nil { + return fmt.Errorf("Not connected") + } + if err := w.client.Logout(); err != nil { + return err + } + w.client = nil + w.worker.PostMessage(&types.Done{types.RespondTo(msg)}, nil) case *types.ListDirectories: w.handleListDirectories(msg) case *types.OpenDirectory: @@ -189,7 +201,7 @@ func (w *IMAPWorker) handleMessage(msg types.WorkerMessage) error { reterr = errUnsupported } - if w.idleStop != nil { + if w.client != nil && w.client.State() == imap.SelectedState { w.idleStop = make(chan struct{}) go func() { w.idleDone <- w.client.Idle(w.idleStop, &client.IdleOptions{0, 0})