2019-01-13 18:39:06 +01:00
|
|
|
package widgets
|
|
|
|
|
|
|
|
import (
|
2019-07-10 02:04:21 +02:00
|
|
|
"errors"
|
2019-01-13 19:33:43 +01:00
|
|
|
"fmt"
|
2022-09-25 21:38:46 +02:00
|
|
|
"sync"
|
2022-03-18 22:35:33 +01:00
|
|
|
"time"
|
2019-01-13 19:25:56 +01:00
|
|
|
|
2020-11-30 23:07:03 +01:00
|
|
|
"github.com/gdamore/tcell/v2"
|
2019-01-13 19:03:28 +01:00
|
|
|
|
2021-11-05 10:19:46 +01:00
|
|
|
"git.sr.ht/~rjarry/aerc/config"
|
|
|
|
"git.sr.ht/~rjarry/aerc/lib"
|
2022-08-08 22:21:41 +02:00
|
|
|
"git.sr.ht/~rjarry/aerc/lib/marker"
|
2021-11-05 10:19:46 +01:00
|
|
|
"git.sr.ht/~rjarry/aerc/lib/sort"
|
2022-03-18 22:35:33 +01:00
|
|
|
"git.sr.ht/~rjarry/aerc/lib/statusline"
|
2021-11-05 10:19:46 +01:00
|
|
|
"git.sr.ht/~rjarry/aerc/lib/ui"
|
2022-03-22 09:52:27 +01:00
|
|
|
"git.sr.ht/~rjarry/aerc/logging"
|
2021-11-05 10:19:46 +01:00
|
|
|
"git.sr.ht/~rjarry/aerc/models"
|
|
|
|
"git.sr.ht/~rjarry/aerc/worker"
|
|
|
|
"git.sr.ht/~rjarry/aerc/worker/types"
|
2019-01-13 18:39:06 +01:00
|
|
|
)
|
|
|
|
|
2019-12-18 06:33:57 +01:00
|
|
|
var _ ProvidesMessages = (*AccountView)(nil)
|
|
|
|
|
2019-01-13 18:39:06 +01:00
|
|
|
type AccountView struct {
|
2022-09-25 21:38:46 +02:00
|
|
|
sync.Mutex
|
2019-07-21 23:39:36 +02:00
|
|
|
acct *config.AccountConfig
|
2019-09-06 00:32:36 +02:00
|
|
|
aerc *Aerc
|
2019-07-21 23:39:36 +02:00
|
|
|
conf *config.AercConfig
|
2022-02-21 00:18:42 +01:00
|
|
|
dirlist DirectoryLister
|
2019-12-21 16:21:25 +01:00
|
|
|
labels []string
|
2019-07-21 23:39:36 +02:00
|
|
|
grid *ui.Grid
|
|
|
|
host TabHost
|
|
|
|
msglist *MessageList
|
|
|
|
worker *types.Worker
|
2022-03-18 22:35:33 +01:00
|
|
|
state *statusline.State
|
2022-05-30 14:34:18 +02:00
|
|
|
newConn bool // True if this is a first run after a new connection/reconnection
|
2022-07-03 17:11:13 +02:00
|
|
|
uiConf *config.UIConfig
|
2022-07-29 20:30:02 +02:00
|
|
|
|
|
|
|
// Check-mail ticker
|
|
|
|
ticker *time.Ticker
|
|
|
|
checkingMail bool
|
2019-01-13 18:39:06 +01:00
|
|
|
}
|
|
|
|
|
2022-07-03 17:11:12 +02:00
|
|
|
func (acct *AccountView) UiConfig() *config.UIConfig {
|
2020-08-08 11:38:38 +02:00
|
|
|
if dirlist := acct.Directories(); dirlist != nil {
|
2022-08-12 21:51:25 +02:00
|
|
|
return dirlist.UiConfig("")
|
2020-08-08 11:38:38 +02:00
|
|
|
}
|
2022-07-03 17:11:13 +02:00
|
|
|
return acct.uiConf
|
2020-01-23 13:56:48 +01:00
|
|
|
}
|
|
|
|
|
2019-09-06 00:32:36 +02:00
|
|
|
func NewAccountView(aerc *Aerc, conf *config.AercConfig, acct *config.AccountConfig,
|
2022-07-19 22:31:51 +02:00
|
|
|
host TabHost, deferLoop chan struct{},
|
2022-03-24 10:47:34 +01:00
|
|
|
) (*AccountView, error) {
|
2020-01-24 18:18:49 +01:00
|
|
|
acctUiConf := conf.GetUiConfig(map[config.ContextType]string{
|
2020-01-23 13:56:48 +01:00
|
|
|
config.UI_CONTEXT_ACCOUNT: acct.Name,
|
|
|
|
})
|
|
|
|
|
2020-05-31 13:37:46 +02:00
|
|
|
view := &AccountView{
|
|
|
|
acct: acct,
|
|
|
|
aerc: aerc,
|
|
|
|
conf: conf,
|
|
|
|
host: host,
|
2022-04-18 16:06:27 +02:00
|
|
|
state: statusline.NewState(acct.Name, len(conf.Accounts) > 1, conf.Statusline),
|
2022-07-03 17:11:13 +02:00
|
|
|
uiConf: acctUiConf,
|
2020-05-31 13:37:46 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
view.grid = ui.NewGrid().Rows([]ui.GridSpec{
|
2022-03-18 09:53:02 +01:00
|
|
|
{Strategy: ui.SIZE_WEIGHT, Size: ui.Const(1)},
|
2019-01-13 18:39:06 +01:00
|
|
|
}).Columns([]ui.GridSpec{
|
2022-03-18 09:53:02 +01:00
|
|
|
{Strategy: ui.SIZE_EXACT, Size: func() int {
|
2020-05-31 13:37:46 +02:00
|
|
|
return view.UiConfig().SidebarWidth
|
|
|
|
}},
|
2022-03-18 09:53:02 +01:00
|
|
|
{Strategy: ui.SIZE_WEIGHT, Size: ui.Const(1)},
|
2019-01-13 18:39:06 +01:00
|
|
|
})
|
2019-01-13 19:25:56 +01:00
|
|
|
|
2022-07-19 22:31:51 +02:00
|
|
|
worker, err := worker.NewWorker(acct.Source)
|
2019-01-13 19:25:56 +01:00
|
|
|
if err != nil {
|
2020-07-27 10:03:55 +02:00
|
|
|
host.SetError(fmt.Sprintf("%s: %s", acct.Name, err))
|
2022-07-19 22:31:51 +02:00
|
|
|
logging.Errorf("%s: %v", acct.Name, err)
|
2020-08-08 11:38:38 +02:00
|
|
|
return view, err
|
2019-01-13 19:25:56 +01:00
|
|
|
}
|
2020-05-31 13:37:46 +02:00
|
|
|
view.worker = worker
|
2019-01-13 19:03:28 +01:00
|
|
|
|
2022-07-19 22:31:51 +02:00
|
|
|
view.dirlist = NewDirectoryList(conf, acct, worker)
|
2020-01-23 13:56:48 +01:00
|
|
|
if acctUiConf.SidebarWidth > 0 {
|
2020-07-27 10:03:55 +02:00
|
|
|
view.grid.AddChild(ui.NewBordered(view.dirlist, ui.BORDER_RIGHT, acctUiConf))
|
2019-06-05 23:20:27 +02:00
|
|
|
}
|
2019-01-13 20:25:46 +01:00
|
|
|
|
2022-07-19 22:31:51 +02:00
|
|
|
view.msglist = NewMessageList(conf, aerc)
|
2020-05-31 13:37:46 +02:00
|
|
|
view.grid.AddChild(view.msglist).At(0, 1)
|
2019-01-13 19:03:28 +01:00
|
|
|
|
2022-03-22 09:52:27 +01:00
|
|
|
go func() {
|
|
|
|
defer logging.PanicHandler()
|
|
|
|
|
2022-03-24 10:47:34 +01:00
|
|
|
if deferLoop != nil {
|
|
|
|
<-deferLoop
|
|
|
|
}
|
|
|
|
|
2022-03-22 09:52:27 +01:00
|
|
|
worker.Backend.Run()
|
|
|
|
}()
|
2019-01-13 19:03:28 +01:00
|
|
|
|
2019-03-15 06:46:14 +01:00
|
|
|
worker.PostAction(&types.Configure{Config: acct}, nil)
|
2021-11-01 21:38:26 +01:00
|
|
|
worker.PostAction(&types.Connect{}, nil)
|
2022-03-18 22:35:33 +01:00
|
|
|
view.SetStatus(statusline.ConnectionActivity("Connecting..."))
|
2022-05-30 14:34:18 +02:00
|
|
|
if acct.CheckMail.Minutes() > 0 {
|
|
|
|
view.CheckMailTimer(acct.CheckMail)
|
|
|
|
}
|
2019-01-13 19:03:28 +01:00
|
|
|
|
2020-08-08 11:38:38 +02:00
|
|
|
return view, nil
|
2019-01-13 19:03:28 +01:00
|
|
|
}
|
|
|
|
|
2019-05-19 11:49:57 +02:00
|
|
|
func (acct *AccountView) Tick() bool {
|
2019-05-21 01:20:20 +02:00
|
|
|
if acct.worker == nil {
|
|
|
|
return false
|
|
|
|
}
|
2019-05-19 11:49:57 +02:00
|
|
|
select {
|
|
|
|
case msg := <-acct.worker.Messages:
|
|
|
|
msg = acct.worker.ProcessMessage(msg)
|
|
|
|
acct.onMessage(msg)
|
|
|
|
return true
|
|
|
|
default:
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-18 22:35:33 +01:00
|
|
|
func (acct *AccountView) SetStatus(setters ...statusline.SetStateFunc) {
|
|
|
|
for _, fn := range setters {
|
2022-03-21 22:18:51 +01:00
|
|
|
fn(acct.state, acct.SelectedDirectory())
|
2022-03-18 22:35:33 +01:00
|
|
|
}
|
2022-03-21 22:18:51 +01:00
|
|
|
acct.UpdateStatus()
|
2022-03-18 22:35:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (acct *AccountView) UpdateStatus() {
|
2022-03-24 21:42:05 +01:00
|
|
|
if acct.isSelected() {
|
|
|
|
acct.host.SetStatus(acct.state.StatusLine(acct.SelectedDirectory()))
|
|
|
|
}
|
2022-03-18 22:35:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (acct *AccountView) PushStatus(status string, expiry time.Duration) {
|
2022-07-19 22:31:51 +02:00
|
|
|
acct.aerc.PushStatus(fmt.Sprintf("%s: %s", acct.acct.Name, status), expiry)
|
2022-03-18 22:35:33 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (acct *AccountView) PushError(err error) {
|
|
|
|
acct.aerc.PushError(fmt.Sprintf("%s: %v", acct.acct.Name, err))
|
2021-11-01 21:38:26 +01:00
|
|
|
}
|
|
|
|
|
2019-05-13 22:04:01 +02:00
|
|
|
func (acct *AccountView) AccountConfig() *config.AccountConfig {
|
|
|
|
return acct.acct
|
|
|
|
}
|
|
|
|
|
2019-05-16 18:15:34 +02:00
|
|
|
func (acct *AccountView) Worker() *types.Worker {
|
|
|
|
return acct.worker
|
|
|
|
}
|
|
|
|
|
2019-03-15 03:34:34 +01:00
|
|
|
func (acct *AccountView) Name() string {
|
2019-03-15 06:46:14 +01:00
|
|
|
return acct.acct.Name
|
2019-03-15 03:34:34 +01:00
|
|
|
}
|
|
|
|
|
2019-01-13 18:39:06 +01:00
|
|
|
func (acct *AccountView) OnInvalidate(onInvalidate func(d ui.Drawable)) {
|
2019-01-13 19:25:56 +01:00
|
|
|
acct.grid.OnInvalidate(func(_ ui.Drawable) {
|
|
|
|
onInvalidate(acct)
|
|
|
|
})
|
2019-01-13 18:39:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (acct *AccountView) Invalidate() {
|
|
|
|
acct.grid.Invalidate()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (acct *AccountView) Draw(ctx *ui.Context) {
|
2022-04-18 16:06:27 +02:00
|
|
|
if acct.state.SetWidth(ctx.Width()) {
|
|
|
|
acct.UpdateStatus()
|
|
|
|
}
|
2019-01-13 18:39:06 +01:00
|
|
|
acct.grid.Draw(ctx)
|
|
|
|
}
|
2019-01-13 19:33:43 +01:00
|
|
|
|
2019-09-06 00:32:36 +02:00
|
|
|
func (acct *AccountView) MouseEvent(localX int, localY int, event tcell.Event) {
|
|
|
|
acct.grid.MouseEvent(localX, localY, event)
|
|
|
|
}
|
|
|
|
|
2019-03-17 21:19:15 +01:00
|
|
|
func (acct *AccountView) Focus(focus bool) {
|
|
|
|
// TODO: Unfocus children I guess
|
2019-01-13 19:33:43 +01:00
|
|
|
}
|
2019-01-13 20:25:46 +01:00
|
|
|
|
2022-02-21 00:18:42 +01:00
|
|
|
func (acct *AccountView) Directories() DirectoryLister {
|
2019-03-11 02:15:24 +01:00
|
|
|
return acct.dirlist
|
|
|
|
}
|
|
|
|
|
2019-12-21 16:21:25 +01:00
|
|
|
func (acct *AccountView) Labels() []string {
|
|
|
|
return acct.labels
|
|
|
|
}
|
|
|
|
|
2019-03-15 04:41:25 +01:00
|
|
|
func (acct *AccountView) Messages() *MessageList {
|
|
|
|
return acct.msglist
|
|
|
|
}
|
|
|
|
|
2019-06-02 07:15:04 +02:00
|
|
|
func (acct *AccountView) Store() *lib.MessageStore {
|
2019-08-08 12:48:51 +02:00
|
|
|
if acct.msglist == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2019-06-02 07:15:04 +02:00
|
|
|
return acct.msglist.Store()
|
|
|
|
}
|
|
|
|
|
2019-07-05 18:21:12 +02:00
|
|
|
func (acct *AccountView) SelectedAccount() *AccountView {
|
|
|
|
return acct
|
|
|
|
}
|
|
|
|
|
2020-04-24 11:42:22 +02:00
|
|
|
func (acct *AccountView) SelectedDirectory() string {
|
|
|
|
return acct.dirlist.Selected()
|
|
|
|
}
|
|
|
|
|
2019-07-10 02:04:21 +02:00
|
|
|
func (acct *AccountView) SelectedMessage() (*models.MessageInfo, error) {
|
2019-07-17 09:35:50 +02:00
|
|
|
if len(acct.msglist.Store().Uids()) == 0 {
|
2019-07-10 02:04:21 +02:00
|
|
|
return nil, errors.New("no message selected")
|
|
|
|
}
|
2019-09-10 15:53:40 +02:00
|
|
|
msg := acct.msglist.Selected()
|
|
|
|
if msg == nil {
|
|
|
|
return nil, errors.New("message not loaded")
|
|
|
|
}
|
|
|
|
return msg, nil
|
2019-06-02 07:15:04 +02:00
|
|
|
}
|
|
|
|
|
2020-05-09 11:50:31 +02:00
|
|
|
func (acct *AccountView) MarkedMessages() ([]uint32, error) {
|
2022-08-08 22:21:41 +02:00
|
|
|
if store := acct.Store(); store != nil {
|
|
|
|
return store.Marker().Marked(), nil
|
|
|
|
}
|
|
|
|
return nil, errors.New("no store available")
|
2019-12-18 06:33:57 +01:00
|
|
|
}
|
|
|
|
|
2019-07-05 18:21:12 +02:00
|
|
|
func (acct *AccountView) SelectedMessagePart() *PartInfo {
|
|
|
|
return nil
|
2019-06-02 07:15:04 +02:00
|
|
|
}
|
|
|
|
|
2022-03-24 21:42:05 +01:00
|
|
|
func (acct *AccountView) isSelected() bool {
|
2022-07-14 18:29:56 +02:00
|
|
|
return acct == acct.aerc.SelectedAccount()
|
2022-03-24 21:42:05 +01:00
|
|
|
}
|
|
|
|
|
2019-03-11 02:15:24 +01:00
|
|
|
func (acct *AccountView) onMessage(msg types.WorkerMessage) {
|
2019-03-11 04:45:00 +01:00
|
|
|
switch msg := msg.(type) {
|
|
|
|
case *types.Done:
|
|
|
|
switch msg.InResponseTo().(type) {
|
2022-01-19 13:18:10 +01:00
|
|
|
case *types.Connect, *types.Reconnect:
|
2022-03-18 22:35:33 +01:00
|
|
|
acct.SetStatus(statusline.ConnectionActivity("Listing mailboxes..."))
|
2022-07-19 22:31:51 +02:00
|
|
|
logging.Debugf("Listing mailboxes...")
|
2021-11-01 21:38:26 +01:00
|
|
|
acct.dirlist.UpdateList(func(dirs []string) {
|
|
|
|
var dir string
|
|
|
|
for _, _dir := range dirs {
|
|
|
|
if _dir == acct.acct.Default {
|
|
|
|
dir = _dir
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if dir == "" && len(dirs) > 0 {
|
|
|
|
dir = dirs[0]
|
|
|
|
}
|
|
|
|
if dir != "" {
|
|
|
|
acct.dirlist.Select(dir)
|
|
|
|
}
|
|
|
|
acct.msglist.SetInitDone()
|
2022-07-19 22:31:51 +02:00
|
|
|
logging.Infof("%s connected.", acct.acct.Name)
|
2022-05-30 14:34:18 +02:00
|
|
|
acct.SetStatus(statusline.SetConnected(true))
|
|
|
|
acct.newConn = true
|
2021-11-01 21:38:26 +01:00
|
|
|
})
|
|
|
|
case *types.Disconnect:
|
2022-06-07 17:59:05 +02:00
|
|
|
acct.dirlist.ClearList()
|
2021-11-01 21:38:26 +01:00
|
|
|
acct.msglist.SetStore(nil)
|
2022-07-19 22:31:51 +02:00
|
|
|
logging.Infof("%s disconnected.", acct.acct.Name)
|
2022-05-30 14:34:18 +02:00
|
|
|
acct.SetStatus(statusline.SetConnected(false))
|
2019-03-11 04:45:00 +01:00
|
|
|
case *types.OpenDirectory:
|
2019-07-21 23:39:36 +02:00
|
|
|
if store, ok := acct.dirlist.SelectedMsgStore(); ok {
|
2019-03-15 03:41:43 +01:00
|
|
|
// If we've opened this dir before, we can re-render it from
|
|
|
|
// memory while we wait for the update and the UI feels
|
|
|
|
// snappier. If not, we'll unset the store and show the spinner
|
|
|
|
// while we download the UID list.
|
|
|
|
acct.msglist.SetStore(store)
|
|
|
|
} else {
|
|
|
|
acct.msglist.SetStore(nil)
|
|
|
|
}
|
2019-06-08 19:41:56 +02:00
|
|
|
case *types.CreateDirectory:
|
|
|
|
acct.dirlist.UpdateList(nil)
|
2020-08-18 22:27:23 +02:00
|
|
|
case *types.RemoveDirectory:
|
|
|
|
acct.dirlist.UpdateList(nil)
|
2022-05-30 14:34:18 +02:00
|
|
|
case *types.FetchMessageHeaders:
|
2022-07-25 21:32:28 +02:00
|
|
|
if acct.newConn {
|
|
|
|
acct.checkMailOnStartup()
|
2022-05-30 14:34:18 +02:00
|
|
|
}
|
2019-03-11 04:45:00 +01:00
|
|
|
}
|
|
|
|
case *types.DirectoryInfo:
|
2019-07-21 23:39:36 +02:00
|
|
|
if store, ok := acct.dirlist.MsgStore(msg.Info.Name); ok {
|
2019-03-11 04:45:00 +01:00
|
|
|
store.Update(msg)
|
|
|
|
} else {
|
2022-08-12 21:51:25 +02:00
|
|
|
name := msg.Info.Name
|
2019-07-21 22:01:51 +02:00
|
|
|
store = lib.NewMessageStore(acct.worker, msg.Info,
|
2022-03-24 23:12:14 +01:00
|
|
|
acct.GetSortCriteria(),
|
2022-08-12 21:51:25 +02:00
|
|
|
acct.dirlist.UiConfig(name).ThreadingEnabled,
|
|
|
|
acct.dirlist.UiConfig(name).ForceClientThreads,
|
|
|
|
acct.dirlist.UiConfig(name).ClientThreadsDelay,
|
2019-07-21 22:01:51 +02:00
|
|
|
func(msg *models.MessageInfo) {
|
|
|
|
acct.conf.Triggers.ExecNewEmail(acct.acct,
|
|
|
|
acct.conf, msg)
|
2019-07-29 16:50:02 +02:00
|
|
|
}, func() {
|
2022-08-12 21:51:25 +02:00
|
|
|
if acct.dirlist.UiConfig(name).NewMessageBell {
|
2019-07-29 16:50:02 +02:00
|
|
|
acct.host.Beep()
|
|
|
|
}
|
2019-07-21 22:01:51 +02:00
|
|
|
})
|
2022-08-08 22:21:41 +02:00
|
|
|
store.SetMarker(marker.New(store))
|
2019-07-21 23:39:36 +02:00
|
|
|
acct.dirlist.SetMsgStore(msg.Info.Name, store)
|
2019-03-11 04:45:00 +01:00
|
|
|
}
|
|
|
|
case *types.DirectoryContents:
|
2019-07-21 23:39:36 +02:00
|
|
|
if store, ok := acct.dirlist.SelectedMsgStore(); ok {
|
2020-02-29 02:53:32 +01:00
|
|
|
if acct.msglist.Store() == nil {
|
|
|
|
acct.msglist.SetStore(store)
|
|
|
|
}
|
2019-06-02 10:48:03 +02:00
|
|
|
store.Update(msg)
|
2022-07-05 21:48:35 +02:00
|
|
|
acct.SetStatus(statusline.Threading(store.ThreadedView()))
|
2019-06-02 10:48:03 +02:00
|
|
|
}
|
2022-07-25 21:32:28 +02:00
|
|
|
if acct.newConn && len(msg.Uids) == 0 {
|
|
|
|
acct.checkMailOnStartup()
|
|
|
|
}
|
2021-11-12 18:12:02 +01:00
|
|
|
case *types.DirectoryThreaded:
|
|
|
|
if store, ok := acct.dirlist.SelectedMsgStore(); ok {
|
|
|
|
if acct.msglist.Store() == nil {
|
|
|
|
acct.msglist.SetStore(store)
|
|
|
|
}
|
|
|
|
store.Update(msg)
|
2022-07-05 21:48:35 +02:00
|
|
|
acct.SetStatus(statusline.Threading(store.ThreadedView()))
|
2021-11-12 18:12:02 +01:00
|
|
|
}
|
2022-07-25 21:32:28 +02:00
|
|
|
if acct.newConn && len(msg.Threads) == 0 {
|
|
|
|
acct.checkMailOnStartup()
|
|
|
|
}
|
2019-03-31 18:35:51 +02:00
|
|
|
case *types.FullMessage:
|
2019-07-21 23:39:36 +02:00
|
|
|
if store, ok := acct.dirlist.SelectedMsgStore(); ok {
|
2019-06-02 10:48:03 +02:00
|
|
|
store.Update(msg)
|
|
|
|
}
|
2019-03-11 04:45:00 +01:00
|
|
|
case *types.MessageInfo:
|
2019-07-21 23:39:36 +02:00
|
|
|
if store, ok := acct.dirlist.SelectedMsgStore(); ok {
|
2019-06-02 10:48:03 +02:00
|
|
|
store.Update(msg)
|
|
|
|
}
|
2019-03-21 04:23:38 +01:00
|
|
|
case *types.MessagesDeleted:
|
2019-07-21 23:39:36 +02:00
|
|
|
if store, ok := acct.dirlist.SelectedMsgStore(); ok {
|
2022-06-02 02:24:53 +02:00
|
|
|
store.DirInfo.Exists -= len(msg.Uids)
|
|
|
|
// False to trigger recount of recent/unseen
|
|
|
|
store.DirInfo.AccurateCounts = false
|
2019-06-02 10:48:03 +02:00
|
|
|
store.Update(msg)
|
|
|
|
}
|
2022-06-02 02:24:53 +02:00
|
|
|
case *types.MessagesCopied:
|
2022-08-16 23:23:41 +02:00
|
|
|
acct.updateDirCounts(msg.Destination, msg.Uids)
|
|
|
|
case *types.MessagesMoved:
|
|
|
|
acct.updateDirCounts(msg.Destination, msg.Uids)
|
2019-12-21 16:21:25 +01:00
|
|
|
case *types.LabelList:
|
|
|
|
acct.labels = msg.Labels
|
2022-01-19 13:18:09 +01:00
|
|
|
case *types.ConnError:
|
2022-07-19 22:31:51 +02:00
|
|
|
logging.Errorf("%s connection error: %v", acct.acct.Name, msg.Error)
|
2022-05-30 14:34:18 +02:00
|
|
|
acct.SetStatus(statusline.SetConnected(false))
|
2022-03-18 22:35:33 +01:00
|
|
|
acct.PushError(msg.Error)
|
2022-02-05 00:07:16 +01:00
|
|
|
acct.msglist.SetStore(nil)
|
2022-01-19 13:18:10 +01:00
|
|
|
acct.worker.PostAction(&types.Reconnect{}, nil)
|
2019-03-11 04:45:00 +01:00
|
|
|
case *types.Error:
|
2022-07-19 22:31:51 +02:00
|
|
|
logging.Errorf("%s unexpected error: %v", acct.acct.Name, msg.Error)
|
2022-03-18 22:35:33 +01:00
|
|
|
acct.PushError(msg.Error)
|
2019-03-11 04:45:00 +01:00
|
|
|
}
|
2022-03-21 22:18:51 +01:00
|
|
|
acct.UpdateStatus()
|
2019-03-11 02:15:24 +01:00
|
|
|
}
|
2019-09-20 00:37:44 +02:00
|
|
|
|
2022-08-16 23:23:41 +02:00
|
|
|
func (acct *AccountView) updateDirCounts(destination string, uids []uint32) {
|
|
|
|
// Only update the destination destStore if it is initialized
|
|
|
|
if destStore, ok := acct.dirlist.MsgStore(destination); ok {
|
|
|
|
var recent, unseen int
|
|
|
|
var accurate bool = true
|
|
|
|
for _, uid := range uids {
|
|
|
|
// Get the message from the originating store
|
|
|
|
msg, ok := acct.Store().Messages[uid]
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
// If message that was not yet loaded is copied
|
|
|
|
if msg == nil {
|
|
|
|
accurate = false
|
|
|
|
break
|
|
|
|
}
|
|
|
|
seen := false
|
|
|
|
for _, flag := range msg.Flags {
|
|
|
|
if flag == models.SeenFlag {
|
|
|
|
seen = true
|
|
|
|
}
|
|
|
|
if flag == models.RecentFlag {
|
|
|
|
recent++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !seen {
|
|
|
|
unseen++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if accurate {
|
|
|
|
destStore.DirInfo.Recent += recent
|
|
|
|
destStore.DirInfo.Unseen += unseen
|
|
|
|
destStore.DirInfo.Exists += len(uids)
|
|
|
|
// True. For imap, we don't have the message in the store until we
|
|
|
|
// Select so we need to rely on the math we just did for accurate
|
|
|
|
// counts
|
|
|
|
destStore.DirInfo.AccurateCounts = true
|
|
|
|
} else {
|
|
|
|
destStore.DirInfo.Exists += len(uids)
|
|
|
|
// False to trigger recount of recent/unseen
|
|
|
|
destStore.DirInfo.AccurateCounts = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-24 23:12:14 +01:00
|
|
|
func (acct *AccountView) GetSortCriteria() []*types.SortCriterion {
|
2020-01-23 13:56:48 +01:00
|
|
|
if len(acct.UiConfig().Sort) == 0 {
|
2019-09-20 00:37:44 +02:00
|
|
|
return nil
|
|
|
|
}
|
2020-01-23 13:56:48 +01:00
|
|
|
criteria, err := sort.GetSortCriteria(acct.UiConfig().Sort)
|
2019-09-20 00:37:44 +02:00
|
|
|
if err != nil {
|
2022-07-31 15:15:27 +02:00
|
|
|
acct.PushError(fmt.Errorf("ui sort: %w", err))
|
2019-09-20 00:37:44 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return criteria
|
|
|
|
}
|
2022-05-30 14:34:18 +02:00
|
|
|
|
|
|
|
func (acct *AccountView) CheckMail() {
|
2022-09-25 21:38:46 +02:00
|
|
|
acct.Lock()
|
|
|
|
defer acct.Unlock()
|
2022-07-29 20:30:02 +02:00
|
|
|
if acct.checkingMail {
|
|
|
|
return
|
|
|
|
}
|
2022-05-30 14:34:18 +02:00
|
|
|
// Exclude selected mailbox, per IMAP specification
|
2022-07-31 14:32:48 +02:00
|
|
|
exclude := append(acct.AccountConfig().CheckMailExclude, acct.dirlist.Selected()) //nolint:gocritic // intentional append to different slice
|
2022-05-30 14:34:18 +02:00
|
|
|
dirs := acct.dirlist.List()
|
|
|
|
dirs = acct.dirlist.FilterDirs(dirs, acct.AccountConfig().CheckMailInclude, false)
|
|
|
|
dirs = acct.dirlist.FilterDirs(dirs, exclude, true)
|
2022-07-19 22:31:51 +02:00
|
|
|
logging.Infof("Checking for new mail on account %s", acct.Name())
|
2022-05-30 14:34:18 +02:00
|
|
|
acct.SetStatus(statusline.ConnectionActivity("Checking for new mail..."))
|
|
|
|
msg := &types.CheckMail{
|
|
|
|
Directories: dirs,
|
|
|
|
Command: acct.acct.CheckMailCmd,
|
|
|
|
Timeout: acct.acct.CheckMailTimeout,
|
|
|
|
}
|
2022-07-29 20:30:02 +02:00
|
|
|
acct.checkingMail = true
|
2022-05-30 14:34:18 +02:00
|
|
|
acct.worker.PostAction(msg, func(_ types.WorkerMessage) {
|
|
|
|
acct.SetStatus(statusline.ConnectionActivity(""))
|
2022-09-25 21:38:46 +02:00
|
|
|
acct.Lock()
|
2022-07-29 20:30:02 +02:00
|
|
|
acct.checkingMail = false
|
2022-09-25 21:38:46 +02:00
|
|
|
acct.Unlock()
|
2022-05-30 14:34:18 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-07-29 20:30:02 +02:00
|
|
|
// CheckMailReset resets the check-mail timer
|
|
|
|
func (acct *AccountView) CheckMailReset() {
|
|
|
|
if acct.ticker != nil {
|
|
|
|
d := acct.AccountConfig().CheckMail
|
|
|
|
acct.ticker = time.NewTicker(d)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-25 21:32:28 +02:00
|
|
|
func (acct *AccountView) checkMailOnStartup() {
|
|
|
|
if acct.AccountConfig().CheckMail.Minutes() > 0 {
|
|
|
|
acct.newConn = false
|
|
|
|
acct.CheckMail()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-30 14:34:18 +02:00
|
|
|
func (acct *AccountView) CheckMailTimer(d time.Duration) {
|
2022-07-29 20:30:02 +02:00
|
|
|
acct.ticker = time.NewTicker(d)
|
2022-05-30 14:34:18 +02:00
|
|
|
go func() {
|
2022-07-29 20:30:02 +02:00
|
|
|
for range acct.ticker.C {
|
2022-05-30 14:34:18 +02:00
|
|
|
if !acct.state.Connected() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
acct.CheckMail()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|