|
@@ -0,0 +1,215 @@
|
|
|
+package main
|
|
|
+
|
|
|
+import (
|
|
|
+ "errors"
|
|
|
+ "flag"
|
|
|
+ "fmt"
|
|
|
+ "io"
|
|
|
+ "os"
|
|
|
+ "strconv"
|
|
|
+ "strings"
|
|
|
+
|
|
|
+ "git.lattuga.net/blallo/papero/cli"
|
|
|
+ "git.lattuga.net/blallo/papero/imaputils"
|
|
|
+ "github.com/emersion/go-imap"
|
|
|
+)
|
|
|
+
|
|
|
+var setVerbs cli.CommandMap
|
|
|
+
|
|
|
+func init() {
|
|
|
+ setVerbs = cli.CommandMap{
|
|
|
+ "message": SetMessageCmd{},
|
|
|
+ // "subscribe": SetSubscribedCmd{},
|
|
|
+ // "unsubscribe": SetUnsubscribedCmd{},
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+type SetCmd struct{}
|
|
|
+
|
|
|
+func (s SetCmd) Func(args []string) error {
|
|
|
+ flagset := flag.NewFlagSet(args[0], flag.ExitOnError)
|
|
|
+ flagset.Usage = func() { s.Help(os.Stdout, flagset) }
|
|
|
+ flagset.Parse(args[1:])
|
|
|
+ subArgs := flagset.Args()
|
|
|
+ if len(subArgs) == 0 {
|
|
|
+ s.Help(os.Stderr, flagset)
|
|
|
+ os.Exit(1)
|
|
|
+ }
|
|
|
+ cmd := subArgs[0]
|
|
|
+ if Session.Info.Opts.Debug {
|
|
|
+ Log.Debug("set verb:", cmd)
|
|
|
+ }
|
|
|
+
|
|
|
+ return setVerbs[cmd].Func(subArgs)
|
|
|
+}
|
|
|
+
|
|
|
+func (s SetCmd) Help(w io.Writer, set *flag.FlagSet) {
|
|
|
+ fmt.Fprintf(w, "USAGE: %s set VERB [verb opts]\n", Session.Info.Name)
|
|
|
+ fmt.Fprintf(w, "\nVERBS:\n")
|
|
|
+ for verb := range setVerbs {
|
|
|
+ fmt.Fprintf(w, "\t%s\n", verb)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// FLAG UTILS
|
|
|
+
|
|
|
+type pair struct {
|
|
|
+ set, unset bool
|
|
|
+}
|
|
|
+
|
|
|
+type pairFlag struct {
|
|
|
+ *pair
|
|
|
+}
|
|
|
+
|
|
|
+func newPairFlag() pairFlag {
|
|
|
+ return pairFlag{
|
|
|
+ &pair{false, false},
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (p pair) String() string {
|
|
|
+ switch p {
|
|
|
+ case pair{true, false}:
|
|
|
+ return "set"
|
|
|
+ case pair{false, true}:
|
|
|
+ return "unset"
|
|
|
+ default:
|
|
|
+ return "undef"
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (pf pairFlag) String() string {
|
|
|
+ return pf.pair.String()
|
|
|
+}
|
|
|
+
|
|
|
+func (pf pairFlag) Set(s string) error {
|
|
|
+ Log.Debugf("into Set: %s\n", s)
|
|
|
+ if s == "set" {
|
|
|
+ Log.Debug("setting")
|
|
|
+ v := pair{true, false}
|
|
|
+ *pf.pair = v
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ if s == "unset" {
|
|
|
+ Log.Debug("unsetting")
|
|
|
+ v := pair{false, true}
|
|
|
+ *pf.pair = v
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+
|
|
|
+ Log.Debug(fmt.Sprintf("unacceptable value %s\n", s))
|
|
|
+ return errors.New("only `set` or `unset` are allowed")
|
|
|
+}
|
|
|
+
|
|
|
+// VERBS
|
|
|
+
|
|
|
+type SetMessageCmd struct{}
|
|
|
+
|
|
|
+func (sm SetMessageCmd) Func(args []string) error {
|
|
|
+ if Session.Info.Opts.Debug {
|
|
|
+ Log.Debug("enter set message")
|
|
|
+ }
|
|
|
+ flags := imaputils.NewFlagsStatus()
|
|
|
+ var opts imaputils.SetFlagsOpts
|
|
|
+ flagSeen := newPairFlag()
|
|
|
+ flagAnswered := newPairFlag()
|
|
|
+ flagFlagged := newPairFlag()
|
|
|
+ flagDeleted := newPairFlag()
|
|
|
+ flagDraft := newPairFlag()
|
|
|
+
|
|
|
+ flagset := flag.NewFlagSet(args[0], flag.ExitOnError)
|
|
|
+
|
|
|
+ flagset.Var(&flagSeen, "seen", "Set or unset `seen` flag on message")
|
|
|
+ flagset.Var(&flagAnswered, "answered", "Set or unset `answered` flag on message")
|
|
|
+ flagset.Var(&flagFlagged, "flagged", "Set or unset `flagged` flag on message")
|
|
|
+ flagset.Var(&flagDeleted, "deleted", "Set or unset `deleted` flag on message")
|
|
|
+ flagset.Var(&flagDraft, "draft", "Set or unset `draft` flag on message")
|
|
|
+
|
|
|
+ flagset.Usage = func() {
|
|
|
+ sm.Help(os.Stdout, flagset)
|
|
|
+ }
|
|
|
+ flagset.Parse(args[1:])
|
|
|
+
|
|
|
+ subArgs := flagset.Args()
|
|
|
+ if len(subArgs) < 2 {
|
|
|
+ Log.Debugf("Too few arguments: %s\n", subArgs)
|
|
|
+ sm.Help(os.Stderr, flagset)
|
|
|
+ os.Exit(1)
|
|
|
+ }
|
|
|
+
|
|
|
+ opts.Mailbox = subArgs[0]
|
|
|
+ seq := new(imap.SeqSet)
|
|
|
+ for _, msgId := range subArgs[1:] {
|
|
|
+ if err := parseMessageSeq(seq, msgId); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ }
|
|
|
+ opts.MessageSeq = seq
|
|
|
+ opts.Debug = Session.Info.Opts.Debug
|
|
|
+
|
|
|
+ if err := assignFlag(*flagSeen.pair, flags.SetSeen, flags.UnsetSeen); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if err := assignFlag(*flagAnswered.pair, flags.SetAnswered, flags.UnsetAnswered); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if err := assignFlag(*flagFlagged.pair, flags.SetFlagged, flags.UnsetFlagged); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if err := assignFlag(*flagDeleted.pair, flags.SetDeleted, flags.UnsetDeleted); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if err := assignFlag(*flagDraft.pair, flags.SetDraft, flags.UnsetDraft); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ Log.Debugf("Setting flags: %s\n", flags)
|
|
|
+ opts.Flags = flags
|
|
|
+
|
|
|
+ return imaputils.SetFlags(Session.Config, &opts)
|
|
|
+}
|
|
|
+
|
|
|
+func (sm SetMessageCmd) Help(w io.Writer, set *flag.FlagSet) {
|
|
|
+ fmt.Fprintf(w, "USAGE: %s set message [opts] MAILBOX MESSAGE_ID_OR_RANGE [MESSAGE_ID_OR_RANGE [MESSAGE_ID_OR_RANGE ...]]\n", Session.Info.Name)
|
|
|
+ fmt.Fprintln(w, "\nMESSAGE_ID_OR_RANGE being a single message id or a git-like range")
|
|
|
+ fmt.Fprintln(w, "Example:")
|
|
|
+ fmt.Fprintln(w, "\t12345\t- A single message")
|
|
|
+ fmt.Fprintln(w, "\t123...258\t- A range from id 123 to id 258")
|
|
|
+ fmt.Fprintf(w, "\nOPTS:\n")
|
|
|
+ set.PrintDefaults()
|
|
|
+}
|
|
|
+
|
|
|
+func parseMessageSeq(seq *imap.SeqSet, data string) error {
|
|
|
+ if strings.Contains(data, "..") {
|
|
|
+ split := strings.Split(data, "..")
|
|
|
+ start, err := strconv.ParseUint(split[0], 10, 0)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ stop, err := strconv.ParseUint(split[2], 10, 0)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ seq.AddRange(uint32(start), uint32(stop))
|
|
|
+ } else {
|
|
|
+ msg, err := strconv.ParseUint(data, 10, 0)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ seq.AddNum(uint32(msg))
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func assignFlag(flagOp pair, setCallback, unsetCallback func()) error {
|
|
|
+ switch flagOp {
|
|
|
+ case pair{true, false}:
|
|
|
+ setCallback()
|
|
|
+ case pair{false, true}:
|
|
|
+ unsetCallback()
|
|
|
+ default:
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|