From c26d08103b327bd3f2470e542aa55ab354483347 Mon Sep 17 00:00:00 2001 From: Robin Jarry Date: Fri, 25 Feb 2022 00:21:06 +0100 Subject: 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 Reviewed-by: Koni Marti --- widgets/aerc.go | 8 ++++++++ widgets/compose.go | 19 +++++++++---------- widgets/msglist.go | 27 +++++++++++++++------------ 3 files changed, 32 insertions(+), 22 deletions(-) (limited to 'widgets') 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) -- cgit