summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Jarry <robin@jarry.cc>2022-02-25 00:21:06 +0100
committerRobin Jarry <robin@jarry.cc>2022-02-25 13:56:53 +0100
commitc26d08103b327bd3f2470e542aa55ab354483347 (patch)
tree4c0567246916d676b71a4675c76a93a198add65f
parent91ead11c47252ca8998fdad7b0770d6b8d07c987 (diff)
downloadaerc-c26d08103b327bd3f2470e542aa55ab354483347.zip
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.go3
-rw-r--r--commands/account/view.go3
-rw-r--r--commands/commands.go18
-rw-r--r--commands/compose/postpone.go6
-rw-r--r--commands/msg/unsubscribe.go3
-rw-r--r--commands/msgview/next.go5
-rw-r--r--widgets/aerc.go8
-rw-r--r--widgets/compose.go19
-rw-r--r--widgets/msglist.go27
9 files changed, 64 insertions, 28 deletions
diff --git a/commands/account/compose.go b/commands/account/compose.go
index d4128db..1a62d0a 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 4f59d94..53ad267 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 cb5b63b..70a77b9 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 f918b52..9462a9c 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 3a69ff9..428e872 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 4291a6a..742bc66 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 10e9924..98bc1b2 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 7229ec8..e47aa3e 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 50ce24e..ae0d211 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)