From a35d9bab4664bb60163cfce53faa4eb68c1a69f3 Mon Sep 17 00:00:00 2001 From: Koni Marti Date: Mon, 6 Nov 2023 22:25:11 +0100 Subject: rmdir: ensure proper sequence of operations Ensure the proper sequence of opening and removing a directory. Fix a potential race between the OpenDirectory (issued by dirlist.Select()) and the RemoveDirectory messages when removing a directory. Due to the delay in the current dirlist.Select() function, the RemoveDirectory message can arrive at the backend before the directory was changed to a different one. This can cause an error on some imap servers and problems with the watcher on the maildir backends. Introduce dirlist.Open() that accepts a callback function so that the operations can be performed in proper sequence. Dirlist.Select() is now a wrapper call to dirlist.Open(). Reported-by: inwit Signed-off-by: Koni Marti Acked-by: Robin Jarry Tested-by: Inwit --- commands/account/mkdir.go | 4 +++- commands/account/rmdir.go | 52 ++++++++++++++++++++++++++++++++++++----------- 2 files changed, 43 insertions(+), 13 deletions(-) (limited to 'commands/account') diff --git a/commands/account/mkdir.go b/commands/account/mkdir.go index af3d1045..7e49ad8b 100644 --- a/commands/account/mkdir.go +++ b/commands/account/mkdir.go @@ -41,13 +41,15 @@ func (m MakeDir) Execute(args []string) error { if acct == nil { return errors.New("No account selected") } + previous := acct.SelectedDirectory() acct.Worker().PostAction(&types.CreateDirectory{ Directory: m.Folder, }, func(msg types.WorkerMessage) { switch msg := msg.(type) { case *types.Done: app.PushStatus("Directory created.", 10*time.Second) - acct.Directories().Select(m.Folder) + history[acct.Name()] = previous + acct.Directories().Open(m.Folder, 0, nil) case *types.Error: app.PushError(msg.Error.Error()) } diff --git a/commands/account/rmdir.go b/commands/account/rmdir.go index 398f375f..6590a819 100644 --- a/commands/account/rmdir.go +++ b/commands/account/rmdir.go @@ -36,12 +36,30 @@ func (r RemoveDir) Execute(args []string) error { dirFound := false if oldDir, ok := history[acct.Name()]; ok { - if oldDir != curDir { + present := false + for _, dir := range acct.Directories().List() { + if dir == oldDir { + present = true + break + } + } + if oldDir != curDir && present { newDir = oldDir dirFound = true } } + defaultDir := acct.AccountConfig().Default + if !dirFound && defaultDir != curDir { + for _, dir := range acct.Directories().List() { + if defaultDir == dir { + newDir = dir + dirFound = true + break + } + } + } + if !dirFound { for _, dir := range acct.Directories().List() { if dir != curDir { @@ -56,20 +74,30 @@ func (r RemoveDir) Execute(args []string) error { return errors.New("No directory to move to afterwards!") } - acct.Directories().Select(newDir) - - acct.Worker().PostAction(&types.RemoveDirectory{ - Directory: curDir, - Quiet: r.Force, - }, func(msg types.WorkerMessage) { - switch msg := msg.(type) { + acct.Directories().Open(newDir, 0, func(msg types.WorkerMessage) { + switch msg.(type) { case *types.Done: - app.PushStatus("Directory removed.", 10*time.Second) + break case *types.Error: - app.PushError(msg.Error.Error()) - case *types.Unsupported: - app.PushError(":rmdir is not supported by the backend.") + app.PushError("Could not change directory") + acct.Directories().Open(curDir, 0, nil) + return + default: + return } + acct.Worker().PostAction(&types.RemoveDirectory{ + Directory: curDir, + Quiet: r.Force, + }, func(msg types.WorkerMessage) { + switch msg := msg.(type) { + case *types.Done: + app.PushStatus("Directory removed.", 10*time.Second) + case *types.Error: + app.PushError(msg.Error.Error()) + case *types.Unsupported: + app.PushError(":rmdir is not supported by the backend.") + } + }) }) return nil -- cgit