mirror of
https://github.com/git/git.git
synced 2025-12-12 20:36:24 +01:00
Merge branch 'ag/imap-send-resurrection' into jt/imap-send-message-fix
* ag/imap-send-resurrection: imap-send: fix minor mistakes in the logs imap-send: display the destination mailbox when sending a message imap-send: display port alongwith host when git credential is invoked imap-send: add ability to list the available folders imap-send: enable specifying the folder using the command line imap-send: add PLAIN authentication method to OpenSSL imap-send: add support for OAuth2.0 authentication imap-send: gracefully fail if CRAM-MD5 authentication is requested without OpenSSL imap-send: fix memory leak in case auth_cram_md5 fails imap-send: fix bug causing cfg->folder being set to NULL
This commit is contained in:
407
imap-send.c
407
imap-send.c
@@ -45,13 +45,21 @@
|
||||
#endif
|
||||
|
||||
static int verbosity;
|
||||
static int list_folders;
|
||||
static int use_curl = USE_CURL_DEFAULT;
|
||||
static char *opt_folder;
|
||||
|
||||
static const char * const imap_send_usage[] = { "git imap-send [-v] [-q] [--[no-]curl] < <mbox>", NULL };
|
||||
static char const * const imap_send_usage[] = {
|
||||
N_("git imap-send [-v] [-q] [--[no-]curl] [(--folder|-f) <folder>] < <mbox>"),
|
||||
"git imap-send --list",
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct option imap_send_options[] = {
|
||||
OPT__VERBOSITY(&verbosity),
|
||||
OPT_BOOL(0, "curl", &use_curl, "use libcurl to communicate with the IMAP server"),
|
||||
OPT_STRING('f', "folder", &opt_folder, "folder", "specify the IMAP folder"),
|
||||
OPT_BOOL(0, "list", &list_folders, "list all folders on the IMAP server"),
|
||||
OPT_END()
|
||||
};
|
||||
|
||||
@@ -139,7 +147,10 @@ enum CAPABILITY {
|
||||
LITERALPLUS,
|
||||
NAMESPACE,
|
||||
STARTTLS,
|
||||
AUTH_CRAM_MD5
|
||||
AUTH_PLAIN,
|
||||
AUTH_CRAM_MD5,
|
||||
AUTH_OAUTHBEARER,
|
||||
AUTH_XOAUTH2,
|
||||
};
|
||||
|
||||
static const char *cap_list[] = {
|
||||
@@ -148,7 +159,10 @@ static const char *cap_list[] = {
|
||||
"LITERAL+",
|
||||
"NAMESPACE",
|
||||
"STARTTLS",
|
||||
"AUTH=PLAIN",
|
||||
"AUTH=CRAM-MD5",
|
||||
"AUTH=OAUTHBEARER",
|
||||
"AUTH=XOAUTH2",
|
||||
};
|
||||
|
||||
#define RESP_OK 0
|
||||
@@ -197,7 +211,7 @@ static int ssl_socket_connect(struct imap_socket *sock UNUSED,
|
||||
const struct imap_server_conf *cfg UNUSED,
|
||||
int use_tls_only UNUSED)
|
||||
{
|
||||
fprintf(stderr, "SSL requested but SSL support not compiled in\n");
|
||||
fprintf(stderr, "SSL requested, but SSL support is not compiled in\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -421,7 +435,7 @@ static int buffer_gets(struct imap_buffer *b, char **s)
|
||||
if (b->buf[b->offset + 1] == '\n') {
|
||||
b->buf[b->offset] = 0; /* terminate the string */
|
||||
b->offset += 2; /* next line */
|
||||
if (0 < verbosity)
|
||||
if ((0 < verbosity) || (list_folders && strstr(*s, "* LIST")))
|
||||
puts(*s);
|
||||
return 0;
|
||||
}
|
||||
@@ -847,6 +861,38 @@ static char hexchar(unsigned int b)
|
||||
}
|
||||
|
||||
#define ENCODED_SIZE(n) (4 * DIV_ROUND_UP((n), 3))
|
||||
static char *plain_base64(const char *user, const char *pass)
|
||||
{
|
||||
struct strbuf raw = STRBUF_INIT;
|
||||
int b64_len;
|
||||
char *b64;
|
||||
|
||||
/*
|
||||
* Compose the PLAIN string
|
||||
*
|
||||
* The username and password are combined to one string and base64 encoded.
|
||||
* "\0user\0pass"
|
||||
*
|
||||
* The method has been described in RFC4616.
|
||||
*
|
||||
* https://datatracker.ietf.org/doc/html/rfc4616
|
||||
*/
|
||||
strbuf_addch(&raw, '\0');
|
||||
strbuf_addstr(&raw, user);
|
||||
strbuf_addch(&raw, '\0');
|
||||
strbuf_addstr(&raw, pass);
|
||||
|
||||
b64 = xmallocz(ENCODED_SIZE(raw.len));
|
||||
b64_len = EVP_EncodeBlock((unsigned char *)b64, (unsigned char *)raw.buf, raw.len);
|
||||
strbuf_release(&raw);
|
||||
|
||||
if (b64_len < 0) {
|
||||
free(b64);
|
||||
return NULL;
|
||||
}
|
||||
return b64;
|
||||
}
|
||||
|
||||
static char *cram(const char *challenge_64, const char *user, const char *pass)
|
||||
{
|
||||
int i, resp_len, encoded_len, decoded_len;
|
||||
@@ -885,17 +931,83 @@ static char *cram(const char *challenge_64, const char *user, const char *pass)
|
||||
return (char *)response_64;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static char *cram(const char *challenge_64 UNUSED,
|
||||
const char *user UNUSED,
|
||||
const char *pass UNUSED)
|
||||
static char *oauthbearer_base64(const char *user, const char *access_token)
|
||||
{
|
||||
die("If you want to use CRAM-MD5 authenticate method, "
|
||||
"you have to build git-imap-send with OpenSSL library.");
|
||||
int b64_len;
|
||||
char *raw, *b64;
|
||||
|
||||
/*
|
||||
* Compose the OAUTHBEARER string
|
||||
*
|
||||
* "n,a=" {User} ",^Ahost=" {Host} "^Aport=" {Port} "^Aauth=Bearer " {Access Token} "^A^A
|
||||
*
|
||||
* The first part `n,a=" {User} ",` is the gs2 header described in RFC5801.
|
||||
* * gs2-cb-flag `n` -> client does not support CB
|
||||
* * gs2-authzid `a=" {User} "`
|
||||
*
|
||||
* The second part are key value pairs containing host, port and auth as
|
||||
* described in RFC7628.
|
||||
*
|
||||
* https://datatracker.ietf.org/doc/html/rfc5801
|
||||
* https://datatracker.ietf.org/doc/html/rfc7628
|
||||
*/
|
||||
raw = xstrfmt("n,a=%s,\001auth=Bearer %s\001\001", user, access_token);
|
||||
|
||||
/* Base64 encode */
|
||||
b64 = xmallocz(ENCODED_SIZE(strlen(raw)));
|
||||
b64_len = EVP_EncodeBlock((unsigned char *)b64, (unsigned char *)raw, strlen(raw));
|
||||
free(raw);
|
||||
|
||||
if (b64_len < 0) {
|
||||
free(b64);
|
||||
return NULL;
|
||||
}
|
||||
return b64;
|
||||
}
|
||||
|
||||
#endif
|
||||
static char *xoauth2_base64(const char *user, const char *access_token)
|
||||
{
|
||||
int b64_len;
|
||||
char *raw, *b64;
|
||||
|
||||
/*
|
||||
* Compose the XOAUTH2 string
|
||||
* "user=" {User} "^Aauth=Bearer " {Access Token} "^A^A"
|
||||
* https://developers.google.com/workspace/gmail/imap/xoauth2-protocol#initial_client_response
|
||||
*/
|
||||
raw = xstrfmt("user=%s\001auth=Bearer %s\001\001", user, access_token);
|
||||
|
||||
/* Base64 encode */
|
||||
b64 = xmallocz(ENCODED_SIZE(strlen(raw)));
|
||||
b64_len = EVP_EncodeBlock((unsigned char *)b64, (unsigned char *)raw, strlen(raw));
|
||||
free(raw);
|
||||
|
||||
if (b64_len < 0) {
|
||||
free(b64);
|
||||
return NULL;
|
||||
}
|
||||
return b64;
|
||||
}
|
||||
|
||||
static int auth_plain(struct imap_store *ctx, const char *prompt UNUSED)
|
||||
{
|
||||
int ret;
|
||||
char *b64;
|
||||
|
||||
b64 = plain_base64(ctx->cfg->user, ctx->cfg->pass);
|
||||
if (!b64)
|
||||
return error("PLAIN: base64 encoding failed");
|
||||
|
||||
/* Send the base64-encoded response */
|
||||
ret = socket_write(&ctx->imap->buf.sock, b64, strlen(b64));
|
||||
if (ret != (int)strlen(b64)) {
|
||||
free(b64);
|
||||
return error("IMAP error: sending PLAIN response failed");
|
||||
}
|
||||
|
||||
free(b64);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int auth_cram_md5(struct imap_store *ctx, const char *prompt)
|
||||
{
|
||||
@@ -905,21 +1017,72 @@ static int auth_cram_md5(struct imap_store *ctx, const char *prompt)
|
||||
response = cram(prompt, ctx->cfg->user, ctx->cfg->pass);
|
||||
|
||||
ret = socket_write(&ctx->imap->buf.sock, response, strlen(response));
|
||||
if (ret != strlen(response))
|
||||
return error("IMAP error: sending response failed");
|
||||
if (ret != strlen(response)) {
|
||||
free(response);
|
||||
return error("IMAP error: sending CRAM-MD5 response failed");
|
||||
}
|
||||
|
||||
free(response);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int auth_oauthbearer(struct imap_store *ctx, const char *prompt UNUSED)
|
||||
{
|
||||
int ret;
|
||||
char *b64;
|
||||
|
||||
b64 = oauthbearer_base64(ctx->cfg->user, ctx->cfg->pass);
|
||||
if (!b64)
|
||||
return error("OAUTHBEARER: base64 encoding failed");
|
||||
|
||||
/* Send the base64-encoded response */
|
||||
ret = socket_write(&ctx->imap->buf.sock, b64, strlen(b64));
|
||||
if (ret != (int)strlen(b64)) {
|
||||
free(b64);
|
||||
return error("IMAP error: sending OAUTHBEARER response failed");
|
||||
}
|
||||
|
||||
free(b64);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int auth_xoauth2(struct imap_store *ctx, const char *prompt UNUSED)
|
||||
{
|
||||
int ret;
|
||||
char *b64;
|
||||
|
||||
b64 = xoauth2_base64(ctx->cfg->user, ctx->cfg->pass);
|
||||
if (!b64)
|
||||
return error("XOAUTH2: base64 encoding failed");
|
||||
|
||||
/* Send the base64-encoded response */
|
||||
ret = socket_write(&ctx->imap->buf.sock, b64, strlen(b64));
|
||||
if (ret != (int)strlen(b64)) {
|
||||
free(b64);
|
||||
return error("IMAP error: sending XOAUTH2 response failed");
|
||||
}
|
||||
|
||||
free(b64);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define auth_plain NULL
|
||||
#define auth_cram_md5 NULL
|
||||
#define auth_oauthbearer NULL
|
||||
#define auth_xoauth2 NULL
|
||||
|
||||
#endif
|
||||
|
||||
static void server_fill_credential(struct imap_server_conf *srvc, struct credential *cred)
|
||||
{
|
||||
if (srvc->user && srvc->pass)
|
||||
return;
|
||||
|
||||
cred->protocol = xstrdup(srvc->use_ssl ? "imaps" : "imap");
|
||||
cred->host = xstrdup(srvc->host);
|
||||
cred->host = xstrfmt("%s:%d", srvc->host, srvc->port);
|
||||
|
||||
cred->username = xstrdup_or_null(srvc->user);
|
||||
cred->password = xstrdup_or_null(srvc->pass);
|
||||
@@ -932,6 +1095,38 @@ 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;
|
||||
@@ -964,7 +1159,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c
|
||||
imap->buf.sock.fd[0] = tunnel.out;
|
||||
imap->buf.sock.fd[1] = tunnel.in;
|
||||
|
||||
imap_info("ok\n");
|
||||
imap_info("OK\n");
|
||||
} else {
|
||||
#ifndef NO_IPV6
|
||||
struct addrinfo hints, *ai0, *ai;
|
||||
@@ -983,7 +1178,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c
|
||||
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(gai));
|
||||
goto bail;
|
||||
}
|
||||
imap_info("ok\n");
|
||||
imap_info("OK\n");
|
||||
|
||||
for (ai0 = ai; ai; ai = ai->ai_next) {
|
||||
char addr[NI_MAXHOST];
|
||||
@@ -1021,7 +1216,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c
|
||||
perror("gethostbyname");
|
||||
goto bail;
|
||||
}
|
||||
imap_info("ok\n");
|
||||
imap_info("OK\n");
|
||||
|
||||
addr.sin_addr.s_addr = *((int *) he->h_addr_list[0]);
|
||||
|
||||
@@ -1035,7 +1230,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c
|
||||
}
|
||||
#endif
|
||||
if (s < 0) {
|
||||
fputs("Error: unable to connect to server.\n", stderr);
|
||||
fputs("error: unable to connect to server\n", stderr);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
@@ -1047,7 +1242,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const c
|
||||
close(s);
|
||||
goto bail;
|
||||
}
|
||||
imap_info("ok\n");
|
||||
imap_info("OK\n");
|
||||
}
|
||||
|
||||
/* read the greeting string */
|
||||
@@ -1087,30 +1282,25 @@ 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, "CRAM-MD5")) {
|
||||
if (!CAP(AUTH_CRAM_MD5)) {
|
||||
fprintf(stderr, "You specified "
|
||||
"CRAM-MD5 as authentication method, "
|
||||
"but %s doesn't support it.\n", srvc->host);
|
||||
if (!strcmp(srvc->auth_method, "PLAIN")) {
|
||||
if (try_auth_method(srvc, ctx, imap, "PLAIN", AUTH_PLAIN, auth_plain))
|
||||
goto bail;
|
||||
}
|
||||
/* CRAM-MD5 */
|
||||
|
||||
memset(&cb, 0, sizeof(cb));
|
||||
cb.cont = auth_cram_md5;
|
||||
if (imap_exec(ctx, &cb, "AUTHENTICATE CRAM-MD5") != RESP_OK) {
|
||||
fprintf(stderr, "IMAP error: AUTHENTICATE CRAM-MD5 failed\n");
|
||||
} else 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;
|
||||
} else if (!strcmp(srvc->auth_method, "XOAUTH2")) {
|
||||
if (try_auth_method(srvc, ctx, imap, "XOAUTH2", AUTH_XOAUTH2, auth_xoauth2))
|
||||
goto bail;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Unknown authentication method:%s\n", srvc->host);
|
||||
fprintf(stderr, "unknown authentication mechanism: %s\n", srvc->auth_method);
|
||||
goto bail;
|
||||
}
|
||||
} else {
|
||||
if (CAP(NOLOGIN)) {
|
||||
fprintf(stderr, "Skipping account %s@%s, server forbids LOGIN\n",
|
||||
fprintf(stderr, "skipping account %s@%s, server forbids LOGIN\n",
|
||||
srvc->user, srvc->host);
|
||||
goto bail;
|
||||
}
|
||||
@@ -1316,16 +1506,16 @@ static int git_imap_config(const char *var, const char *val,
|
||||
FREE_AND_NULL(cfg->folder);
|
||||
return git_config_string(&cfg->folder, var, val);
|
||||
} else if (!strcmp("imap.user", var)) {
|
||||
FREE_AND_NULL(cfg->folder);
|
||||
FREE_AND_NULL(cfg->user);
|
||||
return git_config_string(&cfg->user, var, val);
|
||||
} else if (!strcmp("imap.pass", var)) {
|
||||
FREE_AND_NULL(cfg->folder);
|
||||
FREE_AND_NULL(cfg->pass);
|
||||
return git_config_string(&cfg->pass, var, val);
|
||||
} else if (!strcmp("imap.tunnel", var)) {
|
||||
FREE_AND_NULL(cfg->folder);
|
||||
FREE_AND_NULL(cfg->tunnel);
|
||||
return git_config_string(&cfg->tunnel, var, val);
|
||||
} else if (!strcmp("imap.authmethod", var)) {
|
||||
FREE_AND_NULL(cfg->folder);
|
||||
FREE_AND_NULL(cfg->auth_method);
|
||||
return git_config_string(&cfg->auth_method, var, val);
|
||||
} else if (!strcmp("imap.port", var)) {
|
||||
cfg->port = git_config_int(var, val, ctx->kvi);
|
||||
@@ -1366,7 +1556,8 @@ static int append_msgs_to_imap(struct imap_server_conf *server,
|
||||
}
|
||||
ctx->name = server->folder;
|
||||
|
||||
fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
|
||||
fprintf(stderr, "Sending %d message%s to %s folder...\n",
|
||||
total, (total != 1) ? "s" : "", server->folder);
|
||||
while (1) {
|
||||
unsigned percent = n * 100 / total;
|
||||
|
||||
@@ -1388,6 +1579,26 @@ static int append_msgs_to_imap(struct imap_server_conf *server,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int list_imap_folders(struct imap_server_conf *server)
|
||||
{
|
||||
struct imap_store *ctx = imap_open_store(server, "INBOX");
|
||||
if (!ctx) {
|
||||
fprintf(stderr, "failed to connect to IMAP server\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Fetching the list of available folders...\n");
|
||||
/* Issue the LIST command and print the results */
|
||||
if (imap_exec(ctx, NULL, "LIST \"\" \"*\"") != RESP_OK) {
|
||||
fprintf(stderr, "failed to list folders\n");
|
||||
imap_close_store(ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
imap_close_store(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef USE_CURL_FOR_IMAP_SEND
|
||||
static CURL *setup_curl(struct imap_server_conf *srvc, struct credential *cred)
|
||||
{
|
||||
@@ -1405,29 +1616,51 @@ static CURL *setup_curl(struct imap_server_conf *srvc, struct credential *cred)
|
||||
|
||||
server_fill_credential(srvc, cred);
|
||||
curl_easy_setopt(curl, CURLOPT_USERNAME, srvc->user);
|
||||
curl_easy_setopt(curl, CURLOPT_PASSWORD, srvc->pass);
|
||||
|
||||
/*
|
||||
* Use CURLOPT_PASSWORD irrespective of whether there is
|
||||
* an auth method specified or not, unless it's OAuth2.0,
|
||||
* where we use CURLOPT_XOAUTH2_BEARER.
|
||||
*/
|
||||
if (!srvc->auth_method ||
|
||||
(strcmp(srvc->auth_method, "XOAUTH2") &&
|
||||
strcmp(srvc->auth_method, "OAUTHBEARER")))
|
||||
curl_easy_setopt(curl, CURLOPT_PASSWORD, srvc->pass);
|
||||
|
||||
strbuf_addstr(&path, srvc->use_ssl ? "imaps://" : "imap://");
|
||||
strbuf_addstr(&path, srvc->host);
|
||||
if (!path.len || path.buf[path.len - 1] != '/')
|
||||
strbuf_addch(&path, '/');
|
||||
|
||||
uri_encoded_folder = curl_easy_escape(curl, srvc->folder, 0);
|
||||
if (!uri_encoded_folder)
|
||||
die("failed to encode server folder");
|
||||
strbuf_addstr(&path, uri_encoded_folder);
|
||||
curl_free(uri_encoded_folder);
|
||||
if (!list_folders) {
|
||||
uri_encoded_folder = curl_easy_escape(curl, srvc->folder, 0);
|
||||
if (!uri_encoded_folder)
|
||||
die("failed to encode server folder");
|
||||
strbuf_addstr(&path, uri_encoded_folder);
|
||||
curl_free(uri_encoded_folder);
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, path.buf);
|
||||
strbuf_release(&path);
|
||||
curl_easy_setopt(curl, CURLOPT_PORT, (long)srvc->port);
|
||||
|
||||
if (srvc->auth_method) {
|
||||
struct strbuf auth = STRBUF_INIT;
|
||||
strbuf_addstr(&auth, "AUTH=");
|
||||
strbuf_addstr(&auth, srvc->auth_method);
|
||||
curl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, auth.buf);
|
||||
strbuf_release(&auth);
|
||||
if (!strcmp(srvc->auth_method, "XOAUTH2") ||
|
||||
!strcmp(srvc->auth_method, "OAUTHBEARER")) {
|
||||
|
||||
/*
|
||||
* While CURLOPT_XOAUTH2_BEARER looks as if it only supports XOAUTH2,
|
||||
* upon debugging, it has been found that it is capable of detecting
|
||||
* the best option out of OAUTHBEARER and XOAUTH2.
|
||||
*/
|
||||
curl_easy_setopt(curl, CURLOPT_XOAUTH2_BEARER, srvc->pass);
|
||||
} else {
|
||||
struct strbuf auth = STRBUF_INIT;
|
||||
strbuf_addstr(&auth, "AUTH=");
|
||||
strbuf_addstr(&auth, srvc->auth_method);
|
||||
curl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, auth.buf);
|
||||
strbuf_release(&auth);
|
||||
}
|
||||
}
|
||||
|
||||
if (!srvc->use_ssl)
|
||||
@@ -1436,10 +1669,6 @@ static CURL *setup_curl(struct imap_server_conf *srvc, struct credential *cred)
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, (long)srvc->ssl_verify);
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, (long)srvc->ssl_verify);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_READFUNCTION, fread_buffer);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
|
||||
|
||||
if (0 < verbosity || getenv("GIT_CURL_VERBOSE"))
|
||||
http_trace_curl_no_data();
|
||||
setup_curl_trace(curl);
|
||||
@@ -1458,9 +1687,14 @@ static int curl_append_msgs_to_imap(struct imap_server_conf *server,
|
||||
struct credential cred = CREDENTIAL_INIT;
|
||||
|
||||
curl = setup_curl(server, &cred);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_READFUNCTION, fread_buffer);
|
||||
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_READDATA, &msgbuf);
|
||||
|
||||
fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
|
||||
fprintf(stderr, "Sending %d message%s to %s folder...\n",
|
||||
total, (total != 1) ? "s" : "", server->folder);
|
||||
while (1) {
|
||||
unsigned percent = n * 100 / total;
|
||||
int prev_len;
|
||||
@@ -1503,6 +1737,31 @@ static int curl_append_msgs_to_imap(struct imap_server_conf *server,
|
||||
|
||||
return res != CURLE_OK;
|
||||
}
|
||||
|
||||
static int curl_list_imap_folders(struct imap_server_conf *server)
|
||||
{
|
||||
CURL *curl;
|
||||
CURLcode res = CURLE_OK;
|
||||
struct credential cred = CREDENTIAL_INIT;
|
||||
|
||||
fprintf(stderr, "Fetching the list of available folders...\n");
|
||||
curl = setup_curl(server, &cred);
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
curl_global_cleanup();
|
||||
|
||||
if (cred.username) {
|
||||
if (res == CURLE_OK)
|
||||
credential_approve(the_repository, &cred);
|
||||
else if (res == CURLE_LOGIN_DENIED)
|
||||
credential_reject(the_repository, &cred);
|
||||
}
|
||||
|
||||
credential_clear(&cred);
|
||||
|
||||
return res != CURLE_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
int cmd_main(int argc, const char **argv)
|
||||
@@ -1520,6 +1779,11 @@ int cmd_main(int argc, const char **argv)
|
||||
|
||||
argc = parse_options(argc, (const char **)argv, "", imap_send_options, imap_send_usage, 0);
|
||||
|
||||
if (opt_folder) {
|
||||
free(server.folder);
|
||||
server.folder = xstrdup(opt_folder);
|
||||
}
|
||||
|
||||
if (argc)
|
||||
usage_with_options(imap_send_usage, imap_send_options);
|
||||
|
||||
@@ -1538,20 +1802,33 @@ int cmd_main(int argc, const char **argv)
|
||||
if (!server.port)
|
||||
server.port = server.use_ssl ? 993 : 143;
|
||||
|
||||
if (!server.folder) {
|
||||
fprintf(stderr, "no imap store specified\n");
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
if (!server.host) {
|
||||
if (!server.tunnel) {
|
||||
fprintf(stderr, "no imap host specified\n");
|
||||
fprintf(stderr, "no IMAP host specified\n");
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
server.host = xstrdup("tunnel");
|
||||
}
|
||||
|
||||
if (list_folders) {
|
||||
if (server.tunnel)
|
||||
ret = list_imap_folders(&server);
|
||||
#ifdef USE_CURL_FOR_IMAP_SEND
|
||||
else if (use_curl)
|
||||
ret = curl_list_imap_folders(&server);
|
||||
#endif
|
||||
else
|
||||
ret = list_imap_folders(&server);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!server.folder) {
|
||||
fprintf(stderr, "no IMAP store specified\n");
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* read the messages */
|
||||
if (strbuf_read(&all_msgs, 0, 0) < 0) {
|
||||
error_errno(_("could not read from stdin"));
|
||||
@@ -1567,7 +1844,7 @@ int cmd_main(int argc, const char **argv)
|
||||
|
||||
total = count_messages(&all_msgs);
|
||||
if (!total) {
|
||||
fprintf(stderr, "no messages to send\n");
|
||||
fprintf(stderr, "no messages found to send\n");
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user