~rjarry/aerc

e41ed82cf3dbb4a1152a562ab754a9dc4a6c57b3 — Robin Jarry 6 months ago 20752df
imap: add manual {dis,}connect support

Signed-off-by: Robin Jarry <robin@jarry.cc>
3 files changed, 82 insertions(+), 30 deletions(-)

A commands/account/connection.go
M widgets/account.go
M worker/imap/worker.go
A commands/account/connection.go => commands/account/connection.go +37 -0
@@ 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
}

M widgets/account.go => widgets/account.go +31 -28
@@ 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

M worker/imap/worker.go => worker/imap/worker.go +14 -2
@@ 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})