Starting from libcurl 7.21.5, libcurl can be tricked into using
an already open socket.
This allows to use tunneling with libcurl instead of the legacy imap code.

Signed-off-by: Nicolas Morey-Chaisemartin <nico...@morey-chaisemartin.com>
---
 Documentation/git-imap-send.txt |  4 ++--
 imap-send.c                     | 45 +++++++++++++++++++++++++++++++++++------
 2 files changed, 41 insertions(+), 8 deletions(-)

diff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.txt
index 5d1e4c80c..e765c08d7 100644
--- a/Documentation/git-imap-send.txt
+++ b/Documentation/git-imap-send.txt
@@ -38,8 +38,8 @@ OPTIONS
        Be quiet.
 
 --curl::
-       Use libcurl to communicate with the IMAP server, unless tunneling
-       into it.  Ignored if Git was built without the USE_CURL_FOR_IMAP_SEND
+       Use libcurl to communicate with the IMAP server.
+       Ignored if Git was built without the USE_CURL_FOR_IMAP_SEND
        option set.
 
 --no-curl::
diff --git a/imap-send.c b/imap-send.c
index e5ff70096..31b93d873 100644
--- a/imap-send.c
+++ b/imap-send.c
@@ -1408,6 +1408,26 @@ static int append_msgs_to_imap(struct imap_server_conf 
*server,
 }
 
 #ifdef USE_CURL_FOR_IMAP_SEND
+static curl_socket_t curl_tunnel_socket(void *clientp,
+                                       curlsocktype purpose,
+                                       struct curl_sockaddr *address)
+{
+       return (unsigned long)clientp;
+}
+
+static int sockopt_callback(void *clientp, curl_socket_t curlfd,
+                                curlsocktype purpose)
+{
+       /* CURL_SOCKOPT_ALREADY_CONNECTED was intreocued in 7.21.5
+        * and is needed to get curl working on an existing fd */
+#if LIBCURL_VERSION_NUM >= 0x071505
+       return CURL_SOCKOPT_ALREADY_CONNECTED;
+#else
+       return CURL_SOCKOPT_ERROR;
+#endif
+}
+
+
 static CURL *setup_curl(struct imap_server_conf *srvc)
 {
        CURL *curl;
@@ -1424,8 +1444,21 @@ static CURL *setup_curl(struct imap_server_conf *srvc)
        curl_easy_setopt(curl, CURLOPT_USERNAME, server.user);
        curl_easy_setopt(curl, CURLOPT_PASSWORD, server.pass);
 
-       strbuf_addstr(&path, server.use_ssl ? "imaps://" : "imap://");
-       strbuf_addstr(&path, server.host);
+       if (srvc->tunnel) {
+               int fds[2];
+
+               setup_tunnel(srvc, fds);
+               curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, 
curl_tunnel_socket);
+               curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, (unsigned 
long)fds[0]);
+               curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, 
sockopt_callback);
+               /* Create a fake hostname to avoid resolution issue and in case
+                * imap.host was not set */
+               strbuf_addstr(&path, "imap://localhost");
+       } else {
+               strbuf_addstr(&path, server.use_ssl ? "imaps://" : "imap://");
+               strbuf_addstr(&path, server.host);
+       }
+
        if (!path.len || path.buf[path.len - 1] != '/')
                strbuf_addch(&path, '/');
        strbuf_addstr(&path, server.folder);
@@ -1570,12 +1603,12 @@ int cmd_main(int argc, const char **argv)
 
        /* write it to the imap server */
 
-       if (server.tunnel)
-               return append_msgs_to_imap(&server, &all_msgs, total);
-
 #ifdef USE_CURL_FOR_IMAP_SEND
        if (use_curl)
-               return curl_append_msgs_to_imap(&server, &all_msgs, total);
+#if LIBCURL_VERSION_NUM < 0x071505
+               if (!server.tunnel)
+#endif
+                       return curl_append_msgs_to_imap(&server, &all_msgs, 
total);
 #endif
 
        return append_msgs_to_imap(&server, &all_msgs, total);
-- 
2.14.0.3.gb4ff627ec.dirty

Reply via email to