diff options
author | Robin Jarry <robin@jarry.cc> | 2022-02-25 00:21:06 +0100 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2022-02-25 13:56:53 +0100 |
commit | c26d08103b327bd3f2470e542aa55ab354483347 (patch) | |
tree | 4c0567246916d676b71a4675c76a93a198add65f | |
parent | 91ead11c47252ca8998fdad7b0770d6b8d07c987 (diff) | |
download | aerc-c26d08103b327bd3f2470e542aa55ab354483347.tar.gz |
aerc: always check SelectedAccount return value
aerc.SelectedAccount() is used in lots of places. Most of them without
checking the return value.
In some cases, the currently selected tab is not related to any account
(widget.Terminal for example). This can lead to unexpected crashes when
accessing account specific configuration.
When possible, return an error when no account is currently selected.
If no error can be returned, fallback to non-account specific
configuration.
Signed-off-by: Robin Jarry <robin@jarry.cc>
Reviewed-by: Koni Marti <koni.marti@gmail.com>
-rw-r--r-- | commands/account/compose.go | 3 | ||||
-rw-r--r-- | commands/account/view.go | 3 | ||||
-rw-r--r-- | commands/commands.go | 18 | ||||
-rw-r--r-- | commands/compose/postpone.go | 6 | ||||
-rw-r--r-- | commands/msg/unsubscribe.go | 3 | ||||
-rw-r--r-- | commands/msgview/next.go | 5 | ||||
-rw-r--r-- | widgets/aerc.go | 8 | ||||
-rw-r--r-- | widgets/compose.go | 19 | ||||
-rw-r--r-- | widgets/msglist.go | 27 |
9 files changed, 64 insertions, 28 deletions
diff --git a/commands/account/compose.go b/commands/account/compose.go index d4128db6..1a62d0a3 100644 --- a/commands/account/compose.go +++ b/commands/account/compose.go @@ -30,6 +30,9 @@ func (Compose) Execute(aerc *widgets.Aerc, args []string) error { return err } acct := aerc.SelectedAccount() + if acct == nil { + return errors.New("No account selected") + } if template == "" { template = aerc.Config().Templates.NewMessage } diff --git a/commands/account/view.go b/commands/account/view.go index 4f59d947..53ad2678 100644 --- a/commands/account/view.go +++ b/commands/account/view.go @@ -26,6 +26,9 @@ func (ViewMessage) Execute(aerc *widgets.Aerc, args []string) error { return errors.New("Usage: view-message") } acct := aerc.SelectedAccount() + if acct == nil { + return errors.New("No account selected") + } if acct.Messages().Empty() { return nil } diff --git a/commands/commands.go b/commands/commands.go index cb5b63bf..70a77b92 100644 --- a/commands/commands.go +++ b/commands/commands.go @@ -117,11 +117,15 @@ func (cmds *Commands) GetCompletions(aerc *widgets.Aerc, cmd string) []string { func GetFolders(aerc *widgets.Aerc, args []string) []string { out := make([]string, 0) + acct := aerc.SelectedAccount() + if acct == nil { + return out + } if len(args) == 0 { - return aerc.SelectedAccount().Directories().List() + return acct.Directories().List() } - for _, dir := range aerc.SelectedAccount().Directories().List() { - if foundInString(dir, args[0], aerc.SelectedAccount().UiConfig().FuzzyFolderComplete) { + for _, dir := range acct.Directories().List() { + if foundInString(dir, args[0], acct.UiConfig().FuzzyFolderComplete) { out = append(out, dir) } } @@ -144,8 +148,12 @@ func CompletionFromList(valid []string, args []string) []string { } func GetLabels(aerc *widgets.Aerc, args []string) []string { + acct := aerc.SelectedAccount() + if acct == nil { + return make([]string, 0) + } if len(args) == 0 { - return aerc.SelectedAccount().Labels() + return acct.Labels() } // + and - are used to denote tag addition / removal and need to be striped @@ -165,7 +173,7 @@ func GetLabels(aerc *widgets.Aerc, args []string) []string { trimmed := strings.TrimLeft(last, "+-") out := make([]string, 0) - for _, label := range aerc.SelectedAccount().Labels() { + for _, label := range acct.Labels() { if hasCaseSmartPrefix(label, trimmed) { var prev string if len(others) > 0 { diff --git a/commands/compose/postpone.go b/commands/compose/postpone.go index f918b527..9462a9cd 100644 --- a/commands/compose/postpone.go +++ b/commands/compose/postpone.go @@ -31,6 +31,10 @@ func (Postpone) Execute(aerc *widgets.Aerc, args []string) error { if len(args) != 1 { return errors.New("Usage: postpone") } + acct := aerc.SelectedAccount() + if acct == nil { + return errors.New("No account selected") + } composer, _ := aerc.SelectedTab().(*widgets.Composer) config := composer.Config() tabName := aerc.TabNames()[aerc.SelectedTabIndex()] @@ -48,7 +52,7 @@ func (Postpone) Execute(aerc *widgets.Aerc, args []string) error { header.SetContentType("text/plain", map[string]string{"charset": "UTF-8"}) header.Set("Content-Transfer-Encoding", "quoted-printable") worker := composer.Worker() - dirs := aerc.SelectedAccount().Directories().List() + dirs := acct.Directories().List() alreadyCreated := false for _, dir := range dirs { if dir == config.Postpone { diff --git a/commands/msg/unsubscribe.go b/commands/msg/unsubscribe.go index 3a69ff98..428e8728 100644 --- a/commands/msg/unsubscribe.go +++ b/commands/msg/unsubscribe.go @@ -89,6 +89,9 @@ func parseUnsubscribeMethods(header string) (methods []*url.URL) { func unsubscribeMailto(aerc *widgets.Aerc, u *url.URL) error { widget := aerc.SelectedTab().(widgets.ProvidesMessage) acct := widget.SelectedAccount() + if acct == nil { + return errors.New("No account selected") + } h := &mail.Header{} h.SetSubject(u.Query().Get("subject")) diff --git a/commands/msgview/next.go b/commands/msgview/next.go index 4291a6a5..742bc665 100644 --- a/commands/msgview/next.go +++ b/commands/msgview/next.go @@ -1,6 +1,8 @@ package msgview import ( + "errors" + "git.sr.ht/~rjarry/aerc/commands/account" "git.sr.ht/~rjarry/aerc/lib" "git.sr.ht/~rjarry/aerc/widgets" @@ -27,6 +29,9 @@ func (NextPrevMsg) Execute(aerc *widgets.Aerc, args []string) error { } mv, _ := aerc.SelectedTab().(*widgets.MessageViewer) acct := mv.SelectedAccount() + if acct == nil { + return errors.New("No account selected") + } store := mv.Store() err = account.ExecuteNextPrevMessage(args, acct, pct, n) if err != nil { diff --git a/widgets/aerc.go b/widgets/aerc.go index 10e9924c..98bc1b23 100644 --- a/widgets/aerc.go +++ b/widgets/aerc.go @@ -309,6 +309,14 @@ func (aerc *Aerc) SelectedAccount() *AccountView { return nil } +func (aerc *Aerc) SelectedAccountUiConfig() config.UIConfig { + acct := aerc.SelectedAccount() + if acct == nil { + return aerc.conf.Ui + } + return acct.UiConfig() +} + func (aerc *Aerc) SelectedTab() ui.Drawable { return aerc.tabs.Tabs[aerc.tabs.Selected].Content } diff --git a/widgets/compose.go b/widgets/compose.go index 7229ec84..e47aa3eb 100644 --- a/widgets/compose.go +++ b/widgets/compose.go @@ -127,15 +127,15 @@ func (c *Composer) buildComposeHeader(aerc *Aerc, cmpl *completer.Completer) { c.layout = aerc.conf.Compose.HeaderLayout c.editors = make(map[string]*headerEditor) c.focusable = make([]ui.MouseableDrawableInteractive, 0) + uiConfig := aerc.SelectedAccountUiConfig() for i, row := range c.layout { for j, h := range row { h = strings.ToLower(h) c.layout[i][j] = h // normalize to lowercase - e := newHeaderEditor(h, c.header, aerc.SelectedAccount().UiConfig()) + e := newHeaderEditor(h, c.header, uiConfig) if aerc.conf.Ui.CompletionPopovers { - e.input.TabComplete(cmpl.ForHeader(h), - aerc.SelectedAccount().UiConfig().CompletionDelay) + e.input.TabComplete(cmpl.ForHeader(h), uiConfig.CompletionDelay) } c.editors[h] = e switch h { @@ -152,9 +152,9 @@ func (c *Composer) buildComposeHeader(aerc *Aerc, cmpl *completer.Completer) { for _, h := range []string{"cc", "bcc"} { if c.header.Has(h) { if _, ok := c.editors[h]; !ok { - e := newHeaderEditor(h, c.header, aerc.SelectedAccount().UiConfig()) + e := newHeaderEditor(h, c.header, uiConfig) if aerc.conf.Ui.CompletionPopovers { - e.input.TabComplete(cmpl.ForHeader(h), aerc.SelectedAccount().UiConfig().CompletionDelay) + e.input.TabComplete(cmpl.ForHeader(h), uiConfig.CompletionDelay) } c.editors[h] = e c.focusable = append(c.focusable, e) @@ -741,11 +741,10 @@ func (c *Composer) AddEditor(header string, value string, appendHeader bool) { e.storeValue() // flush modifications from the user to the header editor = e } else { - e := newHeaderEditor(header, c.header, - c.aerc.SelectedAccount().UiConfig()) - if c.config.Ui.CompletionPopovers { - e.input.TabComplete(c.completer.ForHeader(header), - c.config.Ui.CompletionDelay) + uiConfig := c.aerc.SelectedAccountUiConfig() + e := newHeaderEditor(header, c.header, uiConfig) + if uiConfig.CompletionPopovers { + e.input.TabComplete(c.completer.ForHeader(header), uiConfig.CompletionDelay) } c.editors[header] = e c.layout = append(c.layout, []string{header}) diff --git a/widgets/msglist.go b/widgets/msglist.go index 50ce24ee..ae0d2118 100644 --- a/widgets/msglist.go +++ b/widgets/msglist.go @@ -53,11 +53,13 @@ func (ml *MessageList) Invalidate() { func (ml *MessageList) Draw(ctx *ui.Context) { ml.height = ctx.Height() + uiConfig := ml.aerc.SelectedAccountUiConfig() ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ', - ml.aerc.SelectedAccount().UiConfig().GetStyle(config.STYLE_MSGLIST_DEFAULT)) + uiConfig.GetStyle(config.STYLE_MSGLIST_DEFAULT)) + acct := ml.aerc.SelectedAccount() store := ml.Store() - if store == nil { + if store == nil || acct == nil { if ml.isInitalizing { ml.spinner.Draw(ctx) return @@ -89,7 +91,7 @@ func (ml *MessageList) Draw(ctx *ui.Context) { row int = 0 ) - if ml.aerc.SelectedAccount().UiConfig().ThreadingEnabled || store.BuildThreads() { + if uiConfig.ThreadingEnabled || store.BuildThreads() { threads := store.Threads counter := len(store.Uids()) @@ -119,8 +121,8 @@ func (ml *MessageList) Draw(ctx *ui.Context) { } } fmtCtx := format.Ctx{ - FromAddress: ml.aerc.SelectedAccount().acct.From, - AccountName: ml.aerc.SelectedAccount().Name(), + FromAddress: acct.acct.From, + AccountName: acct.Name(), MsgInfo: msg, MsgNum: row, MsgIsMarked: store.IsMarked(t.Uid), @@ -144,8 +146,8 @@ func (ml *MessageList) Draw(ctx *ui.Context) { uid := uids[i] msg := store.Messages[uid] fmtCtx := format.Ctx{ - FromAddress: ml.aerc.SelectedAccount().acct.From, - AccountName: ml.aerc.SelectedAccount().Name(), + FromAddress: acct.acct.From, + AccountName: acct.Name(), MsgInfo: msg, MsgNum: row, MsgIsMarked: store.IsMarked(uid), @@ -183,8 +185,9 @@ func (ml *MessageList) Draw(ctx *ui.Context) { func (ml *MessageList) drawRow(textWidth int, ctx *ui.Context, uid uint32, row int, needsHeaders *[]uint32, fmtCtx format.Ctx) bool { store := ml.store msg := store.Messages[uid] + acct := ml.aerc.SelectedAccount() - if row >= ctx.Height() { + if row >= ctx.Height() || acct == nil { return true } @@ -195,8 +198,8 @@ func (ml *MessageList) drawRow(textWidth int, ctx *ui.Context, uid uint32, row i } confParams := map[config.ContextType]string{ - config.UI_CONTEXT_ACCOUNT: ml.aerc.SelectedAccount().AccountConfig().Name, - config.UI_CONTEXT_FOLDER: ml.aerc.SelectedAccount().Directories().Selected(), + config.UI_CONTEXT_ACCOUNT: acct.AccountConfig().Name, + config.UI_CONTEXT_FOLDER: acct.Directories().Selected(), } if msg.Envelope != nil { confParams[config.UI_CONTEXT_SUBJECT] = msg.Envelope.Subject @@ -288,7 +291,7 @@ func (ml *MessageList) MouseEvent(localX int, localY int, event tcell.Event) { if ok { ml.Select(selectedMsg) acct := ml.aerc.SelectedAccount() - if acct.Messages().Empty() { + if acct == nil || acct.Messages().Empty() { return } store := acct.Messages().Store() @@ -433,7 +436,7 @@ func (ml *MessageList) ensureScroll() { } func (ml *MessageList) drawEmptyMessage(ctx *ui.Context) { - uiConfig := ml.aerc.SelectedAccount().UiConfig() + uiConfig := ml.aerc.SelectedAccountUiConfig() msg := uiConfig.EmptyMessage ctx.Printf((ctx.Width()/2)-(len(msg)/2), 0, uiConfig.GetStyle(config.STYLE_MSGLIST_DEFAULT), "%s", msg) |