#define USE_THE_REPOSITORY_VARIABLE
#include "git-compat-util.h"
#include "config.h"
#include "credential.h"
#include "gettext.h"
#include "run-command.h"
#include "parse-options.h"
#include "setup.h"
#include "strbuf.h"
#ifdef USE_CURL_FOR_IMAP_SEND
#include "http.h"
#endif
#if defined(USE_CURL_FOR_IMAP_SEND)
#define USE_CURL_DEFAULT …
#else
#define USE_CURL_DEFAULT …
#endif
static int verbosity;
static int use_curl = …;
static const char * const imap_send_usage[] = …;
static struct option imap_send_options[] = …;
#undef DRV_OK
#define DRV_OK …
#define DRV_MSG_BAD …
#define DRV_BOX_BAD …
#define DRV_STORE_BAD …
__attribute__((format (printf, 1, 2)))
static void imap_info(const char *, ...);
__attribute__((format (printf, 1, 2)))
static void imap_warn(const char *, ...);
static char *next_arg(char **);
struct imap_server_conf { … };
struct imap_socket { … };
struct imap_buffer { … };
struct imap_cmd;
struct imap { … };
struct imap_store { … };
struct imap_cmd_cb { … };
struct imap_cmd { … };
#define CAP(cap) …
enum CAPABILITY { … };
static const char *cap_list[] = …;
#define RESP_OK …
#define RESP_NO …
#define RESP_BAD …
static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd);
#ifndef NO_OPENSSL
static void ssl_socket_perror(const char *func)
{ … }
#endif
static void socket_perror(const char *func, struct imap_socket *sock, int ret)
{ … }
#ifdef NO_OPENSSL
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");
return -1;
}
#else
static int host_matches(const char *host, const char *pattern)
{ … }
static int verify_hostname(X509 *cert, const char *hostname)
{ … }
static int ssl_socket_connect(struct imap_socket *sock,
const struct imap_server_conf *cfg,
int use_tls_only)
{ … }
#endif
static int socket_read(struct imap_socket *sock, char *buf, int len)
{ … }
static int socket_write(struct imap_socket *sock, const char *buf, int len)
{ … }
static void socket_shutdown(struct imap_socket *sock)
{ … }
static int buffer_gets(struct imap_buffer *b, char **s)
{ … }
__attribute__((format (printf, 1, 2)))
static void imap_info(const char *msg, ...)
{ … }
__attribute__((format (printf, 1, 2)))
static void imap_warn(const char *msg, ...)
{ … }
static char *next_arg(char **s)
{ … }
static struct imap_cmd *issue_imap_cmd(struct imap_store *ctx,
struct imap_cmd_cb *cb,
const char *fmt, va_list ap)
{ … }
__attribute__((format (printf, 3, 4)))
static int imap_exec(struct imap_store *ctx, struct imap_cmd_cb *cb,
const char *fmt, ...)
{ … }
__attribute__((format (printf, 3, 4)))
static int imap_exec_m(struct imap_store *ctx, struct imap_cmd_cb *cb,
const char *fmt, ...)
{ … }
static int skip_imap_list_l(char **sp, int level)
{ … }
static void skip_list(char **sp)
{ … }
static void parse_capability(struct imap *imap, char *cmd)
{ … }
static int parse_response_code(struct imap_store *ctx, struct imap_cmd_cb *cb,
char *s)
{ … }
static int get_cmd_result(struct imap_store *ctx, struct imap_cmd *tcmd)
{ … }
static void imap_close_server(struct imap_store *ictx)
{ … }
static void imap_close_store(struct imap_store *ctx)
{ … }
#ifndef NO_OPENSSL
static char hexchar(unsigned int b)
{ … }
#define ENCODED_SIZE(n) …
static char *cram(const char *challenge_64, const char *user, const char *pass)
{ … }
#else
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.");
}
#endif
static int auth_cram_md5(struct imap_store *ctx, const char *prompt)
{ … }
static void server_fill_credential(struct imap_server_conf *srvc, struct credential *cred)
{ … }
static struct imap_store *imap_open_store(struct imap_server_conf *srvc, const char *folder)
{ … }
static void lf_to_crlf(struct strbuf *msg)
{ … }
static int imap_store_msg(struct imap_store *ctx, struct strbuf *msg)
{ … }
static void wrap_in_html(struct strbuf *msg)
{ … }
static int count_messages(struct strbuf *all_msgs)
{ … }
static int split_msg(struct strbuf *all_msgs, struct strbuf *msg, int *ofs)
{ … }
static int git_imap_config(const char *var, const char *val,
const struct config_context *ctx, void *cb)
{ … }
static int append_msgs_to_imap(struct imap_server_conf *server,
struct strbuf* all_msgs, int total)
{ … }
#ifdef USE_CURL_FOR_IMAP_SEND
static CURL *setup_curl(struct imap_server_conf *srvc, struct credential *cred)
{
CURL *curl;
struct strbuf path = STRBUF_INIT;
char *uri_encoded_folder;
if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
die("curl_global_init failed");
curl = curl_easy_init();
if (!curl)
die("curl_easy_init failed");
server_fill_credential(srvc, cred);
curl_easy_setopt(curl, CURLOPT_USERNAME, srvc->user);
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);
curl_easy_setopt(curl, CURLOPT_URL, path.buf);
strbuf_release(&path);
curl_easy_setopt(curl, CURLOPT_PORT, srvc->port);
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, srvc->auth_method);
curl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, auth.buf);
strbuf_release(&auth);
#endif
}
if (!srvc->use_ssl)
curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_TRY);
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"))
http_trace_curl_no_data();
setup_curl_trace(curl);
return curl;
}
static int curl_append_msgs_to_imap(struct imap_server_conf *server,
struct strbuf* all_msgs, int total)
{
int ofs = 0;
int n = 0;
struct buffer msgbuf = { STRBUF_INIT, 0 };
CURL *curl;
CURLcode res = CURLE_OK;
struct credential cred = CREDENTIAL_INIT;
curl = setup_curl(server, &cred);
curl_easy_setopt(curl, CURLOPT_READDATA, &msgbuf);
fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
while (1) {
unsigned percent = n * 100 / total;
int prev_len;
fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total);
prev_len = msgbuf.buf.len;
if (!split_msg(all_msgs, &msgbuf.buf, &ofs))
break;
if (server->use_html)
wrap_in_html(&msgbuf.buf);
lf_to_crlf(&msgbuf.buf);
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,
(curl_off_t)(msgbuf.buf.len-prev_len));
res = curl_easy_perform(curl);
if(res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
break;
}
n++;
}
fprintf(stderr, "\n");
curl_easy_cleanup(curl);
curl_global_cleanup();
if (cred.username) {
if (res == CURLE_OK)
credential_approve(&cred);
else if (res == CURLE_LOGIN_DENIED)
credential_reject(&cred);
}
credential_clear(&cred);
return res != CURLE_OK;
}
#endif
int cmd_main(int argc, const char **argv)
{ … }