]> diplodocus.org Git - nmh/commitdiff
Merge remote-tracking branch 'origin' into xoauth
authorDavid Levine <david.levine@gonift.com>
Sun, 26 Jun 2016 01:16:36 +0000 (21:16 -0400)
committerDavid Levine <david.levine@gonift.com>
Sun, 26 Jun 2016 01:16:36 +0000 (21:16 -0400)
1  2 
Makefile.am
h/prototypes.h
uip/inc.c
uip/send.c
uip/whatnowsbr.c

diff --combined Makefile.am
index 2ec9d5ce288bfe8801be9f7e2598482a6e6f3565,fa681971c51a96cce618b8c748df42a2a48cbbe6..de88060ca026a6fe6b4ca0ea4bcc4f42096515fe
@@@ -36,9 -36,6 +36,9 @@@ nmhlibexecdir = @libexecdir@/nm
  ## nmh _does_ have a test suite!
  ##
  TESTS_ENVIRONMENT = MH_OBJ_DIR="@abs_builddir@" \
 +                  MH_VERSION="$(VERSION)" \
 +                  OAUTH_SUPPORT='@OAUTH_SUPPORT@' \
 +                  CURL_USER_AGENT='@CURL_USER_AGENT@' \
                    MH_TEST_DIR="@abs_builddir@/test/testdir" \
                    nmhlibexecdir="$(nmhlibexecdir)" bindir="$(bindir)" \
                    mandir="$(mandir)" nmhetcdir="$(nmhetcdir)" \
@@@ -87,8 -84,6 +87,8 @@@ TESTS = test/ali/test-ali test/anno/tes
        test/mhshow/test-subpart test/mhshow/test-msg-buffer-boundaries \
        test/mhstore/test-mhstore test/mkstemp/test-mkstemp \
        test/new/test-basic test/pick/test-pick test/pick/test-stderr \
 +      test/oauth/test-mhlogin test/oauth/test-mhparam test/oauth/test-send \
 +      test/oauth/test-inc test/oauth/test-share \
        test/post/test-post-aliases test/post/test-post-basic \
        test/post/test-post-multiple test/post/test-post-bcc \
        test/post/test-post-dcc test/post/test-post-fcc \
  
  check_SCRIPTS = test/common.sh
  check_PROGRAMS = test/getfullname test/getcanon test/fakepop test/fakesmtp \
 -               test/getcwidth
 +               test/getcwidth test/fakehttp
  
  ## The location of installed nmhetcdir is, for all purposes except
  ## distcheck, $nmhetcdir.  For distcheck, prepend $MH_INST_DIR (from
@@@ -162,7 -157,7 +162,7 @@@ bin_PROGRAMS = uip/ali uip/anno uip/bur
               uip/mhparam uip/mhpath uip/mhshow uip/mhstore uip/msgchk \
               uip/new uip/packf uip/pick uip/prompter uip/refile \
               uip/repl uip/rmf uip/rmm uip/scan uip/send uip/show uip/sortm \
 -             uip/whatnow uip/whom
 +             uip/whatnow uip/whom uip/mhlogin
  
  bin_SCRIPTS = uip/mhmail etc/sendfiles
  
@@@ -197,8 -192,7 +197,8 @@@ noinst_HEADERS = h/addrsbr.h h/aliasbr.
                 h/mh.h h/mhcachesbr.h h/mhparse.h h/mime.h \
                 h/mts.h h/nmh.h h/picksbr.h h/popsbr.h h/prototypes.h \
                 h/rcvmail.h h/scansbr.h h/signals.h h/tws.h h/utils.h \
 -               mts/smtp/smtp.h sbr/ctype-checked.h
 +               mts/smtp/smtp.h sbr/ctype-checked.h h/oauth.h \
 +               thirdparty/jsmn/jsmn.h
  
  ##
  ## Extra files we need to install in various places
@@@ -259,7 -253,7 +259,7 @@@ man_MANS = man/ali.1 man/anno.1 man/ap.
           man/prompter.1 man/rcvdist.1 man/rcvpack.1 man/rcvstore.1 \
           man/rcvtty.1 man/refile.1 man/repl.1 man/rmf.1 man/rmm.1 \
           man/scan.1 man/send.1 man/sendfiles.1 man/show.1 man/slocal.1 \
 -         man/sortm.1 man/unseen.1 man/whatnow.1 man/whom.1
 +         man/sortm.1 man/unseen.1 man/whatnow.1 man/whom.1 man/mhlogin.1
  
  ##
  ## Sources for our man pages
@@@ -281,7 -275,7 +281,7 @@@ man_SRCS = man/ali.man man/anno.man man
           man/rcvstore.man man/rcvtty.man man/refile.man man/repl.man \
           man/rmf.man man/rmm.man man/scan.man man/send.man \
           man/sendfiles.man man/show.man man/slocal.man man/sortm.man \
 -         man/unseen.man man/whatnow.man man/whom.man
 +         man/unseen.man man/whatnow.man man/whom.man man/mhlogin.man
  
  ##
  ## Files we need to include in the distribution which aren't found by
@@@ -299,9 -293,7 +299,9 @@@ EXTRA_DIST = autogen.sh config/version.
             test/mhbuild/somebinary \
             test/mhbuild/nulls \
             test/mhbuild/textplain \
 -           test/post/test-post-common.sh test/valgrind.supp uip/mhmail \
 +           test/post/test-post-common.sh test/valgrind.supp \
 +           test/oauth/common.sh \
 +           uip/mhmail \
             SPECS/nmh.spec SPECS/build-nmh-cygwin $(man_SRCS)
  
  ##
@@@ -324,11 -316,11 +324,11 @@@ uip_burst_LDADD = $(LDADD) $(ICONVLIB) 
  
  uip_comp_SOURCES = uip/comp.c uip/whatnowproc.c uip/whatnowsbr.c uip/sendsbr.c \
                   uip/annosbr.c uip/distsbr.c
 -uip_comp_LDADD = $(LDADD) $(READLINELIB) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
 +uip_comp_LDADD = $(LDADD) $(READLINELIB) $(TERMLIB) $(ICONVLIB) $(CURLLIB) $(POSTLINK)
  
  uip_dist_SOURCES = uip/dist.c uip/whatnowproc.c uip/whatnowsbr.c uip/sendsbr.c \
                   uip/annosbr.c uip/distsbr.c uip/forwsbr.c
 -uip_dist_LDADD = $(LDADD) $(READLINELIB) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
 +uip_dist_LDADD = $(LDADD) $(READLINELIB) $(TERMLIB) $(ICONVLIB) $(CURLLIB) $(POSTLINK)
  
  uip_flist_SOURCES = uip/flist.c
  uip_flist_LDADD = $(LDADD) $(POSTLINK)
@@@ -338,10 -330,10 +338,10 @@@ uip_folder_LDADD = $(LDADD) $(POSTLINK
  
  uip_forw_SOURCES = uip/forw.c uip/whatnowproc.c uip/whatnowsbr.c uip/sendsbr.c \
                   uip/annosbr.c uip/distsbr.c uip/forwsbr.c
 -uip_forw_LDADD = $(LDADD) $(READLINELIB) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
 +uip_forw_LDADD = $(LDADD) $(READLINELIB) $(TERMLIB) $(ICONVLIB) $(CURLLIB) $(POSTLINK)
  
  uip_inc_SOURCES = uip/inc.c uip/scansbr.c uip/dropsbr.c uip/popsbr.c
 -uip_inc_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(SASLLIB) $(POSTLINK)
 +uip_inc_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(SASLLIB) $(CURLLIB) $(POSTLINK)
  
  uip_install_mh_SOURCES = uip/install-mh.c
  uip_install_mh_LDADD = $(LDADD) $(POSTLINK)
@@@ -389,7 -381,7 +389,7 @@@ uip_mhstore_SOURCES = uip/mhstore.c uip
  uip_mhstore_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
  
  uip_msgchk_SOURCES = uip/msgchk.c uip/popsbr.c
 -uip_msgchk_LDADD = $(LDADD) $(SASLLIB) $(POSTLINK)
 +uip_msgchk_LDADD = $(LDADD) $(SASLLIB) $(CURLLIB) $(POSTLINK)
  
  uip_new_SOURCES = uip/new.c
  uip_new_LDADD = $(LDADD) $(POSTLINK)
@@@ -408,7 -400,7 +408,7 @@@ uip_refile_LDADD = $(LDADD) $(POSTLINK
  
  uip_repl_SOURCES = uip/repl.c uip/replsbr.c uip/whatnowproc.c uip/whatnowsbr.c \
                   uip/sendsbr.c uip/annosbr.c uip/distsbr.c
 -uip_repl_LDADD = $(LDADD) $(READLINELIB) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
 +uip_repl_LDADD = $(LDADD) $(READLINELIB) $(TERMLIB) $(ICONVLIB) $(CURLLIB) $(POSTLINK)
  
  uip_rmf_SOURCES = uip/rmf.c
  uip_rmf_LDADD = $(LDADD) $(POSTLINK)
@@@ -421,7 -413,7 +421,7 @@@ uip_scan_LDADD = $(LDADD) $(TERMLIB) $(
  
  uip_send_SOURCES = uip/send.c uip/sendsbr.c uip/annosbr.c \
                   uip/distsbr.c
 -uip_send_LDADD = $(LDADD) $(POSTLINK)
 +uip_send_LDADD = $(LDADD) $(CURLLIB) $(POSTLINK)
  
  uip_show_SOURCES = uip/show.c uip/mhlsbr.c
  uip_show_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
@@@ -431,7 -423,7 +431,7 @@@ uip_sortm_LDADD = $(LDADD) $(POSTLINK
  
  uip_whatnow_SOURCES = uip/whatnow.c uip/whatnowsbr.c uip/sendsbr.c \
                      uip/annosbr.c uip/distsbr.c
 -uip_whatnow_LDADD = $(LDADD) $(READLINELIB) $(TERMLIB) $(POSTLINK)
 +uip_whatnow_LDADD = $(LDADD) $(READLINELIB) $(TERMLIB) $(CURLLIB) $(POSTLINK)
  
  uip_whom_SOURCES = uip/whom.c uip/distsbr.c
  uip_whom_LDADD = $(LDADD) $(POSTLINK)
@@@ -455,9 -447,6 +455,9 @@@ uip_fmttest_LDADD = $(LDADD) $(TERMLIB
  uip_mhl_SOURCES = uip/mhl.c uip/mhlsbr.c
  uip_mhl_LDADD = $(LDADD) $(TERMLIB) $(ICONVLIB) $(POSTLINK)
  
 +uip_mhlogin_SOURCES = uip/mhlogin.c
 +uip_mhlogin_LDADD = mts/libmts.a $(LDADD) $(CURLLIB) $(POSTLINK)
 +
  uip_mkstemp_SOURCES = uip/mkstemp.c
  uip_mkstemp_LDADD = $(LDADD) $(POSTLINK)
  
@@@ -483,40 -472,37 +483,45 @@@ uip_viamail_SOURCES = uip/viamail.c uip
                      uip/annosbr.c uip/distsbr.c
  uip_viamail_LDADD = $(LDADD) $(POSTLINK)
  
 +##
 +## Other program definitions
 +##
 +
  test_getfullname_SOURCES = test/getfullname.c
  test_getfullname_LDADD = $(LDADD) $(POSTLINK)
  
+ ##
+ ## Other program definitions
+ ##
  test_getcanon_SOURCES = test/getcanon.c
  test_getcanon_LDADD = $(POSTLINK)
  
 -test_fakepop_SOURCES = test/fakepop.c
 +test_fakepop_SOURCES = test/fakepop.c test/server.c
  test_fakepop_LDADD = $(POSTLINK)
  
 -test_fakesmtp_SOURCES = test/fakesmtp.c
 +test_fakesmtp_SOURCES = test/fakesmtp.c test/server.c
  test_fakesmtp_LDADD = $(POSTLINK)
  
 +test_fakehttp_SOURCES = test/fakehttp.c test/server.c
 +test_fakehttp_LDADD = $(POSTLINK)
 +
  test_getcwidth_SOURCES = test/getcwidth.c
  test_getcwidth_LDADD = $(POSTLINK)
  
  etc_gen_ctype_checked_SOURCES = etc/gen-ctype-checked.c
  etc_gen_ctype_checked_LDADD = $(POSTLINK)
  
 +docs_contrib_sendfrom_SOURCES = docs/contrib/sendfrom.c
 +docs_contrib_sendfrom_LDADD = $(LDADD) $(TERMLIB) $(CURLLIB) $(POSTLINK)
 +
  ##
  ## Our rebuild rules for files that aren't built via the normal mechanisms
  ##
  
  ## Hard-code the config/version.c target, instead of using $@, so this
  ## rule works for the distcheck target with Solaris (System V) make.
 -docs_contrib_sendfrom_SOURCES = docs/contrib/sendfrom.c
 -docs_contrib_sendfrom_LDADD = $(LDADD) $(TERMLIB) $(CURLLIB) $(POSTLINK)
  ## distcheck uses VPATH, causes that make to prepend the VPATH to $@.
  config/version.c: Makefile $(srcdir)/config/version.sh
        env srcdir="$(srcdir)" sh $(srcdir)/config/version.sh $(VERSION) > ./config/version.c
@@@ -601,10 -587,10 +606,11 @@@ sbr_libmh_a_SOURCES = sbr/addrsbr.c sbr
                      sbr/error.c sbr/ext_hook.c sbr/fdcompare.c \
                      sbr/folder_addmsg.c sbr/folder_delmsgs.c \
                      sbr/folder_free.c sbr/folder_pack.c \
-                     sbr/folder_read.c sbr/folder_realloc.c sbr/gans.c \
-                     sbr/getans.c sbr/getanswer.c sbr/getarguments.c \
+                     sbr/folder_read.c sbr/folder_realloc.c sbr/read_switch.c \
 -                    sbr/read_switch_multiword.c sbr/read_yes_or_no_if_tty.c sbr/getarguments.c \
++                    sbr/read_switch_multiword.c sbr/read_switch_multiword_via_readline.c \
++                    sbr/read_yes_or_no_if_tty.c sbr/getarguments.c \
                      sbr/getcpy.c sbr/geteditor.c sbr/getfolder.c \
-                     sbr/getpass.c \
+                     sbr/getpass.c sbr/read_line.c \
                      sbr/fmt_addr.c sbr/fmt_compile.c sbr/fmt_new.c \
                      sbr/fmt_rfc2047.c sbr/fmt_scan.c \
                      sbr/icalparse.y sbr/icalendar.l sbr/datetime.c \
                      sbr/trimcpy.c sbr/unquote.c \
                      sbr/uprf.c sbr/vfgets.c \
                      sbr/mf.c sbr/utils.c sbr/ctype-checked.c \
-                     sbr/m_mktemp.c sbr/getansreadline.c sbr/vector.c \
-                     config/config.c config/version.c sbr/oauth.c \
 -                    sbr/m_mktemp.c sbr/read_switch_multiword_via_readline.c sbr/vector.c \
 -                    config/config.c config/version.c
++                    sbr/m_mktemp.c sbr/vector.c sbr/oauth.c \
++                    config/config.c config/version.c \
 +                    thirdparty/jsmn/jsmn.c
  
  ##
  ## Because these files use the definitions in the libmh rule below,
diff --combined h/prototypes.h
index fc969094cdee8d1ecf1a8e24609ee988c37225cc,82e39fa67f26f8aa22f5331bd68110323556c6fc..782939be1069345b3a64f84169d0313e552e4e75
@@@ -26,7 -26,7 +26,7 @@@ char **argsplit (char *, char **, int *
  void argsplit_msgarg (struct msgs_array *, char *, char **);
  void argsplit_insert (struct msgs_array *, char *, char **);
  void arglist_free (char *, char **);
- void ambigsw (char *, struct swit *);
+ void ambigsw (const char *, const struct swit *);
  int atooi(char *);
  char **brkstring (char *, char *, char *);
  
@@@ -118,12 -118,44 +118,44 @@@ int folder_pack (struct msgs **, int)
  struct msgs *folder_read (char *name, int lockflag);
  
  struct msgs *folder_realloc (struct msgs *, int, int);
- int gans (char *, struct swit *);
- char **getans (char *, struct swit *);
+ /*
+  * Flush standard output, read a line from standard input into a static buffer,
+  * zero out the newline, and return a pointer to the buffer.
+  * On error, return NULL.
+  */
+ const char *read_line(void);
+ /*
+  * Print null-terminated PROMPT to and flush standard output.  Read answers from
+  * standard input until one matches an entry in SWITCHES.  When one matches,
+  * return its swret field.  Return 0 on EOF.
+  */
+ int read_switch(const char *PROMPT, const struct swit *SWITCHES);
+ /*
+  * If standard input is not a tty, return 1 without printing anything.  Else,
+  * print null-terminated PROMPT to and flush standard output.  Read answers from
+  * standard input until one is "yes" or "no", returning 1 for "yes" and 0 for
+  * "no".  Also return 0 on EOF.
+  */
+ int read_yes_or_no_if_tty(const char *PROMPT);
+ /*
+  * Print null-terminated PROMPT to and flush standard output.  Read multi-word
+  * answers from standard input until a first word matches an entry in SWITCHES.
+  * When one matches, return a pointer to an array of pointers to the words.
+  * Return NULL on EOF, interrupt, or other error.
+  */
+ char **read_switch_multiword(const char *PROMPT, const struct swit *SWITCHES);
+ /*
+  * Same as read_switch_multiword but using readline(3) for input.
+  */
  #ifdef READLINE_SUPPORT
- char **getans_via_readline (char *, struct swit *);
+ char **read_switch_multiword_via_readline (char *, struct swit *);
  #endif /* READLINE_SUPPORT */
- int getanswer (char *);
  char **getarguments (char *, int, char **, int);
  
  /*
@@@ -247,7 -279,7 +279,7 @@@ void m_popen(char *name, int savestdout
  void m_pclose(void);
  
  void m_unknown(m_getfld_state_t *, FILE *);
- int makedir (char *);
+ int makedir (const char *);
  char *message_id (time_t, int);
  
  /*
@@@ -282,12 -314,12 +314,12 @@@ int pidwait (pid_t, int)
  int pidstatus (int, FILE *, char *);
  char *pluspath(char *);
  void print_help (char *, struct swit *, int);
- void print_sw (char *, struct swit *, char *, FILE *);
+ void print_sw (const char *, const struct swit *, char *, FILE *);
  void print_version (char *);
  void push (void);
  char *pwd (void);
  char *r1bindex(char *, int);
 -void readconfig (struct node **, FILE *, char *, int);
 +void readconfig (struct node **, FILE *, const char *, int);
  int refile (char **, char *);
  void ruserpass (char *, char **, char **);
  int remdir (char *);
@@@ -328,7 -360,7 +360,7 @@@ void seq_setcur (struct msgs *, int)
  void seq_setprev (struct msgs *);
  void seq_setunseen (struct msgs *, int);
  int showfile (char **, char *);
- int smatch(char *, struct swit *);
+ int smatch(const char *, const struct swit *);
  
  /*
   * Convert a set of bit flags to printable format.
   * from least significant bit to most significant.
   */
  char *snprintb (char *buffer, size_t size, unsigned flags, char *bitfield);
- int ssequal (char *, char *);
+ int ssequal (const char *, const char *);
  int stringdex (char *, char *);
  char *trimcpy (char *);
  int unputenv (char *);
diff --combined uip/inc.c
index f1bafd905252713c83fcf67ae8fae3ec17bbb821,41e785ff3a80f94c439fff881e1b3fe6d3dbae0a..78914533137bf686949dc9817e590ce08ba70403
+++ b/uip/inc.c
      X("version", 0, VERSIONSW) \
      X("help", 0, HELPSW) \
      X("snoop", -5, SNOOPSW) \
 -    X("sasl", SASLminc(-4), SASLSW) \
 -    X("nosasl", SASLminc(-6), NOSASLSW) \
 -    X("saslmech", SASLminc(-8), SASLMECHSW) \
 +    X("sasl", SASLminc(5), SASLSW) \
 +    X("nosasl", SASLminc(3), NOSASLSW) \
 +    X("saslmech", SASLminc(5), SASLMECHSW) \
 +    X("authservice", SASLminc(0), AUTHSERVICESW) \
      X("proxy command", 0, PROXYSW) \
  
  #define X(sw, minchars, id) id,
@@@ -191,7 -190,7 +191,7 @@@ main (int argc, char **argv
      char *cp, *maildir = NULL, *folder = NULL;
      char *format = NULL, *form = NULL;
      char *host = NULL, *port = NULL, *user = NULL, *proxy = NULL;
 -    char *audfile = NULL, *from = NULL, *saslmech = NULL;
 +    char *audfile = NULL, *from = NULL, *saslmech = NULL, *auth_svc = NULL;
      char buf[BUFSIZ], **argp, *nfs, **arguments;
      struct msgs *mp = NULL;
      struct stat st, s1;
  
      int nmsgs, nbytes;
      char *MAILHOST_env_variable;
 -
      done=inc_done;
  
  /* absolutely the first thing we do is save our privileges,
                if (!(saslmech = *argp++) || *saslmech == '-')
                    adios (NULL, "missing argument to %s", argp[-2]);
                continue;
 +
 +          case AUTHSERVICESW:
 +#ifdef OAUTH_SUPPORT
 +                if (!(auth_svc = *argp++) || *auth_svc == '-')
 +                    adios (NULL, "missing argument to %s", argp[-2]);
 +#else
 +                adios (NULL, "not built with OAuth support");
 +#endif
 +                continue;
 +
            case PROXYSW:
                if (!(proxy = *argp++) || *proxy == '-')
                    adios (NULL, "missing argument to %s", argp[-2]);
      if (inc_type == INC_POP) {
        struct nmh_creds creds = { 0, 0, 0 };
  
 +      if (auth_svc == NULL) {
 +          if (saslmech  &&  ! strcasecmp(saslmech, "xoauth2")) {
 +              adios (NULL, "must specify -authservice with -saslmech xoauth2");
 +          }
 +          nmh_get_credentials (host, user, sasl, &creds);
 +      } else {
 +          if (user == NULL) {
 +              adios (NULL, "must specify -user with -saslmech xoauth2");
 +          }
 +          creds.user = user;
 +      }
 +
        /*
         * initialize POP connection
         */
 -      nmh_get_credentials (host, user, sasl, &creds);
        if (pop_init (host, port, creds.user, creds.password, proxy, snoop,
 -                    sasl, saslmech) == NOTOK)
 +                    sasl, saslmech, auth_svc) == NOTOK)
            adios (NULL, "%s", response);
  
        /* Check if there are any messages */
@@@ -605,7 -584,7 +605,7 @@@ go_to_it
                if (errno != ENOENT)
                    adios (packfile, "error on file");
                cp = concat ("Create file \"", packfile, "\"? ", NULL);
-               if (noisy && !getanswer (cp))
+               if (noisy && !read_yes_or_no_if_tty (cp))
                    done (1);
                free (cp);
            }
diff --combined uip/send.c
index a623964fe0baffab3f3239c3b574f07faa62f8dd,f4c4910673a9552c941504a60839ded959b3a5ba..03a54698ac3b6a0ccc77edced07f212442597e53
@@@ -9,11 -9,7 +9,11 @@@
  
  #include <h/mh.h>
  #include <fcntl.h>
 +#include <h/utils.h>
  
 +#ifdef OAUTH_SUPPORT
 +# include <h/oauth.h>
 +#endif
  
  #ifndef CYRUS_SASL
  # define SASLminc(a) (a)
      X("server host", 6, SERVSW) \
      X("snoop", 5, SNOOPSW) \
      X("sasl", SASLminc(4), SASLSW) \
 -    X("nosasl", SASLminc(-6), NOSASLSW) \
 -    X("saslmaxssf", SASLminc(-10), SASLMXSSFSW) \
 -    X("saslmech mechanism", SASLminc(-5), SASLMECHSW) \
 +    X("nosasl", SASLminc(6), NOSASLSW) \
 +    X("saslmaxssf", SASLminc(6), SASLMXSSFSW) \
 +    X("saslmech mechanism", SASLminc(6), SASLMECHSW) \
 +    X("authservice", SASLminc(0), AUTHSERVICESW) \
      X("user username", SASLminc(-4), USERSW) \
      X("attach", -6, ATTACHSW) \
      X("noattach", -8, NOATTACHSW) \
@@@ -121,11 -116,8 +121,11 @@@ main (int argc, char **argv
      char *cp, *dfolder = NULL, *maildir = NULL;
      char buf[BUFSIZ], **ap, **argp, **arguments, *program;
      char *msgs[MAXARGS], **vec;
 +    const char *user = NULL, *saslmech = NULL;
      struct msgs *mp;
      struct stat st;
 +    int snoop = 0;
 +    char *auth_svc = NULL;
  
      if (nmh_init(argv[0], 1)) { return 1; }
  
                    vec[vecp++] = --cp;
                    continue;
  
 +              case SNOOPSW:
 +                    snoop++;
 +                  vec[vecp++] = --cp;
 +                  continue;
 +
                case DEBUGSW: 
                    debugsw++;  /* fall */
                case NFILTSW: 
                case NMSGDSW: 
                case WATCSW: 
                case NWATCSW: 
 -              case SNOOPSW: 
                case SASLSW:
                case NOSASLSW:
                case TLSSW:
                    vec[vecp++] = --cp;
                    continue;
  
 +              case USERSW:
 +                  vec[vecp++] = --cp;
 +                  if (!(cp = *argp++) || *cp == '-')
 +                      adios (NULL, "missing argument to %s", argp[-2]);
 +                  vec[vecp++] = cp;
 +                    user = cp;
 +                  continue;
 +
 +              case SASLMECHSW:
 +                  if (!(saslmech = *argp++) || *saslmech == '-')
 +                      adios (NULL, "missing argument to %s", argp[-2]);
 +                  continue;
 +
 +              case AUTHSERVICESW:
 +#ifdef OAUTH_SUPPORT
 +                  if (!(auth_svc = *argp++) || *auth_svc == '-')
 +                      adios (NULL, "missing argument to %s", argp[-2]);
 +#else
 +                  adios (NULL, "not built with OAuth support");
 +#endif
 +                  continue;
 +
                case ALIASW: 
                case FILTSW: 
                case WIDTHSW: 
                case CLIESW: 
                case SERVSW: 
 -              case SASLMECHSW:
                case SASLMXSSFSW:
 -              case USERSW:
                case PORTSW:
                case MTSSM:
                case MTSSW:
                adios (msgs[0], "unable to stat draft file");
            cp = concat ("Use \"", msgs[0], "\"? ", NULL);
            for (status = LISTDSW; status != YESW;) {
-               if (!(argp = getans (cp, anyl)))
+               if (!(argp = read_switch_multiword (cp, anyl)))
                    done (1);
                switch (status = smatch (*argp, anyl)) {
                    case NOSW: 
@@@ -450,29 -418,6 +450,29 @@@ go_to_it
        distfile = NULL;
      }
  
 +#ifdef OAUTH_SUPPORT
 +    if (auth_svc == NULL) {
 +        if (saslmech  &&  ! strcasecmp(saslmech, "xoauth2")) {
 +            adios (NULL, "must specify -authservice with -saslmech xoauth2");
 +        }
 +    } else {
 +        if (user == NULL) {
 +            adios (NULL, "must specify -user with -saslmech xoauth2");
 +        }
 +
 +        vec[vecp++] = "-authservice";
 +        if (saslmech  &&  ! strcasecmp(saslmech, "xoauth2")) {
 +            vec[vecp++] = mh_oauth_do_xoauth (user, auth_svc, snoop ? stderr : NULL);
 +        } else {
 +            vec[vecp++] = auth_svc;
 +        }
 +    }
 +#else
 +    NMH_UNUSED(auth_svc);
 +    NMH_UNUSED(user);
 +    NMH_UNUSED(saslmech);
 +#endif /* OAUTH_SUPPORT */
 +
      if (altmsg == NULL || stat (altmsg, &st) == NOTOK) {
        st.st_mtime = 0;
        st.st_dev = 0;
diff --combined uip/whatnowsbr.c
index 21988791ba2729b075f212f8252a89568e852e40,303f1b8682c957af97576cdd54bf8ae70c4d2028..d0423f53957db48bd16e2ac619da18b1ee80c7c3
  #include <h/mime.h>
  #include <h/utils.h>
  
 +#ifdef OAUTH_SUPPORT
 +# include <h/oauth.h>
 +#endif
 +
  #define WHATNOW_SWITCHES \
      X("draftfolder +folder", 0, DFOLDSW) \
      X("draftmessage msg", 0, DMSGSW) \
@@@ -237,9 -233,9 +237,9 @@@ WhatNow (int argc, char **argv
      snprintf (prompt, sizeof(prompt), myprompt, invo_name);
      for (;;) {
  #ifdef READLINE_SUPPORT
-       if (!(argp = getans_via_readline (prompt, aleqs))) {
+       if (!(argp = read_switch_multiword_via_readline (prompt, aleqs))) {
  #else /* ! READLINE_SUPPORT */
-       if (!(argp = getans (prompt, aleqs))) {
+       if (!(argp = read_switch_multiword (prompt, aleqs))) {
  #endif /* READLINE_SUPPORT */
            (void) m_unlink (LINK);
            done (1);
@@@ -945,12 -941,11 +945,12 @@@ buildfile (char **argp, char *file
      X("draftfolder +folder", -6, SDRFSW) \
      X("draftmessage msg", -6, SDRMSW) \
      X("nodraftfolder", -3, SNDRFSW) \
 -    X("sasl", SASLminc(-4), SASLSW) \
 -    X("nosasl", SASLminc(-6), NOSASLSW) \
 -    X("saslmaxssf", SASLminc(-10), SASLMXSSFSW) \
 -    X("saslmech", SASLminc(-5), SASLMECHSW) \
 -    X("user", SASLminc(-4), USERSW) \
 +    X("sasl", SASLminc(4), SASLSW) \
 +    X("nosasl", SASLminc(6), NOSASLSW) \
 +    X("saslmaxssf", SASLminc(10), SASLMXSSFSW) \
 +    X("saslmech", SASLminc(5), SASLMECHSW) \
 +    X("authservice", SASLminc(0), AUTHSERVICESW) \
 +    X("user username", SASLminc(4), USERSW) \
      X("attach fieldname", 6, SNDATTACHSW) \
      X("noattach", 0, SNDNOATTACHSW) \
      X("attachformat", 7, SNDATTACHFORMAT) \
@@@ -990,9 -985,6 +990,9 @@@ sendit (char *sp, char **arg, char *fil
      int       vecp, n = 1;
      char *cp, buf[BUFSIZ], **argp, *program;
      char **arguments, *savearg[MAXARGS], **vec;
 +    const char *user = NULL, *saslmech = NULL;
 +    char *auth_svc = NULL;
 +    int snoop = 0;
      struct stat st;
  
  #ifndef       lint
                case NMSGDSW:
                case WATCSW:
                case NWATCSW:
 -              case SNOOPSW:
                case SASLSW:
                case NOSASLSW:
                case TLSSW:
                    vec[vecp++] = --cp;
                    continue;
  
 +              case SNOOPSW:
 +                    snoop++;
 +                  vec[vecp++] = --cp;
 +                  continue;
 +
 +              case AUTHSERVICESW:
 +#ifdef OAUTH_SUPPORT
 +                  if (!(auth_svc = *argp++) || *auth_svc == '-')
 +                      adios (NULL, "missing argument to %s", argp[-2]);
 +#else
 +                    NMH_UNUSED (user);
 +                    NMH_UNUSED (auth_svc);
 +                  adios (NULL, "not built with OAuth support");
 +#endif
 +                  continue;
 +
 +              case SASLMECHSW:
 +                    saslmech = *argp;
 +                  /* fall thru */
                case ALIASW:
                case FILTSW:
                case WIDTHSW:
                case CLIESW:
                case SERVSW:
                case SASLMXSSFSW:
 -              case SASLMECHSW:
                case USERSW:
                case PORTSW:
                case MTSSM:
                        return;
                    }
                    vec[vecp++] = cp;
 +                    user = cp;
                    continue;
  
                case SDRFSW:
        distfile = NULL;
      }
  
 +#ifdef OAUTH_SUPPORT
 +    if (auth_svc == NULL) {
 +        if (saslmech  &&  ! strcasecmp(saslmech, "xoauth2")) {
 +            adios (NULL, "must specify -authservice with -saslmech xoauth2");
 +        }
 +    } else {
 +        if (user == NULL) {
 +            adios (NULL, "must specify -user with -saslmech xoauth2");
 +        }
 +
 +        vec[vecp++] = "-authservice";
 +        if (saslmech  &&  ! strcasecmp(saslmech, "xoauth2")) {
 +            vec[vecp++] = mh_oauth_do_xoauth (user, auth_svc, snoop ? stderr : NULL);
 +        } else {
 +            vec[vecp++] = auth_svc;
 +        }
 +    }
 +#else
 +    NMH_UNUSED(saslmech);
 +#endif /* OAUTH_SUPPORT */
 +
      if (altmsg == NULL || stat (altmsg, &st) == NOTOK) {
        st.st_mtime = 0;
        st.st_dev = 0;