X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/8e0f9bd3daae9d05dec58026d5a5924367e4e874..9291a5f82480f2458e04cb9ea7e6749bc952b308:/uip/mhlogin.c diff --git a/uip/mhlogin.c b/uip/mhlogin.c index a08305c8..72a90b72 100644 --- a/uip/mhlogin.c +++ b/uip/mhlogin.c @@ -1,23 +1,32 @@ -/* - * mhlogin.c -- login to external (OAuth) services +/* mhlogin.c -- login to external (OAuth) services * * This code is Copyright (c) 2014, by the authors of nmh. See the * COPYRIGHT file in the root directory of the nmh distribution for * complete copyright information. */ +#include #include #include -#include -#include +#include "h/mh.h" +#include "sbr/ambigsw.h" +#include "sbr/print_version.h" +#include "sbr/print_help.h" +#include "sbr/error.h" +#include "h/done.h" +#include "h/utils.h" +#include "h/oauth.h" +#include "sbr/lock_file.h" #define MHLOGIN_SWITCHES \ - X("saslmech", 1, SASLMECHSW) \ - X("authservice", -11, AUTHSERVICESW) \ - X("snoop", 1, SNOOPSW) \ - X("help", 1, HELPSW) \ - X("version", 1, VERSIONSW) \ + X("user username", 0, USERSW) \ + X("saslmech", 0, SASLMECHSW) \ + X("authservice", 0, AUTHSERVICESW) \ + X("browser", 0, BROWSERSW) \ + X("snoop", 0, SNOOPSW) \ + X("help", 0, HELPSW) \ + X("version", 0, VERSIONSW) \ #define X(sw, minchars, id) id, DEFINE_SWITCH_ENUM(MHLOGIN); @@ -32,18 +41,17 @@ DEFINE_SWITCH_ARRAY(MHLOGIN, switches); static char * geta (void) { - char *cp; static char line[BUFSIZ]; if (fgets(line, sizeof(line), stdin) == NULL) done (1); - if ((cp = strchr(line, '\n'))) - *cp = 0; + trim_suffix_c(line, '\n'); + return line; } static int -do_login(const char *svc, int snoop) +do_login(const char *svc, const char *user, const char *browser, int snoop) { char *fn, *code; mh_oauth_ctx *ctx; @@ -53,53 +61,78 @@ do_login(const char *svc, int snoop) const char *url; if (svc == NULL) { - adios(NULL, "missing -authservice switch"); + die("missing -authservice switch"); + } + + if (user == NULL) { + die("missing -user switch"); } if (!mh_oauth_new(&ctx, svc)) { - adios(NULL, mh_oauth_get_err_string(ctx)); + die("%s", mh_oauth_get_err_string(ctx)); } if (snoop) { mh_oauth_log_to(stderr, ctx); } - fn = getcpy(mh_oauth_cred_fn(ctx)); + fn = mh_oauth_cred_fn(svc); if ((url = mh_oauth_get_authorize_url(ctx)) == NULL) { - adios(NULL, mh_oauth_get_err_string(ctx)); + die("%s", mh_oauth_get_err_string(ctx)); } - printf("Load the following URL in your browser and authorize nmh" - " to access %s:\n" - "\n%s\n\n" - "Enter the authorization code: ", - mh_oauth_svc_display_name(ctx), url); + if (browser) { + char *command = concat(browser, " '", url, "'", NULL); + int status = OK; + + printf("Follow the prompts in your browser to authorize nmh" + " to access %s.\n", + mh_oauth_svc_display_name(ctx)); + sleep(1); + + status = system(command); + free(command); + + if (status != OK) { + adios ((char *) browser, "SYSTEM"); + } + } else { + printf("Load the following URL in your browser and authorize nmh" + " to access %s:\n\n%s\n\n", + mh_oauth_svc_display_name(ctx), url); + } + fputs("Enter the authorization code: ", stdout); fflush(stdout); code = geta(); - while ((cred = mh_oauth_authorize(code, ctx)) == NULL - && mh_oauth_get_err_code(ctx) == MH_OAUTH_BAD_GRANT) { - printf("Code rejected; try again? "); + while (!*code || + ((cred = mh_oauth_authorize(code, ctx)) == NULL + && mh_oauth_get_err_code(ctx) == MH_OAUTH_BAD_GRANT)) { + printf(!*code ? "Empty code; try again? " : "Code rejected; try again? "); fflush(stdout); code = geta(); } if (cred == NULL) { - advise(NULL, "error exchanging code for OAuth2 token"); - adios(NULL, mh_oauth_get_err_string(ctx)); + inform("error exchanging code for OAuth2 token"); + die("%s", mh_oauth_get_err_string(ctx)); } - cred_file = lkfopendata(fn, "w", &failed_to_lock); + cred_file = lkfopendata(fn, "r+", &failed_to_lock); + if (cred_file == NULL && errno == ENOENT) { + cred_file = lkfopendata(fn, "w+", &failed_to_lock); + } if (cred_file == NULL || failed_to_lock) { adios(fn, "oops"); } - if (!mh_oauth_cred_save(cred_file, cred)) { - adios(NULL, mh_oauth_get_err_string(ctx)); + if (!mh_oauth_cred_save(cred_file, cred, user)) { + die("%s", mh_oauth_get_err_string(ctx)); } if (lkfclosedata(cred_file, fn) != 0) { adios (fn, "oops"); } + free(fn); mh_oauth_cred_free(cred); mh_oauth_free(ctx); @@ -111,10 +144,10 @@ int main(int argc, char **argv) { char *cp, **argp, **arguments; - char *saslmech = NULL, *svc = NULL; + const char *user = NULL, *saslmech = NULL, *svc = NULL, *browser = NULL; int snoop = 0; - if (nmh_init(argv[0], 1)) { return 1; } + if (nmh_init(argv[0], true, true)) { return 1; } arguments = getarguments (invo_name, argc, argv, 1); argp = arguments; @@ -127,7 +160,7 @@ main(int argc, char **argv) ambigsw (cp, switches); done (1); case UNKWNSW: - adios (NULL, "-%s unknown", cp); + die("-%s unknown", cp); case HELPSW: snprintf(help, sizeof(help), "%s [switches]", @@ -138,14 +171,24 @@ main(int argc, char **argv) print_version(invo_name); done (0); + case USERSW: + if (!(user = *argp++) || *user == '-') + die("missing argument to %s", argp[-2]); + continue; + case SASLMECHSW: if (!(saslmech = *argp++) || *saslmech == '-') - adios (NULL, "missing argument to %s", argp[-2]); + die("missing argument to %s", argp[-2]); continue; case AUTHSERVICESW: if (!(svc = *argp++) || *svc == '-') - adios (NULL, "missing argument to %s", argp[-2]); + die("missing argument to %s", argp[-2]); + continue; + + case BROWSERSW: + if (!(browser = *argp++) || *browser == '-') + die("missing argument to %s", argp[-2]); continue; case SNOOPSW: @@ -153,15 +196,22 @@ main(int argc, char **argv) continue; } } - adios(NULL, "extraneous arguments"); + die("extraneous arguments"); + } + + if (saslmech && strcasecmp(saslmech, "xoauth2")) { + /* xoauth is assumed */ + die("only -saslmech xoauth2 is supported"); } + free(arguments); #ifdef OAUTH_SUPPORT - return do_login(svc, snoop); + return do_login(svc, user, browser, snoop); #else NMH_UNUSED(svc); + NMH_UNUSED(browser); NMH_UNUSED(snoop); - adios(NULL, "not built with OAuth support"); + die("not built with OAuth support"); return 1; #endif }