Skip to content

Commit 1e16b25

Browse files
ockhamgitster
authored andcommitted
git-imap-send: use libcurl for implementation
Use libcurl's high-level API functions to implement git-imap-send instead of the previous low-level OpenSSL-based functions. Since version 7.30.0, libcurl's API has been able to communicate with IMAP servers. Using those high-level functions instead of the current ones would reduce imap-send.c by some 1200 lines of code. For now, the old ones are wrapped in #ifdefs, and the new functions are enabled by make if curl's version is >= 7.34.0, from which version on curl's CURLOPT_LOGIN_OPTIONS (enabling IMAP authentication) parameter has been available. The low-level functions will still be used for tunneling into the server for now. As I don't have access to that many IMAP servers, I haven't been able to test the new code with a wide variety of parameter combinations. I did test both secure and insecure (imaps:// and imap://) connections and values of "PLAIN" and "LOGIN" for the authMethod. In order to suppress a sparse warning about "using sizeof on a function", we use the same solution used in commit 9371322 ("sparse: suppress some "using sizeof on a function" warnings", 06-10-2013) which solved exactly this problem for the other commands using libcurl. Helped-by: Ramsay Jones <[email protected]> Signed-off-by: Bernhard Reiter <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent f1a3529 commit 1e16b25

File tree

4 files changed

+191
-37
lines changed

4 files changed

+191
-37
lines changed

Documentation/git-imap-send.txt

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ git-imap-send - Send a collection of patches from stdin to an IMAP folder
99
SYNOPSIS
1010
--------
1111
[verse]
12-
'git imap-send' [-v] [-q]
12+
'git imap-send' [-v] [-q] [--[no-]curl]
1313

1414

1515
DESCRIPTION
@@ -37,6 +37,15 @@ OPTIONS
3737
--quiet::
3838
Be quiet.
3939

40+
--curl::
41+
Use libcurl to communicate with the IMAP server, unless tunneling
42+
into it. Ignored if Git was built without the USE_CURL_FOR_IMAP_SEND
43+
option set.
44+
45+
--no-curl::
46+
Talk to the IMAP server using git's own IMAP routines instead of
47+
using libcurl.
48+
4049

4150
CONFIGURATION
4251
-------------
@@ -87,7 +96,9 @@ imap.preformattedHTML::
8796

8897
imap.authMethod::
8998
Specify authenticate method for authentication with IMAP server.
90-
Current supported method is 'CRAM-MD5' only. If this is not set
99+
If Git was built with the NO_CURL option, or if your curl version is older
100+
than 7.34.0, or if you're running git-imap-send with the `--no-curl`
101+
option, the only supported method is 'CRAM-MD5'. If this is not set
91102
then 'git imap-send' uses the basic IMAP plaintext LOGIN command.
92103

93104
Examples

INSTALL

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,18 +108,21 @@ Issues of note:
108108
so you might need to install additional packages other than Perl
109109
itself, e.g. Time::HiRes.
110110

111-
- "openssl" library is used by git-imap-send to use IMAP over SSL.
112-
If you don't need it, use NO_OPENSSL.
111+
- git-imap-send needs the OpenSSL library to talk IMAP over SSL if
112+
you are using libcurl older than 7.34.0. Otherwise you can use
113+
NO_OPENSSL without losing git-imap-send.
113114

114115
By default, git uses OpenSSL for SHA1 but it will use its own
115116
library (inspired by Mozilla's) with either NO_OPENSSL or
116117
BLK_SHA1. Also included is a version optimized for PowerPC
117118
(PPC_SHA1).
118119

119-
- "libcurl" library is used by git-http-fetch and git-fetch. You
120-
might also want the "curl" executable for debugging purposes.
121-
If you do not use http:// or https:// repositories, you do not
122-
have to have them (use NO_CURL).
120+
- "libcurl" library is used by git-http-fetch, git-fetch, and, if
121+
the curl version >= 7.34.0, for git-imap-send. You might also
122+
want the "curl" executable for debugging purposes. If you do not
123+
use http:// or https:// repositories, and do not want to put
124+
patches into an IMAP mailbox, you do not have to have them
125+
(use NO_CURL).
123126

124127
- "expat" library; git-http-push uses it for remote lock
125128
management over DAV. Similar to "curl" above, this is optional

Makefile

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,9 @@ ifdef HAVE_ALLOCA_H
995995
BASIC_CFLAGS += -DHAVE_ALLOCA_H
996996
endif
997997

998+
IMAP_SEND_BUILDDEPS =
999+
IMAP_SEND_LDFLAGS = $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)
1000+
9981001
ifdef NO_CURL
9991002
BASIC_CFLAGS += -DNO_CURL
10001003
REMOTE_CURL_PRIMARY =
@@ -1029,6 +1032,15 @@ else
10291032
PROGRAM_OBJS += http-push.o
10301033
endif
10311034
endif
1035+
curl_check := $(shell (echo 072200; curl-config --vernum) 2>/dev/null | sort -r | sed -ne 2p)
1036+
ifeq "$(curl_check)" "072200"
1037+
USE_CURL_FOR_IMAP_SEND = YesPlease
1038+
endif
1039+
ifdef USE_CURL_FOR_IMAP_SEND
1040+
BASIC_CFLAGS += -DUSE_CURL_FOR_IMAP_SEND
1041+
IMAP_SEND_BUILDDEPS = http.o
1042+
IMAP_SEND_LDFLAGS += $(CURL_LIBCURL)
1043+
endif
10321044
ifndef NO_EXPAT
10331045
ifdef EXPATDIR
10341046
BASIC_CFLAGS += -I$(EXPATDIR)/include
@@ -1874,7 +1886,7 @@ gettext.sp gettext.s gettext.o: GIT-PREFIX
18741886
gettext.sp gettext.s gettext.o: EXTRA_CPPFLAGS = \
18751887
-DGIT_LOCALE_PATH='"$(localedir_SQ)"'
18761888

1877-
http-push.sp http.sp http-walker.sp remote-curl.sp: SPARSE_FLAGS += \
1889+
http-push.sp http.sp http-walker.sp remote-curl.sp imap-send.sp: SPARSE_FLAGS += \
18781890
-DCURL_DISABLE_TYPECHECK
18791891

18801892
ifdef NO_EXPAT
@@ -1895,9 +1907,9 @@ endif
18951907
git-%$X: %.o GIT-LDFLAGS $(GITLIBS)
18961908
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
18971909

1898-
git-imap-send$X: imap-send.o GIT-LDFLAGS $(GITLIBS)
1910+
git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)
18991911
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \
1900-
$(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)
1912+
$(LIBS) $(IMAP_SEND_LDFLAGS)
19011913

19021914
git-http-fetch$X: http.o http-walker.o http-fetch.o GIT-LDFLAGS $(GITLIBS)
19031915
$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \

imap-send.c

Lines changed: 154 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,18 @@
3030
#ifdef NO_OPENSSL
3131
typedef void *SSL;
3232
#endif
33+
#ifdef USE_CURL_FOR_IMAP_SEND
34+
#include "http.h"
35+
#endif
3336

3437
static int verbosity;
38+
static int use_curl; /* strictly opt in */
3539

36-
static const char * const imap_send_usage[] = { "git imap-send [-v] [-q] < <mbox>", NULL };
40+
static const char * const imap_send_usage[] = { "git imap-send [-v] [-q] [--[no-]curl] < <mbox>", NULL };
3741

3842
static struct option imap_send_options[] = {
3943
OPT__VERBOSITY(&verbosity),
44+
OPT_BOOL(0, "curl", &use_curl, "use libcurl to communicate with the IMAP server"),
4045
OPT_END()
4146
};
4247

@@ -1344,14 +1349,145 @@ static void git_imap_config(void)
13441349
git_config_get_string("imap.authmethod", &server.auth_method);
13451350
}
13461351

1347-
int main(int argc, char **argv)
1352+
static int append_msgs_to_imap(struct imap_server_conf *server,
1353+
struct strbuf* all_msgs, int total)
13481354
{
1349-
struct strbuf all_msgs = STRBUF_INIT;
13501355
struct strbuf msg = STRBUF_INIT;
13511356
struct imap_store *ctx = NULL;
13521357
int ofs = 0;
13531358
int r;
1354-
int total, n = 0;
1359+
int n = 0;
1360+
1361+
ctx = imap_open_store(server, server->folder);
1362+
if (!ctx) {
1363+
fprintf(stderr, "failed to open store\n");
1364+
return 1;
1365+
}
1366+
ctx->name = server->folder;
1367+
1368+
fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
1369+
while (1) {
1370+
unsigned percent = n * 100 / total;
1371+
1372+
fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total);
1373+
1374+
if (!split_msg(all_msgs, &msg, &ofs))
1375+
break;
1376+
if (server->use_html)
1377+
wrap_in_html(&msg);
1378+
r = imap_store_msg(ctx, &msg);
1379+
if (r != DRV_OK)
1380+
break;
1381+
n++;
1382+
}
1383+
fprintf(stderr, "\n");
1384+
1385+
imap_close_store(ctx);
1386+
1387+
return 0;
1388+
}
1389+
1390+
#ifdef USE_CURL_FOR_IMAP_SEND
1391+
static CURL *setup_curl(struct imap_server_conf *srvc)
1392+
{
1393+
CURL *curl;
1394+
struct strbuf path = STRBUF_INIT;
1395+
1396+
if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
1397+
die("curl_global_init failed");
1398+
1399+
curl = curl_easy_init();
1400+
1401+
if (!curl)
1402+
die("curl_easy_init failed");
1403+
1404+
curl_easy_setopt(curl, CURLOPT_USERNAME, server.user);
1405+
curl_easy_setopt(curl, CURLOPT_PASSWORD, server.pass);
1406+
1407+
strbuf_addstr(&path, server.host);
1408+
if (!path.len || path.buf[path.len - 1] != '/')
1409+
strbuf_addch(&path, '/');
1410+
strbuf_addstr(&path, server.folder);
1411+
1412+
curl_easy_setopt(curl, CURLOPT_URL, path.buf);
1413+
strbuf_release(&path);
1414+
curl_easy_setopt(curl, CURLOPT_PORT, server.port);
1415+
1416+
if (server.auth_method) {
1417+
struct strbuf auth = STRBUF_INIT;
1418+
strbuf_addstr(&auth, "AUTH=");
1419+
strbuf_addstr(&auth, server.auth_method);
1420+
curl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, auth.buf);
1421+
strbuf_release(&auth);
1422+
}
1423+
1424+
if (server.use_ssl)
1425+
curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
1426+
1427+
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, server.ssl_verify);
1428+
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, server.ssl_verify);
1429+
1430+
curl_easy_setopt(curl, CURLOPT_READFUNCTION, fread_buffer);
1431+
1432+
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
1433+
1434+
if (0 < verbosity)
1435+
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
1436+
1437+
return curl;
1438+
}
1439+
1440+
static int curl_append_msgs_to_imap(struct imap_server_conf *server,
1441+
struct strbuf* all_msgs, int total) {
1442+
int ofs = 0;
1443+
int n = 0;
1444+
struct buffer msgbuf = { STRBUF_INIT, 0 };
1445+
CURL *curl;
1446+
CURLcode res = CURLE_OK;
1447+
1448+
curl = setup_curl(server);
1449+
curl_easy_setopt(curl, CURLOPT_READDATA, &msgbuf);
1450+
1451+
fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
1452+
while (1) {
1453+
unsigned percent = n * 100 / total;
1454+
int prev_len;
1455+
1456+
fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total);
1457+
1458+
prev_len = msgbuf.buf.len;
1459+
if (!split_msg(all_msgs, &msgbuf.buf, &ofs))
1460+
break;
1461+
if (server->use_html)
1462+
wrap_in_html(&msgbuf.buf);
1463+
lf_to_crlf(&msgbuf.buf);
1464+
1465+
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,
1466+
(curl_off_t)(msgbuf.buf.len-prev_len));
1467+
1468+
res = curl_easy_perform(curl);
1469+
1470+
if(res != CURLE_OK) {
1471+
fprintf(stderr, "curl_easy_perform() failed: %s\n",
1472+
curl_easy_strerror(res));
1473+
break;
1474+
}
1475+
1476+
n++;
1477+
}
1478+
fprintf(stderr, "\n");
1479+
1480+
curl_easy_cleanup(curl);
1481+
curl_global_cleanup();
1482+
1483+
return 0;
1484+
}
1485+
#endif
1486+
1487+
int main(int argc, char **argv)
1488+
{
1489+
struct strbuf all_msgs = STRBUF_INIT;
1490+
int total;
13551491
int nongit_ok;
13561492

13571493
git_extract_argv0_path(argv[0]);
@@ -1366,6 +1502,13 @@ int main(int argc, char **argv)
13661502
if (argc)
13671503
usage_with_options(imap_send_usage, imap_send_options);
13681504

1505+
#ifndef USE_CURL_FOR_IMAP_SEND
1506+
if (use_curl) {
1507+
warning("--use-curl not supported in this build");
1508+
use_curl = 0;
1509+
}
1510+
#endif
1511+
13691512
if (!server.port)
13701513
server.port = server.use_ssl ? 993 : 143;
13711514

@@ -1399,29 +1542,14 @@ int main(int argc, char **argv)
13991542
}
14001543

14011544
/* write it to the imap server */
1402-
ctx = imap_open_store(&server, server.folder);
1403-
if (!ctx) {
1404-
fprintf(stderr, "failed to open store\n");
1405-
return 1;
1406-
}
1407-
1408-
fprintf(stderr, "sending %d message%s\n", total, (total != 1) ? "s" : "");
1409-
while (1) {
1410-
unsigned percent = n * 100 / total;
14111545

1412-
fprintf(stderr, "%4u%% (%d/%d) done\r", percent, n, total);
1413-
if (!split_msg(&all_msgs, &msg, &ofs))
1414-
break;
1415-
if (server.use_html)
1416-
wrap_in_html(&msg);
1417-
r = imap_store_msg(ctx, &msg);
1418-
if (r != DRV_OK)
1419-
break;
1420-
n++;
1421-
}
1422-
fprintf(stderr, "\n");
1546+
if (server.tunnel)
1547+
return append_msgs_to_imap(&server, &all_msgs, total);
14231548

1424-
imap_close_store(ctx);
1549+
#ifdef USE_CURL_FOR_IMAP_SEND
1550+
if (use_curl)
1551+
return curl_append_msgs_to_imap(&server, &all_msgs, total);
1552+
#endif
14251553

1426-
return 0;
1554+
return append_msgs_to_imap(&server, &all_msgs, total);
14271555
}

0 commit comments

Comments
 (0)