Karl M added the CURLOPT_CONNECT_ONLY and CURLINFO_LASTSOCKET options that
an app can use to let libcurl only connect to a remote host and then extract
the socket from libcurl. libcurl will then not attempt to do any transfer at
all after the connect is done.
diff --git a/CHANGES b/CHANGES
index 88961d3..826b021 100644
--- a/CHANGES
+++ b/CHANGES
@@ -7,6 +7,11 @@
                                   Changelog
 
 Daniel (11 February 2006)
+- Karl M added the CURLOPT_CONNECT_ONLY and CURLINFO_LASTSOCKET options that
+  an app can use to let libcurl only connect to a remote host and then extract
+  the socket from libcurl. libcurl will then not attempt to do any transfer at
+  all after the connect is done.
+
 - Kent Boortz improved the configure check for GnuTLS to properly set LIBS
   instead of LDFLAGS.
 
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index d7babaa..5cd89a4 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -2,21 +2,22 @@
 
  Public curl release number:               92
  Releases counted from the very beginning: 119
- Available command line options:           109
- Available curl_easy_setopt() options:     125
+ Available command line options:           111
+ Available curl_easy_setopt() options:     129
  Number of public functions in libcurl:    46
- Amount of public web site mirrors:        30
+ Amount of public web site mirrors:        31
  Number of known libcurl bindings:         32
  Number of contributors:                   474
 
 This release includes the following changes:
 
+ o CURLOPT_CONNECT_ONLY and CURLINFO_LASTSOCKET added
  o CURLOPT_LOCALPORT and CURLOPT_LOCALPORTRANGE (--local-port) added
  o Dropped support for the LPRT ftp command
- o Gopher is now officially abandoned as a protocol (lib)curl tries to support.
+ o Gopher is now officially abandoned as a protocol (lib)curl tries to support
  o curl_global_init() and curl_global_cleanup() are now using a refcount so
    that it is now legal to call them multiple times. See updated info for
-   details.
+   details
 
 This release includes the following bugfixes:
 
@@ -60,7 +61,7 @@
 
  Dov Murik, Jean Jacques Drouin, Andres Garcia, Yang Tse, Gisle Vanem, Dan
  Fandrich, Alexander Lazic, Michael Jahn, Andrew Benham, Bryan Henderson,
- David Shaw, Jon Turner, Duane Cathey, Michal Marek, Philippe Vaucher,
- Kent Boortz
+ David Shaw, Jon Turner, Duane Cathey, Michal Marek, Philippe Vaucher, Kent
+ Boortz, Karl M
  
         Thanks! (and sorry if I forgot to mention someone)
diff --git a/docs/libcurl/curl_easy_getinfo.3 b/docs/libcurl/curl_easy_getinfo.3
index bc4f206..2119ea2 100644
--- a/docs/libcurl/curl_easy_getinfo.3
+++ b/docs/libcurl/curl_easy_getinfo.3
@@ -141,6 +141,12 @@
 cookies (cookies for the handle have not been enabled or simply none have been
 received) 'struct curl_slist *' will be set to point to NULL. (Added in
 7.14.1)
+.IP CURLINFO_LASTSOCKET
+Pass a pointer to a long to receive the last socket used by this curl
+session. If the socket is no longer valid, -1 is returned. When you finish
+working with the socket, you must call curl_easy_cleanup() as usual and let
+libcurl close the socket and cleanup other resources associated with the
+handle. (Added in 7.15.2)
 .SH TIMES
 .NF
 An overview of the six time values available from curl_easy_getinfo()
diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3
index 25e7e77..8a15294 100644
--- a/docs/libcurl/curl_easy_setopt.3
+++ b/docs/libcurl/curl_easy_setopt.3
@@ -1044,6 +1044,14 @@
 .IP CURL_IPRESOLVE_V6
 Resolve to ipv6 addresses.
 .RE
+.SH CURLOPT_CONNECT_ONLY
+Pass a long. A non-zero parameter tells the library to perform any required
+proxy authentication and connection setup, but no data transfer.
+
+This option is useful with the \fICURLINFO_LASTSOCKET\fP option to
+\fIcurl_easy_getinfo(3)\fP. The library can set up the connection and then the
+application can obtain the most recently used socket for special data
+transfers. (Added in 7.15.2)
 .SH SSL and SECURITY OPTIONS
 .IP CURLOPT_SSLCERT
 Pass a pointer to a zero terminated string as parameter. The string should be
diff --git a/include/curl/curl.h b/include/curl/curl.h
index 95c478a..1ad282d 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -923,6 +923,10 @@
   */
   CINIT(LOCALPORTRANGE, LONG, 140),
 
+  /* no transfer, set up connection and let application use the socket by
+     extracting it with CURLINFO_LASTSOCKET */
+  CINIT(CONNECT_ONLY, LONG, 141),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
@@ -1277,9 +1281,10 @@
   CURLINFO_NUM_CONNECTS     = CURLINFO_LONG   + 26,
   CURLINFO_SSL_ENGINES      = CURLINFO_SLIST  + 27,
   CURLINFO_COOKIELIST       = CURLINFO_SLIST  + 28,
+  CURLINFO_LASTSOCKET       = CURLINFO_LONG   + 29,
   /* Fill in new entries below here! */
 
-  CURLINFO_LASTONE          = 28
+  CURLINFO_LASTONE          = 29
 } CURLINFO;
 
 /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
diff --git a/lib/easy.c b/lib/easy.c
index 2de1803..d86b755 100644
--- a/lib/easy.c
+++ b/lib/easy.c
@@ -527,6 +527,8 @@
     memset(outcurl->state.connects, 0,
            sizeof(struct connectdata *)*outcurl->state.numconnects);
 
+    outcurl->state.lastconnect = -1;
+
     outcurl->progress.flags    = data->progress.flags;
     outcurl->progress.callback = data->progress.callback;
 
diff --git a/lib/ftp.c b/lib/ftp.c
index ecb7176..02732f4 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -1689,7 +1689,7 @@
     ftp_pasv_verbose(conn, conninfo, newhost, connectport);
 
 #ifndef CURL_DISABLE_HTTP
-  if(conn->bits.tunnel_proxy) {
+  if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
     /* FIX: this MUST wait for a proper connect first if 'connected' is
      * FALSE */
 
@@ -2786,7 +2786,7 @@
   ftp->response_time = 3600; /* set default response time-out */
 
 #ifndef CURL_DISABLE_HTTP
-  if (conn->bits.tunnel_proxy) {
+  if (conn->bits.tunnel_proxy && conn->bits.httpproxy) {
     /* BLOCKING */
     /* We want "seamless" FTP operations through HTTP proxy tunnel */
 
diff --git a/lib/getinfo.c b/lib/getinfo.c
index 4782821..2a4c3aa 100644
--- a/lib/getinfo.c
+++ b/lib/getinfo.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2006, 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
@@ -187,6 +187,14 @@
   case CURLINFO_COOKIELIST:
     *param_slistp = Curl_cookie_list(data);
     break;
+  case CURLINFO_LASTSOCKET:
+    if((data->state.lastconnect != -1) &&
+       (data->state.connects[data->state.lastconnect] != NULL))
+      *param_longp = data->state.connects[data->state.lastconnect]->
+        sock[FIRSTSOCKET];
+    else
+      *param_longp = -1;
+    break;
   default:
     return CURLE_BAD_FUNCTION_ARGUMENT;
   }
diff --git a/lib/http.c b/lib/http.c
index 39e2940..e15054f 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -1361,7 +1361,7 @@
    * after the connect has occured, can we start talking SSL
    */
 
-  if(conn->bits.tunnel_proxy) {
+  if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
 
     /* either SSL over proxy, or explicitly asked for */
     result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
diff --git a/lib/multi.c b/lib/multi.c
index a60e1f5..a7d1988 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2006, 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
@@ -522,40 +522,49 @@
         break;
 
       case CURLM_STATE_DO:
-        /* Perform the protocol's DO action */
-        easy->result = Curl_do(&easy->easy_conn, &dophase_done);
-
-        if(CURLE_OK == easy->result) {
-
-          if(!dophase_done) {
-            /* DO was not completed in one function call, we must continue
-               DOING... */
-            multistate(easy, CURLM_STATE_DOING);
-            result = CURLM_OK;
-          }
-
-          /* after DO, go PERFORM... or DO_MORE */
-          else if(easy->easy_conn->bits.do_more) {
-            /* we're supposed to do more, but we need to sit down, relax
-               and wait a little while first */
-            multistate(easy, CURLM_STATE_DO_MORE);
-            result = CURLM_OK;
-          }
-          else {
-            /* we're done with the DO, now PERFORM */
-            easy->result = Curl_readwrite_init(easy->easy_conn);
-            if(CURLE_OK == easy->result) {
-              multistate(easy, CURLM_STATE_PERFORM);
-              result = CURLM_CALL_MULTI_PERFORM;
-            }
-          }
+        if(easy->easy_handle->set.connect_only) {
+          /* keep connection open for application to use the socket */
+          easy->easy_conn->bits.close = FALSE;
+          multistate(easy, CURLM_STATE_DONE);
+          easy->result = CURLE_OK;
+          result = CURLM_OK;
         }
         else {
-          /* failure detected */
-          Curl_posttransfer(easy->easy_handle);
-          Curl_done(&easy->easy_conn, easy->result);
-          Curl_disconnect(easy->easy_conn); /* close the connection */
-          easy->easy_conn = NULL;           /* no more connection */
+          /* Perform the protocol's DO action */
+          easy->result = Curl_do(&easy->easy_conn, &dophase_done);
+
+          if(CURLE_OK == easy->result) {
+
+            if(!dophase_done) {
+              /* DO was not completed in one function call, we must continue
+                 DOING... */
+              multistate(easy, CURLM_STATE_DOING);
+              result = CURLM_OK;
+            }
+
+            /* after DO, go PERFORM... or DO_MORE */
+            else if(easy->easy_conn->bits.do_more) {
+              /* we're supposed to do more, but we need to sit down, relax
+                 and wait a little while first */
+              multistate(easy, CURLM_STATE_DO_MORE);
+              result = CURLM_OK;
+            }
+            else {
+              /* we're done with the DO, now PERFORM */
+              easy->result = Curl_readwrite_init(easy->easy_conn);
+              if(CURLE_OK == easy->result) {
+                multistate(easy, CURLM_STATE_PERFORM);
+                result = CURLM_CALL_MULTI_PERFORM;
+              }
+            }
+          }
+          else {
+            /* failure detected */
+            Curl_posttransfer(easy->easy_handle);
+            Curl_done(&easy->easy_conn, easy->result);
+            Curl_disconnect(easy->easy_conn); /* close the connection */
+            easy->easy_conn = NULL;           /* no more connection */
+          }
         }
         break;
 
diff --git a/lib/transfer.c b/lib/transfer.c
index 50a8bae..2fbc2c6 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -2159,6 +2159,12 @@
 
     if(res == CURLE_OK) {
       bool do_done;
+      if(data->set.connect_only) {
+        /* keep connection open for application to use the socket */
+        conn->bits.close = FALSE;
+        res = Curl_done(&conn, CURLE_OK);
+        break;
+      }
       res = Curl_do(&conn, &do_done);
 
       /* for non 3rd party transfer only */
diff --git a/lib/url.c b/lib/url.c
index f17213f..49e7c1c 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -352,6 +352,9 @@
       memset(data->state.connects, 0,
              sizeof(struct connectdata *)*data->state.numconnects);
 
+    /* most recent connection is not yet defined */
+    data->state.lastconnect = -1;
+
     /*
      * libcurl 7.10 introduced SSL verification *by default*! This needs to be
      * switched off unless wanted.
@@ -432,6 +435,10 @@
            are being removed! */
         for(i=newconnects; i< data->state.numconnects; i++)
           Curl_disconnect(data->state.connects[i]);
+
+        /* If the most recent connection is no longer valid, mark it invalid. */
+        if(data->state.lastconnect <= newconnects)
+          data->state.lastconnect = -1;
       }
       if(newconnects) {
         newptr= (struct connectdata **)
@@ -453,8 +460,9 @@
         /* zero makes NO cache at all */
         if(data->state.connects)
           free(data->state.connects);
-        data->state.connects=NULL;
-        data->state.numconnects=0;
+        data->state.connects = NULL;
+        data->state.numconnects = 0;
+        data->state.lastconnect = -1;
       }
     }
     break;
@@ -1471,6 +1479,13 @@
     data->set.ignorecl = va_arg(param, long)?TRUE:FALSE;
     break;
 
+  case CURLOPT_CONNECT_ONLY:
+    /*
+     * No data transfer, set up connection and let application use the socket
+     */
+    data->set.connect_only = va_arg(param, long)?TRUE:FALSE;
+    break;
+
   default:
     /* unknown tag and its companion, just ignore: */
     result = CURLE_FAILED_INIT; /* correct this */
@@ -3811,10 +3826,14 @@
     if(!result && res2)
       result = res2;
   }
-  else
+  else {
+    /* remember the most recently used connection */
+    data->state.lastconnect = conn->connectindex;
+
     infof(data, "Connection #%ld to host %s left intact\n",
           conn->connectindex,
           conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
+  }
 
   return result;
 }
diff --git a/lib/urldata.h b/lib/urldata.h
index 96494a7..a3802b7 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -856,6 +856,7 @@
      set, it holds an allocated connection. */
   struct connectdata **connects;
   long numconnects; /* size of the 'connects' array */
+  int lastconnect;  /* index of most recent connect or -1 if undefined */
 
   char *headerbuff; /* allocated buffer to store headers in */
   size_t headersize;   /* size of the allocation */
@@ -1083,6 +1084,7 @@
   bool ignorecl;         /* ignore content length */
   bool ftp_skip_ip;      /* skip the IP address the FTP server passes on to
                             us */
+  bool connect_only;     /* make connection, let application use the socket */
 };
 
 /*