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>
This commit is contained in:
parent
91ead11c47
commit
c26d08103b
9 changed files with 65 additions and 29 deletions
|
@ -30,6 +30,9 @@ func (Compose) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
acct := aerc.SelectedAccount()
|
acct := aerc.SelectedAccount()
|
||||||
|
if acct == nil {
|
||||||
|
return errors.New("No account selected")
|
||||||
|
}
|
||||||
if template == "" {
|
if template == "" {
|
||||||
template = aerc.Config().Templates.NewMessage
|
template = aerc.Config().Templates.NewMessage
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,9 @@ func (ViewMessage) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
return errors.New("Usage: view-message")
|
return errors.New("Usage: view-message")
|
||||||
}
|
}
|
||||||
acct := aerc.SelectedAccount()
|
acct := aerc.SelectedAccount()
|
||||||
|
if acct == nil {
|
||||||
|
return errors.New("No account selected")
|
||||||
|
}
|
||||||
if acct.Messages().Empty() {
|
if acct.Messages().Empty() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,11 +117,15 @@ func (cmds *Commands) GetCompletions(aerc *widgets.Aerc, cmd string) []string {
|
||||||
|
|
||||||
func GetFolders(aerc *widgets.Aerc, args []string) []string {
|
func GetFolders(aerc *widgets.Aerc, args []string) []string {
|
||||||
out := make([]string, 0)
|
out := make([]string, 0)
|
||||||
if len(args) == 0 {
|
acct := aerc.SelectedAccount()
|
||||||
return aerc.SelectedAccount().Directories().List()
|
if acct == nil {
|
||||||
|
return out
|
||||||
}
|
}
|
||||||
for _, dir := range aerc.SelectedAccount().Directories().List() {
|
if len(args) == 0 {
|
||||||
if foundInString(dir, args[0], aerc.SelectedAccount().UiConfig().FuzzyFolderComplete) {
|
return acct.Directories().List()
|
||||||
|
}
|
||||||
|
for _, dir := range acct.Directories().List() {
|
||||||
|
if foundInString(dir, args[0], acct.UiConfig().FuzzyFolderComplete) {
|
||||||
out = append(out, dir)
|
out = append(out, dir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,8 +148,12 @@ func CompletionFromList(valid []string, args []string) []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetLabels(aerc *widgets.Aerc, 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 {
|
if len(args) == 0 {
|
||||||
return aerc.SelectedAccount().Labels()
|
return acct.Labels()
|
||||||
}
|
}
|
||||||
|
|
||||||
// + and - are used to denote tag addition / removal and need to be striped
|
// + 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, "+-")
|
trimmed := strings.TrimLeft(last, "+-")
|
||||||
|
|
||||||
out := make([]string, 0)
|
out := make([]string, 0)
|
||||||
for _, label := range aerc.SelectedAccount().Labels() {
|
for _, label := range acct.Labels() {
|
||||||
if hasCaseSmartPrefix(label, trimmed) {
|
if hasCaseSmartPrefix(label, trimmed) {
|
||||||
var prev string
|
var prev string
|
||||||
if len(others) > 0 {
|
if len(others) > 0 {
|
||||||
|
|
|
@ -31,6 +31,10 @@ func (Postpone) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
if len(args) != 1 {
|
if len(args) != 1 {
|
||||||
return errors.New("Usage: postpone")
|
return errors.New("Usage: postpone")
|
||||||
}
|
}
|
||||||
|
acct := aerc.SelectedAccount()
|
||||||
|
if acct == nil {
|
||||||
|
return errors.New("No account selected")
|
||||||
|
}
|
||||||
composer, _ := aerc.SelectedTab().(*widgets.Composer)
|
composer, _ := aerc.SelectedTab().(*widgets.Composer)
|
||||||
config := composer.Config()
|
config := composer.Config()
|
||||||
tabName := aerc.TabNames()[aerc.SelectedTabIndex()]
|
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.SetContentType("text/plain", map[string]string{"charset": "UTF-8"})
|
||||||
header.Set("Content-Transfer-Encoding", "quoted-printable")
|
header.Set("Content-Transfer-Encoding", "quoted-printable")
|
||||||
worker := composer.Worker()
|
worker := composer.Worker()
|
||||||
dirs := aerc.SelectedAccount().Directories().List()
|
dirs := acct.Directories().List()
|
||||||
alreadyCreated := false
|
alreadyCreated := false
|
||||||
for _, dir := range dirs {
|
for _, dir := range dirs {
|
||||||
if dir == config.Postpone {
|
if dir == config.Postpone {
|
||||||
|
|
|
@ -89,6 +89,9 @@ func parseUnsubscribeMethods(header string) (methods []*url.URL) {
|
||||||
func unsubscribeMailto(aerc *widgets.Aerc, u *url.URL) error {
|
func unsubscribeMailto(aerc *widgets.Aerc, u *url.URL) error {
|
||||||
widget := aerc.SelectedTab().(widgets.ProvidesMessage)
|
widget := aerc.SelectedTab().(widgets.ProvidesMessage)
|
||||||
acct := widget.SelectedAccount()
|
acct := widget.SelectedAccount()
|
||||||
|
if acct == nil {
|
||||||
|
return errors.New("No account selected")
|
||||||
|
}
|
||||||
|
|
||||||
h := &mail.Header{}
|
h := &mail.Header{}
|
||||||
h.SetSubject(u.Query().Get("subject"))
|
h.SetSubject(u.Query().Get("subject"))
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package msgview
|
package msgview
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
|
||||||
"git.sr.ht/~rjarry/aerc/commands/account"
|
"git.sr.ht/~rjarry/aerc/commands/account"
|
||||||
"git.sr.ht/~rjarry/aerc/lib"
|
"git.sr.ht/~rjarry/aerc/lib"
|
||||||
"git.sr.ht/~rjarry/aerc/widgets"
|
"git.sr.ht/~rjarry/aerc/widgets"
|
||||||
|
@ -27,6 +29,9 @@ func (NextPrevMsg) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
}
|
}
|
||||||
mv, _ := aerc.SelectedTab().(*widgets.MessageViewer)
|
mv, _ := aerc.SelectedTab().(*widgets.MessageViewer)
|
||||||
acct := mv.SelectedAccount()
|
acct := mv.SelectedAccount()
|
||||||
|
if acct == nil {
|
||||||
|
return errors.New("No account selected")
|
||||||
|
}
|
||||||
store := mv.Store()
|
store := mv.Store()
|
||||||
err = account.ExecuteNextPrevMessage(args, acct, pct, n)
|
err = account.ExecuteNextPrevMessage(args, acct, pct, n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -309,6 +309,14 @@ func (aerc *Aerc) SelectedAccount() *AccountView {
|
||||||
return nil
|
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 {
|
func (aerc *Aerc) SelectedTab() ui.Drawable {
|
||||||
return aerc.tabs.Tabs[aerc.tabs.Selected].Content
|
return aerc.tabs.Tabs[aerc.tabs.Selected].Content
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,15 +127,15 @@ func (c *Composer) buildComposeHeader(aerc *Aerc, cmpl *completer.Completer) {
|
||||||
c.layout = aerc.conf.Compose.HeaderLayout
|
c.layout = aerc.conf.Compose.HeaderLayout
|
||||||
c.editors = make(map[string]*headerEditor)
|
c.editors = make(map[string]*headerEditor)
|
||||||
c.focusable = make([]ui.MouseableDrawableInteractive, 0)
|
c.focusable = make([]ui.MouseableDrawableInteractive, 0)
|
||||||
|
uiConfig := aerc.SelectedAccountUiConfig()
|
||||||
|
|
||||||
for i, row := range c.layout {
|
for i, row := range c.layout {
|
||||||
for j, h := range row {
|
for j, h := range row {
|
||||||
h = strings.ToLower(h)
|
h = strings.ToLower(h)
|
||||||
c.layout[i][j] = h // normalize to lowercase
|
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 {
|
if aerc.conf.Ui.CompletionPopovers {
|
||||||
e.input.TabComplete(cmpl.ForHeader(h),
|
e.input.TabComplete(cmpl.ForHeader(h), uiConfig.CompletionDelay)
|
||||||
aerc.SelectedAccount().UiConfig().CompletionDelay)
|
|
||||||
}
|
}
|
||||||
c.editors[h] = e
|
c.editors[h] = e
|
||||||
switch h {
|
switch h {
|
||||||
|
@ -152,9 +152,9 @@ func (c *Composer) buildComposeHeader(aerc *Aerc, cmpl *completer.Completer) {
|
||||||
for _, h := range []string{"cc", "bcc"} {
|
for _, h := range []string{"cc", "bcc"} {
|
||||||
if c.header.Has(h) {
|
if c.header.Has(h) {
|
||||||
if _, ok := c.editors[h]; !ok {
|
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 {
|
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.editors[h] = e
|
||||||
c.focusable = append(c.focusable, 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
|
e.storeValue() // flush modifications from the user to the header
|
||||||
editor = e
|
editor = e
|
||||||
} else {
|
} else {
|
||||||
e := newHeaderEditor(header, c.header,
|
uiConfig := c.aerc.SelectedAccountUiConfig()
|
||||||
c.aerc.SelectedAccount().UiConfig())
|
e := newHeaderEditor(header, c.header, uiConfig)
|
||||||
if c.config.Ui.CompletionPopovers {
|
if uiConfig.CompletionPopovers {
|
||||||
e.input.TabComplete(c.completer.ForHeader(header),
|
e.input.TabComplete(c.completer.ForHeader(header), uiConfig.CompletionDelay)
|
||||||
c.config.Ui.CompletionDelay)
|
|
||||||
}
|
}
|
||||||
c.editors[header] = e
|
c.editors[header] = e
|
||||||
c.layout = append(c.layout, []string{header})
|
c.layout = append(c.layout, []string{header})
|
||||||
|
|
|
@ -53,11 +53,13 @@ func (ml *MessageList) Invalidate() {
|
||||||
|
|
||||||
func (ml *MessageList) Draw(ctx *ui.Context) {
|
func (ml *MessageList) Draw(ctx *ui.Context) {
|
||||||
ml.height = ctx.Height()
|
ml.height = ctx.Height()
|
||||||
|
uiConfig := ml.aerc.SelectedAccountUiConfig()
|
||||||
ctx.Fill(0, 0, ctx.Width(), ctx.Height(), ' ',
|
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()
|
store := ml.Store()
|
||||||
if store == nil {
|
if store == nil || acct == nil {
|
||||||
if ml.isInitalizing {
|
if ml.isInitalizing {
|
||||||
ml.spinner.Draw(ctx)
|
ml.spinner.Draw(ctx)
|
||||||
return
|
return
|
||||||
|
@ -89,7 +91,7 @@ func (ml *MessageList) Draw(ctx *ui.Context) {
|
||||||
row int = 0
|
row int = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
if ml.aerc.SelectedAccount().UiConfig().ThreadingEnabled || store.BuildThreads() {
|
if uiConfig.ThreadingEnabled || store.BuildThreads() {
|
||||||
threads := store.Threads
|
threads := store.Threads
|
||||||
counter := len(store.Uids())
|
counter := len(store.Uids())
|
||||||
|
|
||||||
|
@ -119,8 +121,8 @@ func (ml *MessageList) Draw(ctx *ui.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fmtCtx := format.Ctx{
|
fmtCtx := format.Ctx{
|
||||||
FromAddress: ml.aerc.SelectedAccount().acct.From,
|
FromAddress: acct.acct.From,
|
||||||
AccountName: ml.aerc.SelectedAccount().Name(),
|
AccountName: acct.Name(),
|
||||||
MsgInfo: msg,
|
MsgInfo: msg,
|
||||||
MsgNum: row,
|
MsgNum: row,
|
||||||
MsgIsMarked: store.IsMarked(t.Uid),
|
MsgIsMarked: store.IsMarked(t.Uid),
|
||||||
|
@ -144,8 +146,8 @@ func (ml *MessageList) Draw(ctx *ui.Context) {
|
||||||
uid := uids[i]
|
uid := uids[i]
|
||||||
msg := store.Messages[uid]
|
msg := store.Messages[uid]
|
||||||
fmtCtx := format.Ctx{
|
fmtCtx := format.Ctx{
|
||||||
FromAddress: ml.aerc.SelectedAccount().acct.From,
|
FromAddress: acct.acct.From,
|
||||||
AccountName: ml.aerc.SelectedAccount().Name(),
|
AccountName: acct.Name(),
|
||||||
MsgInfo: msg,
|
MsgInfo: msg,
|
||||||
MsgNum: row,
|
MsgNum: row,
|
||||||
MsgIsMarked: store.IsMarked(uid),
|
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 {
|
func (ml *MessageList) drawRow(textWidth int, ctx *ui.Context, uid uint32, row int, needsHeaders *[]uint32, fmtCtx format.Ctx) bool {
|
||||||
store := ml.store
|
store := ml.store
|
||||||
msg := store.Messages[uid]
|
msg := store.Messages[uid]
|
||||||
|
acct := ml.aerc.SelectedAccount()
|
||||||
|
|
||||||
if row >= ctx.Height() {
|
if row >= ctx.Height() || acct == nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,8 +198,8 @@ func (ml *MessageList) drawRow(textWidth int, ctx *ui.Context, uid uint32, row i
|
||||||
}
|
}
|
||||||
|
|
||||||
confParams := map[config.ContextType]string{
|
confParams := map[config.ContextType]string{
|
||||||
config.UI_CONTEXT_ACCOUNT: ml.aerc.SelectedAccount().AccountConfig().Name,
|
config.UI_CONTEXT_ACCOUNT: acct.AccountConfig().Name,
|
||||||
config.UI_CONTEXT_FOLDER: ml.aerc.SelectedAccount().Directories().Selected(),
|
config.UI_CONTEXT_FOLDER: acct.Directories().Selected(),
|
||||||
}
|
}
|
||||||
if msg.Envelope != nil {
|
if msg.Envelope != nil {
|
||||||
confParams[config.UI_CONTEXT_SUBJECT] = msg.Envelope.Subject
|
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 {
|
if ok {
|
||||||
ml.Select(selectedMsg)
|
ml.Select(selectedMsg)
|
||||||
acct := ml.aerc.SelectedAccount()
|
acct := ml.aerc.SelectedAccount()
|
||||||
if acct.Messages().Empty() {
|
if acct == nil || acct.Messages().Empty() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
store := acct.Messages().Store()
|
store := acct.Messages().Store()
|
||||||
|
@ -433,7 +436,7 @@ func (ml *MessageList) ensureScroll() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ml *MessageList) drawEmptyMessage(ctx *ui.Context) {
|
func (ml *MessageList) drawEmptyMessage(ctx *ui.Context) {
|
||||||
uiConfig := ml.aerc.SelectedAccount().UiConfig()
|
uiConfig := ml.aerc.SelectedAccountUiConfig()
|
||||||
msg := uiConfig.EmptyMessage
|
msg := uiConfig.EmptyMessage
|
||||||
ctx.Printf((ctx.Width()/2)-(len(msg)/2), 0,
|
ctx.Printf((ctx.Width()/2)-(len(msg)/2), 0,
|
||||||
uiConfig.GetStyle(config.STYLE_MSGLIST_DEFAULT), "%s", msg)
|
uiConfig.GetStyle(config.STYLE_MSGLIST_DEFAULT), "%s", msg)
|
||||||
|
|
Loading…
Reference in a new issue