241 lines
4.6 KiB
Go
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
|
|
}
|