From 4ffb8a6398ed561b8b4fabce9790af26577f914a Mon Sep 17 00:00:00 2001
From: Steve Holme <steve_holme@hotmail.com>
Date: Tue, 8 Jan 2013 11:31:48 +0000
Subject: [PATCH] pop3: Added support for non-blocking SSL upgrade

Added support for asynchronous SSL upgrade when using the
multi-interface.
---
 lib/pop3.c | 38 ++++++++++++++++++++++++++++++++------
 lib/pop3.h |  6 +++++-
 2 files changed, 37 insertions(+), 7 deletions(-)

diff --git a/lib/pop3.c b/lib/pop3.c
index 1f6126c118..dcb2e693f6 100644
--- a/lib/pop3.c
+++ b/lib/pop3.c
@@ -103,6 +103,7 @@ static int pop3_getsock(struct connectdata *conn,
                         int numsocks);
 static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done);
 static CURLcode pop3_setup_connection(struct connectdata *conn);
+static CURLcode pop3_state_upgrade_tls(struct connectdata *conn);
 
 /*
  * POP3 protocol handler.
@@ -227,7 +228,7 @@ static int pop3_endofresp(struct pingpong *pp, int *resp)
     return FALSE;
   }
 
-  /* Are we processing servergreet responses */
+  /* Are we processing servergreet responses? */
   if(pop3c->state == POP3_SERVERGREET) {
     /* Look for the APOP timestamp */
     if(len >= 3 && line[len - 3] == '>') {
@@ -345,6 +346,7 @@ static void state(struct connectdata *conn, pop3state newstate)
     "STOP",
     "SERVERGREET",
     "STARTTLS",
+    "UPGRADETLS",
     "CAPA",
     "AUTH_PLAIN",
     "AUTH_LOGIN",
@@ -568,17 +570,37 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
       result = pop3_state_capa(conn);
   }
   else {
-    /* Curl_ssl_connect is BLOCKING */
-    result = Curl_ssl_connect(conn, FIRSTSOCKET);
-    if(CURLE_OK == result) {
-      pop3_to_pop3s(conn);
-      result = pop3_state_capa(conn);
+    if(data->state.used_interface == Curl_if_multi) {
+      state(conn, POP3_UPGRADETLS);
+      result = pop3_state_upgrade_tls(conn);
+    }
+    else {
+      result = Curl_ssl_connect(conn, FIRSTSOCKET);
+      if(CURLE_OK == result) {
+        pop3_to_pop3s(conn);
+        result = pop3_state_capa(conn);
+      }
     }
   }
 
   return result;
 }
 
+static CURLcode pop3_state_upgrade_tls(struct connectdata *conn)
+{
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  CURLcode result;
+
+  result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone);
+
+  if(pop3c->ssldone) {
+    pop3_to_pop3s(conn);
+    result = pop3_state_capa(conn);
+  }
+
+  return result;
+}
+
 /* For CAPA responses */
 static CURLcode pop3_state_capa_resp(struct connectdata *conn,
                                      int pop3code,
@@ -1114,6 +1136,10 @@ static CURLcode pop3_statemach_act(struct connectdata *conn)
   struct pingpong *pp = &pop3c->pp;
   size_t nread = 0;
 
+  /* Busy upgrading the connection; right now all I/O is SSL/TLS, not POP3 */
+  if(pop3c->state == POP3_UPGRADETLS)
+    return pop3_state_upgrade_tls(conn);
+
   /* Flush any data that needs to be sent */
   if(pp->sendleft)
     return Curl_pp_flushsend(pp);
diff --git a/lib/pop3.h b/lib/pop3.h
index 1b68599554..a07236c40f 100644
--- a/lib/pop3.h
+++ b/lib/pop3.h
@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2009 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2009 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -30,6 +30,8 @@ typedef enum {
   POP3_SERVERGREET,  /* waiting for the initial greeting immediately after
                         a connect */
   POP3_STARTTLS,
+  POP3_UPGRADETLS,   /* asynchronously upgrade the connection to SSL/TLS
+                       (multi mode only) */
   POP3_CAPA,
   POP3_AUTH_PLAIN,
   POP3_AUTH_LOGIN,
@@ -63,6 +65,8 @@ struct pop3_conn {
   unsigned int authused;  /* SASL auth mechanism used for the connection */
   char *apoptimestamp;    /* APOP timestamp from the server greeting */
   pop3state state;        /* Always use pop3.c:state() to change state! */
+  bool ssldone;           /* Is connect() over SSL done? Only relevant in
+                             multi mode */
 };
 
 extern const struct Curl_handler Curl_handler_pop3;
-- 
GitLab