Hi, The attached patches add support to lib/imap.c for asynchronously:
1) connecting to an IMAPS server, and 2) upgrading the connection in-flight to SSL/TLS (STARTTLS) Here is the pull request: https://github.com/bagder/curl/pull/7 I'd like to turn this[1] into an official test case. I've been rooting through test/libtest/ and I think I've a handle on how to construct tests for IMAPS but not STARTTLS. If anyone has some pointers on this, I'd love to hear it. Feedback on the patches is welcome too, of course. :-) [1] https://gist.github.com/828613
From c4185d34e3ebb102f5973762db3b54a190307bd7 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis <[email protected]> Date: Mon, 14 Feb 2011 19:41:42 +0100 Subject: [PATCH 1/2] IMAP in multi mode: use Curl_ssl_connect_nonblocking() when connecting. --- lib/imap.c | 11 +++++++++-- lib/imap.h | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/imap.c b/lib/imap.c index 5e29415..4e71fb3 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -588,7 +588,14 @@ static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done) { struct imap_conn *imapc = &conn->proto.imapc; - CURLcode result = Curl_pp_multi_statemach(&imapc->pp); + CURLcode result; + + if((conn->protocol & PROT_IMAPS) && !imapc->ssldone) { + result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone); + } + else { + result = Curl_pp_multi_statemach(&imapc->pp); + } *done = (bool)(imapc->state == IMAP_STOP); @@ -700,7 +707,7 @@ static CURLcode imap_connect(struct connectdata *conn, } #endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */ - if(conn->protocol & PROT_IMAPS) { + if((conn->protocol & PROT_IMAPS) && data->state.used_interface != Curl_if_multi) { /* BLOCKING */ /* IMAPS is simply imap with SSL for the control channel */ /* now, perform the SSL initialization for this socket */ diff --git a/lib/imap.h b/lib/imap.h index 2f0b62a..ab4cf2f 100644 --- a/lib/imap.h +++ b/lib/imap.h @@ -47,6 +47,7 @@ struct imap_conn { imapstate state; /* always use imap.c:state() to change state! */ int cmdid; /* id number/index */ const char *idstr; /* pointer to a string for which to wait for as id */ + bool ssldone; /* is connect() over SSL done? only relevant in multi mode */ }; extern const struct Curl_handler Curl_handler_imap; -- 1.7.0.4
From 3420db7a04cfb6fb007ee0003c5edbd3e1793790 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis <[email protected]> Date: Wed, 16 Feb 2011 00:56:46 +0100 Subject: [PATCH 2/2] IMAP in multi mode: use Curl_ssl_connect_nonblocking() when upgrading the connection to TLS/SSL. --- lib/imap.c | 36 +++++++++++++++++++++++++++++++----- lib/imap.h | 1 + 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/lib/imap.c b/lib/imap.c index 4e71fb3..3e7daa1 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -108,6 +108,7 @@ static int imap_getsock(struct connectdata *conn, static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done); static CURLcode imap_setup_connection(struct connectdata * conn); +static CURLcode imap_state_upgrade_tls(struct connectdata *conn); /* * IMAP protocol handler. @@ -342,17 +343,38 @@ static CURLcode imap_state_starttls_resp(struct connectdata *conn, result = CURLE_LOGIN_DENIED; } else { - /* Curl_ssl_connect is BLOCKING */ - result = Curl_ssl_connect(conn, FIRSTSOCKET); - if(CURLE_OK == result) { - conn->protocol |= PROT_IMAPS; - result = imap_state_login(conn); + if (data->state.used_interface == Curl_if_multi) { + state(conn, IMAP_UPGRADETLS); + return imap_state_upgrade_tls(conn); + } + else { + result = Curl_ssl_connect(conn, FIRSTSOCKET); + if(CURLE_OK == result) { + conn->protocol |= PROT_IMAPS; + result = imap_state_login(conn); + } } } state(conn, IMAP_STOP); return result; } +static CURLcode imap_state_upgrade_tls(struct connectdata *conn) +{ + struct imap_conn *imapc = &conn->proto.imapc; + CURLcode result; + + result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone); + + if (imapc->ssldone) { + conn->protocol |= PROT_IMAPS; + result = imap_state_login(conn); + state(conn, IMAP_STOP); + } + + return result; +} + /* for LOGIN responses */ static CURLcode imap_state_login_resp(struct connectdata *conn, int imapcode, @@ -524,6 +546,10 @@ static CURLcode imap_statemach_act(struct connectdata *conn) struct pingpong *pp = &imapc->pp; size_t nread = 0; + /* busy upgrading the connection; right now all I/O is SSL/TLS, not IMAP */ + if(imapc->state == IMAP_UPGRADETLS) + return imap_state_upgrade_tls(conn); + if(pp->sendleft) return Curl_pp_flushsend(pp); diff --git a/lib/imap.h b/lib/imap.h index ab4cf2f..c139516 100644 --- a/lib/imap.h +++ b/lib/imap.h @@ -33,6 +33,7 @@ typedef enum { a connect */ IMAP_LOGIN, IMAP_STARTTLS, + IMAP_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS (multi mode only) */ IMAP_SELECT, IMAP_FETCH, IMAP_LOGOUT, -- 1.7.0.4
------------------------------------------------------------------- List admin: http://cool.haxx.se/list/listinfo/curl-library Etiquette: http://curl.haxx.se/mail/etiquette.html
