diff --git a/cli/papero/add.go b/cli/papero/add.go new file mode 100644 index 0000000..ccf62d5 --- /dev/null +++ b/cli/papero/add.go @@ -0,0 +1,152 @@ +package main + +import ( + "bufio" + "bytes" + "flag" + "fmt" + "io" + "io/ioutil" + "os" + + "git.sr.ht/~blallo/papero/cli" + "git.sr.ht/~blallo/papero/imaputils" +) + +var addVerbs cli.CommandMap + +func init() { + addVerbs = cli.CommandMap{ + "message": PutMessageCmd{}, + // "mailbox": CreateMailboxCmd{}, + } +} + +type AddCmd struct{} + +func (a AddCmd) Func(args []string) error { + flagset := flag.NewFlagSet(args[0], flag.ExitOnError) + flagset.Usage = func() { a.Help(os.Stdout, flagset) } + flagset.Parse(args[1:]) + subArgs := flagset.Args() + if len(subArgs) == 0 { + a.Help(os.Stderr, flagset) + os.Exit(1) + } + cmd := subArgs[0] + if Session.Info.Opts.Debug { + Log.Debug("add verb:", cmd) + } + + return addVerbs[cmd].Func(subArgs) +} + +func (a AddCmd) Help(w io.Writer, set *flag.FlagSet) { + fmt.Fprintf(w, "USAGE: %s add VERB [verb opts]\n", Session.Info.Name) + fmt.Fprintf(w, "\nVERBS:\n") + for verb := range addVerbs { + fmt.Fprintf(w, "\t%s\n", verb) + } +} + +// VERBS + +type PutMessageCmd struct{} + +func (pm PutMessageCmd) Func(args []string) error { + var opts imaputils.PutMessageOpts + var err error + var bodyReader io.Reader + var flagSeen, flagAnswered, flagFlagged, flagDeleted, flagDraft bool + var messageTime = cli.NewAbsTimeFlag() + if Session.Info.Opts.Debug { + Log.Debug("enter add message") + } + + flagset := flag.NewFlagSet(args[0], flag.ExitOnError) + flagset.BoolVar(&flagSeen, "seen", false, "set the seen flag") + flagset.BoolVar(&flagAnswered, "answered", false, "set the answered flag") + flagset.BoolVar(&flagFlagged, "flagged", false, "set the flagged flag") + flagset.BoolVar(&flagDeleted, "deleted", false, "set the deleted flag") + flagset.BoolVar(&flagDraft, "draft", false, "set the draft flag") + flagset.Var(&messageTime, "time", "time at which the message has been sent") + flagset.Usage = func() { + pm.Help(os.Stdout, flagset) + } + + flagset.Parse(args[1:]) + + subArgs := flagset.Args() + if len(subArgs) != 2 { + Log.Debugf("Too few arguments: %s\n", subArgs) + pm.Help(os.Stderr, flagset) + os.Exit(1) + } + + opts.Debug = Session.Info.Opts.Debug + + opts.Mailbox = subArgs[0] + + if subArgs[1] == "-" { + bodyReader = os.Stdin + } else { + file, err := os.Open(subArgs[1]) + if err != nil { + return err + } + bodyReader = bufio.NewReader(file) + } + opts.Body, err = readIntoBuffer(bodyReader) + if err != nil { + return err + } + + opts.Flags = intoList(flagSeen, flagAnswered, flagFlagged, flagDeleted, flagDraft) + + opts.Time = *messageTime.Time + + Log.Debugf("Opts: %+v\n", opts) + + imaputils.PutMessage(Session.Config, &opts) + + return nil +} + +func (pm PutMessageCmd) Help(w io.Writer, set *flag.FlagSet) { + fmt.Fprintf(w, "USAGE: %s set put MAILBOX PATH_OR_STDIN\n", Session.Info.Name) + fmt.Fprintln(w, "\nPATH_OR_STDIN being either a path to a file or `-` to accept input from stdin") + set.PrintDefaults() +} + +func readIntoBuffer(r io.Reader) (*bytes.Buffer, error) { + var empty bytes.Buffer + + b, err := ioutil.ReadAll(r) + if err != nil { + return &empty, err + } + + Log.Debugf("content %+v\n", b) + buff := bytes.NewBuffer(b) + return buff, nil +} + +func intoList(flagSeen, flagAnswered, flagFlagged, flagDeleted, flagDraft bool) []string { + var result []string + if flagSeen { + result = append(result, "seen") + } + if flagAnswered { + result = append(result, "answered") + } + if flagFlagged { + result = append(result, "flagged") + } + if flagDeleted { + result = append(result, "deleted") + } + if flagDraft { + result = append(result, "draft") + } + return result +} diff --git a/cli/papero/main.go b/cli/papero/main.go index e4b64a8..b0d4148 100644 --- a/cli/papero/main.go +++ b/cli/papero/main.go @@ -18,9 +18,13 @@ var Log *log.Logger func init() { get := GetCmd{} set := SetCmd{} + add := AddCmd{} + // del := DelCmd{} Session.Info.Commands = cli.CommandMap{ "get": get, "set": set, + "add": add, + // "del": del, } Session.Info.Name = "papero" flag.Usage = func() { cli.Usage(os.Stdout, Session.Info) } diff --git a/cli/utils.go b/cli/utils.go index 8542039..2b73ec6 100644 --- a/cli/utils.go +++ b/cli/utils.go @@ -5,6 +5,7 @@ import ( "flag" "fmt" "io" + "time" ) type GlobalOpts struct { @@ -84,3 +85,34 @@ func (pf PairFlag) Set(s string) error { } var ErrAllowedPairFlagValues = errors.New("only `set` or `unset` are allowed") + +type AbsTimeFlag struct { + *time.Time +} + +func NewAbsTimeFlag() AbsTimeFlag { + return AbsTimeFlag{ + Time: &time.Time{}, + } +} + +func (t AbsTimeFlag) String() string { + return fmt.Sprint(t.Time) +} + +func (t AbsTimeFlag) Set(s string) error { + const layout = "2006-01-02T15:04:05" + var parsedTime time.Time + var err error + if s == "" { + t.Time = &parsedTime + return nil + } + parsedTime, err = time.Parse(layout, s) + if err != nil { + return err + } + + t.Time = &parsedTime + return nil +} diff --git a/imaputils/put_message.go b/imaputils/put_message.go new file mode 100644 index 0000000..f3a02de --- /dev/null +++ b/imaputils/put_message.go @@ -0,0 +1,47 @@ +package imaputils + +import ( + "bytes" + "time" + + "git.sr.ht/~blallo/papero/config" +) + +var zeroTime = time.Time{} + +type PutMessageOpts struct { + Debug bool + Mailbox string + Body *bytes.Buffer + Flags []string + Time time.Time +} + +func PutMessage(conf *config.AccountData, opts *PutMessageOpts) error { + conn := NewConnection(conf) + + err := conn.Start(opts.Debug) + if err != nil { + return err + } + defer conn.Close() + + return PutMessageInSession(conn, opts) +} + +func PutMessageInSession(conn *IMAPConnection, opts *PutMessageOpts) error { + var err error + var msgTime time.Time + + _, err = conn.client.Select(opts.Mailbox, false) + if err != nil { + return err + } + + if opts.Time == zeroTime { + msgTime = time.Now() + } else { + msgTime = opts.Time + } + return conn.client.Append(opts.Mailbox, opts.Flags, msgTime, opts.Body) +}