2019-06-09 20:55:34 +02:00
|
|
|
package msg
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
2019-12-22 12:05:28 +01:00
|
|
|
"sync"
|
2020-05-28 16:32:32 +02:00
|
|
|
"time"
|
2019-06-09 20:55:34 +02:00
|
|
|
|
2019-07-15 19:51:07 +02:00
|
|
|
"git.sr.ht/~sircmpwn/getopt"
|
|
|
|
|
2019-12-22 12:05:28 +01:00
|
|
|
"git.sr.ht/~sircmpwn/aerc/lib"
|
2019-07-15 19:51:07 +02:00
|
|
|
"git.sr.ht/~sircmpwn/aerc/models"
|
2019-06-09 20:55:34 +02:00
|
|
|
"git.sr.ht/~sircmpwn/aerc/widgets"
|
|
|
|
"git.sr.ht/~sircmpwn/aerc/worker/types"
|
|
|
|
)
|
|
|
|
|
2019-06-27 19:33:11 +02:00
|
|
|
type Read struct{}
|
|
|
|
|
2019-06-09 20:55:34 +02:00
|
|
|
func init() {
|
2019-06-27 19:33:11 +02:00
|
|
|
register(Read{})
|
|
|
|
}
|
|
|
|
|
2019-09-03 21:34:03 +02:00
|
|
|
func (Read) Aliases() []string {
|
2019-06-27 19:33:11 +02:00
|
|
|
return []string{"read", "unread"}
|
|
|
|
}
|
|
|
|
|
2019-09-03 21:34:03 +02:00
|
|
|
func (Read) Complete(aerc *widgets.Aerc, args []string) []string {
|
2019-06-27 19:33:11 +02:00
|
|
|
return nil
|
2019-06-09 20:55:34 +02:00
|
|
|
}
|
|
|
|
|
2019-09-03 21:34:03 +02:00
|
|
|
func (Read) Execute(aerc *widgets.Aerc, args []string) error {
|
2019-07-15 19:51:07 +02:00
|
|
|
opts, optind, err := getopt.Getopts(args, "t")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if optind != len(args) {
|
2019-07-23 20:46:32 +02:00
|
|
|
return errors.New("Usage: " + args[0] + " [-t]")
|
2019-07-15 19:51:07 +02:00
|
|
|
}
|
|
|
|
var toggle bool
|
|
|
|
|
|
|
|
for _, opt := range opts {
|
|
|
|
switch opt.Option {
|
|
|
|
case 't':
|
|
|
|
toggle = true
|
|
|
|
}
|
2019-06-09 20:55:34 +02:00
|
|
|
}
|
|
|
|
|
2019-12-22 12:05:28 +01:00
|
|
|
h := newHelper(aerc)
|
|
|
|
store, err := h.store()
|
2019-07-10 02:04:21 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-12-22 12:05:28 +01:00
|
|
|
|
2019-07-15 19:51:07 +02:00
|
|
|
if toggle {
|
2020-05-20 02:48:23 +02:00
|
|
|
// ignore command given, simply toggle all the read states
|
2019-12-22 12:05:28 +01:00
|
|
|
return submitToggle(aerc, store, h)
|
|
|
|
}
|
2020-05-09 11:50:30 +02:00
|
|
|
msgUids, err := h.markedOrSelectedUids()
|
2019-12-22 12:05:28 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
switch args[0] {
|
|
|
|
case "read":
|
|
|
|
submitReadChange(aerc, store, msgUids, true)
|
|
|
|
case "unread":
|
|
|
|
submitReadChange(aerc, store, msgUids, false)
|
|
|
|
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func splitMessages(msgs []*models.MessageInfo) (read []uint32, unread []uint32) {
|
|
|
|
for _, m := range msgs {
|
|
|
|
var seen bool
|
|
|
|
for _, flag := range m.Flags {
|
2019-07-15 19:51:07 +02:00
|
|
|
if flag == models.SeenFlag {
|
2019-12-22 12:05:28 +01:00
|
|
|
seen = true
|
|
|
|
break
|
2019-07-15 19:51:07 +02:00
|
|
|
}
|
|
|
|
}
|
2019-12-22 12:05:28 +01:00
|
|
|
if seen {
|
|
|
|
read = append(read, m.Uid)
|
|
|
|
} else {
|
|
|
|
unread = append(unread, m.Uid)
|
|
|
|
}
|
2019-07-15 19:51:07 +02:00
|
|
|
}
|
2019-12-22 12:05:28 +01:00
|
|
|
return read, unread
|
|
|
|
}
|
2019-06-09 20:55:34 +02:00
|
|
|
|
2019-12-22 12:05:28 +01:00
|
|
|
func submitReadChange(aerc *widgets.Aerc, store *lib.MessageStore,
|
|
|
|
uids []uint32, newState bool) {
|
|
|
|
store.Read(uids, newState, func(msg types.WorkerMessage) {
|
2019-06-09 20:55:34 +02:00
|
|
|
switch msg := msg.(type) {
|
|
|
|
case *types.Done:
|
2020-05-28 16:32:32 +02:00
|
|
|
aerc.PushStatus(msg_success, 10*time.Second)
|
2019-06-09 20:55:34 +02:00
|
|
|
case *types.Error:
|
2020-05-28 16:32:42 +02:00
|
|
|
aerc.PushError(" " + msg.Error.Error())
|
2019-06-09 20:55:34 +02:00
|
|
|
}
|
|
|
|
})
|
2019-12-22 12:05:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func submitReadChangeWg(aerc *widgets.Aerc, store *lib.MessageStore,
|
2020-05-07 00:36:52 +02:00
|
|
|
uids []uint32, newState bool, wg *sync.WaitGroup, success *bool) {
|
2019-12-22 12:05:28 +01:00
|
|
|
store.Read(uids, newState, func(msg types.WorkerMessage) {
|
|
|
|
wg.Add(1)
|
|
|
|
switch msg := msg.(type) {
|
|
|
|
case *types.Done:
|
|
|
|
wg.Done()
|
|
|
|
case *types.Error:
|
2020-05-28 16:32:42 +02:00
|
|
|
aerc.PushError(" " + msg.Error.Error())
|
2019-12-22 12:05:28 +01:00
|
|
|
*success = false
|
|
|
|
wg.Done()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func submitToggle(aerc *widgets.Aerc, store *lib.MessageStore, h *helper) error {
|
|
|
|
msgs, err := h.messages()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
read, unread := splitMessages(msgs)
|
|
|
|
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
success := true
|
|
|
|
|
|
|
|
if len(read) != 0 {
|
|
|
|
newState := false
|
2020-05-07 00:36:52 +02:00
|
|
|
submitReadChangeWg(aerc, store, read, newState, &wg, &success)
|
2019-12-22 12:05:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if len(unread) != 0 {
|
|
|
|
newState := true
|
2020-05-07 00:36:52 +02:00
|
|
|
submitReadChangeWg(aerc, store, unread, newState, &wg, &success)
|
2019-12-22 12:05:28 +01:00
|
|
|
}
|
|
|
|
// we need to do that in the background, else we block the main thread
|
|
|
|
go func() {
|
|
|
|
wg.Wait()
|
|
|
|
if success {
|
2020-05-28 16:32:32 +02:00
|
|
|
aerc.PushStatus(msg_success, 10*time.Second)
|
2019-12-22 12:05:28 +01:00
|
|
|
}
|
|
|
|
}()
|
2019-06-09 20:55:34 +02:00
|
|
|
return nil
|
2019-12-22 12:05:28 +01:00
|
|
|
|
2019-06-09 20:55:34 +02:00
|
|
|
}
|
2019-12-22 12:05:28 +01:00
|
|
|
|
|
|
|
const msg_success = "read state set successfully"
|