{"thread":{"id":"37350","subject":"Re: [PATCH/RFC] git-imap-send: use libcurl for implementation","startedAt":"2014-08-14T21:46:46Z","lastAt":"2014-08-25T21:08:48Z","messageCount":4,"participants":["Bernhard Reiter","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"247729","messageId":"53ED2E46.5020403@raz.or.at","threadId":"37350","inReplyTo":null,"subject":"Re: [PATCH/RFC] git-imap-send: use libcurl for implementation","fromName":"Bernhard Reiter","fromEmail":"ockham@raz.or.at","sentAt":"2014-08-14T21:46:46Z","receivedAt":"2014-08-14T21:46:46Z","isPatch":true,"sender":{"key":"ockham@raz.or.at","avatar":"https://avatars.githubusercontent.com/u/96308?v=4"},"body":"\nUse libcurl's high-level API functions to implement git-imap-send\ninstead of the previous low-level OpenSSL-based functions.\n\nSince version 7.30.0, libcurl's API has been able to communicate with\nIMAP servers. Using those high-level functions instead of the current\nones would reduce imap-send.c by some 1200 lines of code. For now,\nthe old ones are wrapped in #ifdefs, and the new functions are enabled\nby make if curl's version is >= 7.35.0, from which version on curl's\nCURLOPT_LOGIN_OPTIONS (enabling IMAP authentication) parameter has been\navailable.\n\nAs I don't have access to that many IMAP servers, I haven't been able to\ntest the new code with a wide variety of parameter combinations. I did\ntest both secure and insecure (imaps:// and imap://) connections and\nvalues of \"PLAIN\" and \"LOGIN\" for the authMethod.\n\nSigned-off-by: Bernhard Reiter <ockham@raz.or.at>\n---\nAm 2014-08-13 um 03:59 schrieb Jonathan Nieder:\n> Bernhard Reiter wrote:\n>> [...]\n>\n> Wow!  This sounds lovely.  Thanks for working on this.\n\nWell thanks for the friendly welcome and the helpful comments!\n\nI'm attaching a patch where I've applied the fixes you suggested, plus:\n\n* I added the lf_to_crlf conversion to the curl codepath as\ncommunication with another IMAP server I tried was broken without it.\n\n* I added STARTTLS. (That's just the\ncurl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);\nline)\n\n* I tested (and fixed) authentication, i.e. the auth_method stuff. As\nthe corresponding CURLOPT_LOGIN_OPTIONS flag has only been available\nstarting with curl 7.35.0, I've bumped the required version to that.\n(Apparently it was possible to achieve the same effect with a different\noption in between versions 7.31.0 and 7.34.0 [1], but I haven't found\nyet how. Is it worth the effort?)\n\n* I made that file scope imap_folder a member of struct imap_server_conf\n(named folder), which makes some things easier.\n\n>> @@ -1417,31 +269,89 @@ int main(int argc, char **argv)\n>>  \t\treturn 1;\n>>  \t}\n>>\n>> +\tcurl_global_init(CURL_GLOBAL_ALL);\n>\n> http.c seems to make the same mistake,\n\nPatch at http://permalink.gmane.org/gmane.comp.version-control.git/255221\n\n> [...]\n>> +\tif (server.tunnel) {\n>> +\t\tconst char *argv[] = { server.tunnel, NULL };\n>> +\t\tstruct child_process tunnel = {NULL};\n>\n> (not about this patch) Could use the child_proccess's internal\n> argv_array:\n>\n> \t\tstruct child_process tunnel = {NULL};\n> \t\targv_array_push(&tunnel.args, server.tunnel);\n\nPatch at\nhttp://permalink.gmane.org/gmane.comp.version-control.git/255220 (The\npatch attached to this mail depends on that one.)\n\nNo comments on those patches yet, though.\n\n> (about this patch) Would there be a way to make this part reuse the\n> existing code?  The only difference I see is that *srvc has been\n> renamed to server, which doesn't seem to be related to the change of\n> transport API from OpenSSL to libcurl.\n>\n> [...]\n>> +\t\tcurl_socket_t sockfd = tunnel.out; // what about tunnel.in ?\n>\n> Hmm.  curl expects to get a socket it can send(), recv(), setsockopt(),\n> etc on instead of a pair of fds to read() and write().\n>\n> I wonder why someone would want to use SSL through a tunnel, though.\n> Currently it's impossible to get to the SSL codepath when a tunnel\n> is active (it's in the 'else' block an 'if (srvc->tunnel)').  If that\n> property is preserved, then we should be safe.\n\nNow this turns out to be the one major annoyance left, because we only\nhave those two fds (actually pipes, right?), and not a socket that we\ncould pass to curl, so we can't use it to talk to the IMAP server. So if\nthe tunnel parameter is set, we're stuck with the old hand-written IMAP\nhandling routines, even with USE_CURL_FOR_IMAP set, meaning I can't wrap\nas much in #ifdef...#endif blocks as I'd like. :-( BTW, due to two of\nthe blocks that I do add I get a compiler warning about the curl handle\nremaining possibly unitialized :-/\nI've removed the curl specific socket handling routines, as we can't use\nthem anyway for now.\n\nI've asked about passing two pipes instead of a socket to curl on their\nML [1] as this has even been discussed before [2], but unfortunately,\nthere doesn't seem to be a solution as of yet. I've also asked on SO\n[3], but no answers yet.\n\n> To summarize:\n> [...]\n>\n>  * As soon as you're ready to roll this out to a wider audience of\n>    testers, let me know, and we can try to get it into shape for\n>    Junio's \"next\" branch (and hence Debian experimental).\n\nIs this one good enough already?\n\nBernhard\n\n[1] http://sourceforge.net/p/curl/bugs/1372/\n[2] http://curl.haxx.se/mail/lib-2014-08/0102.html\n[3] http://curl.haxx.se/mail/lib-2011-05/0102.html\n[4]\nhttp://stackoverflow.com/questions/25306264/connect-in-and-out-pipes-to-network-socket\n\n Documentation/git-imap-send.txt |   3 +-\n INSTALL                         |  15 +++---\n Makefile                        |  16 +++++-\n git.spec.in                     |   5 +-\n imap-send.c                     | 109\n+++++++++++++++++++++++++++++++++++++---\n 5 files changed, 132 insertions(+), 16 deletions(-)\n\n\n\n\ndiff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.txt\nindex 875d283..abce2a6 100644\n--- a/Documentation/git-imap-send.txt\n+++ b/Documentation/git-imap-send.txt\n@@ -76,7 +76,8 @@ imap.preformattedHTML::\n \n imap.authMethod::\n \tSpecify authenticate method for authentication with IMAP server.\n-\tCurrent supported method is 'CRAM-MD5' only.\n+\tIf you compiled git with the NO_CURL option or if your curl version is\n+\t< 7.35.0, the only supported method is 'CRAM-MD5'.\n \n Examples\n ~~~~~~~~\ndiff --git a/INSTALL b/INSTALL\nindex 6ec7a24..e2770a0 100644\n--- a/INSTALL\n+++ b/INSTALL\n@@ -108,18 +108,21 @@ Issues of note:\n \t  so you might need to install additional packages other than Perl\n \t  itself, e.g. Time::HiRes.\n \n-\t- \"openssl\" library is used by git-imap-send to use IMAP over SSL.\n-\t  If you don't need it, use NO_OPENSSL.\n+\t- \"openssl\" library is used by git-imap-send to use IMAP over SSL,\n+\t  unless you're using curl >= 7.35.0, in which case that will be\n+\t  used. If you don't need git-imap-send, you can use NO_OPENSSL.\n \n \t  By default, git uses OpenSSL for SHA1 but it will use its own\n \t  library (inspired by Mozilla's) with either NO_OPENSSL or\n \t  BLK_SHA1.  Also included is a version optimized for PowerPC\n \t  (PPC_SHA1).\n \n-\t- \"libcurl\" library is used by git-http-fetch and git-fetch.  You\n-\t  might also want the \"curl\" executable for debugging purposes.\n-\t  If you do not use http:// or https:// repositories, you do not\n-\t  have to have them (use NO_CURL).\n+\t- \"libcurl\" library is used by git-http-fetch, git-fetch, and, if\n+\t  the curl version >= 7.35.0, for git-imap-send.  You might also\n+\t  want the \"curl\" executable for debugging purposes. If you do not\n+\t  use http:// or https:// repositories, and do not want to put\n+\t  patches into an IMAP mailbox, you do not have to have them\n+\t  (use NO_CURL).\n \n \t- \"expat\" library; git-http-push uses it for remote lock\n \t  management over DAV.  Similar to \"curl\" above, this is optional\ndiff --git a/Makefile b/Makefile\nindex 2320de5..a5e89ec 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1120,6 +1120,9 @@ ifdef HAVE_ALLOCA_H\n \tBASIC_CFLAGS += -DHAVE_ALLOCA_H\n endif\n \n+IMAP_SEND_BUILDDEPS =\n+IMAP_SEND_LDFLAGS = $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)\n+\n ifdef NO_CURL\n \tBASIC_CFLAGS += -DNO_CURL\n \tREMOTE_CURL_PRIMARY =\n@@ -1154,6 +1157,15 @@ else\n \t\t\tPROGRAM_OBJS += http-push.o\n \t\tendif\n \tendif\n+\tcurl_check := $(shell (echo 072300; curl-config --vernum) 2>/dev/null | sort -r | sed -ne 2p)\n+\tifeq \"$(curl_check)\" \"072300\"\n+\t\tUSE_CURL_FOR_IMAP_SEND = YesPlease\n+\tendif\n+\tifdef USE_CURL_FOR_IMAP_SEND\n+\t\tBASIC_CFLAGS += -DUSE_CURL_FOR_IMAP_SEND\n+\t\tIMAP_SEND_BUILDDEPS = http.o\n+\t\tIMAP_SEND_LDFLAGS = $(CURL_LIBCURL)\n+\tendif\n \tifndef NO_EXPAT\n \t\tifdef EXPATDIR\n \t\t\tBASIC_CFLAGS += -I$(EXPATDIR)/include\n@@ -2067,9 +2079,9 @@ endif\n git-%$X: %.o GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)\n \n-git-imap-send$X: imap-send.o GIT-LDFLAGS $(GITLIBS)\n+git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n-\t\t$(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)\n+\t\t$(LIBS) $(IMAP_SEND_LDFLAGS)\n \n git-http-fetch$X: http.o http-walker.o http-fetch.o GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\ndiff --git a/git.spec.in b/git.spec.in\nindex d61d537..9535cc3 100644\n--- a/git.spec.in\n+++ b/git.spec.in\n@@ -8,7 +8,7 @@ License: \tGPL\n Group: \t\tDevelopment/Tools\n URL: \t\thttp://kernel.org/pub/software/scm/git/\n Source: \thttp://kernel.org/pub/software/scm/git/%{name}-%{version}.tar.gz\n-BuildRequires:\tzlib-devel >= 1.2, openssl-devel, curl-devel, expat-devel, gettext  %{!?_without_docs:, xmlto, asciidoc > 6.0.3}\n+BuildRequires:\tzlib-devel >= 1.2, openssl-devel, curl-devel >= 7.35.0, expat-devel, gettext  %{!?_without_docs:, xmlto, asciidoc > 6.0.3}\n BuildRoot:\t%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)\n \n Requires:\tperl-Git = %{version}-%{release}\n@@ -214,6 +214,9 @@ rm -rf $RPM_BUILD_ROOT\n # No files for you!\n \n %changelog\n+* Mon Aug 11 2014 Bernhard Reiter <ockham@raz.or.at>\n+- Require version >= 7.35.0 of curl-devel for IMAP functions.\n+\n * Sun Sep 18 2011 Jakub Narebski <jnareb@gmail.com>\n - Add gitweb manpages to 'gitweb' subpackage\n \ndiff --git a/imap-send.c b/imap-send.c\nindex fb01a9c..a45570d 100644\n--- a/imap-send.c\n+++ b/imap-send.c\n@@ -22,6 +22,10 @@\n  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n  */\n \n+#ifdef USE_CURL_FOR_IMAP_SEND\n+#define NO_OPENSSL\n+#endif\n+\n #include \"cache.h\"\n #include \"credential.h\"\n #include \"exec_cmd.h\"\n@@ -29,6 +33,9 @@\n #ifdef NO_OPENSSL\n typedef void *SSL;\n #endif\n+#ifdef USE_CURL_FOR_IMAP_SEND\n+#include \"http.h\"\n+#endif\n \n static const char imap_send_usage[] = \"git imap-send < <mbox>\";\n \n@@ -44,9 +51,7 @@ __attribute__((format (printf, 1, 2)))\n static void imap_info(const char *, ...);\n __attribute__((format (printf, 1, 2)))\n static void imap_warn(const char *, ...);\n-\n static char *next_arg(char **);\n-\n __attribute__((format (printf, 3, 4)))\n static int nfsnprintf(char *buf, int blen, const char *fmt, ...);\n \n@@ -69,6 +74,7 @@ struct imap_server_conf {\n \tchar *tunnel;\n \tchar *host;\n \tint port;\n+\tchar *folder;\n \tchar *user;\n \tchar *pass;\n \tint use_ssl;\n@@ -82,6 +88,7 @@ static struct imap_server_conf server = {\n \tNULL,\t/* tunnel */\n \tNULL,\t/* host */\n \t0,\t/* port */\n+\tNULL,\t/* folder */\n \tNULL,\t/* user */\n \tNULL,\t/* pass */\n \t0,   \t/* use_ssl */\n@@ -1323,7 +1330,54 @@ static int split_msg(struct strbuf *all_msgs, struct strbuf *msg, int *ofs)\n \treturn 1;\n }\n \n-static char *imap_folder;\n+#ifdef USE_CURL_FOR_IMAP_SEND\n+static CURL *setup_curl(struct imap_server_conf *srvc)\n+{\n+\tCURL *curl;\n+\tstruct strbuf path = STRBUF_INIT;\n+\tstruct strbuf auth = STRBUF_INIT;\n+\n+\tif (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)\n+\t\tdie(\"curl_global_init failed\");\n+\n+\tcurl = curl_easy_init();\n+\n+\tif (!curl)\n+\t\tdie(\"curl_easy_init failed\");\n+\n+\tcurl_easy_setopt(curl, CURLOPT_USERNAME, server.user);\n+\tcurl_easy_setopt(curl, CURLOPT_PASSWORD, server.pass);\n+\n+\tstrbuf_addstr(&path, server.host);\n+\tif (!path.len || path.buf[path.len - 1] != '/')\n+\t\tstrbuf_addch(&path, '/');\n+\tstrbuf_addstr(&path, server.folder);\n+\n+\tcurl_easy_setopt(curl, CURLOPT_URL, path.buf);\n+\tcurl_easy_setopt(curl, CURLOPT_PORT, server.port);\n+\n+\tif (server.auth_method) {\n+\t\tstrbuf_addstr(&auth, \"AUTH=\");\n+\t\tstrbuf_addstr(&auth, server.auth_method);\n+\t\tcurl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, auth.buf);\n+\t}\n+\n+\tif (server.use_ssl)\n+\t\tcurl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);\n+\n+\tcurl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, server.ssl_verify);\n+\tcurl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, server.ssl_verify);\n+\n+\tcurl_easy_setopt(curl, CURLOPT_READFUNCTION, fread_buffer);\n+\n+\tcurl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);\n+\n+\tif (Verbose)\n+\t\tcurl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);\n+\n+\treturn curl;\n+}\n+#endif\n \n static int git_imap_config(const char *key, const char *val, void *cb)\n {\n@@ -1339,7 +1393,7 @@ static int git_imap_config(const char *key, const char *val, void *cb)\n \t\treturn config_error_nonbool(key);\n \n \tif (!strcmp(\"folder\", key)) {\n-\t\timap_folder = xstrdup(val);\n+\t\tserver.folder = xstrdup(val);\n \t} else if (!strcmp(\"host\", key)) {\n \t\tif (starts_with(val, \"imap:\"))\n \t\t\tval += 5;\n@@ -1373,6 +1427,11 @@ int main(int argc, char **argv)\n \tint r;\n \tint total, n = 0;\n \tint nongit_ok;\n+#ifdef USE_CURL_FOR_IMAP_SEND\n+\tstruct buffer msgbuf = { STRBUF_INIT, 0 };\n+\tCURL *curl;\n+\tCURLcode res = CURLE_OK;\n+#endif /* #ifndef USE_CURL_FOR_IMAP_SEND */\n \n \tgit_extract_argv0_path(argv[0]);\n \n@@ -1387,7 +1446,7 @@ int main(int argc, char **argv)\n \tif (!server.port)\n \t\tserver.port = server.use_ssl ? 993 : 143;\n \n-\tif (!imap_folder) {\n+\tif (!server.folder) {\n \t\tfprintf(stderr, \"no imap store specified\\n\");\n \t\treturn 1;\n \t}\n@@ -1417,18 +1476,48 @@ int main(int argc, char **argv)\n \t}\n \n \t/* write it to the imap server */\n+\n+#ifdef USE_CURL_FOR_IMAP_SEND\n+\tif (!server.tunnel) {\n+\t\tcurl = setup_curl(&server);\n+\t\tcurl_easy_setopt(curl, CURLOPT_READDATA, &msgbuf);\n+\t} else {\n+#endif\n \tctx = imap_open_store(&server);\n \tif (!ctx) {\n \t\tfprintf(stderr, \"failed to open store\\n\");\n \t\treturn 1;\n \t}\n+\tctx->name = server.folder;\n+#ifdef USE_CURL_FOR_IMAP_SEND\n+\t}\n+#endif\n \n \tfprintf(stderr, \"sending %d message%s\\n\", total, (total != 1) ? \"s\" : \"\");\n-\tctx->name = imap_folder;\n \twhile (1) {\n \t\tunsigned percent = n * 100 / total;\n \n \t\tfprintf(stderr, \"%4u%% (%d/%d) done\\r\", percent, n, total);\n+#ifdef USE_CURL_FOR_IMAP_SEND\n+\t\tif (!server.tunnel) {\n+\t\t\tint prev_len = msgbuf.buf.len;\n+\t\t\tif (!split_msg(&all_msgs, &msgbuf.buf, &ofs))\n+\t\t\t\tbreak;\n+\t\t\tif (server.use_html)\n+\t\t\t\twrap_in_html(&msgbuf.buf);\n+\t\t\tlf_to_crlf(&msgbuf.buf);\n+\n+\t\t\tcurl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)(msgbuf.buf.len-prev_len));\n+\n+\t\t\tres = curl_easy_perform(curl);\n+\n+\t\t\tif(res != CURLE_OK) {\n+\t\t\t\tfprintf(stderr, \"curl_easy_perform() failed: %s\\n\",\n+\t\t\t\t\t\tcurl_easy_strerror(res));\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t} else {\n+#endif\n \t\tif (!split_msg(&all_msgs, &msg, &ofs))\n \t\t\tbreak;\n \t\tif (server.use_html)\n@@ -1436,11 +1525,19 @@ int main(int argc, char **argv)\n \t\tr = imap_store_msg(ctx, &msg);\n \t\tif (r != DRV_OK)\n \t\t\tbreak;\n+#ifdef USE_CURL_FOR_IMAP_SEND\n+\t\t}\n+#endif\n \t\tn++;\n \t}\n \tfprintf(stderr, \"\\n\");\n \n+#ifdef USE_CURL_FOR_IMAP_SEND\n+\tcurl_easy_cleanup(curl);\n+\tcurl_global_cleanup();\n+#else\n \timap_close_store(ctx);\n+#endif\n \n \treturn 0;\n }\n\n"},{"id":"247954","messageId":"xmqq1tscwepa.fsf@gitster.dls.corp.google.com","threadId":"37350","inReplyTo":"53ED2E46.5020403@raz.or.at","subject":"Re: [PATCH/RFC] git-imap-send: use libcurl for implementation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-08-19T17:51:13Z","receivedAt":"2014-08-19T17:51:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Bernhard Reiter <ockham@raz.or.at> writes:\n\n> Use libcurl's high-level API functions to implement git-imap-send\n> instead of the previous low-level OpenSSL-based functions.\n>\n> Since version 7.30.0, libcurl's API has been able to communicate with\n> IMAP servers. Using those high-level functions instead of the current\n> ones would reduce imap-send.c by some 1200 lines of code. For now,\n> the old ones are wrapped in #ifdefs, and the new functions are enabled\n> by make if curl's version is >= 7.35.0, from which version on curl's\n> CURLOPT_LOGIN_OPTIONS (enabling IMAP authentication) parameter has been\n> available.\n>\n> As I don't have access to that many IMAP servers, I haven't been able to\n> test the new code with a wide variety of parameter combinations. I did\n> test both secure and insecure (imaps:// and imap://) connections and\n> values of \"PLAIN\" and \"LOGIN\" for the authMethod.\n>\n> Signed-off-by: Bernhard Reiter <ockham@raz.or.at>\n> ---\n\nI think people have missed this one, partly because it was hidden as\nan attachment.\n\n>  Documentation/git-imap-send.txt |   3 +-\n>  INSTALL                         |  15 +++---\n>  Makefile                        |  16 +++++-\n>  git.spec.in                     |   5 +-\n>  imap-send.c                     | 109\n> +++++++++++++++++++++++++++++++++++++---\n>  5 files changed, 132 insertions(+), 16 deletions(-)\n\nI smell a line-wrapped patch but it probably is at my receiving end,\nforcing the attachment into a flattened form inside my MUA.\n\nNice to see git.spec.in updated; I like it when I see that the\nauthor paid attention to details.\n\n> diff --git a/imap-send.c b/imap-send.c\n> index fb01a9c..a45570d 100644\n> --- a/imap-send.c\n> +++ b/imap-send.c\n> @@ -22,6 +22,10 @@\n>   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\n>   */\n>  \n> +#ifdef USE_CURL_FOR_IMAP_SEND\n> +#define NO_OPENSSL\n> +#endif\n> +\n\nThis looks strange and stands out like a sore thumb.  Do any of our\nother sources do this kind of macro tweaking inside C source before\nincluding git-compat-util.h (or its equivalent like cache.h)?\n\nI think what you are trying to do is to change the meaning of\nNO_OPENSSL, which merely means \"we do not have OpenSSL library and\ndo not want to link with it\", locally to \"we may or may not have and\nuse OpenSSL library elsewhere in Git, but in the code below we do\nnot want to use the code written to work on top of OpenSSL and\ninstead use libcurl\".  Because of that, you define NO_OPENSSL before\nincluding any of our headers to cause us not to include the headers,\nand typedef away SSL, for example.\n\n>  #include \"cache.h\"\n>  #include \"credential.h\"\n>  #include \"exec_cmd.h\"\n> @@ -29,6 +33,9 @@\n>  #ifdef NO_OPENSSL\n>  typedef void *SSL;\n>  #endif\n> +#ifdef USE_CURL_FOR_IMAP_SEND\n> +#include \"http.h\"\n> +#endif\n\nBut does it have to be that way?  For one thing, doing it this way,\nthe user has to make a compilation-time choice, but if you separate\nthese compilation time macro into two, one for \"can we even link\nwith and use OpenSSL?\" (which is what NO_OPENSSL is about) and\nanother for \"do we want an ability to talk to imap via libcurl?\",\nwouldn't it make it possible for you to switch between them at\nruntime (e.g. you might want to go over the direct connection when\ntunneling, while letting libcurl do the heavy lifting in\nnon-tunneled operation)?\n\n> @@ -44,9 +51,7 @@ __attribute__((format (printf, 1, 2)))\n>  static void imap_info(const char *, ...);\n>  __attribute__((format (printf, 1, 2)))\n>  static void imap_warn(const char *, ...);\n> -\n>  static char *next_arg(char **);\n> -\n>  __attribute__((format (printf, 3, 4)))\n>  static int nfsnprintf(char *buf, int blen, const char *fmt, ...);\n>  \n> @@ -69,6 +74,7 @@ struct imap_server_conf {\n>  \tchar *tunnel;\n>  \tchar *host;\n>  \tint port;\n> +\tchar *folder;\n>  \tchar *user;\n>  \tchar *pass;\n>  \tint use_ssl;\n> @@ -82,6 +88,7 @@ static struct imap_server_conf server = {\n>  \tNULL,\t/* tunnel */\n>  \tNULL,\t/* host */\n>  \t0,\t/* port */\n> +\tNULL,\t/* folder */\n>  \tNULL,\t/* user */\n>  \tNULL,\t/* pass */\n>  \t0,   \t/* use_ssl */\n> @@ -1323,7 +1330,54 @@ static int split_msg(struct strbuf *all_msgs, struct strbuf *msg, int *ofs)\n>  \treturn 1;\n>  }\n>  \n> -static char *imap_folder;\n\nAll of the above seem to have meant well, but these changes are not\nabout talking with IMAP servers via libcurl.  We'd prefer to see\nchanges like these as preliminary clean-up before the main change as\nseparate patch(es).\n\n> @@ -1417,18 +1476,48 @@ int main(int argc, char **argv)\n>  \t}\n>  \n>  \t/* write it to the imap server */\n> +\n> +#ifdef USE_CURL_FOR_IMAP_SEND\n> +\tif (!server.tunnel) {\n> +\t\tcurl = setup_curl(&server);\n> +\t\tcurl_easy_setopt(curl, CURLOPT_READDATA, &msgbuf);\n> +\t} else {\n> +#endif\n>  \tctx = imap_open_store(&server);\n>  \tif (!ctx) {\n>  \t\tfprintf(stderr, \"failed to open store\\n\");\n>  \t\treturn 1;\n>  \t}\n> +\tctx->name = server.folder;\n> +#ifdef USE_CURL_FOR_IMAP_SEND\n> +\t}\n> +#endif\n>  \n>  \tfprintf(stderr, \"sending %d message%s\\n\", total, (total != 1) ? \"s\" : \"\");\n> -\tctx->name = imap_folder;\n>  \twhile (1) {\n>  \t\tunsigned percent = n * 100 / total;\n>  \n>  \t\tfprintf(stderr, \"%4u%% (%d/%d) done\\r\", percent, n, total);\n> +#ifdef USE_CURL_FOR_IMAP_SEND\n> +\t\tif (!server.tunnel) {\n> ...\n> +\t\t\t}\n> +\t\t} else {\n> +#endif\n>  \t\tif (!split_msg(&all_msgs, &msg, &ofs))\n>  \t\t\tbreak;\n>  \t\tif (server.use_html)\n> @@ -1436,11 +1525,19 @@ int main(int argc, char **argv)\n>  \t\tr = imap_store_msg(ctx, &msg);\n>  \t\tif (r != DRV_OK)\n>  \t\t\tbreak;\n> +#ifdef USE_CURL_FOR_IMAP_SEND\n> +\t\t}\n> +#endif\n>  \t\tn++;\n>  \t}\n>  \tfprintf(stderr, \"\\n\");\n>  \n> +#ifdef USE_CURL_FOR_IMAP_SEND\n> +\tcurl_easy_cleanup(curl);\n> +\tcurl_global_cleanup();\n> +#else\n>  \timap_close_store(ctx);\n> +#endif\n>  \n>  \treturn 0;\n>  }\n\nUgly.  Can we do this with less #ifdef/#else/#endif in the primary\ncode path?\n\nIf we were to keep these two modes as a choice the users have to\nmake at the compilation time, that is.\n\nThanks.\n"},{"id":"248264","messageId":"53FB985F.8080608@raz.or.at","threadId":"37350","inReplyTo":"xmqq1tscwepa.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH/RFC] git-imap-send: use libcurl for implementation","fromName":"Bernhard Reiter","fromEmail":"ockham@raz.or.at","sentAt":"2014-08-25T20:11:11Z","receivedAt":"2014-08-25T20:11:11Z","isPatch":true,"sender":{"key":"ockham@raz.or.at","avatar":"https://avatars.githubusercontent.com/u/96308?v=4"},"body":"Am 2014-08-19 um 19:51 schrieb Junio C Hamano:\n> This looks strange and stands out like a sore thumb.  Do any of our\n> other sources do this kind of macro tweaking inside C source before\n> including git-compat-util.h (or its equivalent like cache.h)?\n\nI haven't checked, but I agree that it's desirable to avoid.\n\n> I think what you are trying to do is to change the meaning of\n> NO_OPENSSL, which merely means \"we do not have OpenSSL library and\n> do not want to link with it\", locally to \"we may or may not have and\n> use OpenSSL library elsewhere in Git, but in the code below we do\n> not want to use the code written to work on top of OpenSSL and\n> instead use libcurl\".  \n\n\"...and we don't want to link to OpenSSL in that case.\" Yeah.\n\n> Because of that, you define NO_OPENSSL before\n> including any of our headers to cause us not to include the headers,\n> and typedef away SSL, for example.\n\nThe SSL un-typedef'ing was there before, but it's true that I'm defining\nNO_OPENSSL on the very top so the included headers don't require OpenSSL\n(and so we don't have to link to it later).\n\n>>  #include \"cache.h\"\n>>  #include \"credential.h\"\n>>  #include \"exec_cmd.h\"\n>> @@ -29,6 +33,9 @@\n>>  #ifdef NO_OPENSSL\n>>  typedef void *SSL;\n>>  #endif\n>> +#ifdef USE_CURL_FOR_IMAP_SEND\n>> +#include \"http.h\"\n>> +#endif\n> \n> But does it have to be that way?  For one thing, doing it this way,\n> the user has to make a compilation-time choice, but if you separate\n> these compilation time macro into two, one for \"can we even link\n> with and use OpenSSL?\" (which is what NO_OPENSSL is about) and\n> another for \"do we want an ability to talk to imap via libcurl?\",\n> wouldn't it make it possible for you to switch between them at\n> runtime (e.g. you might want to go over the direct connection when\n> tunneling, while letting libcurl do the heavy lifting in\n> non-tunneled operation)?\n\nYeah, but I still need to wrap the non-tunneled operation in #ifdefs in\ncase we don't USE_CURL_FOR_IMAP_SEND in which case we fall back to the\nhandwritten IMAP code, don't I?\n\nMaybe I'm not getting you entirely right, but if I don't typedef\nNO_OPENSSL if USE_CURL_FOR_IMAP_SEND is defined, I don't see any way to\nnot link to OpenSSL, even if it's not required. I'm including a slightly\nmodified patch which does that (hoping that I've finally managed to send\na usable patch). Sorry it's nothing breathtakingly better than before,\neven after giving this some thought I didn't arrive at a very elegant\nnew solution... (see below for more on that)\n\n>> @@ -1417,18 +1476,48 @@ int main(int argc, char **argv)\n>>  \t}\n>>  \n>>  \t/* write it to the imap server */\n>> +\n>> +#ifdef USE_CURL_FOR_IMAP_SEND\n>> +\tif (!server.tunnel) {\n>> +\t\tcurl = setup_curl(&server);\n>> +\t\tcurl_easy_setopt(curl, CURLOPT_READDATA, &msgbuf);\n>> +\t} else {\n>> +#endif\n>>  \tctx = imap_open_store(&server);\n>>  \tif (!ctx) {\n>>  \t\tfprintf(stderr, \"failed to open store\\n\");\n>>  \t\treturn 1;\n>>  \t}\n>> +\tctx->name = server.folder;\n>> +#ifdef USE_CURL_FOR_IMAP_SEND\n>> +\t}\n>> +#endif\n>>  \n>>  \tfprintf(stderr, \"sending %d message%s\\n\", total, (total != 1) ? \"s\" : \"\");\n>> -\tctx->name = imap_folder;\n>>  \twhile (1) {\n>>  \t\tunsigned percent = n * 100 / total;\n>>  \n>>  \t\tfprintf(stderr, \"%4u%% (%d/%d) done\\r\", percent, n, total);\n>> +#ifdef USE_CURL_FOR_IMAP_SEND\n>> +\t\tif (!server.tunnel) {\n>> ...\n>> +\t\t\t}\n>> +\t\t} else {\n>> +#endif\n>>  \t\tif (!split_msg(&all_msgs, &msg, &ofs))\n>>  \t\t\tbreak;\n>>  \t\tif (server.use_html)\n>> @@ -1436,11 +1525,19 @@ int main(int argc, char **argv)\n>>  \t\tr = imap_store_msg(ctx, &msg);\n>>  \t\tif (r != DRV_OK)\n>>  \t\t\tbreak;\n>> +#ifdef USE_CURL_FOR_IMAP_SEND\n>> +\t\t}\n>> +#endif\n>>  \t\tn++;\n>>  \t}\n>>  \tfprintf(stderr, \"\\n\");\n>>  \n>> +#ifdef USE_CURL_FOR_IMAP_SEND\n>> +\tcurl_easy_cleanup(curl);\n>> +\tcurl_global_cleanup();\n>> +#else\n>>  \timap_close_store(ctx);\n>> +#endif\n>>  \n>>  \treturn 0;\n>>  }\n> \n> Ugly.  Can we do this with less #ifdef/#else/#endif in the primary\n> code path?\n\nIt is ugly, but as much as I'd love to put e.g.\n\n+#ifdef USE_CURL_FOR_IMAP_SEND\n+\tif (!server.tunnel) {\n+\t\tcurl = setup_curl(&server);\n\netc into imap_open_store (and similarly for imap_store_msg etc), I don't\nsee any easy way to do it; imap_open_store's return type would still be\nstruct imap_store* in the non-tunneling case, and CURL* otherwise.\n\nSo the best I can come up with here is merging some of the #ifdef\nblocks, but that means duplicating the code that applies in both cases.\nBut that isn't any better, is it?\n\n> If we were to keep these two modes as a choice the users have to\n> make at the compilation time, that is.\n\nAs stated above, I'm not sure how to do entirely without at least those\ntwo compile time switches (NO_OPENSSL and USE_CURL_FOR_IMAP_SEND).\n\nSorry, perhaps I missed something obvious; grateful for any hints on how\nto do it better.\n\nBernhard\n\n Documentation/git-imap-send.txt |  3 +-\n INSTALL                         | 15 ++++---\n Makefile                        | 16 ++++++-\n git.spec.in                     |  5 ++-\n imap-send.c                     | 96 +++++++++++++++++++++++++++++++++++++++++\n 5 files changed, 125 insertions(+), 10 deletions(-)\n\ndiff --git a/Documentation/git-imap-send.txt b/Documentation/git-imap-send.txt\nindex 7d991d9..9d244c4 100644\n--- a/Documentation/git-imap-send.txt\n+++ b/Documentation/git-imap-send.txt\n@@ -75,7 +75,8 @@ imap.preformattedHTML::\n \n imap.authMethod::\n \tSpecify authenticate method for authentication with IMAP server.\n-\tCurrent supported method is 'CRAM-MD5' only. If this is not set\n+\tIf you compiled git with the NO_CURL option or if your curl version is\n+\t< 7.35.0, the only supported method is 'CRAM-MD5'. If this is not set\n \tthen 'git imap-send' uses the basic IMAP plaintext LOGIN command.\n \n Examples\ndiff --git a/INSTALL b/INSTALL\nindex 6ec7a24..e2770a0 100644\n--- a/INSTALL\n+++ b/INSTALL\n@@ -108,18 +108,21 @@ Issues of note:\n \t  so you might need to install additional packages other than Perl\n \t  itself, e.g. Time::HiRes.\n \n-\t- \"openssl\" library is used by git-imap-send to use IMAP over SSL.\n-\t  If you don't need it, use NO_OPENSSL.\n+\t- \"openssl\" library is used by git-imap-send to use IMAP over SSL,\n+\t  unless you're using curl >= 7.35.0, in which case that will be\n+\t  used. If you don't need git-imap-send, you can use NO_OPENSSL.\n \n \t  By default, git uses OpenSSL for SHA1 but it will use its own\n \t  library (inspired by Mozilla's) with either NO_OPENSSL or\n \t  BLK_SHA1.  Also included is a version optimized for PowerPC\n \t  (PPC_SHA1).\n \n-\t- \"libcurl\" library is used by git-http-fetch and git-fetch.  You\n-\t  might also want the \"curl\" executable for debugging purposes.\n-\t  If you do not use http:// or https:// repositories, you do not\n-\t  have to have them (use NO_CURL).\n+\t- \"libcurl\" library is used by git-http-fetch, git-fetch, and, if\n+\t  the curl version >= 7.35.0, for git-imap-send.  You might also\n+\t  want the \"curl\" executable for debugging purposes. If you do not\n+\t  use http:// or https:// repositories, and do not want to put\n+\t  patches into an IMAP mailbox, you do not have to have them\n+\t  (use NO_CURL).\n \n \t- \"expat\" library; git-http-push uses it for remote lock\n \t  management over DAV.  Similar to \"curl\" above, this is optional\ndiff --git a/Makefile b/Makefile\nindex 237bc05..c08963c 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1133,6 +1133,9 @@ ifdef HAVE_ALLOCA_H\n \tBASIC_CFLAGS += -DHAVE_ALLOCA_H\n endif\n \n+IMAP_SEND_BUILDDEPS =\n+IMAP_SEND_LDFLAGS = $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)\n+\n ifdef NO_CURL\n \tBASIC_CFLAGS += -DNO_CURL\n \tREMOTE_CURL_PRIMARY =\n@@ -1167,6 +1170,15 @@ else\n \t\t\tPROGRAM_OBJS += http-push.o\n \t\tendif\n \tendif\n+\tcurl_check := $(shell (echo 072300; curl-config --vernum) 2>/dev/null | sort -r | sed -ne 2p)\n+\tifeq \"$(curl_check)\" \"072300\"\n+\t\tUSE_CURL_FOR_IMAP_SEND = YesPlease\n+\tendif\n+\tifdef USE_CURL_FOR_IMAP_SEND\n+\t\tBASIC_CFLAGS += -DUSE_CURL_FOR_IMAP_SEND\n+\t\tIMAP_SEND_BUILDDEPS = http.o\n+\t\tIMAP_SEND_LDFLAGS += $(CURL_LIBCURL)\n+\tendif\n \tifndef NO_EXPAT\n \t\tifdef EXPATDIR\n \t\t\tBASIC_CFLAGS += -I$(EXPATDIR)/include\n@@ -2084,9 +2096,9 @@ endif\n git-%$X: %.o GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)\n \n-git-imap-send$X: imap-send.o GIT-LDFLAGS $(GITLIBS)\n+git-imap-send$X: imap-send.o $(IMAP_SEND_BUILDDEPS) GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\n-\t\t$(LIBS) $(OPENSSL_LINK) $(OPENSSL_LIBSSL) $(LIB_4_CRYPTO)\n+\t\t$(LIBS) $(IMAP_SEND_LDFLAGS)\n \n git-http-fetch$X: http.o http-walker.o http-fetch.o GIT-LDFLAGS $(GITLIBS)\n \t$(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) \\\ndiff --git a/git.spec.in b/git.spec.in\nindex d61d537..9535cc3 100644\n--- a/git.spec.in\n+++ b/git.spec.in\n@@ -8,7 +8,7 @@ License: \tGPL\n Group: \t\tDevelopment/Tools\n URL: \t\thttp://kernel.org/pub/software/scm/git/\n Source: \thttp://kernel.org/pub/software/scm/git/%{name}-%{version}.tar.gz\n-BuildRequires:\tzlib-devel >= 1.2, openssl-devel, curl-devel, expat-devel, gettext  %{!?_without_docs:, xmlto, asciidoc > 6.0.3}\n+BuildRequires:\tzlib-devel >= 1.2, openssl-devel, curl-devel >= 7.35.0, expat-devel, gettext  %{!?_without_docs:, xmlto, asciidoc > 6.0.3}\n BuildRoot:\t%{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)\n \n Requires:\tperl-Git = %{version}-%{release}\n@@ -214,6 +214,9 @@ rm -rf $RPM_BUILD_ROOT\n # No files for you!\n \n %changelog\n+* Mon Aug 11 2014 Bernhard Reiter <ockham@raz.or.at>\n+- Require version >= 7.35.0 of curl-devel for IMAP functions.\n+\n * Sun Sep 18 2011 Jakub Narebski <jnareb@gmail.com>\n - Add gitweb manpages to 'gitweb' subpackage\n \ndiff --git a/imap-send.c b/imap-send.c\nindex ad330a6..3343429 100644\n--- a/imap-send.c\n+++ b/imap-send.c\n@@ -29,6 +29,9 @@\n #ifdef NO_OPENSSL\n typedef void *SSL;\n #endif\n+#ifdef USE_CURL_FOR_IMAP_SEND\n+#include \"http.h\"\n+#endif\n \n static const char imap_send_usage[] = \"git imap-send < <mbox>\";\n \n@@ -1307,6 +1310,55 @@ static int split_msg(struct strbuf *all_msgs, struct strbuf *msg, int *ofs)\n \treturn 1;\n }\n \n+#ifdef USE_CURL_FOR_IMAP_SEND\n+static CURL *setup_curl(struct imap_server_conf *srvc)\n+{\n+\tCURL *curl;\n+\tstruct strbuf path = STRBUF_INIT;\n+\tstruct strbuf auth = STRBUF_INIT;\n+\n+\tif (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)\n+\t\tdie(\"curl_global_init failed\");\n+\n+\tcurl = curl_easy_init();\n+\n+\tif (!curl)\n+\t\tdie(\"curl_easy_init failed\");\n+\n+\tcurl_easy_setopt(curl, CURLOPT_USERNAME, server.user);\n+\tcurl_easy_setopt(curl, CURLOPT_PASSWORD, server.pass);\n+\n+\tstrbuf_addstr(&path, server.host);\n+\tif (!path.len || path.buf[path.len - 1] != '/')\n+\t\tstrbuf_addch(&path, '/');\n+\tstrbuf_addstr(&path, server.folder);\n+\n+\tcurl_easy_setopt(curl, CURLOPT_URL, path.buf);\n+\tcurl_easy_setopt(curl, CURLOPT_PORT, server.port);\n+\n+\tif (server.auth_method) {\n+\t\tstrbuf_addstr(&auth, \"AUTH=\");\n+\t\tstrbuf_addstr(&auth, server.auth_method);\n+\t\tcurl_easy_setopt(curl, CURLOPT_LOGIN_OPTIONS, auth.buf);\n+\t}\n+\n+\tif (server.use_ssl)\n+\t\tcurl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);\n+\n+\tcurl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, server.ssl_verify);\n+\tcurl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, server.ssl_verify);\n+\n+\tcurl_easy_setopt(curl, CURLOPT_READFUNCTION, fread_buffer);\n+\n+\tcurl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);\n+\n+\tif (Verbose)\n+\t\tcurl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);\n+\n+\treturn curl;\n+}\n+#endif\n+\n static void git_imap_config(void)\n {\n \tconst char *val = NULL;\n@@ -1347,6 +1399,11 @@ int main(int argc, char **argv)\n \tint r;\n \tint total, n = 0;\n \tint nongit_ok;\n+#ifdef USE_CURL_FOR_IMAP_SEND\n+\tstruct buffer msgbuf = { STRBUF_INIT, 0 };\n+\tCURL *curl;\n+\tCURLcode res = CURLE_OK;\n+#endif /* #ifndef USE_CURL_FOR_IMAP_SEND */\n \n \tgit_extract_argv0_path(argv[0]);\n \n@@ -1391,17 +1448,48 @@ int main(int argc, char **argv)\n \t}\n \n \t/* write it to the imap server */\n+\n+#ifdef USE_CURL_FOR_IMAP_SEND\n+\tif (!server.tunnel) {\n+\t\tcurl = setup_curl(&server);\n+\t\tcurl_easy_setopt(curl, CURLOPT_READDATA, &msgbuf);\n+\t} else {\n+#endif\n \tctx = imap_open_store(&server, server.folder);\n \tif (!ctx) {\n \t\tfprintf(stderr, \"failed to open store\\n\");\n \t\treturn 1;\n \t}\n+\tctx->name = server.folder;\n+#ifdef USE_CURL_FOR_IMAP_SEND\n+\t}\n+#endif\n \n \tfprintf(stderr, \"sending %d message%s\\n\", total, (total != 1) ? \"s\" : \"\");\n \twhile (1) {\n \t\tunsigned percent = n * 100 / total;\n \n \t\tfprintf(stderr, \"%4u%% (%d/%d) done\\r\", percent, n, total);\n+#ifdef USE_CURL_FOR_IMAP_SEND\n+\t\tif (!server.tunnel) {\n+\t\t\tint prev_len = msgbuf.buf.len;\n+\t\t\tif (!split_msg(&all_msgs, &msgbuf.buf, &ofs))\n+\t\t\t\tbreak;\n+\t\t\tif (server.use_html)\n+\t\t\t\twrap_in_html(&msgbuf.buf);\n+\t\t\tlf_to_crlf(&msgbuf.buf);\n+\n+\t\t\tcurl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)(msgbuf.buf.len-prev_len));\n+\n+\t\t\tres = curl_easy_perform(curl);\n+\n+\t\t\tif(res != CURLE_OK) {\n+\t\t\t\tfprintf(stderr, \"curl_easy_perform() failed: %s\\n\",\n+\t\t\t\t\t\tcurl_easy_strerror(res));\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t} else {\n+#endif\n \t\tif (!split_msg(&all_msgs, &msg, &ofs))\n \t\t\tbreak;\n \t\tif (server.use_html)\n@@ -1409,11 +1497,19 @@ int main(int argc, char **argv)\n \t\tr = imap_store_msg(ctx, &msg);\n \t\tif (r != DRV_OK)\n \t\t\tbreak;\n+#ifdef USE_CURL_FOR_IMAP_SEND\n+\t\t}\n+#endif\n \t\tn++;\n \t}\n \tfprintf(stderr, \"\\n\");\n \n+#ifdef USE_CURL_FOR_IMAP_SEND\n+\tcurl_easy_cleanup(curl);\n+\tcurl_global_cleanup();\n+#else\n \timap_close_store(ctx);\n+#endif\n \n \treturn 0;\n }\n-- \n2.1.0.372.g89e5a25\n"},{"id":"248270","messageId":"xmqqlhqcl1jz.fsf@gitster.dls.corp.google.com","threadId":"37350","inReplyTo":"53FB985F.8080608@raz.or.at","subject":"Re: [PATCH/RFC] git-imap-send: use libcurl for implementation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-08-25T21:08:48Z","receivedAt":"2014-08-25T21:08:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Bernhard Reiter <ockham@raz.or.at> writes:\n\n> Yeah, but I still need to wrap the non-tunneled operation in #ifdefs in\n> case we don't USE_CURL_FOR_IMAP_SEND in which case we fall back to the\n> handwritten IMAP code, don't I?\n\nWe do not mind multiple implementations of the same helper function\nthat are guarded with #ifdef/#endif, and we do use that style quite\na lot.  Would it help?\n"}]}