diff options
Diffstat (limited to 'imap-send.c')
-rw-r--r-- | imap-send.c | 205 |
1 files changed, 84 insertions, 121 deletions
diff --git a/imap-send.c b/imap-send.c index 6c54d8c..0afd088 100644 --- a/imap-send.c +++ b/imap-send.c @@ -18,16 +18,18 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. + * along with this program; if not, see <https://www.gnu.org/licenses/>. */ -#include "cache.h" +#include "git-compat-util.h" #include "config.h" #include "credential.h" -#include "exec-cmd.h" +#include "gettext.h" #include "run-command.h" #include "parse-options.h" -#ifdef NO_OPENSSL +#include "setup.h" +#include "strbuf.h" +#if defined(NO_OPENSSL) && !defined(HAVE_OPENSSL_CSPRNG) typedef void *SSL; #endif #ifdef USE_CURL_FOR_IMAP_SEND @@ -66,49 +68,22 @@ static void imap_warn(const char *, ...); static char *next_arg(char **); -__attribute__((format (printf, 3, 4))) -static int nfsnprintf(char *buf, int blen, const char *fmt, ...); - -static int nfvasprintf(char **strp, const char *fmt, va_list ap) -{ - int len; - char tmp[8192]; - - len = vsnprintf(tmp, sizeof(tmp), fmt, ap); - if (len < 0) - die("Fatal: Out of memory"); - if (len >= sizeof(tmp)) - die("imap command overflow!"); - *strp = xmemdupz(tmp, len); - return len; -} - struct imap_server_conf { - char *name; - char *tunnel; - char *host; + const char *name; + const char *tunnel; + const char *host; int port; - char *folder; - char *user; - char *pass; + const char *folder; + const char *user; + const char *pass; int use_ssl; int ssl_verify; int use_html; - char *auth_method; + const char *auth_method; }; static struct imap_server_conf server = { - NULL, /* name */ - NULL, /* tunnel */ - NULL, /* host */ - 0, /* port */ - NULL, /* folder */ - NULL, /* user */ - NULL, /* pass */ - 0, /* use_ssl */ - 1, /* ssl_verify */ - 0, /* use_html */ - NULL, /* auth_method */ + .ssl_verify = 1, }; struct imap_socket { @@ -143,12 +118,10 @@ struct imap_store { }; struct imap_cmd_cb { - int (*cont)(struct imap_store *ctx, struct imap_cmd *cmd, const char *prompt); - void (*done)(struct imap_store *ctx, struct imap_cmd *cmd, int response); + int (*cont)(struct imap_store *ctx, const char *prompt); void *ctx; char *data; int dlen; - int uid; }; struct imap_cmd { @@ -215,10 +188,14 @@ static void socket_perror(const char *func, struct imap_socket *sock, int ret) else fprintf(stderr, "%s: unexpected EOF\n", func); } + /* mark as used to appease -Wunused-parameter with NO_OPENSSL */ + (void)sock; } #ifdef NO_OPENSSL -static int ssl_socket_connect(struct imap_socket *sock, int use_tls_only, int verify) +static int ssl_socket_connect(struct imap_socket *sock UNUSED, + int use_tls_only UNUSED, + int verify UNUSED) { fprintf(stderr, "SSL requested but SSL support not compiled in\n"); return -1; @@ -451,6 +428,7 @@ static int buffer_gets(struct imap_buffer *b, char **s) /* not reached */ } +__attribute__((format (printf, 1, 2))) static void imap_info(const char *msg, ...) { va_list va; @@ -463,6 +441,7 @@ static void imap_info(const char *msg, ...) } } +__attribute__((format (printf, 1, 2))) static void imap_warn(const char *msg, ...) { va_list va; @@ -504,29 +483,17 @@ static char *next_arg(char **s) return ret; } -static int nfsnprintf(char *buf, int blen, const char *fmt, ...) -{ - int ret; - va_list va; - - va_start(va, fmt); - if (blen <= 0 || (unsigned)(ret = vsnprintf(buf, blen, fmt, va)) >= (unsigned)blen) - BUG("buffer too small. Please report a bug."); - va_end(va); - return ret; -} - static struct imap_cmd *issue_imap_cmd(struct imap_store *ctx, struct imap_cmd_cb *cb, const char *fmt, va_list ap) { struct imap *imap = ctx->imap; struct imap_cmd *cmd; - int n, bufl; - char buf[1024]; + int n; + struct strbuf buf = STRBUF_INIT; cmd = xmalloc(sizeof(struct imap_cmd)); - nfvasprintf(&cmd->cmd, fmt, ap); + cmd->cmd = xstrvfmt(fmt, ap); cmd->tag = ++imap->nexttag; if (cb) @@ -538,27 +505,30 @@ static struct imap_cmd *issue_imap_cmd(struct imap_store *ctx, get_cmd_result(ctx, NULL); if (!cmd->cb.data) - bufl = nfsnprintf(buf, sizeof(buf), "%d %s\r\n", cmd->tag, cmd->cmd); + strbuf_addf(&buf, "%d %s\r\n", cmd->tag, cmd->cmd); else - bufl = nfsnprintf(buf, sizeof(buf), "%d %s{%d%s}\r\n", - cmd->tag, cmd->cmd, cmd->cb.dlen, - CAP(LITERALPLUS) ? "+" : ""); + strbuf_addf(&buf, "%d %s{%d%s}\r\n", cmd->tag, cmd->cmd, + cmd->cb.dlen, CAP(LITERALPLUS) ? "+" : ""); + if (buf.len > INT_MAX) + die("imap command overflow!"); if (0 < verbosity) { if (imap->num_in_progress) printf("(%d in progress) ", imap->num_in_progress); if (!starts_with(cmd->cmd, "LOGIN")) - printf(">>> %s", buf); + printf(">>> %s", buf.buf); else printf(">>> %d LOGIN <user> <pass>\n", cmd->tag); } - if (socket_write(&imap->buf.sock, buf, bufl) != bufl) { + if (socket_write(&imap->buf.sock, buf.buf, buf.len) != buf.len) { free(cmd->cmd); free(cmd); if (cb) free(cb->data); + strbuf_release(&buf); return NULL; } + strbuf_release(&buf); if (cmd->cb.data) { if (CAP(LITERALPLUS)) { n = socket_write(&imap->buf.sock, cmd->cb.data, cmd->cb.dlen); @@ -789,7 +759,7 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd) if (n != (int)cmdp->cb.dlen) return RESP_BAD; } else if (cmdp->cb.cont) { - if (cmdp->cb.cont(ctx, cmdp, cmd)) + if (cmdp->cb.cont(ctx, cmd)) return RESP_BAD; } else { fprintf(stderr, "IMAP error: unexpected command continuation request\n"); @@ -831,8 +801,6 @@ static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd) } if ((resp2 = parse_response_code(ctx, &cmdp->cb, cmd)) > resp) resp = resp2; - if (cmdp->cb.done) - cmdp->cb.done(ctx, cmdp, resp); free(cmdp->cb.data); free(cmdp->cmd); free(cmdp); @@ -864,7 +832,7 @@ static void imap_close_store(struct imap_store *ctx) /* * hexchar() and cram() functions are based on the code from the isync - * project (http://isync.sf.net/). + * project (https://isync.sourceforge.io/). */ static char hexchar(unsigned int b) { @@ -912,7 +880,9 @@ static char *cram(const char *challenge_64, const char *user, const char *pass) #else -static char *cram(const char *challenge_64, const char *user, const char *pass) +static char *cram(const char *challenge_64 UNUSED, + const char *user UNUSED, + const char *pass UNUSED) { die("If you want to use CRAM-MD5 authenticate method, " "you have to build git-imap-send with OpenSSL library."); @@ -920,7 +890,7 @@ static char *cram(const char *challenge_64, const char *user, const char *pass) #endif -static int auth_cram_md5(struct imap_store *ctx, struct imap_cmd *cmd, const char *prompt) +static int auth_cram_md5(struct imap_store *ctx, const char *prompt) { int ret; char *response; @@ -955,7 +925,7 @@ static void server_fill_credential(struct imap_server_conf *srvc, struct credent srvc->pass = xstrdup(cred->password); } -static struct imap_store *imap_open_store(struct imap_server_conf *srvc, char *folder) +static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const char *folder) { struct credential cred = CREDENTIAL_INIT; struct imap_store *ctx; @@ -963,9 +933,9 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, char *f char *arg, *rsp; int s = -1, preauth; - ctx = xcalloc(1, sizeof(*ctx)); + CALLOC_ARRAY(ctx, 1); - ctx->imap = imap = xcalloc(1, sizeof(*imap)); + ctx->imap = CALLOC_ARRAY(imap, 1); imap->buf.sock.fd[0] = imap->buf.sock.fd[1] = -1; imap->in_progress_append = &imap->in_progress; @@ -976,7 +946,7 @@ static struct imap_store *imap_open_store(struct imap_server_conf *srvc, char *f imap_info("Starting tunnel '%s'... ", srvc->tunnel); - argv_array_push(&tunnel.args, srvc->tunnel); + strvec_push(&tunnel.args, srvc->tunnel); tunnel.use_shell = 1; tunnel.in = -1; tunnel.out = -1; @@ -1266,18 +1236,6 @@ static void wrap_in_html(struct strbuf *msg) *msg = buf; } -#define CHUNKSIZE 0x1000 - -static int read_message(FILE *f, struct strbuf *all_msgs) -{ - do { - if (strbuf_fread(all_msgs, CHUNKSIZE, f) <= 0) - break; - } while (!feof(f)); - - return ferror(f) ? -1 : 0; -} - static int count_messages(struct strbuf *all_msgs) { int count = 0; @@ -1338,17 +1296,29 @@ static int split_msg(struct strbuf *all_msgs, struct strbuf *msg, int *ofs) return 1; } -static void git_imap_config(void) +static int git_imap_config(const char *var, const char *val, + const struct config_context *ctx, void *cb) { - const char *val = NULL; - - git_config_get_bool("imap.sslverify", &server.ssl_verify); - git_config_get_bool("imap.preformattedhtml", &server.use_html); - git_config_get_string("imap.folder", &server.folder); - if (!git_config_get_value("imap.host", &val)) { + if (!strcmp("imap.sslverify", var)) + server.ssl_verify = git_config_bool(var, val); + else if (!strcmp("imap.preformattedhtml", var)) + server.use_html = git_config_bool(var, val); + else if (!strcmp("imap.folder", var)) + return git_config_string(&server.folder, var, val); + else if (!strcmp("imap.user", var)) + return git_config_string(&server.user, var, val); + else if (!strcmp("imap.pass", var)) + return git_config_string(&server.pass, var, val); + else if (!strcmp("imap.tunnel", var)) + return git_config_string(&server.tunnel, var, val); + else if (!strcmp("imap.authmethod", var)) + return git_config_string(&server.auth_method, var, val); + else if (!strcmp("imap.port", var)) + server.port = git_config_int(var, val, ctx->kvi); + else if (!strcmp("imap.host", var)) { if (!val) { - git_die_config("imap.host", "Missing value for 'imap.host'"); + return config_error_nonbool(var); } else { if (starts_with(val, "imap:")) val += 5; @@ -1360,13 +1330,10 @@ static void git_imap_config(void) val += 2; server.host = xstrdup(val); } - } + } else + return git_default_config(var, val, ctx, cb); - git_config_get_string("imap.user", &server.user); - git_config_get_string("imap.pass", &server.pass); - git_config_get_int("imap.port", &server.port); - git_config_get_string("imap.tunnel", &server.tunnel); - git_config_get_string("imap.authmethod", &server.auth_method); + return 0; } static int append_msgs_to_imap(struct imap_server_conf *server, @@ -1422,16 +1389,16 @@ static CURL *setup_curl(struct imap_server_conf *srvc, struct credential *cred) if (!curl) die("curl_easy_init failed"); - server_fill_credential(&server, cred); - curl_easy_setopt(curl, CURLOPT_USERNAME, server.user); - curl_easy_setopt(curl, CURLOPT_PASSWORD, server.pass); + server_fill_credential(srvc, cred); + curl_easy_setopt(curl, CURLOPT_USERNAME, srvc->user); + curl_easy_setopt(curl, CURLOPT_PASSWORD, srvc->pass); - strbuf_addstr(&path, server.use_ssl ? "imaps://" : "imap://"); - strbuf_addstr(&path, server.host); + 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, server.folder, 0); + 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); @@ -1439,32 +1406,32 @@ static CURL *setup_curl(struct imap_server_conf *srvc, struct credential *cred) curl_easy_setopt(curl, CURLOPT_URL, path.buf); strbuf_release(&path); - curl_easy_setopt(curl, CURLOPT_PORT, server.port); + curl_easy_setopt(curl, CURLOPT_PORT, srvc->port); - if (server.auth_method) { -#if LIBCURL_VERSION_NUM < 0x072200 + if (srvc->auth_method) { +#ifndef GIT_CURL_HAVE_CURLOPT_LOGIN_OPTIONS warning("No LOGIN_OPTIONS support in this cURL version"); #else struct strbuf auth = STRBUF_INIT; strbuf_addstr(&auth, "AUTH="); - strbuf_addstr(&auth, server.auth_method); + strbuf_addstr(&auth, srvc->auth_method); curl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, auth.buf); strbuf_release(&auth); #endif } - if (!server.use_ssl) + if (!srvc->use_ssl) curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_TRY); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, server.ssl_verify); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, server.ssl_verify); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, srvc->ssl_verify); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 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")) - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + http_trace_curl_no_data(); setup_curl_trace(curl); return curl; @@ -1518,11 +1485,7 @@ static int curl_append_msgs_to_imap(struct imap_server_conf *server, if (cred.username) { if (res == CURLE_OK) credential_approve(&cred); -#if LIBCURL_VERSION_NUM >= 0x070d01 else if (res == CURLE_LOGIN_DENIED) -#else - else -#endif credential_reject(&cred); } @@ -1539,7 +1502,7 @@ int cmd_main(int argc, const char **argv) int nongit_ok; setup_git_directory_gently(&nongit_ok); - git_imap_config(); + git_config(git_imap_config, NULL); argc = parse_options(argc, (const char **)argv, "", imap_send_options, imap_send_usage, 0); @@ -1574,8 +1537,8 @@ int cmd_main(int argc, const char **argv) } /* read the messages */ - if (read_message(stdin, &all_msgs)) { - fprintf(stderr, "error reading input\n"); + if (strbuf_read(&all_msgs, 0, 0) < 0) { + error_errno(_("could not read from stdin")); return 1; } |