git/imap-send.c

/*
 * git-imap-send - drops patches into an imap Drafts folder
 *                 derived from isync/mbsync - mailbox synchronizer
 *
 * Copyright (C) 2000-2002 Michael R. Elkins <[email protected]>
 * Copyright (C) 2002-2004 Oswald Buddenhagen <[email protected]>
 * Copyright (C) 2004 Theodore Y. Ts'o <[email protected]>
 * Copyright (C) 2006 Mike McCormack
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  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 <https://www.gnu.org/licenses/>.
 */

#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)
/* Always default to curl if it's available. */
#define USE_CURL_DEFAULT
#else
/* We don't have curl, so continue to use the historical implementation */
#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)
{}

/* simple line buffering */
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

/*
 * hexchar() and cram() functions are based on the code from the isync
 * project (https://isync.sourceforge.io/).
 */
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)
{}

/*
 * Insert CR characters as necessary in *msg to ensure that every LF
 * character in *msg is preceded by a CR.
 */
static void lf_to_crlf(struct strbuf *msg)
{}

/*
 * Store msg to IMAP.  Also detach and free the data from msg->data,
 * leaving msg->data empty.
 */
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)
{}

/*
 * Copy the next message from all_msgs, starting at offset *ofs, to
 * msg.  Update *ofs to the start of the following message.  Return
 * true iff a message was successfully copied.
 */
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)
{}