package main import ( "flag" "fmt" "io" "os" "strconv" "strings" "git.sr.ht/~blallo/papero/cli" "git.sr.ht/~blallo/papero/imaputils" "github.com/emersion/go-imap" ) var setVerbs cli.CommandMap func init() { setVerbs = cli.CommandMap{ "flags": SetFlagsCmd{}, // "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) } } // VERBS type SetFlagsCmd struct{} func (sm SetFlagsCmd) Func(args []string) error { if Session.Info.Opts.Debug { Log.Debug("enter set message") } flags := imaputils.NewFlagsStatus() var opts imaputils.SetFlagsOpts flagSeen := cli.NewPairFlag() flagAnswered := cli.NewPairFlag() flagFlagged := cli.NewPairFlag() flagDeleted := cli.NewPairFlag() flagDraft := cli.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 SetFlagsCmd) 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 cli.Pair, setCallback, unsetCallback func()) error { switch flagOp { case cli.Pair{true, false}: setCallback() case cli.Pair{false, true}: unsetCallback() default: return nil } return nil }