papero/imaputils/set_flags.go
2021-04-05 19:49:39 +02:00

241 lines
4.6 KiB
Go

package imaputils
import (
"errors"
"fmt"
"git.sr.ht/~blallo/papero/config"
"github.com/emersion/go-imap"
)
type tristate int
const (
undef tristate = 0
doSet tristate = 1
doUnset tristate = 2
)
func (t tristate) IsSet() bool {
switch t {
case undef:
return false
case doSet:
return true
case doUnset:
return false
default:
panic(errors.New(fmt.Sprintf("unexpected tristate value %d", t)))
}
}
func (t tristate) IsUnset() bool {
switch t {
case undef:
return false
case doSet:
return false
case doUnset:
return true
default:
panic(errors.New(fmt.Sprintf("unexpected tristate value %d", t)))
}
}
func (t tristate) String() string {
switch t {
case undef:
return "undef"
case doSet:
return "set"
case doUnset:
return "unset"
}
panic("unexpected value for tristate")
}
type FlagsStatus struct {
FlagSeen tristate
FlagAnswered tristate
FlagFlagged tristate
FlagDeleted tristate
FlagDraft tristate
//FlagUnknown bool
}
func NewFlagsStatus() *FlagsStatus {
return &FlagsStatus{
undef,
undef,
undef,
undef,
undef,
}
}
func (f *FlagsStatus) IntoSetFlagList() []interface{} {
var result []interface{}
switch {
case f.FlagSeen.IsSet():
result = append(result, imap.SeenFlag)
case f.FlagAnswered.IsSet():
result = append(result, imap.AnsweredFlag)
case f.FlagFlagged.IsSet():
result = append(result, imap.FlaggedFlag)
case f.FlagDeleted.IsSet():
result = append(result, imap.DeletedFlag)
case f.FlagDraft.IsSet():
result = append(result, imap.DraftFlag)
}
return result
}
func (f *FlagsStatus) IntoUnsetFlagList() []interface{} {
var result []interface{}
switch {
case f.FlagSeen.IsUnset():
result = append(result, imap.SeenFlag)
case f.FlagAnswered.IsUnset():
result = append(result, imap.AnsweredFlag)
case f.FlagFlagged.IsUnset():
result = append(result, imap.FlaggedFlag)
case f.FlagDeleted.IsUnset():
result = append(result, imap.DeletedFlag)
case f.FlagDraft.IsUnset():
result = append(result, imap.DraftFlag)
}
return result
}
func (f *FlagsStatus) WillSet() bool {
switch {
case f.FlagSeen.IsSet():
return true
case f.FlagAnswered.IsSet():
return true
case f.FlagFlagged.IsSet():
return true
case f.FlagDeleted.IsSet():
return true
case f.FlagDraft.IsSet():
return true
}
return false
}
func (f *FlagsStatus) WillUnset() bool {
switch {
case f.FlagSeen.IsUnset():
return true
case f.FlagAnswered.IsUnset():
return true
case f.FlagFlagged.IsUnset():
return true
case f.FlagDeleted.IsUnset():
return true
case f.FlagDraft.IsUnset():
return true
}
return false
}
func (f *FlagsStatus) SetSeen() {
f.FlagSeen = doSet
}
func (f *FlagsStatus) UnsetSeen() {
f.FlagSeen = doUnset
}
func (f *FlagsStatus) SetAnswered() {
f.FlagAnswered = doSet
}
func (f *FlagsStatus) UnsetAnswered() {
f.FlagAnswered = doUnset
}
func (f *FlagsStatus) SetFlagged() {
f.FlagFlagged = doSet
}
func (f *FlagsStatus) UnsetFlagged() {
f.FlagFlagged = doUnset
}
func (f *FlagsStatus) SetDeleted() {
f.FlagDeleted = doSet
}
func (f *FlagsStatus) UnsetDeleted() {
f.FlagDeleted = doUnset
}
func (f *FlagsStatus) SetDraft() {
f.FlagDraft = doSet
}
func (f *FlagsStatus) UnsetDraft() {
f.FlagDraft = doUnset
}
//func (f *FlagsStatus) SetUnknown() {
// f.FlagUnknown = doSet
//}
//func (f *FlagsStatus) UnsetUnknown() {
// f.FlagUnknown = doUnset
//}
type SetFlagsOpts struct {
Mailbox string
MessageSeq *imap.SeqSet
Flags *FlagsStatus
Debug bool
}
// SetFlags changes the flags on the specified message in the specified mailbox.
// First it adds the new flags set, then in removes the flags explicitly unset.
// Unfortunately, this operation is not atomic.
func SetFlags(conf *config.AccountData, opts *SetFlagsOpts) error {
conn := NewConnection(conf)
err := conn.Start(opts.Debug)
if err != nil {
return err
}
defer conn.Close()
return SetFlagsInSession(conn, opts)
}
// SetFlagsInSession does the same as SetFlags, but has to be provided
// with a started *IMAPConnection.
func SetFlagsInSession(conn *IMAPConnection, opts *SetFlagsOpts) error {
var err error
_, err = conn.client.Select(opts.Mailbox, false)
if err != nil {
return err
}
if opts.Flags.WillSet() {
item := imap.FormatFlagsOp(imap.AddFlags, true)
flags := opts.Flags.IntoSetFlagList()
err = conn.client.Store(opts.MessageSeq, item, flags, nil)
if err != nil {
return err
}
}
if opts.Flags.WillUnset() {
item := imap.FormatFlagsOp(imap.RemoveFlags, true)
flags := opts.Flags.IntoUnsetFlagList()
err = conn.client.Store(opts.MessageSeq, item, flags, nil)
if err != nil {
return err
}
}
return nil
}