This patch series does the following things: Firstly it basically makes the imap-send command usable again since it was broken because of not being able to correctly parse the config file. Further it adds support for OAuth2.0 and PLAIN authentication to git imap-send. Lastly, it does some minor improvements including adding the ability to specify the folder using the command line and ability to list the available folders by adding a `--list` option. v2: - Added support for OAuth2.0 with curl. - Fixed the memory leak in case auth_cram_md5 fails. v3: - Improve wording in first patch - Change misleading message if OAuth2.0 is used without OpenSSL v4: - Add PLAIN authentication mechanism for OpenSSL - Improved wording in the first patch a bit more v5: - Add ability to specify destination folder using the command line - Add ability to set a default between curl and openssl using the config v6: - Fix minor mistakes in --folder documentation v7: - Fix spelling and grammar mistakes in logs shown to the user when running imap-send - Display port alongwith host when git credential is invoked and asks for a password - Display the destination mailbox when sending a message v8: - Drop the patch that enabled user to choose between libcurl and openssl using the config - Add ability to list the available folders by adding a `--list` option v9: - Encourage users to use OAuth2.0 for Gmail (similar change done for send-email docs). v10: - Fix comment styles - Fix failing tests v11: - Use lower case letters for the first word of a sendtence in an error message and avoid using full stops at the end of a sentence. v12: - Gracefully exit PLAIN, CRAM-MD5, OAUTHBEARER and XOAUTH2 authentication methods if OpenSSL support is not compiled in, but is requested by the user. - Use backticks for string literals. - Wrap documentation text to 75 columns. - End the last member of enum CAPABILITY with a trailing comma. v13: - Fix logic error which was using || instead of && when checking if the authentication method is neither XOAUTH2 nor OAUTHBEARER. v14: - Specify why we are not using CURLOPT_PASSWORD for OAuth2.0 methods using a comment. - Add a function try_auth_method() to reduce code duplication when trying to authenticate using a specific method. v15: - Simply rearrange the patches to make the cram md5 patches come before adding OAuth2.0 and PLAIN authentication methods. No change has been done to the code itself. Aditya Garg (10): imap-send: fix bug causing cfg->folder being set to NULL imap-send: fix memory leak in case auth_cram_md5 fails imap-send: gracefully fail if CRAM-MD5 authentication is requested without OpenSSL imap-send: add support for OAuth2.0 authentication imap-send: add PLAIN authentication method to OpenSSL imap-send: enable specifying the folder using the command line imap-send: fix minor mistakes in the logs imap-send: display port alongwith host when git credential is invoked imap-send: display the destination mailbox when sending a message imap-send: add ability to list the available folders Documentation/config/imap.adoc | 11 +- Documentation/git-imap-send.adoc | 68 ++++- imap-send.c | 412 ++++++++++++++++++++++++++----- 3 files changed, 414 insertions(+), 77 deletions(-) Range-diff against v14: -: ---------- > 1: 3e3ddf7077 imap-send: fix bug causing cfg->folder being set to NULL 3: 1510127888 = 2: 417b3b8e38 imap-send: fix memory leak in case auth_cram_md5 fails 4: 731fcbb602 ! 3: c4216528e7 imap-send: gracefully fail if CRAM-MD5 authentication is requested without OpenSSL @@ Commit message Signed-off-by: Aditya Garg <gargaditya08@xxxxxxxx> ## imap-send.c ## -@@ imap-send.c: static int auth_plain(struct imap_store *ctx, const char *prompt UNUSED) - return 0; +@@ imap-send.c: static char *cram(const char *challenge_64, const char *user, const char *pass) + return (char *)response_64; } -+static int auth_cram_md5(struct imap_store *ctx, const char *prompt) -+{ -+ int ret; -+ char *response; -+ -+ response = cram(prompt, ctx->cfg->user, ctx->cfg->pass); -+ -+ ret = socket_write(&ctx->imap->buf.sock, response, strlen(response)); -+ if (ret != strlen(response)) { -+ free(response); -+ return error("IMAP error: sending response failed"); -+ } -+ -+ free(response); -+ -+ return 0; -+} -+ - static int auth_oauthbearer(struct imap_store *ctx, const char *prompt UNUSED) - { - int ret; -@@ imap-send.c: static int auth_xoauth2(struct imap_store *ctx, const char *prompt UNUSED) - - #else - +-#else +- -static char *cram(const char *challenge_64 UNUSED, - const char *user UNUSED, - const char *pass UNUSED) @@ imap-send.c: static int auth_xoauth2(struct imap_store *ctx, const char *prompt - "you have to build git-imap-send with OpenSSL library."); -} - - #define auth_plain NULL -+#define auth_cram_md5 NULL - #define auth_oauthbearer NULL - #define auth_xoauth2 NULL - - #endif - --static int auth_cram_md5(struct imap_store *ctx, const char *prompt) --{ -- int ret; -- char *response; -- -- response = cram(prompt, ctx->cfg->user, ctx->cfg->pass); -- -- ret = socket_write(&ctx->imap->buf.sock, response, strlen(response)); -- if (ret != strlen(response)) { -- free(response); -- return error("IMAP error: sending response failed"); -- } -- -- free(response); -- -- return 0; --} +-#endif - + static int auth_cram_md5(struct imap_store *ctx, const char *prompt) + { + int ret; +@@ imap-send.c: static int auth_cram_md5(struct imap_store *ctx, const char *prompt) + return 0; + } + ++#else ++ ++#define auth_cram_md5 NULL ++ ++#endif ++ static void server_fill_credential(struct imap_server_conf *srvc, struct credential *cred) { if (srvc->user && srvc->pass) +@@ imap-send.c: static void server_fill_credential(struct imap_server_conf *srvc, struct credent + srvc->pass = xstrdup(cred->password); + } + ++static int try_auth_method(struct imap_server_conf *srvc, ++ struct imap_store *ctx, ++ struct imap *imap, ++ const char *auth_method, ++ enum CAPABILITY cap, ++ int (*fn)(struct imap_store *, const char *)) ++{ ++ struct imap_cmd_cb cb = {0}; ++ ++ if (!CAP(cap)) { ++ fprintf(stderr, "You specified " ++ "%s as authentication method, " ++ "but %s doesn't support it.\n", ++ auth_method, srvc->host); ++ return -1; ++ } ++ cb.cont = fn; ++ ++ if (NOT_CONSTANT(!cb.cont)) { ++ fprintf(stderr, "If you want to use %s authentication mechanism, " ++ "you have to build git-imap-send with OpenSSL library.", ++ auth_method); ++ return -1; ++ } ++ if (imap_exec(ctx, &cb, "AUTHENTICATE %s", auth_method) != RESP_OK) { ++ fprintf(stderr, "IMAP error: AUTHENTICATE %s failed\n", ++ auth_method); ++ return -1; ++ } ++ return 0; ++} ++ + static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const char *folder) + { + struct credential cred = CREDENTIAL_INIT; @@ imap-send.c: static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c server_fill_credential(srvc, &cred); if (srvc->auth_method) { - struct imap_cmd_cb cb; - - if (!strcmp(srvc->auth_method, "PLAIN")) { - if (try_auth_method(srvc, ctx, imap, "PLAIN", AUTH_PLAIN, auth_plain)) - goto bail; - } else if (!strcmp(srvc->auth_method, "CRAM-MD5")) { + if (!strcmp(srvc->auth_method, "CRAM-MD5")) { - if (!CAP(AUTH_CRAM_MD5)) { - fprintf(stderr, "You specified " - "CRAM-MD5 as authentication method, " @@ imap-send.c: static struct imap_store *imap_open_store(struct imap_server_conf * + if (try_auth_method(srvc, ctx, imap, "CRAM-MD5", AUTH_CRAM_MD5, auth_cram_md5)) goto bail; - } - } else if (!strcmp(srvc->auth_method, "OAUTHBEARER")) { - if (try_auth_method(srvc, ctx, imap, "OAUTHBEARER", AUTH_OAUTHBEARER, auth_oauthbearer)) - goto bail; + } else { + fprintf(stderr, "Unknown authentication method:%s\n", srvc->host); + goto bail; 1: 34d56c3b57 ! 4: b38fca0e6a imap-send: add support for OAuth2.0 authentication @@ imap-send.c: static char *cram(const char *challenge_64, const char *user, const + return b64; +} + + static int auth_cram_md5(struct imap_store *ctx, const char *prompt) + { + int ret; +@@ imap-send.c: static int auth_cram_md5(struct imap_store *ctx, const char *prompt) + return 0; + } + +static int auth_oauthbearer(struct imap_store *ctx, const char *prompt UNUSED) +{ + int ret; @@ imap-send.c: static char *cram(const char *challenge_64, const char *user, const + #else - static char *cram(const char *challenge_64 UNUSED, -@@ imap-send.c: static char *cram(const char *challenge_64 UNUSED, - "you have to build git-imap-send with OpenSSL library."); - } - + #define auth_cram_md5 NULL +#define auth_oauthbearer NULL +#define auth_xoauth2 NULL -+ - #endif - static int auth_cram_md5(struct imap_store *ctx, const char *prompt) -@@ imap-send.c: static void server_fill_credential(struct imap_server_conf *srvc, struct credent - srvc->pass = xstrdup(cred->password); - } + #endif -+static int try_auth_method(struct imap_server_conf *srvc, -+ struct imap_store *ctx, -+ struct imap *imap, -+ const char *auth_method, -+ enum CAPABILITY cap, -+ int (*fn)(struct imap_store *, const char *)) -+{ -+ struct imap_cmd_cb cb = {0}; -+ -+ if (!CAP(cap)) { -+ fprintf(stderr, "You specified " -+ "%s as authentication method, " -+ "but %s doesn't support it.\n", -+ auth_method, srvc->host); -+ return -1; -+ } -+ cb.cont = fn; -+ -+ if (NOT_CONSTANT(!cb.cont)) { -+ fprintf(stderr, "If you want to use %s authentication mechanism, " -+ "you have to build git-imap-send with OpenSSL library.", -+ auth_method); -+ return -1; -+ } -+ if (imap_exec(ctx, &cb, "AUTHENTICATE %s", auth_method) != RESP_OK) { -+ fprintf(stderr, "IMAP error: AUTHENTICATE %s failed\n", -+ auth_method); -+ return -1; -+ } -+ return 0; -+} -+ - static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const char *folder) - { - struct credential cred = CREDENTIAL_INIT; @@ imap-send.c: static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c - fprintf(stderr, "IMAP error: AUTHENTICATE CRAM-MD5 failed\n"); + if (!strcmp(srvc->auth_method, "CRAM-MD5")) { + if (try_auth_method(srvc, ctx, imap, "CRAM-MD5", AUTH_CRAM_MD5, auth_cram_md5)) goto bail; - } + } else if (!strcmp(srvc->auth_method, "OAUTHBEARER")) { + if (try_auth_method(srvc, ctx, imap, "OAUTHBEARER", AUTH_OAUTHBEARER, auth_oauthbearer)) + goto bail; 2: 69fb8f63f1 ! 5: 86d3d2c54d imap-send: add PLAIN authentication method to OpenSSL @@ imap-send.c: static char *xoauth2_base64(const char *user, const char *access_to + return 0; +} + - static int auth_oauthbearer(struct imap_store *ctx, const char *prompt UNUSED) + static int auth_cram_md5(struct imap_store *ctx, const char *prompt) { int ret; -@@ imap-send.c: static char *cram(const char *challenge_64 UNUSED, - "you have to build git-imap-send with OpenSSL library."); - } +@@ imap-send.c: static int auth_xoauth2(struct imap_store *ctx, const char *prompt UNUSED) + + #else +#define auth_plain NULL + #define auth_cram_md5 NULL #define auth_oauthbearer NULL #define auth_xoauth2 NULL - @@ imap-send.c: static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c - if (srvc->auth_method) { - struct imap_cmd_cb cb; + server_fill_credential(srvc, &cred); + if (srvc->auth_method) { - if (!strcmp(srvc->auth_method, "CRAM-MD5")) { + if (!strcmp(srvc->auth_method, "PLAIN")) { + if (try_auth_method(srvc, ctx, imap, "PLAIN", AUTH_PLAIN, auth_plain)) + goto bail; + } else if (!strcmp(srvc->auth_method, "CRAM-MD5")) { - if (!CAP(AUTH_CRAM_MD5)) { - fprintf(stderr, "You specified " - "CRAM-MD5 as authentication method, " + if (try_auth_method(srvc, ctx, imap, "CRAM-MD5", AUTH_CRAM_MD5, auth_cram_md5)) + goto bail; + } else if (!strcmp(srvc->auth_method, "OAUTHBEARER")) { 5: 36154d3276 = 6: 7674e749c8 imap-send: enable specifying the folder using the command line 6: 85ce1205ca = 7: a67322ce06 imap-send: fix minor mistakes in the logs 7: 8dd19a4613 = 8: b2e7ef35ed imap-send: display port alongwith host when git credential is invoked 8: cc1398bb7c = 9: 668e62c0e0 imap-send: display the destination mailbox when sending a message 9: 0975df9fc0 = 10: 4d9a3b5661 imap-send: add ability to list the available folders -- 2.49.0