0c85b5a6cf
Archive, delete, and move all remove messages from the message store. The commands themselves invalidated the message list. The message list was also invalidated for every MessagesDeleted message received. Remove the call in the command logic to reduce redraws of the message list Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Robin Jarry <robin@jarry.cc>
121 lines
2.5 KiB
Go
121 lines
2.5 KiB
Go
package msg
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"path"
|
|
"sync"
|
|
"time"
|
|
|
|
"git.sr.ht/~rjarry/aerc/commands"
|
|
"git.sr.ht/~rjarry/aerc/logging"
|
|
"git.sr.ht/~rjarry/aerc/models"
|
|
"git.sr.ht/~rjarry/aerc/widgets"
|
|
"git.sr.ht/~rjarry/aerc/worker/types"
|
|
)
|
|
|
|
const (
|
|
ARCHIVE_FLAT = "flat"
|
|
ARCHIVE_YEAR = "year"
|
|
ARCHIVE_MONTH = "month"
|
|
)
|
|
|
|
type Archive struct{}
|
|
|
|
func init() {
|
|
register(Archive{})
|
|
}
|
|
|
|
func (Archive) Aliases() []string {
|
|
return []string{"archive"}
|
|
}
|
|
|
|
func (Archive) Complete(aerc *widgets.Aerc, args []string) []string {
|
|
valid := []string{"flat", "year", "month"}
|
|
return commands.CompletionFromList(aerc, valid, args)
|
|
}
|
|
|
|
func (Archive) Execute(aerc *widgets.Aerc, args []string) error {
|
|
if len(args) != 2 {
|
|
return errors.New("Usage: archive <flat|year|month>")
|
|
}
|
|
h := newHelper(aerc)
|
|
acct, err := h.account()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
store, err := h.store()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
msgs, err := h.messages()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
archiveDir := acct.AccountConfig().Archive
|
|
var uids []uint32
|
|
for _, msg := range msgs {
|
|
uids = append(uids, msg.Uid)
|
|
}
|
|
store.ClearVisualMark()
|
|
findNextNonDeleted(uids, store)
|
|
|
|
var uidMap map[string][]uint32
|
|
switch args[1] {
|
|
case ARCHIVE_MONTH:
|
|
uidMap = groupBy(msgs, func(msg *models.MessageInfo) string {
|
|
dir := path.Join(archiveDir,
|
|
fmt.Sprintf("%d", msg.Envelope.Date.Year()),
|
|
fmt.Sprintf("%02d", msg.Envelope.Date.Month()))
|
|
return dir
|
|
})
|
|
case ARCHIVE_YEAR:
|
|
uidMap = groupBy(msgs, func(msg *models.MessageInfo) string {
|
|
dir := path.Join(archiveDir, fmt.Sprintf("%v",
|
|
msg.Envelope.Date.Year()))
|
|
return dir
|
|
})
|
|
case ARCHIVE_FLAT:
|
|
uidMap = make(map[string][]uint32)
|
|
uidMap[archiveDir] = commands.UidsFromMessageInfos(msgs)
|
|
}
|
|
|
|
var wg sync.WaitGroup
|
|
wg.Add(len(uidMap))
|
|
success := true
|
|
|
|
for dir, uids := range uidMap {
|
|
store.Move(uids, dir, true, func(
|
|
msg types.WorkerMessage) {
|
|
switch msg := msg.(type) {
|
|
case *types.Done:
|
|
wg.Done()
|
|
case *types.Error:
|
|
aerc.PushError(msg.Error.Error())
|
|
success = false
|
|
wg.Done()
|
|
store.Remark()
|
|
}
|
|
})
|
|
}
|
|
// we need to do that in the background, else we block the main thread
|
|
go func() {
|
|
defer logging.PanicHandler()
|
|
|
|
wg.Wait()
|
|
if success {
|
|
aerc.PushStatus("Messages archived.", 10*time.Second)
|
|
}
|
|
}()
|
|
return nil
|
|
}
|
|
|
|
func groupBy(msgs []*models.MessageInfo,
|
|
grouper func(*models.MessageInfo) string) map[string][]uint32 {
|
|
m := make(map[string][]uint32)
|
|
for _, msg := range msgs {
|
|
group := grouper(msg)
|
|
m[group] = append(m[group], msg.Uid)
|
|
}
|
|
return m
|
|
}
|