From 7c730973bba620ba50e02fb1330e99c2230d3d8b Mon Sep 17 00:00:00 2001
From: Andy Cedilnik <andy.cedilnik@kitware.com>
Date: Fri, 24 Jun 2005 09:02:17 -0400
Subject: ENH: Initial import

---
 Source/CTest/Curl/Testing/CMakeLists.txt      |    4 +-
 Utilities/cmcurl/CMake/CheckTypeSize.c.in     |   34 +
 Utilities/cmcurl/CMake/CheckTypeSize.cmake    |   51 +
 Utilities/cmcurl/CMake/CurlTests.c            |  535 ++++
 Utilities/cmcurl/CMakeLists.txt               |  586 ++++
 Utilities/cmcurl/Platforms/WindowsCache.cmake |  123 +
 Utilities/cmcurl/Platforms/config-aix.h       |  486 ++++
 Utilities/cmcurl/Testing/CMakeLists.txt       |   19 +
 Utilities/cmcurl/Testing/curlgtk.c            |   95 +
 Utilities/cmcurl/Testing/curltest.c           |  143 +
 Utilities/cmcurl/Testing/ftpget.c             |   83 +
 Utilities/cmcurl/Testing/ftpgetresp.c         |   63 +
 Utilities/cmcurl/Testing/ftpupload.c          |   92 +
 Utilities/cmcurl/Testing/getinmemory.c        |   83 +
 Utilities/cmcurl/Testing/http-post.c          |   35 +
 Utilities/cmcurl/Testing/httpput.c            |  100 +
 Utilities/cmcurl/Testing/multithread.c        |   70 +
 Utilities/cmcurl/Testing/persistant.c         |   53 +
 Utilities/cmcurl/Testing/postit2.c            |   92 +
 Utilities/cmcurl/Testing/sepheaders.c         |   78 +
 Utilities/cmcurl/Testing/simple.c             |   28 +
 Utilities/cmcurl/Testing/simplessl.c          |  118 +
 Utilities/cmcurl/Testing/testconfig.h.in      |    7 +
 Utilities/cmcurl/Testing/win32sockets.c       |   49 +
 Utilities/cmcurl/amigaos.c                    |   49 +
 Utilities/cmcurl/amigaos.h                    |   52 +
 Utilities/cmcurl/arpa_telnet.h                |  101 +
 Utilities/cmcurl/base64.c                     |  288 ++
 Utilities/cmcurl/base64.h                     |   27 +
 Utilities/cmcurl/ca-bundle.h                  |    1 +
 Utilities/cmcurl/config.h.in                  |  512 ++++
 Utilities/cmcurl/connect.c                    |  788 ++++++
 Utilities/cmcurl/connect.h                    |   44 +
 Utilities/cmcurl/content_encoding.c           |  363 +++
 Utilities/cmcurl/content_encoding.h           |   41 +
 Utilities/cmcurl/cookie.c                     |  879 ++++++
 Utilities/cmcurl/cookie.h                     |   95 +
 Utilities/cmcurl/curl.copyright               |   25 +
 Utilities/cmcurl/curl/curl.h                  | 1340 +++++++++
 Utilities/cmcurl/curl/curlver.h               |   55 +
 Utilities/cmcurl/curl/easy.h                  |   81 +
 Utilities/cmcurl/curl/mprintf.h               |   54 +
 Utilities/cmcurl/curl/multi.h                 |  221 ++
 Utilities/cmcurl/curl/stdcheaders.h           |   34 +
 Utilities/cmcurl/curl/types.h                 |    1 +
 Utilities/cmcurl/curl_memory.h                |   50 +
 Utilities/cmcurl/curlx.h                      |   95 +
 Utilities/cmcurl/dict.c                       |  221 ++
 Utilities/cmcurl/dict.h                       |   30 +
 Utilities/cmcurl/easy.c                       |  583 ++++
 Utilities/cmcurl/escape.c                     |  135 +
 Utilities/cmcurl/escape.h                     |   32 +
 Utilities/cmcurl/file.c                       |  390 +++
 Utilities/cmcurl/file.h                       |   31 +
 Utilities/cmcurl/formdata.c                   | 1484 ++++++++++
 Utilities/cmcurl/formdata.h                   |   92 +
 Utilities/cmcurl/ftp.c                        | 2774 +++++++++++++++++++
 Utilities/cmcurl/ftp.h                        |   37 +
 Utilities/cmcurl/getdate.c                    | 2471 +++++++++++++++++
 Utilities/cmcurl/getdate.h                    |   37 +
 Utilities/cmcurl/getenv.c                     |   70 +
 Utilities/cmcurl/getinfo.c                    |  174 ++
 Utilities/cmcurl/getinfo.h                    |   28 +
 Utilities/cmcurl/hash.c                       |  267 ++
 Utilities/cmcurl/hash.h                       |   60 +
 Utilities/cmcurl/hostares.c                   |  301 ++
 Utilities/cmcurl/hostasyn.c                   |  170 ++
 Utilities/cmcurl/hostip.c                     |  540 ++++
 Utilities/cmcurl/hostip.h                     |  255 ++
 Utilities/cmcurl/hostip4.c                    |  456 +++
 Utilities/cmcurl/hostip6.c                    |  263 ++
 Utilities/cmcurl/hostsyn.c                    |  149 +
 Utilities/cmcurl/hostthre.c                   |  551 ++++
 Utilities/cmcurl/http.c                       | 1996 +++++++++++++
 Utilities/cmcurl/http.h                       |   61 +
 Utilities/cmcurl/http_chunks.c                |  264 ++
 Utilities/cmcurl/http_chunks.h                |   88 +
 Utilities/cmcurl/http_digest.c                |  482 ++++
 Utilities/cmcurl/http_digest.h                |   53 +
 Utilities/cmcurl/http_negotiate.c             |  332 +++
 Utilities/cmcurl/http_negotiate.h             |   39 +
 Utilities/cmcurl/http_ntlm.c                  |  585 ++++
 Utilities/cmcurl/http_ntlm.h                  |  143 +
 Utilities/cmcurl/if2ip.c                      |  142 +
 Utilities/cmcurl/if2ip.h                      |   69 +
 Utilities/cmcurl/inet_ntoa_r.h                |    9 +
 Utilities/cmcurl/inet_ntop.c                  |  204 ++
 Utilities/cmcurl/inet_ntop.h                  |   37 +
 Utilities/cmcurl/inet_pton.c                  |  240 ++
 Utilities/cmcurl/inet_pton.h                  |   37 +
 Utilities/cmcurl/krb4.c                       |  408 +++
 Utilities/cmcurl/krb4.h                       |   27 +
 Utilities/cmcurl/ldap.c                       |  625 +++++
 Utilities/cmcurl/ldap.h                       |   29 +
 Utilities/cmcurl/llist.c                      |  130 +
 Utilities/cmcurl/llist.h                      |   56 +
 Utilities/cmcurl/md5.c                        |  348 +++
 Utilities/cmcurl/md5.h                        |   29 +
 Utilities/cmcurl/memdebug.c                   |  293 ++
 Utilities/cmcurl/memdebug.h                   |  108 +
 Utilities/cmcurl/mprintf.c                    | 1219 ++++++++
 Utilities/cmcurl/multi.c                      |  648 +++++
 Utilities/cmcurl/netrc.c                      |  247 ++
 Utilities/cmcurl/netrc.h                      |   34 +
 Utilities/cmcurl/nwlib.c                      |  300 ++
 Utilities/cmcurl/progress.c                   |  426 +++
 Utilities/cmcurl/progress.h                   |   70 +
 Utilities/cmcurl/security.c                   |  483 ++++
 Utilities/cmcurl/security.h                   |   72 +
 Utilities/cmcurl/sendf.c                      |  496 ++++
 Utilities/cmcurl/sendf.h                      |   56 +
 Utilities/cmcurl/setup.h                      |  294 ++
 Utilities/cmcurl/share.c                      |  219 ++
 Utilities/cmcurl/share.h                      |   55 +
 Utilities/cmcurl/speedcheck.c                 |   67 +
 Utilities/cmcurl/speedcheck.h                 |   34 +
 Utilities/cmcurl/ssluse.c                     | 1487 ++++++++++
 Utilities/cmcurl/ssluse.h                     |   38 +
 Utilities/cmcurl/strequal.c                   |  140 +
 Utilities/cmcurl/strequal.h                   |   47 +
 Utilities/cmcurl/strerror.c                   |  569 ++++
 Utilities/cmcurl/strerror.h                   |   30 +
 Utilities/cmcurl/strtok.c                     |   68 +
 Utilities/cmcurl/strtok.h                     |   38 +
 Utilities/cmcurl/strtoofft.c                  |  164 ++
 Utilities/cmcurl/strtoofft.h                  |   62 +
 Utilities/cmcurl/telnet.c                     | 1389 ++++++++++
 Utilities/cmcurl/telnet.h                     |   30 +
 Utilities/cmcurl/timeval.c                    |  116 +
 Utilities/cmcurl/timeval.h                    |   74 +
 Utilities/cmcurl/transfer.c                   | 2191 +++++++++++++++
 Utilities/cmcurl/transfer.h                   |   52 +
 Utilities/cmcurl/url.c                        | 3686 +++++++++++++++++++++++++
 Utilities/cmcurl/url.h                        |   47 +
 Utilities/cmcurl/urldata.h                    |  962 +++++++
 Utilities/cmcurl/version.c                    |  261 ++
 136 files changed, 42827 insertions(+), 2 deletions(-)
 create mode 100644 Utilities/cmcurl/CMake/CheckTypeSize.c.in
 create mode 100644 Utilities/cmcurl/CMake/CheckTypeSize.cmake
 create mode 100644 Utilities/cmcurl/CMake/CurlTests.c
 create mode 100644 Utilities/cmcurl/CMakeLists.txt
 create mode 100644 Utilities/cmcurl/Platforms/WindowsCache.cmake
 create mode 100644 Utilities/cmcurl/Platforms/config-aix.h
 create mode 100644 Utilities/cmcurl/Testing/CMakeLists.txt
 create mode 100644 Utilities/cmcurl/Testing/curlgtk.c
 create mode 100644 Utilities/cmcurl/Testing/curltest.c
 create mode 100644 Utilities/cmcurl/Testing/ftpget.c
 create mode 100644 Utilities/cmcurl/Testing/ftpgetresp.c
 create mode 100644 Utilities/cmcurl/Testing/ftpupload.c
 create mode 100644 Utilities/cmcurl/Testing/getinmemory.c
 create mode 100644 Utilities/cmcurl/Testing/http-post.c
 create mode 100644 Utilities/cmcurl/Testing/httpput.c
 create mode 100644 Utilities/cmcurl/Testing/multithread.c
 create mode 100644 Utilities/cmcurl/Testing/persistant.c
 create mode 100644 Utilities/cmcurl/Testing/postit2.c
 create mode 100644 Utilities/cmcurl/Testing/sepheaders.c
 create mode 100644 Utilities/cmcurl/Testing/simple.c
 create mode 100644 Utilities/cmcurl/Testing/simplessl.c
 create mode 100644 Utilities/cmcurl/Testing/testconfig.h.in
 create mode 100644 Utilities/cmcurl/Testing/win32sockets.c
 create mode 100644 Utilities/cmcurl/amigaos.c
 create mode 100644 Utilities/cmcurl/amigaos.h
 create mode 100644 Utilities/cmcurl/arpa_telnet.h
 create mode 100644 Utilities/cmcurl/base64.c
 create mode 100644 Utilities/cmcurl/base64.h
 create mode 100644 Utilities/cmcurl/ca-bundle.h
 create mode 100644 Utilities/cmcurl/config.h.in
 create mode 100644 Utilities/cmcurl/connect.c
 create mode 100644 Utilities/cmcurl/connect.h
 create mode 100644 Utilities/cmcurl/content_encoding.c
 create mode 100644 Utilities/cmcurl/content_encoding.h
 create mode 100644 Utilities/cmcurl/cookie.c
 create mode 100644 Utilities/cmcurl/cookie.h
 create mode 100644 Utilities/cmcurl/curl.copyright
 create mode 100644 Utilities/cmcurl/curl/curl.h
 create mode 100644 Utilities/cmcurl/curl/curlver.h
 create mode 100644 Utilities/cmcurl/curl/easy.h
 create mode 100644 Utilities/cmcurl/curl/mprintf.h
 create mode 100644 Utilities/cmcurl/curl/multi.h
 create mode 100644 Utilities/cmcurl/curl/stdcheaders.h
 create mode 100644 Utilities/cmcurl/curl/types.h
 create mode 100644 Utilities/cmcurl/curl_memory.h
 create mode 100644 Utilities/cmcurl/curlx.h
 create mode 100644 Utilities/cmcurl/dict.c
 create mode 100644 Utilities/cmcurl/dict.h
 create mode 100644 Utilities/cmcurl/easy.c
 create mode 100644 Utilities/cmcurl/escape.c
 create mode 100644 Utilities/cmcurl/escape.h
 create mode 100644 Utilities/cmcurl/file.c
 create mode 100644 Utilities/cmcurl/file.h
 create mode 100644 Utilities/cmcurl/formdata.c
 create mode 100644 Utilities/cmcurl/formdata.h
 create mode 100644 Utilities/cmcurl/ftp.c
 create mode 100644 Utilities/cmcurl/ftp.h
 create mode 100644 Utilities/cmcurl/getdate.c
 create mode 100644 Utilities/cmcurl/getdate.h
 create mode 100644 Utilities/cmcurl/getenv.c
 create mode 100644 Utilities/cmcurl/getinfo.c
 create mode 100644 Utilities/cmcurl/getinfo.h
 create mode 100644 Utilities/cmcurl/hash.c
 create mode 100644 Utilities/cmcurl/hash.h
 create mode 100644 Utilities/cmcurl/hostares.c
 create mode 100644 Utilities/cmcurl/hostasyn.c
 create mode 100644 Utilities/cmcurl/hostip.c
 create mode 100644 Utilities/cmcurl/hostip.h
 create mode 100644 Utilities/cmcurl/hostip4.c
 create mode 100644 Utilities/cmcurl/hostip6.c
 create mode 100644 Utilities/cmcurl/hostsyn.c
 create mode 100644 Utilities/cmcurl/hostthre.c
 create mode 100644 Utilities/cmcurl/http.c
 create mode 100644 Utilities/cmcurl/http.h
 create mode 100644 Utilities/cmcurl/http_chunks.c
 create mode 100644 Utilities/cmcurl/http_chunks.h
 create mode 100644 Utilities/cmcurl/http_digest.c
 create mode 100644 Utilities/cmcurl/http_digest.h
 create mode 100644 Utilities/cmcurl/http_negotiate.c
 create mode 100644 Utilities/cmcurl/http_negotiate.h
 create mode 100644 Utilities/cmcurl/http_ntlm.c
 create mode 100644 Utilities/cmcurl/http_ntlm.h
 create mode 100644 Utilities/cmcurl/if2ip.c
 create mode 100644 Utilities/cmcurl/if2ip.h
 create mode 100644 Utilities/cmcurl/inet_ntoa_r.h
 create mode 100644 Utilities/cmcurl/inet_ntop.c
 create mode 100644 Utilities/cmcurl/inet_ntop.h
 create mode 100644 Utilities/cmcurl/inet_pton.c
 create mode 100644 Utilities/cmcurl/inet_pton.h
 create mode 100644 Utilities/cmcurl/krb4.c
 create mode 100644 Utilities/cmcurl/krb4.h
 create mode 100644 Utilities/cmcurl/ldap.c
 create mode 100644 Utilities/cmcurl/ldap.h
 create mode 100644 Utilities/cmcurl/llist.c
 create mode 100644 Utilities/cmcurl/llist.h
 create mode 100644 Utilities/cmcurl/md5.c
 create mode 100644 Utilities/cmcurl/md5.h
 create mode 100644 Utilities/cmcurl/memdebug.c
 create mode 100644 Utilities/cmcurl/memdebug.h
 create mode 100644 Utilities/cmcurl/mprintf.c
 create mode 100644 Utilities/cmcurl/multi.c
 create mode 100644 Utilities/cmcurl/netrc.c
 create mode 100644 Utilities/cmcurl/netrc.h
 create mode 100644 Utilities/cmcurl/nwlib.c
 create mode 100644 Utilities/cmcurl/progress.c
 create mode 100644 Utilities/cmcurl/progress.h
 create mode 100644 Utilities/cmcurl/security.c
 create mode 100644 Utilities/cmcurl/security.h
 create mode 100644 Utilities/cmcurl/sendf.c
 create mode 100644 Utilities/cmcurl/sendf.h
 create mode 100644 Utilities/cmcurl/setup.h
 create mode 100644 Utilities/cmcurl/share.c
 create mode 100644 Utilities/cmcurl/share.h
 create mode 100644 Utilities/cmcurl/speedcheck.c
 create mode 100644 Utilities/cmcurl/speedcheck.h
 create mode 100644 Utilities/cmcurl/ssluse.c
 create mode 100644 Utilities/cmcurl/ssluse.h
 create mode 100644 Utilities/cmcurl/strequal.c
 create mode 100644 Utilities/cmcurl/strequal.h
 create mode 100644 Utilities/cmcurl/strerror.c
 create mode 100644 Utilities/cmcurl/strerror.h
 create mode 100644 Utilities/cmcurl/strtok.c
 create mode 100644 Utilities/cmcurl/strtok.h
 create mode 100644 Utilities/cmcurl/strtoofft.c
 create mode 100644 Utilities/cmcurl/strtoofft.h
 create mode 100644 Utilities/cmcurl/telnet.c
 create mode 100644 Utilities/cmcurl/telnet.h
 create mode 100644 Utilities/cmcurl/timeval.c
 create mode 100644 Utilities/cmcurl/timeval.h
 create mode 100644 Utilities/cmcurl/transfer.c
 create mode 100644 Utilities/cmcurl/transfer.h
 create mode 100644 Utilities/cmcurl/url.c
 create mode 100644 Utilities/cmcurl/url.h
 create mode 100644 Utilities/cmcurl/urldata.h
 create mode 100644 Utilities/cmcurl/version.c

diff --git a/Source/CTest/Curl/Testing/CMakeLists.txt b/Source/CTest/Curl/Testing/CMakeLists.txt
index ebf89b4..214410f 100644
--- a/Source/CTest/Curl/Testing/CMakeLists.txt
+++ b/Source/CTest/Curl/Testing/CMakeLists.txt
@@ -15,5 +15,5 @@ INCLUDE_DIRECTORIES(${LIBCURL_BINARY_DIR}/Testing)
 
 FOREACH(TEST ${CURL_TESTS})
   ADD_EXECUTABLE(${TEST} ${TEST}.c)
-  TARGET_LINK_LIBRARIES(${TEST} Curl)
-ENDFOREACH(TEST)
\ No newline at end of file
+  TARGET_LINK_LIBRARIES(${TEST} cmcurl)
+ENDFOREACH(TEST)
diff --git a/Utilities/cmcurl/CMake/CheckTypeSize.c.in b/Utilities/cmcurl/CMake/CheckTypeSize.c.in
new file mode 100644
index 0000000..822d9c5
--- /dev/null
+++ b/Utilities/cmcurl/CMake/CheckTypeSize.c.in
@@ -0,0 +1,34 @@
+#ifdef CHECK_TYPE_SIZE_TYPE
+
+@CHECK_TYPE_SIZE_PREINCLUDE@
+
+#ifdef HAVE_SYS_TYPES_H
+#  include <sys/types.h>
+#endif /* HAVE_SYS_TYPES_H */
+
+#ifdef HAVE_STDINT_H
+#  include <stdint.h>
+#endif /* HAVE_STDINT_H */
+
+#ifdef HAVE_STDDEF_H
+#  include <stddef.h>
+#endif /* HAVE_STDDEF_H */
+
+@CHECK_TYPE_SIZE_PREMAIN@
+
+#ifdef __CLASSIC_C__
+int main(){
+  int ac;
+  char*av[];
+#else
+int main(int ac, char*av[]){
+#endif
+  if(ac > 1000){return *av[0];}
+  return sizeof(CHECK_TYPE_SIZE_TYPE);
+}
+
+#else  /* CHECK_TYPE_SIZE_TYPE */
+
+#  error "CHECK_TYPE_SIZE_TYPE has to specify the type"
+
+#endif /* CHECK_TYPE_SIZE_TYPE */
diff --git a/Utilities/cmcurl/CMake/CheckTypeSize.cmake b/Utilities/cmcurl/CMake/CheckTypeSize.cmake
new file mode 100644
index 0000000..ddc990a
--- /dev/null
+++ b/Utilities/cmcurl/CMake/CheckTypeSize.cmake
@@ -0,0 +1,51 @@
+#
+# Check if the type exists and determine size of type.  if the type
+# exists, the size will be stored to the variable.
+#
+# CHECK_TYPE_SIZE - macro which checks the size of type
+# VARIABLE - variable to store size if the type exists.
+# HAVE_${VARIABLE} - does the variable exists or not
+#
+
+MACRO(CHECK_TYPE_SIZE TYPE VARIABLE)
+  SET(CMAKE_ALLOW_UNKNOWN_VARIABLE_READ_ACCESS 1)
+  IF("HAVE_${VARIABLE}" MATCHES "^HAVE_${VARIABLE}$")
+    SET(MACRO_CHECK_TYPE_SIZE_FLAGS 
+      "-DCHECK_TYPE_SIZE_TYPE=\"${TYPE}\" ${CMAKE_REQUIRED_FLAGS}")
+    FOREACH(def HAVE_SYS_TYPES_H HAVE_STDINT_H HAVE_STDDEF_H)
+      IF("${def}")
+        SET(MACRO_CHECK_TYPE_SIZE_FLAGS 
+          "${MACRO_CHECK_TYPE_SIZE_FLAGS} -D${def}")
+      ENDIF("${def}")
+    ENDFOREACH(def)
+    SET(CHECK_TYPE_SIZE_PREMAIN)
+    FOREACH(def ${CMAKE_EXTRA_INCLUDE_FILES})
+      SET(CHECK_TYPE_SIZE_PREMAIN "${CHECK_TYPE_SIZE_PREMAIN}#include \"${def}\"\n")
+    ENDFOREACH(def)
+    CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/CMake/CheckTypeSize.c.in"
+      "${CMAKE_BINARY_DIR}/CMakeTmp/CheckTypeSize.c" IMMEDIATE @ONLY)
+    FILE(READ "${CMAKE_BINARY_DIR}/CMakeTmp/CheckTypeSize.c"
+      CHECK_TYPE_SIZE_FILE_CONTENT)
+    MESSAGE(STATUS "Check size of ${TYPE}")
+    IF(CMAKE_REQUIRED_LIBRARIES)
+      SET(CHECK_TYPE_SIZE_ADD_LIBRARIES 
+        "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
+    ENDIF(CMAKE_REQUIRED_LIBRARIES)
+    TRY_RUN(${VARIABLE} HAVE_${VARIABLE}
+      ${CMAKE_BINARY_DIR}
+      "${CMAKE_BINARY_DIR}/CMakeTmp/CheckTypeSize.c"
+      CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_TYPE_SIZE_FLAGS}
+      "${CHECK_TYPE_SIZE_ADD_LIBRARIES}"
+      OUTPUT_VARIABLE OUTPUT)
+    IF(HAVE_${VARIABLE})
+      MESSAGE(STATUS "Check size of ${TYPE} - done")
+      FILE(APPEND ${CMAKE_BINARY_DIR}/CMakeOutput.log 
+        "Determining size of ${TYPE} passed with the following output:\n${OUTPUT}\n\n")
+    ELSE(HAVE_${VARIABLE})
+      MESSAGE(STATUS "Check size of ${TYPE} - failed")
+      FILE(APPEND ${CMAKE_BINARY_DIR}/CMakeError.log 
+        "Determining size of ${TYPE} failed with the following output:\n${OUTPUT}\nCheckTypeSize.c:\n${CHECK_TYPE_SIZE_FILE_CONTENT}\n\n")
+    ENDIF(HAVE_${VARIABLE})
+  ENDIF("HAVE_${VARIABLE}" MATCHES "^HAVE_${VARIABLE}$")
+  SET(CMAKE_ALLOW_UNKNOWN_VARIABLE_READ_ACCESS )
+ENDMACRO(CHECK_TYPE_SIZE)
diff --git a/Utilities/cmcurl/CMake/CurlTests.c b/Utilities/cmcurl/CMake/CurlTests.c
new file mode 100644
index 0000000..61278ea
--- /dev/null
+++ b/Utilities/cmcurl/CMake/CurlTests.c
@@ -0,0 +1,535 @@
+#ifdef TIME_WITH_SYS_TIME
+/* Time with sys/time test */
+ 
+#include <sys/types.h>
+#include <sys/time.h>
+#include <time.h>
+
+int
+main ()
+{
+if ((struct tm *) 0)
+return 0;
+  ;
+  return 0;
+}
+
+#endif
+
+#ifdef HAVE_O_NONBLOCK
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int
+main ()
+{
+  /* try to compile O_NONBLOCK */
+
+#if defined(sun) || defined(__sun__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+# if defined(__SVR4) || defined(__srv4__)
+#  define PLATFORM_SOLARIS
+# else
+#  define PLATFORM_SUNOS4
+# endif
+#endif
+#if (defined(_AIX) || defined(__xlC__)) && !defined(_AIX4)
+# define PLATFORM_AIX_V3
+#endif
+
+#if defined(PLATFORM_SUNOS4) || defined(PLATFORM_AIX_V3) || defined(__BEOS__)
+#error "O_NONBLOCK does not work on this platform"
+#endif
+  int socket;
+  int flags = fcntl(socket, F_SETFL, flags | O_NONBLOCK);
+  return 0;
+}
+#endif
+
+#ifdef HAVE_GETHOSTBYADDR_R_5
+#include <sys/types.h>
+#include <netdb.h>
+int
+main ()
+{
+
+char * address;
+int length;
+int type;
+struct hostent h;
+struct hostent_data hdata;
+int rc;
+#ifndef gethostbyaddr_r
+  (void)gethostbyaddr_r;
+#endif
+rc = gethostbyaddr_r(address, length, type, &h, &hdata);
+  ;
+  return 0;
+}
+#endif
+#ifdef HAVE_GETHOSTBYADDR_R_5_REENTRANT
+#define _REENTRANT
+#include <sys/types.h>
+#include <netdb.h>
+int
+main ()
+{
+
+char * address;
+int length;q
+int type;
+struct hostent h;
+struct hostent_data hdata;
+int rc;
+#ifndef gethostbyaddr_r
+  (void)gethostbyaddr_r;
+#endif
+rc = gethostbyaddr_r(address, length, type, &h, &hdata);
+  ;
+  return 0;
+}
+#endif
+#ifdef HAVE_GETHOSTBYADDR_R_7
+#include <sys/types.h>
+#include <netdb.h>
+int
+main ()
+{
+
+char * address;
+int length;
+int type;
+struct hostent h;
+char buffer[8192];
+int h_errnop;
+struct hostent * hp;
+
+#ifndef gethostbyaddr_r
+  (void)gethostbyaddr_r;
+#endif
+hp = gethostbyaddr_r(address, length, type, &h,
+                     buffer, 8192, &h_errnop);
+  ;
+  return 0;
+}
+#endif
+#ifdef HAVE_GETHOSTBYADDR_R_7_REENTRANT
+#define _REENTRANT
+#include <sys/types.h>
+#include <netdb.h>
+int
+main ()
+{
+
+char * address;
+int length;
+int type;
+struct hostent h;
+char buffer[8192];
+int h_errnop;
+struct hostent * hp;
+
+#ifndef gethostbyaddr_r
+  (void)gethostbyaddr_r;
+#endif
+hp = gethostbyaddr_r(address, length, type, &h,
+                     buffer, 8192, &h_errnop);
+  ;
+  return 0;
+}
+#endif
+#ifdef HAVE_GETHOSTBYADDR_R_8
+#include <sys/types.h>
+#include <netdb.h>
+int
+main ()
+{
+
+char * address;
+int length;
+int type;
+struct hostent h;
+char buffer[8192];
+int h_errnop;
+struct hostent * hp;
+int rc;
+
+#ifndef gethostbyaddr_r
+  (void)gethostbyaddr_r;
+#endif
+rc = gethostbyaddr_r(address, length, type, &h,
+                     buffer, 8192, &hp, &h_errnop);
+  ;
+  return 0;
+}
+#endif
+#ifdef HAVE_GETHOSTBYADDR_R_8_REENTRANT
+#define _REENTRANT
+#include <sys/types.h>
+#include <netdb.h>
+int
+main ()
+{
+
+char * address;
+int length;
+int type;
+struct hostent h;
+char buffer[8192];
+int h_errnop;
+struct hostent * hp;
+int rc;
+
+#ifndef gethostbyaddr_r
+  (void)gethostbyaddr_r;
+#endif
+rc = gethostbyaddr_r(address, length, type, &h,
+                     buffer, 8192, &hp, &h_errnop);
+  ;
+  return 0;
+}
+#endif
+#ifdef HAVE_GETHOSTBYNAME_R_3
+#include <string.h>
+#include <sys/types.h>
+#include <netdb.h>
+#undef NULL
+#define NULL (void *)0
+
+int
+main ()
+{
+
+struct hostent_data data;
+#ifndef gethostbyname_r
+  (void)gethostbyname_r;
+#endif
+gethostbyname_r(NULL, NULL, NULL);
+  ;
+  return 0;
+}
+#endif
+#ifdef HAVE_GETHOSTBYNAME_R_3_REENTRANT
+#define _REENTRANT
+#include <string.h>
+#include <sys/types.h>
+#include <netdb.h>
+#undef NULL
+#define NULL (void *)0
+
+int
+main ()
+{
+
+struct hostent_data data;
+#ifndef gethostbyname_r
+  (void)gethostbyname_r;
+#endif
+gethostbyname_r(NULL, NULL, NULL);
+  ;
+  return 0;
+}
+#endif
+#ifdef HAVE_GETHOSTBYNAME_R_5
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#undef NULL
+#define NULL (void *)0
+
+int
+main ()
+{
+#ifndef gethostbyname_r
+  (void)gethostbyname_r;
+#endif
+gethostbyname_r(NULL, NULL, NULL, 0, NULL);
+  ;
+  return 0;
+}
+#endif
+#ifdef HAVE_GETHOSTBYNAME_R_5_REENTRANT
+#define _REENTRANT
+#include <sys/types.h>
+#include <netdb.h>
+#undef NULL
+#define NULL (void *)0
+
+int
+main ()
+{
+
+#ifndef gethostbyname_r
+  (void)gethostbyname_r;
+#endif
+gethostbyname_r(NULL, NULL, NULL, 0, NULL);
+  ;
+  return 0;
+}
+#endif
+#ifdef HAVE_GETHOSTBYNAME_R_6
+#include <sys/types.h>
+#include <netdb.h>
+#undef NULL
+#define NULL (void *)0
+
+int
+main ()
+{
+
+#ifndef gethostbyname_r
+  (void)gethostbyname_r;
+#endif
+gethostbyname_r(NULL, NULL, NULL, 0, NULL, NULL);
+  ;
+  return 0;
+}
+#endif
+#ifdef HAVE_GETHOSTBYNAME_R_6_REENTRANT
+#define _REENTRANT
+#include <sys/types.h>
+#include <netdb.h>
+#undef NULL
+#define NULL (void *)0
+
+int
+main ()
+{
+
+#ifndef gethostbyname_r
+  (void)gethostbyname_r;
+#endif
+gethostbyname_r(NULL, NULL, NULL, 0, NULL, NULL);
+  ;
+  return 0;
+}
+#endif
+#ifdef HAVE_SOCKLEN_T
+#include <sys/types.h>
+#include <sys/socket.h>
+
+int
+main ()
+{
+if ((socklen_t *) 0)
+  return 0;
+if (sizeof (socklen_t))
+  return 0;
+  ;
+  return 0;
+}
+#endif
+#ifdef HAVE_IN_ADDR_T
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+int
+main ()
+{
+if ((in_addr_t *) 0)
+  return 0;
+if (sizeof (in_addr_t))
+  return 0;
+  ;
+  return 0;
+}
+#endif
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+int main() { return 0; }
+#endif
+#ifdef RETSIGTYPE_TEST
+#include <sys/types.h>
+#include <signal.h>
+#ifdef signal
+# undef signal
+#endif
+#ifdef __cplusplus
+extern "C" void (*signal (int, void (*)(int)))(int);
+#else
+void (*signal ()) ();
+#endif
+
+int
+main ()
+{
+  return 0;
+}
+#endif
+#ifdef HAVE_INET_NTOA_R_DECL
+#include <arpa/inet.h>
+
+typedef void (*func_type)();
+
+int main()
+{
+#ifndef inet_ntoa_r
+  func_type func;
+  func = (func_type)inet_ntoa_r;
+#endif
+  return 0;
+}
+#endif
+#ifdef HAVE_INET_NTOA_R_DECL_REENTRANT
+#define _REENTRANT
+#include <arpa/inet.h>
+
+typedef void (*func_type)();
+
+int main()
+{
+#ifndef inet_ntoa_r
+  func_type func;
+  func = (func_type)&inet_ntoa_r;
+#endif
+  return 0;
+}
+#endif
+#ifdef HAVE_GETADDRINFO
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+int main(void) {
+    struct addrinfo hints, *ai;
+    int error;
+
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+#ifndef getaddrinfo
+    (void)getaddrinfo;
+#endif
+    error = getaddrinfo("127.0.0.1", "8080", &hints, &ai);
+    if (error) {
+        return 1;
+    }
+    return 0;
+}
+#endif
+#ifdef HAVE_FILE_OFFSET_BITS
+#ifdef _FILE_OFFSET_BITS
+#undef _FILE_OFFSET_BITS
+#endif
+#define _FILE_OFFSET_BITS 64
+#include <sys/types.h>
+ /* Check that off_t can represent 2**63 - 1 correctly.
+    We can't simply define LARGE_OFF_T to be 9223372036854775807,
+    since some C++ compilers masquerading as C compilers
+    incorrectly reject 9223372036854775807.  */
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+                       && LARGE_OFF_T % 2147483647 == 1)
+                      ? 1 : -1];
+int main () { ; return 0; }
+#endif
+#ifdef HAVE_IOCTLSOCKET
+#include <windows.h>
+
+int
+main ()
+{
+
+/* ioctlsocket source code */
+ int socket;
+ unsigned long flags = ioctlsocket(socket, FIONBIO, &flags);
+
+  ;
+  return 0;
+}
+
+#endif
+#ifdef HAVE_IOCTLSOCKET_CASE
+#include <windows.h>
+
+int
+main ()
+{
+
+/* IoctlSocket source code */
+ int socket;
+ int flags = IoctlSocket(socket, FIONBIO, (long)1);
+
+  ;
+  return 0;
+}
+#endif
+#ifdef HAVE_FIONBIO
+/* headers for FIONBIO test */
+#include <unistd.h>
+#include <stropts.h>
+
+int
+main ()
+{
+
+/* FIONBIO source test (old-style unix) */
+ int socket;
+ int flags = ioctl(socket, FIONBIO, &flags);
+
+  ;
+  return 0;
+}
+#endif
+#ifdef HAVE_SO_NONBLOCK
+
+/* headers for SO_NONBLOCK test (BeOS) */
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int main()
+{
+/* SO_NONBLOCK source code */
+ long b = 1;
+ int socket;
+ int flags = setsockopt(socket, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
+ return 0;
+}
+#endif
+#ifdef HAVE_GLIBC_STRERROR_R
+#include <string.h>
+#include <errno.h>
+int
+main () {
+  char buffer[1024]; /* big enough to play with */
+  char *string =
+    strerror_r(EACCES, buffer, sizeof(buffer));
+    /* this should've returned a string */
+    if(!string || !string[0])
+      return 99;
+    return 0;
+}
+#endif
+#ifdef HAVE_POSIX_STRERROR_R
+#include <string.h>
+#include <errno.h>
+int
+main () {
+  char buffer[1024]; /* big enough to play with */
+  int error =
+    strerror_r(EACCES, buffer, sizeof(buffer));
+    /* This should've returned zero, and written an error string in the
+       buffer.*/
+    if(!buffer[0] || error)
+      return 99;
+    return 0;
+}
+#endif
+#ifdef HAVE_LONG_LONG_CONSTANT
+int main()
+{
+  long long c = 0x8000000000000000LL;
+  long long k = 0x7FFFFFFFFFFFFFFFLL;
+  if ( c == 0x8000000000000000LL && c != k )
+    {
+    return 0;
+    }
+  return 1;
+}
+#endif
diff --git a/Utilities/cmcurl/CMakeLists.txt b/Utilities/cmcurl/CMakeLists.txt
new file mode 100644
index 0000000..afd027a
--- /dev/null
+++ b/Utilities/cmcurl/CMakeLists.txt
@@ -0,0 +1,586 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.0)
+PROJECT(LIBCURL C)
+
+INCLUDE_REGULAR_EXPRESSION("^.*\\.h$")
+
+# Setup package meta-data
+SET(PACKAGE "curl")
+SET(VERSION "7.12.1")
+SET(PACKAGE_TARNAME "curl")
+SET(PACKAGE_BUGREPORT " ")
+SET(PACKAGE_NAME "curl")
+SET(PACKAGE_VERSION "-")
+SET(PACKAGE_STRING "curl-")
+SET(PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/")
+SET(OPERATING_SYSTEM "${CMAKE_SYSTEM_NAME}")
+
+# We need ansi c-flags, especially on HP
+SET(CMAKE_C_FLAGS "${CMAKE_ANSI_CFLAGS} ${CMAKE_C_FLAGS}")
+SET(CMAKE_REQUIRED_FLAGS ${CMAKE_ANSI_CFLAGS})
+
+# If we are on AIX, do the _ALL_SOURCE magic
+IF(${CMAKE_SYSTEM_NAME} MATCHES AIX)
+  SET(_ALL_SOURCE 1)
+ENDIF(${CMAKE_SYSTEM_NAME} MATCHES AIX)
+
+# Include all the necessary files for macros
+SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake")
+INCLUDE (CheckFunctionExists)
+INCLUDE (CheckIncludeFile)
+INCLUDE (CheckIncludeFiles)
+INCLUDE (CheckLibraryExists)
+INCLUDE (CheckSymbolExists)
+INCLUDE (CheckTypeSize)
+
+SET(libCurl_SRCS
+  base64.c
+  connect.c
+  content_encoding.c
+  cookie.c
+  dict.c
+  easy.c
+  escape.c
+  file.c
+  formdata.c
+  ftp.c
+  getdate.c
+  getenv.c
+  getinfo.c
+  hash.c
+  hostares.c
+  hostasyn.c
+  hostip.c
+  hostip4.c
+  hostip6.c
+  hostsyn.c
+  hostthre.c
+  http.c
+  http_chunks.c
+  http_digest.c
+  http_negotiate.c
+  http_ntlm.c
+  if2ip.c
+  inet_ntop.c
+  inet_pton.c
+  krb4.c
+  llist.c
+  md5.c
+  memdebug.c
+  mprintf.c
+  multi.c
+  netrc.c
+  progress.c
+  sendf.c
+  share.c
+  speedcheck.c
+  ssluse.c
+  strequal.c
+  strerror.c
+  telnet.c
+  timeval.c
+  transfer.c
+  url.c
+  version.c
+  )
+
+SET(CURL_DISABLE_LDAP 1)
+IF(NOT CURL_DISABLE_LDAP)
+  SET(libCurl_SRCS
+    ${libCurl_SRCS}
+    ldap.c
+    )
+ENDIF(NOT CURL_DISABLE_LDAP)
+
+# if we have Kerberos 4, right now this is never on
+#OPTION(CURL_KRB4 "Use Kerberos 4" OFF)
+IF(CURL_KRB4)
+  SET(libCurl_SRCS ${libCurl_SRCS}
+    krb4.c
+    security.c
+    )
+ENDIF(CURL_KRB4)
+
+#OPTION(CURL_MALLOC_DEBUG "Debug mallocs in Curl" OFF)
+MARK_AS_ADVANCED(CURL_MALLOC_DEBUG)
+IF(CURL_MALLOC_DEBUG)
+  SET(libCurl_SRCS ${libCurl_SRCS}
+    memdebug.c
+    )
+ENDIF(CURL_MALLOC_DEBUG)
+
+# On windows preload settings
+IF(WIN32)
+  INCLUDE(${LIBCURL_SOURCE_DIR}/Platforms/WindowsCache.cmake)
+ENDIF(WIN32)
+
+# This macro checks if the symbol exists in the library and if it
+# does, it appends library to the list.
+SET(CURL_LIBS "")
+MACRO(CHECK_LIBRARY_EXISTS_CONCAT LIBRARY SYMBOL VARIABLE)
+  CHECK_LIBRARY_EXISTS("${LIBRARY};${CURL_LIBS}" ${SYMBOL} "" 
+    ${VARIABLE})
+  IF(${VARIABLE})
+    SET(CURL_LIBS ${CURL_LIBS} ${LIBRARY})
+  ENDIF(${VARIABLE})
+ENDMACRO(CHECK_LIBRARY_EXISTS_CONCAT)
+
+# Check for all needed libraries
+CHECK_LIBRARY_EXISTS_CONCAT("dl"     dlopen       HAVE_LIBDL)
+CHECK_LIBRARY_EXISTS_CONCAT("ucb"    gethostname  HAVE_LIBUCB)
+CHECK_LIBRARY_EXISTS_CONCAT("socket" connect      HAVE_LIBSOCKET)
+CHECK_LIBRARY_EXISTS("c" gethostbyname "" NOT_NEED_LIBNSL)
+
+IF(NOT NOT_NEED_LIBNSL)
+  CHECK_LIBRARY_EXISTS_CONCAT("nsl"    gethostbyname  HAVE_LIBNSL)
+ENDIF(NOT NOT_NEED_LIBNSL)
+
+CHECK_LIBRARY_EXISTS_CONCAT("ws2_32" getch        HAVE_LIBWS2_32)
+CHECK_LIBRARY_EXISTS_CONCAT("winmm"  getch        HAVE_LIBWINMM)
+IF(NOT CURL_SPECIAL_LIBZ)
+  CHECK_LIBRARY_EXISTS_CONCAT("z"      inflateEnd   HAVE_LIBZ)
+ENDIF(NOT CURL_SPECIAL_LIBZ)
+
+#OPTION(CMAKE_USE_OPENSSL "Use OpenSSL code. Experimental" OFF)
+MARK_AS_ADVANCED(CMAKE_USE_OPENSSL)
+IF(CMAKE_USE_OPENSSL)
+  CHECK_LIBRARY_EXISTS_CONCAT("crypto" CRYPTO_lock  HAVE_LIBCRYPTO)
+  CHECK_LIBRARY_EXISTS_CONCAT("ssl"    SSL_connect  HAVE_LIBSSL)
+ENDIF(CMAKE_USE_OPENSSL)
+
+# Check for symbol dlopen (same as HAVE_LIBDL)
+CHECK_LIBRARY_EXISTS("${CURL_LIBS}" dlopen "" HAVE_DLOPEN)
+
+# For other tests to use the same libraries
+SET(CMAKE_REQUIRED_LIBRARIES ${CURL_LIBS})
+
+IF(CURL_SPECIAL_LIBZ)
+  SET(CURL_LIBS ${CURL_LIBS} "${CURL_SPECIAL_LIBZ}")
+  INCLUDE_DIRECTORIES(${CURL_SPECIAL_LIBZ_INCLUDES})
+  SET(HAVE_LIBZ 0)
+  SET(HAVE_ZLIB_H 0)
+ENDIF(CURL_SPECIAL_LIBZ)
+
+
+# If we have features.h, then do the _BSD_SOURCE magic
+CHECK_INCLUDE_FILE("features.h"       HAVE_FEATURES_H)
+IF(HAVE_FEATURES_H)
+  SET_SOURCE_FILES_PROPERTIES(
+    cookie.c
+    easy.c
+    formdata.c
+    getenv.c
+    hash.c
+    http.c
+    if2ip.c 
+    mprintf.c
+    multi.c
+    sendf.c
+    telnet.c
+    transfer.c
+    url.c
+    COMPILE_FLAGS -D_BSD_SOURCE)
+ENDIF(HAVE_FEATURES_H)
+
+# Check if header file exists and add it to the list.
+MACRO(CHECK_INCLUDE_FILE_CONCAT FILE VARIABLE)
+  CHECK_INCLUDE_FILES("${CURL_INCLUDES};${FILE}" ${VARIABLE})
+  IF(${VARIABLE})
+    SET(CURL_INCLUDES ${CURL_INCLUDES} ${FILE})
+  ENDIF(${VARIABLE})
+ENDMACRO(CHECK_INCLUDE_FILE_CONCAT)
+
+# Check for header files
+CHECK_INCLUDE_FILE_CONCAT("stdio.h"          HAVE_STDIO_H)
+CHECK_INCLUDE_FILE_CONCAT("stddef.h"         HAVE_STDDEF_H)
+CHECK_INCLUDE_FILE_CONCAT("sys/types.h"      HAVE_SYS_TYPES_H)
+CHECK_INCLUDE_FILE_CONCAT("inttypes.h"       HAVE_INTTYPES_H)
+CHECK_INCLUDE_FILE_CONCAT("alloca.h"         HAVE_ALLOCA_H)
+CHECK_INCLUDE_FILE_CONCAT("arpa/inet.h"      HAVE_ARPA_INET_H)
+CHECK_INCLUDE_FILE_CONCAT("dlfcn.h"          HAVE_DLFCN_H)
+CHECK_INCLUDE_FILE_CONCAT("fcntl.h"          HAVE_FCNTL_H)
+CHECK_INCLUDE_FILE_CONCAT("malloc.h"         HAVE_MALLOC_H)
+CHECK_INCLUDE_FILE_CONCAT("memory.h"         HAVE_MEMORY_H)
+CHECK_INCLUDE_FILE_CONCAT("netdb.h"          HAVE_NETDB_H)
+CHECK_INCLUDE_FILE_CONCAT("sys/poll.h"       HAVE_SYS_POLL_H)
+CHECK_INCLUDE_FILE_CONCAT("assert.h"         HAVE_ASSERT_H)
+CHECK_INCLUDE_FILE_CONCAT("limits.h"         HAVE_LIMITS_H)
+
+IF(CMAKE_USE_OPENSSL)
+  CHECK_INCLUDE_FILE_CONCAT("openssl/x509.h"   HAVE_OPENSSL_X509_H)
+  CHECK_INCLUDE_FILE_CONCAT("openssl/engine.h" HAVE_OPENSSL_ENGINE_H)
+  CHECK_INCLUDE_FILE_CONCAT("openssl/rsa.h"    HAVE_OPENSSL_RSA_H)
+  CHECK_INCLUDE_FILE_CONCAT("openssl/crypto.h" HAVE_OPENSSL_CRYPTO_H)
+  CHECK_INCLUDE_FILE_CONCAT("openssl/pem.h"    HAVE_OPENSSL_PEM_H)
+  CHECK_INCLUDE_FILE_CONCAT("openssl/ssl.h"    HAVE_OPENSSL_SSL_H)
+  CHECK_INCLUDE_FILE_CONCAT("openssl/err.h"    HAVE_OPENSSL_ERR_H)
+  CHECK_INCLUDE_FILE_CONCAT("openssl/rand.h"   HAVE_OPENSSL_RAND_H)
+ENDIF(CMAKE_USE_OPENSSL)
+
+IF(NOT CURL_SPECIAL_LIBZ)
+  CHECK_INCLUDE_FILE_CONCAT("zlib.h"           HAVE_ZLIB_H)
+ENDIF(NOT CURL_SPECIAL_LIBZ)
+CHECK_INCLUDE_FILE_CONCAT("sys/socket.h"     HAVE_SYS_SOCKET_H)
+CHECK_INCLUDE_FILE_CONCAT("netinet/in.h"     HAVE_NETINET_IN_H)
+CHECK_INCLUDE_FILE_CONCAT("net/if.h"         HAVE_NET_IF_H)
+CHECK_INCLUDE_FILE_CONCAT("netinet/if_ether.h" 
+  HAVE_NETINET_IF_ETHER_H)
+CHECK_INCLUDE_FILE_CONCAT("netinet/tcp.h" 
+  HAVE_NETINET_TCP_H)
+CHECK_INCLUDE_FILE_CONCAT("sys/select.h"    HAVE_SYS_SELECT_H)
+CHECK_INCLUDE_FILE_CONCAT("utime.h"         HAVE_UTIME_H)
+CHECK_INCLUDE_FILE_CONCAT("netinet/in.h"    HAVE_NETINET_IN_H)
+CHECK_INCLUDE_FILE_CONCAT("pwd.h"           HAVE_PWD_H)
+CHECK_INCLUDE_FILE_CONCAT("sgtty.h"         HAVE_SGTTY_H)
+CHECK_INCLUDE_FILE_CONCAT("stdint.h"        HAVE_STDINT_H)
+CHECK_INCLUDE_FILE_CONCAT("stdlib.h"        HAVE_STDLIB_H)
+CHECK_INCLUDE_FILE_CONCAT("string.h"        HAVE_STRING_H)
+CHECK_INCLUDE_FILE_CONCAT("strings.h"       HAVE_STRINGS_H)
+CHECK_INCLUDE_FILE_CONCAT("sys/param.h"     HAVE_SYS_PARAM_H)
+CHECK_INCLUDE_FILE_CONCAT("sys/stat.h"      HAVE_SYS_STAT_H)
+CHECK_INCLUDE_FILE_CONCAT("sys/time.h"      HAVE_SYS_TIME_H)
+CHECK_INCLUDE_FILE_CONCAT("termios.h"       HAVE_TERMIOS_H)
+CHECK_INCLUDE_FILE_CONCAT("termio.h"        HAVE_TERMIO_H)
+CHECK_INCLUDE_FILE_CONCAT("io.h"            HAVE_IO_H)
+CHECK_INCLUDE_FILE_CONCAT("time.h"          HAVE_TIME_H)
+CHECK_INCLUDE_FILE_CONCAT("unistd.h"        HAVE_UNISTD_H)
+CHECK_INCLUDE_FILE_CONCAT("sys/utime.h"     HAVE_SYS_UTIME_H)
+CHECK_INCLUDE_FILE_CONCAT("winsock.h"       HAVE_WINSOCK_H)
+CHECK_INCLUDE_FILE_CONCAT("sockio.h"        HAVE_SOCKIO_H)
+CHECK_INCLUDE_FILE_CONCAT("sys/sockio.h"    HAVE_SYS_SOCKIO_H)
+CHECK_INCLUDE_FILE_CONCAT("x509.h"          HAVE_X509_H)
+CHECK_INCLUDE_FILE_CONCAT("setjmp.h"        HAVE_SETJMP_H)
+CHECK_INCLUDE_FILE_CONCAT("signal.h"        HAVE_SIGNAL_H)
+CHECK_INCLUDE_FILE_CONCAT("sys/ioctl.h"     HAVE_SYS_IOCTL_H)
+CHECK_INCLUDE_FILE_CONCAT("sys/utsname.h"   HAVE_SYS_UTSNAME_H)
+
+CHECK_TYPE_SIZE(size_t  SIZEOF_SIZE_T)
+CHECK_TYPE_SIZE(ssize_t  SIZEOF_SSIZE_T)
+CHECK_TYPE_SIZE("long long"  SIZEOF_LONG_LONG)
+CHECK_TYPE_SIZE("long double"  SIZEOF_LONG_DOUBLE)
+IF(NOT HAVE_SIZEOF_SSIZE_T)
+  SET(ssize_t int)
+ENDIF(NOT HAVE_SIZEOF_SSIZE_T)
+IF(HAVE_SIZEOF_LONG_LONG)
+  SET(HAVE_LONGLONG 1)
+ENDIF(HAVE_SIZEOF_LONG_LONG)
+
+FIND_FILE(RANDOM_FILE urandom /dev)
+MARK_AS_ADVANCED(RANDOM_FILE)
+
+# Check for some functions that are used
+CHECK_SYMBOL_EXISTS(socket        "${CURL_INCLUDES}" HAVE_SOCKET)
+CHECK_SYMBOL_EXISTS(poll          "${CURL_INCLUDES}" HAVE_POLL)
+CHECK_SYMBOL_EXISTS(select        "${CURL_INCLUDES}" HAVE_SELECT)
+CHECK_SYMBOL_EXISTS(strdup        "${CURL_INCLUDES}" HAVE_STRDUP)
+CHECK_SYMBOL_EXISTS(strstr        "${CURL_INCLUDES}" HAVE_STRSTR)
+CHECK_SYMBOL_EXISTS(strtok_r      "${CURL_INCLUDES}" HAVE_STRTOK_R)
+CHECK_SYMBOL_EXISTS(strftime      "${CURL_INCLUDES}" HAVE_STRFTIME)
+CHECK_SYMBOL_EXISTS(uname         "${CURL_INCLUDES}" HAVE_UNAME)
+CHECK_SYMBOL_EXISTS(strcasecmp    "${CURL_INCLUDES}" HAVE_STRCASECMP)
+CHECK_SYMBOL_EXISTS(stricmp       "${CURL_INCLUDES}" HAVE_STRICMP)
+CHECK_SYMBOL_EXISTS(strcmpi       "${CURL_INCLUDES}" HAVE_STRCMPI)
+CHECK_SYMBOL_EXISTS(strncmpi      "${CURL_INCLUDES}" HAVE_STRNCMPI)
+IF(NOT HAVE_STRNCMPI)
+  SET(HAVE_STRCMPI)
+ENDIF(NOT HAVE_STRNCMPI)
+CHECK_SYMBOL_EXISTS(gethostbyaddr "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR)
+CHECK_SYMBOL_EXISTS(gettimeofday  "${CURL_INCLUDES}" HAVE_GETTIMEOFDAY)
+CHECK_SYMBOL_EXISTS(inet_addr     "${CURL_INCLUDES}" HAVE_INET_ADDR)
+CHECK_SYMBOL_EXISTS(inet_pton     "${CURL_INCLUDES}" HAVE_INET_PTON)
+CHECK_SYMBOL_EXISTS(inet_ntoa     "${CURL_INCLUDES}" HAVE_INET_NTOA)
+CHECK_SYMBOL_EXISTS(inet_ntoa_r   "${CURL_INCLUDES}" HAVE_INET_NTOA_R)
+CHECK_SYMBOL_EXISTS(tcsetattr     "${CURL_INCLUDES}" HAVE_TCSETATTR)
+CHECK_SYMBOL_EXISTS(tcgetattr     "${CURL_INCLUDES}" HAVE_TCGETATTR)
+CHECK_SYMBOL_EXISTS(perror        "${CURL_INCLUDES}" HAVE_PERROR)
+CHECK_SYMBOL_EXISTS(closesocket   "${CURL_INCLUDES}" HAVE_CLOSESOCKET)
+CHECK_SYMBOL_EXISTS(setvbuf       "${CURL_INCLUDES}" HAVE_SETVBUF)
+CHECK_SYMBOL_EXISTS(sigsetjmp     "${CURL_INCLUDES}" HAVE_SIGSETJMP)
+CHECK_SYMBOL_EXISTS(getpass_r     "${CURL_INCLUDES}" HAVE_GETPASS_R)
+CHECK_SYMBOL_EXISTS(strlcat       "${CURL_INCLUDES}" HAVE_STRLCAT)
+CHECK_SYMBOL_EXISTS(getpwuid      "${CURL_INCLUDES}" HAVE_GETPWUID)
+CHECK_SYMBOL_EXISTS(geteuid       "${CURL_INCLUDES}" HAVE_GETEUID)
+CHECK_SYMBOL_EXISTS(utime         "${CURL_INCLUDES}" HAVE_UTIME)
+IF(CMAKE_USE_OPENSSL)
+  CHECK_SYMBOL_EXISTS(RAND_status   "${CURL_INCLUDES}" HAVE_RAND_STATUS)
+  CHECK_SYMBOL_EXISTS(RAND_screen   "${CURL_INCLUDES}" HAVE_RAND_SCREEN)
+  CHECK_SYMBOL_EXISTS(RAND_egd      "${CURL_INCLUDES}" HAVE_RAND_EGD)
+  CHECK_SYMBOL_EXISTS(CRYPTO_cleanup_all_ex_data "${CURL_INCLUDES}" 
+    HAVE_CRYPTO_CLEANUP_ALL_EX_DATA)
+ENDIF(CMAKE_USE_OPENSSL)
+CHECK_SYMBOL_EXISTS(gmtime_r      "${CURL_INCLUDES}" HAVE_GMTIME_R)
+CHECK_SYMBOL_EXISTS(localtime_r   "${CURL_INCLUDES}" HAVE_LOCALTIME_R)
+
+CHECK_SYMBOL_EXISTS(gethostbyname   "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME)
+CHECK_SYMBOL_EXISTS(gethostbyname_r "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME_R)
+CHECK_SYMBOL_EXISTS(gethostbyaddr_r "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR_R)
+
+CHECK_SYMBOL_EXISTS(signal        "${CURL_INCLUDES}" HAVE_SIGNAL_FUNC)
+CHECK_SYMBOL_EXISTS(SIGALRM       "${CURL_INCLUDES}" HAVE_SIGNAL_MACRO)
+IF(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO)
+  SET(HAVE_SIGNAL 1)
+ENDIF(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO)
+CHECK_SYMBOL_EXISTS(uname         "${CURL_INCLUDES}" HAVE_UNAME)
+CHECK_SYMBOL_EXISTS(strtoll       "${CURL_INCLUDES}" HAVE_STRTOLL)
+CHECK_SYMBOL_EXISTS(_strtoi64     "${CURL_INCLUDES}" HAVE__STRTOI64)
+CHECK_SYMBOL_EXISTS(strerror_r    "${CURL_INCLUDES}" HAVE_STRERROR_R)
+CHECK_SYMBOL_EXISTS(siginterrupt  "${CURL_INCLUDES}" HAVE_SIGINTERRUPT)
+CHECK_SYMBOL_EXISTS(perror        "${CURL_INCLUDES}" HAVE_PERROR)
+
+# only build compat strtok if we need to
+IF (NOT HAVE_STRTOK_R)
+  SET(libCurl_SRCS ${libCurl_SRCS}
+    strtok.c
+    )
+ENDIF (NOT HAVE_STRTOK_R)
+IF(NOT HAVE_STRTOLL AND NOT HAVE__STRTOI64)
+  SET(libCurl_SRCS ${libCurl_SRCS}
+    strtoofft.c
+    )
+ENDIF(NOT HAVE_STRTOLL AND NOT HAVE__STRTOI64)
+
+# sigaction and sigsetjmp are special. Use special mechanism for
+# detecting those, but only if previous attempt failed.
+IF(HAVE_SIGNAL_H)
+  CHECK_SYMBOL_EXISTS(sigaction "signal.h" HAVE_SIGACTION)
+ENDIF(HAVE_SIGNAL_H)
+
+IF(NOT HAVE_SIGSETJMP)
+  IF(HAVE_SETJMP_H)
+    CHECK_SYMBOL_EXISTS(sigsetjmp "setjmp.h" HAVE_MACRO_SIGSETJMP)
+    IF(HAVE_MACRO_SIGSETJMP)
+      SET(HAVE_SIGSETJMP 1)
+    ENDIF(HAVE_MACRO_SIGSETJMP)
+  ENDIF(HAVE_SETJMP_H)
+ENDIF(NOT HAVE_SIGSETJMP)
+
+# For other curl specific tests, use this macro.
+MACRO(CURL_INTERNAL_TEST CURL_TEST)
+  IF("${CURL_TEST}" MATCHES "^${CURL_TEST}$")
+    SET(MACRO_CHECK_FUNCTION_DEFINITIONS 
+      "-D${CURL_TEST} ${CMAKE_REQUIRED_FLAGS}")
+    IF(CMAKE_REQUIRED_LIBRARIES)
+      SET(CURL_TEST_ADD_LIBRARIES
+        "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
+    ENDIF(CMAKE_REQUIRED_LIBRARIES)
+
+    MESSAGE(STATUS "Performing Curl Test ${CURL_TEST}")
+    TRY_COMPILE(${CURL_TEST}
+      ${CMAKE_BINARY_DIR}
+      ${LIBCURL_SOURCE_DIR}/CMake/CurlTests.c
+      CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
+      "${CURL_TEST_ADD_LIBRARIES}"
+      OUTPUT_VARIABLE OUTPUT)
+    IF(${CURL_TEST})
+      SET(${CURL_TEST} 1 CACHE INTERNAL "Curl test ${FUNCTION}")
+      MESSAGE(STATUS "Performing Curl Test ${CURL_TEST} - Success")
+    ELSE(${CURL_TEST})
+      MESSAGE(STATUS "Performing Curl Test ${CURL_TEST} - Failed")
+      SET(${CURL_TEST} "" CACHE INTERNAL "Curl test ${FUNCTION}")
+      FILE(APPEND ${CMAKE_BINARY_DIR}/CMakeError.log 
+        "Performing Curl Test ${CURL_TEST} failed with the following output:\n"
+        "${OUTPUT}\n")
+    ENDIF(${CURL_TEST})
+  ENDIF("${CURL_TEST}" MATCHES "^${CURL_TEST}$")
+ENDMACRO(CURL_INTERNAL_TEST) 
+MACRO(CURL_INTERNAL_TEST_RUN CURL_TEST)
+  IF("${CURL_TEST}_COMPILE" MATCHES "^${CURL_TEST}_COMPILE$")
+    SET(MACRO_CHECK_FUNCTION_DEFINITIONS 
+      "-D${CURL_TEST} ${CMAKE_REQUIRED_FLAGS}")
+    IF(CMAKE_REQUIRED_LIBRARIES)
+      SET(CURL_TEST_ADD_LIBRARIES
+        "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
+    ENDIF(CMAKE_REQUIRED_LIBRARIES)
+
+    MESSAGE(STATUS "Performing Curl Test ${CURL_TEST}")
+    TRY_RUN(${CURL_TEST} ${CURL_TEST}_COMPILE
+      ${CMAKE_BINARY_DIR}
+      ${LIBCURL_SOURCE_DIR}/CMake/CurlTests.c
+      CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
+      "${CURL_TEST_ADD_LIBRARIES}"
+      OUTPUT_VARIABLE OUTPUT)
+    IF(${CURL_TEST}_COMPILE AND NOT ${CURL_TEST})
+      SET(${CURL_TEST} 1 CACHE INTERNAL "Curl test ${FUNCTION}")
+      MESSAGE(STATUS "Performing Curl Test ${CURL_TEST} - Success")
+    ELSE(${CURL_TEST}_COMPILE AND NOT ${CURL_TEST})
+      MESSAGE(STATUS "Performing Curl Test ${CURL_TEST} - Failed")
+      SET(${CURL_TEST} "" CACHE INTERNAL "Curl test ${FUNCTION}")
+      FILE(APPEND "${CMAKE_BINARY_DIR}/CMakeError.log"
+        "Performing Curl Test ${CURL_TEST} failed with the following output:\n"
+        "${OUTPUT}")
+      IF(${CURL_TEST}_COMPILE)
+        FILE(APPEND "${CMAKE_BINARY_DIR}/CMakeError.log" 
+          "There was a running problem of this test\n")
+      ENDIF(${CURL_TEST}_COMPILE)
+      FILE(APPEND "${CMAKE_BINARY_DIR}/CMakeError.log" 
+        "\n\n")
+    ENDIF(${CURL_TEST}_COMPILE AND NOT ${CURL_TEST})
+  ENDIF("${CURL_TEST}_COMPILE" MATCHES "^${CURL_TEST}_COMPILE$")
+ENDMACRO(CURL_INTERNAL_TEST_RUN) 
+
+# Do curl specific tests
+#OPTION(CURL_HAVE_DISABLED_NONBLOCKING "Disable non-blocking socket detection" OFF)
+SET(CURL_NONBLOCKING_TESTS)
+IF(NOT CURL_HAVE_DISABLED_NONBLOCKING)
+  SET(CURL_NONBLOCKING_TESTS
+    HAVE_FIONBIO
+    HAVE_IOCTLSOCKET
+    HAVE_IOCTLSOCKET_CASE
+    HAVE_O_NONBLOCK
+    HAVE_SO_NONBLOCK
+    )
+ENDIF(NOT CURL_HAVE_DISABLED_NONBLOCKING)
+FOREACH(CURL_TEST 
+    ${CURL_NONBLOCKING_TESTS}
+    TIME_WITH_SYS_TIME
+    HAVE_O_NONBLOCKHAVE_GETHOSTBYADDR_R_5
+    HAVE_GETHOSTBYADDR_R_7
+    HAVE_GETHOSTBYADDR_R_8
+    HAVE_GETHOSTBYADDR_R_5_REENTRANT
+    HAVE_GETHOSTBYADDR_R_7_REENTRANT
+    HAVE_GETHOSTBYADDR_R_8_REENTRANT
+    HAVE_GETHOSTBYNAME_R_3
+    HAVE_GETHOSTBYNAME_R_5
+    HAVE_GETHOSTBYNAME_R_6
+    HAVE_GETHOSTBYNAME_R_3_REENTRANT
+    HAVE_GETHOSTBYNAME_R_5_REENTRANT
+    HAVE_GETHOSTBYNAME_R_6_REENTRANT
+    HAVE_SOCKLEN_T
+    HAVE_IN_ADDR_T
+    STDC_HEADERS
+    RETSIGTYPE_TEST
+    HAVE_INET_NTOA_R_DECL
+    HAVE_INET_NTOA_R_DECL_REENTRANT
+    HAVE_GETADDRINFO
+    HAVE_FILE_OFFSET_BITS
+    )
+  CURL_INTERNAL_TEST(${CURL_TEST})
+ENDFOREACH(CURL_TEST)
+IF(HAVE_FILE_OFFSET_BITS)
+  SET(_FILE_OFFSET_BITS 64)
+ENDIF(HAVE_FILE_OFFSET_BITS)
+
+FOREACH(CURL_TEST 
+    HAVE_GLIBC_STRERROR_R
+    HAVE_POSIX_STRERROR_R
+    HAVE_LONG_LONG_CONSTANT
+    )
+  CURL_INTERNAL_TEST_RUN(${CURL_TEST})
+ENDFOREACH(CURL_TEST)
+
+# Check for reentrant
+FOREACH(CURL_TEST
+    HAVE_GETHOSTBYADDR_R_5
+    HAVE_GETHOSTBYADDR_R_7
+    HAVE_GETHOSTBYADDR_R_8
+    HAVE_GETHOSTBYNAME_R_3
+    HAVE_GETHOSTBYNAME_R_5
+    HAVE_GETHOSTBYNAME_R_6
+    HAVE_INET_NTOA_R_DECL_REENTRANT)
+  IF(NOT ${CURL_TEST})
+    IF(${CURL_TEST}_REENTRANT)
+      SET(NEED_REENTRANT 1)
+    ENDIF(${CURL_TEST}_REENTRANT)
+  ENDIF(NOT ${CURL_TEST})
+ENDFOREACH(CURL_TEST)
+
+IF(NEED_REENTRANT)
+  FOREACH(CURL_TEST
+      HAVE_GETHOSTBYADDR_R_5
+      HAVE_GETHOSTBYADDR_R_7
+      HAVE_GETHOSTBYADDR_R_8
+      HAVE_GETHOSTBYNAME_R_3
+      HAVE_GETHOSTBYNAME_R_5
+      HAVE_GETHOSTBYNAME_R_6)
+    SET(${CURL_TEST} 0)
+    IF(${CURL_TEST}_REENTRANT)
+      SET(${CURL_TEST} 1)
+    ENDIF(${CURL_TEST}_REENTRANT)
+  ENDFOREACH(CURL_TEST)
+ENDIF(NEED_REENTRANT)
+
+IF(HAVE_INET_NTOA_R_DECL_REENTRANT)
+  SET(HAVE_INET_NTOA_R_DECL 1)
+  SET(NEED_REENTRANT 1)
+ENDIF(HAVE_INET_NTOA_R_DECL_REENTRANT)
+
+# Some other minor tests
+
+IF(NOT HAVE_SOCKLEN_T)
+  SET(socklen_t "int")
+ENDIF(NOT HAVE_SOCKLEN_T)
+
+IF(NOT HAVE_IN_ADDR_T)
+  SET(in_addr_t "unsigned long")
+ENDIF(NOT HAVE_IN_ADDR_T)
+
+# Fix libz / zlib.h
+
+IF(NOT CURL_SPECIAL_LIBZ)
+  IF(NOT HAVE_LIBZ)
+    SET(HAVE_ZLIB_H 0)
+  ENDIF(NOT HAVE_LIBZ)
+
+  IF(NOT HAVE_ZLIB_H)
+    SET(HAVE_LIBZ 0)
+  ENDIF(NOT HAVE_ZLIB_H)
+ENDIF(NOT CURL_SPECIAL_LIBZ)
+
+IF(_FILE_OFFSET_BITS)
+  SET(_FILE_OFFSET_BITS 64)
+ENDIF(_FILE_OFFSET_BITS)
+SET(CMAKE_REQUIRED_FLAGS "-D_FILE_OFFSET_BITS=64")
+SET(CMAKE_EXTRA_INCLUDE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/curl/curl.h")
+CHECK_TYPE_SIZE("curl_off_t" SIZEOF_CURL_OFF_T)
+SET(CMAKE_EXTRA_INCLUDE_FILES)
+SET(CMAKE_REQUIRED_FLAGS)
+
+
+# Check for nonblocking
+SET(HAVE_DISABLED_NONBLOCKING 1)
+IF(HAVE_FIONBIO OR 
+    HAVE_IOCTLSOCKET OR
+    HAVE_IOCTLSOCKET_CASE OR
+    HAVE_O_NONBLOCK)
+  SET(HAVE_DISABLED_NONBLOCKING)
+ENDIF(HAVE_FIONBIO OR 
+  HAVE_IOCTLSOCKET OR
+  HAVE_IOCTLSOCKET_CASE OR
+  HAVE_O_NONBLOCK)
+
+IF(RETSIGTYPE_TEST)
+  SET(RETSIGTYPE void)
+ELSE(RETSIGTYPE_TEST)
+  SET(RETSIGTYPE int)
+ENDIF(RETSIGTYPE_TEST)
+
+IF(CMAKE_COMPILER_IS_GNUCC AND APPLE)
+  # The Mac version of GCC warns about use of long double.  Disable it.
+  GET_SOURCE_FILE_PROPERTY(MPRINTF_COMPILE_FLAGS mprintf.c COMPILE_FLAGS)
+  IF(MPRINTF_COMPILE_FLAGS)
+    SET(MPRINTF_COMPILE_FLAGS "${MPRINTF_COMPILE_FLAGS} -Wno-long-double")
+  ELSE(MPRINTF_COMPILE_FLAGS)
+    SET(MPRINTF_COMPILE_FLAGS "-Wno-long-double")
+  ENDIF(MPRINTF_COMPILE_FLAGS)
+  SET_SOURCE_FILES_PROPERTIES(mprintf.c PROPERTIES
+    COMPILE_FLAGS ${MPRINTF_COMPILE_FLAGS})
+ENDIF(CMAKE_COMPILER_IS_GNUCC AND APPLE)
+
+# The rest of the build
+
+INCLUDE_DIRECTORIES(${LIBCURL_SOURCE_DIR})
+INCLUDE_DIRECTORIES(${LIBCURL_BINARY_DIR})
+ADD_DEFINITIONS(-DHAVE_CONFIG_H)
+CONFIGURE_FILE(${LIBCURL_SOURCE_DIR}/config.h.in
+  ${LIBCURL_BINARY_DIR}/config.h)
+
+ADD_LIBRARY(cmcurl ${libCurl_SRCS})
+TARGET_LINK_LIBRARIES(cmcurl ${CURL_LIBS})
+
+OPTION(CURL_TESTING "Do libCurl testing" OFF)
+IF(CURL_TESTING)
+  SUBDIRS(Testing)
+ENDIF(CURL_TESTING)
+
+ADD_EXECUTABLE(LIBCURL Testing/curltest.c)
+TARGET_LINK_LIBRARIES(LIBCURL cmcurl)
+ADD_TEST(curl "${EXECUTABLE_OUTPUT_PATH}/LIBCURL")
diff --git a/Utilities/cmcurl/Platforms/WindowsCache.cmake b/Utilities/cmcurl/Platforms/WindowsCache.cmake
new file mode 100644
index 0000000..1a84b37
--- /dev/null
+++ b/Utilities/cmcurl/Platforms/WindowsCache.cmake
@@ -0,0 +1,123 @@
+IF(NOT UNIX)
+  IF(WIN32)
+    SET(HAVE_LIBDL 0)
+    SET(HAVE_LIBUCB 0)
+    SET(HAVE_LIBSOCKET 0)
+    SET(NOT_NEED_LIBNSL 0)
+    SET(HAVE_LIBNSL 0)
+    SET(HAVE_LIBZ 0)
+    SET(HAVE_LIBCRYPTO 0)
+
+    SET(HAVE_DLOPEN 0)
+
+    SET(HAVE_ALLOCA_H 0)
+    SET(HAVE_ARPA_INET_H 0)
+    SET(HAVE_DLFCN_H 0)
+    SET(HAVE_FCNTL_H 1)
+    SET(HAVE_FEATURES_H 0)
+    SET(HAVE_INTTYPES_H 0)
+    SET(HAVE_IO_H 1)
+    SET(HAVE_MALLOC_H 1)
+    SET(HAVE_MEMORY_H 1)
+    SET(HAVE_NETDB_H 0)
+    SET(HAVE_NETINET_IF_ETHER_H 0)
+    SET(HAVE_NETINET_IN_H 0)
+    SET(HAVE_NET_IF_H 0)
+    SET(HAVE_PWD_H 0)
+    SET(HAVE_SETJMP_H 1)
+    SET(HAVE_SGTTY_H 0)
+    SET(HAVE_SIGNAL_H 1)
+    SET(HAVE_SOCKIO_H 0)
+    SET(HAVE_STDINT_H 0)
+    SET(HAVE_STDLIB_H 1)
+    SET(HAVE_STRINGS_H 0)
+    SET(HAVE_STRING_H 1)
+    SET(HAVE_SYS_PARAM_H 0)
+    SET(HAVE_SYS_POLL_H 0)
+    SET(HAVE_SYS_SELECT_H 0)
+    SET(HAVE_SYS_SOCKET_H 0)
+    SET(HAVE_SYS_SOCKIO_H 0)
+    SET(HAVE_SYS_STAT_H 1)
+    SET(HAVE_SYS_TIME_H 0)
+    SET(HAVE_SYS_TYPES_H 1)
+    SET(HAVE_SYS_UTIME_H 1)
+    SET(HAVE_TERMIOS_H 0)
+    SET(HAVE_TERMIO_H 0)
+    SET(HAVE_TIME_H 1)
+    SET(HAVE_UNISTD_H 0)
+    SET(HAVE_UTIME_H 0)
+    SET(HAVE_WINSOCK_H 1)
+    SET(HAVE_X509_H 0)
+    SET(HAVE_ZLIB_H 0)
+
+    SET(HAVE_SIZEOF_LONG_DOUBLE 1)
+    SET(HAVE_SIZEOF_SSIZE_T 0)
+    SET(SIZEOF_LONG_DOUBLE 8)
+
+    SET(HAVE_SOCKET 1)
+    SET(HAVE_POLL 0)
+    SET(HAVE_SELECT 1)
+    SET(HAVE_STRDUP 1)
+    SET(HAVE_STRSTR 1)
+    SET(HAVE_STRTOK_R 0)
+    SET(HAVE_STRFTIME 1)
+    SET(HAVE_UNAME 0)
+    SET(HAVE_STRCASECMP 0)
+    SET(HAVE_STRICMP 1)
+    SET(HAVE_STRCMPI 1)
+    SET(HAVE_GETHOSTBYADDR 1)
+    SET(HAVE_GETTIMEOFDAY 0)
+    SET(HAVE_INET_ADDR 1)
+    SET(HAVE_INET_NTOA 1)
+    SET(HAVE_INET_NTOA_R 0)
+    SET(HAVE_TCGETATTR 0)
+    SET(HAVE_TCSETATTR 0)
+    SET(HAVE_PERROR 1)
+    SET(HAVE_CLOSESOCKET 1)
+    SET(HAVE_SETVBUF 0)
+    SET(HAVE_SIGSETJMP 0)
+    SET(HAVE_GETPASS_R 0)
+    SET(HAVE_STRLCAT 0)
+    SET(HAVE_GETPWUID 0)
+    SET(HAVE_GETEUID 0)
+    SET(HAVE_UTIME 1)
+    SET(HAVE_RAND_EGD 0)
+    SET(HAVE_RAND_SCREEN 0)
+    SET(HAVE_RAND_STATUS 0)
+    SET(HAVE_GMTIME_R 0)
+    SET(HAVE_LOCALTIME_R 0)
+    SET(HAVE_GETHOSTBYADDR_R 0)
+    SET(HAVE_GETHOSTBYNAME_R 0)
+    SET(HAVE_SIGNAL_FUNC 1)
+    SET(HAVE_SIGNAL_MACRO 0)
+
+    SET(HAVE_GETHOSTBYADDR_R_5 0)
+    SET(HAVE_GETHOSTBYADDR_R_5_REENTRANT 0)
+    SET(HAVE_GETHOSTBYADDR_R_7 0)
+    SET(HAVE_GETHOSTBYADDR_R_7_REENTRANT 0)
+    SET(HAVE_GETHOSTBYADDR_R_8 0)
+    SET(HAVE_GETHOSTBYADDR_R_8_REENTRANT 0)
+    SET(HAVE_GETHOSTBYNAME_R_3 0)
+    SET(HAVE_GETHOSTBYNAME_R_3_REENTRANT 0)
+    SET(HAVE_GETHOSTBYNAME_R_5 0)
+    SET(HAVE_GETHOSTBYNAME_R_5_REENTRANT 0)
+    SET(HAVE_GETHOSTBYNAME_R_6 0)
+    SET(HAVE_GETHOSTBYNAME_R_6_REENTRANT 0)
+
+    SET(TIME_WITH_SYS_TIME 0)
+    SET(HAVE_O_NONBLOCK 0)
+    SET(HAVE_IN_ADDR_T 0)
+    SET(HAVE_SOCKLEN_T 0)
+    SET(HAVE_INET_NTOA_R_DECL 0)
+    SET(HAVE_INET_NTOA_R_DECL_REENTRANT 0)
+    SET(HAVE_GETADDRINFO 0)
+    SET(STDC_HEADERS 1)
+    SET(RETSIGTYPE_TEST 1)
+
+    SET(HAVE_SIGACTION 0)
+    SET(HAVE_MACRO_SIGSETJMP 0)
+  ELSE(WIN32)
+    MESSAGE("This file should be included on Windows platform only")
+  ENDIF(WIN32)
+ENDIF(NOT UNIX)
+
diff --git a/Utilities/cmcurl/Platforms/config-aix.h b/Utilities/cmcurl/Platforms/config-aix.h
new file mode 100644
index 0000000..86d1093
--- /dev/null
+++ b/Utilities/cmcurl/Platforms/config-aix.h
@@ -0,0 +1,486 @@
+/* lib/config.h.  Generated by configure.  */
+/* lib/config.h.in.  Generated from configure.in by autoheader.  */
+/* Name of this package! */
+#define PACKAGE "curl"
+
+/* Version number of this archive. */
+#define VERSION "7.10.2"
+
+/* Define if you have the getpass function.  */
+/* #undef HAVE_GETPASS */
+
+/* Define cpu-machine-OS */
+#define OS "powerpc-ibm-aix5.1.0.0"
+
+/* Define if you have the gethostbyaddr_r() function with 5 arguments */
+#define HAVE_GETHOSTBYADDR_R_5 1
+
+/* Define if you have the gethostbyaddr_r() function with 7 arguments */
+/* #undef HAVE_GETHOSTBYADDR_R_7 */
+
+/* Define if you have the gethostbyaddr_r() function with 8 arguments */
+/* #undef HAVE_GETHOSTBYADDR_R_8 */
+
+/* Define if you have the gethostbyname_r() function with 3 arguments */
+#define HAVE_GETHOSTBYNAME_R_3 1
+
+/* Define if you have the gethostbyname_r() function with 5 arguments */
+/* #undef HAVE_GETHOSTBYNAME_R_5 */
+
+/* Define if you have the gethostbyname_r() function with 6 arguments */
+/* #undef HAVE_GETHOSTBYNAME_R_6 */
+
+/* Define if you have the inet_ntoa_r function declared. */
+/* #undef HAVE_INET_NTOA_R_DECL */
+
+/* Define if you need the _REENTRANT define for some functions */
+/* #undef NEED_REENTRANT */
+
+/* Define if you have the Kerberos4 libraries (including -ldes) */
+/* #undef KRB4 */
+
+/* Define if you want to enable IPv6 support */
+#define ENABLE_IPV6 1
+
+/* Define this to 'int' if ssize_t is not an available typedefed type */
+/* #undef ssize_t */
+
+/* Define this to 'int' if socklen_t is not an available typedefed type */
+/* #undef socklen_t */
+
+/* Define this as a suitable file to read random data from */
+/* #undef RANDOM_FILE */
+
+/* Define this to your Entropy Gathering Daemon socket pathname */
+/* #undef EGD_SOCKET */
+
+/* Define if you have a working OpenSSL installation */
+/* #undef OPENSSL_ENABLED */
+
+/* Define the one correct non-blocking socket method below */
+/* #undef HAVE_FIONBIO */
+/* #undef HAVE_IOCTLSOCKET */
+/* #undef HAVE_IOCTLSOCKET_CASE */
+/* #undef HAVE_O_NONBLOCK */
+#define HAVE_DISABLED_NONBLOCKING 1
+
+/* Define this to 'int' if in_addr_t is not an available typedefed type */
+/* #undef in_addr_t */
+
+/* Define to disable DICT */
+/* #undef CURL_DISABLE_DICT */
+
+/* Define to disable FILE */
+/* #undef CURL_DISABLE_FILE */
+
+/* Define to disable FTP */
+/* #undef CURL_DISABLE_FTP */
+
+/* Define to disable GOPHER */
+/* #undef CURL_DISABLE_GOPHER */
+
+/* Define to disable HTTP */
+/* #undef CURL_DISABLE_HTTP */
+
+/* Define to disable LDAP */
+/* #undef CURL_DISABLE_LDAP */
+
+/* Define to disable TELNET */
+/* #undef CURL_DISABLE_TELNET */
+
+/* Define if you have zlib present */
+#define HAVE_LIBZ 1
+
+/* CA bundle full path name */
+#define CURL_CA_BUNDLE "/usr/local/share/curl/curl-ca-bundle.crt"
+
+/* to disable FILE */
+/* #undef CURL_DISABLE_FILE */
+
+/* to disable FTP */
+/* #undef CURL_DISABLE_FTP */
+
+/* to disable GOPHER */
+/* #undef CURL_DISABLE_GOPHER */
+
+/* to disable HTTP */
+/* #undef CURL_DISABLE_HTTP */
+
+/* to disable LDAP */
+/* #undef CURL_DISABLE_LDAP */
+
+/* to disable TELNET */
+/* #undef CURL_DISABLE_TELNET */
+
+/* Set to explicitly specify we don't want to use thread-safe functions */
+/* #undef DISABLED_THREADSAFE */
+
+/* your Entropy Gathering Daemon socket pathname */
+/* #undef EGD_SOCKET */
+
+/* Define if you want to enable IPv6 support */
+#define ENABLE_IPV6 1
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the `closesocket' function. */
+/* #undef HAVE_CLOSESOCKET */
+
+/* Define to 1 if you have the <crypto.h> header file. */
+/* #undef HAVE_CRYPTO_H */
+
+/* Define to 1 if you have the <des.h> header file. */
+/* #undef HAVE_DES_H */
+
+/* to disable NON-BLOCKING connections */
+#define HAVE_DISABLED_NONBLOCKING 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `dlopen' function. */
+#define HAVE_DLOPEN 1
+
+/* Define to 1 if you have the <err.h> header file. */
+/* #undef HAVE_ERR_H */
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define if getaddrinfo exists and works */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the `gethostbyaddr' function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* Define to 1 if you have the `gethostbyaddr_r' function. */
+#define HAVE_GETHOSTBYADDR_R 1
+
+/* Define to 1 if you have the `gethostbyname_r' function. */
+#define HAVE_GETHOSTBYNAME_R 1
+
+/* Define to 1 if you have the `getpass_r' function. */
+/* #undef HAVE_GETPASS_R */
+
+/* Define to 1 if you have the `getpwuid' function. */
+#define HAVE_GETPWUID 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `gmtime_r' function. */
+#define HAVE_GMTIME_R 1
+
+/* Define to 1 if you have the `inet_addr' function. */
+#define HAVE_INET_ADDR 1
+
+/* Define to 1 if you have the `inet_ntoa' function. */
+#define HAVE_INET_NTOA 1
+
+/* Define to 1 if you have the `inet_ntoa_r' function. */
+#define HAVE_INET_NTOA_R 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <io.h> header file. */
+/* #undef HAVE_IO_H */
+
+/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
+/* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */
+
+/* Define to 1 if you have the <krb.h> header file. */
+/* #undef HAVE_KRB_H */
+
+/* Define to 1 if you have the `crypto' library (-lcrypto). */
+/* #undef HAVE_LIBCRYPTO */
+
+/* Define to 1 if you have the `dl' library (-ldl). */
+/* #undef HAVE_LIBDL */
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+/* #undef HAVE_LIBNSL */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+/* #undef HAVE_LIBRESOLV */
+
+/* Define to 1 if you have the `resolve' library (-lresolve). */
+/* #undef HAVE_LIBRESOLVE */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+/* #undef HAVE_LIBSSL */
+
+/* If zlib is available */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the `localtime_r' function. */
+#define HAVE_LOCALTIME_R 1
+
+/* Define to 1 if you have the <malloc.h> header file. */
+#define HAVE_MALLOC_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/if_ether.h> header file. */
+#define HAVE_NETINET_IF_ETHER_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+/* #undef HAVE_OPENSSL_CRYPTO_H */
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+/* #undef HAVE_OPENSSL_ENGINE_H */
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+/* #undef HAVE_OPENSSL_ERR_H */
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+/* #undef HAVE_OPENSSL_PEM_H */
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+/* #undef HAVE_OPENSSL_RSA_H */
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+/* #undef HAVE_OPENSSL_SSL_H */
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+/* #undef HAVE_OPENSSL_X509_H */
+
+/* Define to 1 if you have the <pem.h> header file. */
+/* #undef HAVE_PEM_H */
+
+/* Define to 1 if you have the `perror' function. */
+#define HAVE_PERROR 1
+
+/* Define to 1 if you have the `poll' function. */
+#define HAVE_POLL 1
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define to 1 if you have the `RAND_egd' function. */
+/* #undef HAVE_RAND_EGD */
+
+/* Define to 1 if you have the `RAND_screen' function. */
+/* #undef HAVE_RAND_SCREEN */
+
+/* Define to 1 if you have the `RAND_status' function. */
+/* #undef HAVE_RAND_STATUS */
+
+/* Define to 1 if you have the <rsa.h> header file. */
+/* #undef HAVE_RSA_H */
+
+/* Define to 1 if you have the `select' function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#define HAVE_SETJMP_H 1
+
+/* Define to 1 if you have the `setvbuf' function. */
+#define HAVE_SETVBUF 1
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+#define HAVE_SGTTY_H 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define HAVE_SIGNAL 1
+
+/* If you have sigsetjmp */
+#define HAVE_SIGSETJMP 1
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define to 1 if you have the <ssl.h> header file. */
+/* #undef HAVE_SSL_H */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+/* #undef HAVE_STDINT_H */
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strcasecmp' function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the `strcmpi' function. */
+/* #undef HAVE_STRCMPI */
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strftime' function. */
+#define HAVE_STRFTIME 1
+
+/* Define to 1 if you have the `stricmp' function. */
+/* #undef HAVE_STRICMP */
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcat' function. */
+/* #undef HAVE_STRLCAT */
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the `strstr' function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#define HAVE_SYS_POLL_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+/* #undef HAVE_SYS_SOCKIO_H */
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+/* #undef HAVE_SYS_UTIME_H */
+
+/* Define to 1 if you have the `tcgetattr' function. */
+#define HAVE_TCGETATTR 1
+
+/* Define to 1 if you have the `tcsetattr' function. */
+#define HAVE_TCSETATTR 1
+
+/* Define to 1 if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define to 1 if you have the <termio.h> header file. */
+#define HAVE_TERMIO_H 1
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define to 1 if you have the `uname' function. */
+#define HAVE_UNAME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if you have the <winsock.h> header file. */
+/* #undef HAVE_WINSOCK_H */
+
+/* Define to 1 if you have the <x509.h> header file. */
+/* #undef HAVE_X509_H */
+
+/* if you have the zlib.h header file */
+/* #undef HAVE_ZLIB_H */
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+/* #undef KRB4 */
+
+/* cpu-machine-OS */
+#define OS "powerpc-ibm-aix5.1.0.0"
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION ""
+
+/* a suitable file to read random data from */
+/* #undef RANDOM_FILE */
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define VERSION "7.10.2"
+
+/* Define to 1 if on AIX 3.
+   System headers sometimes define this.
+   We just want to avoid a redefinition error message.  */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+#define _LARGE_FILES 1
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* type to use in place of in_addr_t if not defined */
+/* #undef in_addr_t */
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* type to use in place of socklen_t if not defined */
+/* #undef socklen_t */
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef ssize_t */
diff --git a/Utilities/cmcurl/Testing/CMakeLists.txt b/Utilities/cmcurl/Testing/CMakeLists.txt
new file mode 100644
index 0000000..214410f
--- /dev/null
+++ b/Utilities/cmcurl/Testing/CMakeLists.txt
@@ -0,0 +1,19 @@
+SET(CURL_TESTS
+    ftpget
+    ftpgetresp
+    ftpupload
+    getinmemory
+    persistant
+    sepheaders
+    simple
+   )
+
+CONFIGURE_FILE(${LIBCURL_SOURCE_DIR}/Testing/testconfig.h.in
+               ${LIBCURL_BINARY_DIR}/Testing/testconfig.h)
+
+INCLUDE_DIRECTORIES(${LIBCURL_BINARY_DIR}/Testing)
+
+FOREACH(TEST ${CURL_TESTS})
+  ADD_EXECUTABLE(${TEST} ${TEST}.c)
+  TARGET_LINK_LIBRARIES(${TEST} cmcurl)
+ENDFOREACH(TEST)
diff --git a/Utilities/cmcurl/Testing/curlgtk.c b/Utilities/cmcurl/Testing/curlgtk.c
new file mode 100644
index 0000000..7c9ce2a
--- /dev/null
+++ b/Utilities/cmcurl/Testing/curlgtk.c
@@ -0,0 +1,95 @@
+/*****************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * $Id$
+ */
+/* Copyright (c) 2000 David Odin (aka DindinX) for MandrakeSoft */
+/* an attempt to use the curl library in concert with a gtk-threaded application */
+
+#include <stdio.h>
+#include <gtk/gtk.h>
+
+#include <curl/curl.h>
+#include <curl/types.h> /* new for v7 */
+#include <curl/easy.h> /* new for v7 */
+
+#include <pthread.h>
+
+GtkWidget *Bar;
+
+size_t my_read_func(void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+  return fread(ptr, size, nmemb, stream);
+}
+
+int my_progress_func(GtkWidget *Bar, int t, int d)
+{
+/*  printf("%d / %d (%g %%)\n", d, t, d*100.0/t);*/
+  gdk_threads_enter();
+  gtk_progress_set_value(GTK_PROGRESS(Bar), d*100.0/t);
+  gdk_threads_leave();
+  return 0;
+}
+
+void *curl_thread(void *ptr)
+{
+  CURL *curl;
+  CURLcode res;
+  FILE *outfile;
+  gchar *url = ptr;
+  
+  curl = curl_easy_init();
+  if(curl)
+  {
+    outfile = fopen("/tmp/test.curl", "w");
+
+    curl_easy_setopt(curl, CURLOPT_URL, url);
+    curl_easy_setopt(curl, CURLOPT_FILE, outfile);
+    curl_easy_setopt(curl, CURLOPT_READFUNCTION, my_read_func);
+    curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, my_progress_func);
+    curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, Bar);
+    
+    res = curl_easy_perform(curl);
+
+    fclose(outfile);
+    /* always cleanup */
+    curl_easy_cleanup(curl);
+  }
+  return NULL;
+}
+
+int main(int argc, char **argv)
+{
+  GtkWidget *Window, *Frame, *Frame2;
+  GtkAdjustment *adj;
+  pthread_t curl_tid;
+
+  /* Init thread */
+  g_thread_init(NULL);
+  
+  gtk_init(&argc, &argv);
+  Window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+  Frame = gtk_frame_new(NULL);
+  gtk_frame_set_shadow_type(GTK_FRAME(Frame), GTK_SHADOW_OUT);
+  gtk_container_add(GTK_CONTAINER(Window), Frame);
+  Frame2 = gtk_frame_new(NULL);
+  gtk_frame_set_shadow_type(GTK_FRAME(Frame2), GTK_SHADOW_IN);
+  gtk_container_add(GTK_CONTAINER(Frame), Frame2);
+  gtk_container_set_border_width(GTK_CONTAINER(Frame2), 5);
+  adj = (GtkAdjustment*)gtk_adjustment_new(0, 0, 100, 0, 0, 0);
+  Bar = gtk_progress_bar_new_with_adjustment(adj);
+  gtk_container_add(GTK_CONTAINER(Frame2), Bar);
+  gtk_widget_show_all(Window);
+
+  pthread_create(&curl_tid, NULL, curl_thread, argv[1]);
+    
+  gdk_threads_enter();
+  gtk_main();
+  gdk_threads_leave();
+  return 0;
+}
+
diff --git a/Utilities/cmcurl/Testing/curltest.c b/Utilities/cmcurl/Testing/curltest.c
new file mode 100644
index 0000000..c21774a
--- /dev/null
+++ b/Utilities/cmcurl/Testing/curltest.c
@@ -0,0 +1,143 @@
+/* Prevent warnings on Visual Studio */
+struct _RPC_ASYNC_STATE;
+
+#include "curl/curl.h"
+#include <stdlib.h>
+#include <string.h>
+
+int GetFtpFile(void)
+{
+  int retVal = 0;
+  CURL *curl;
+  CURLcode res;
+  curl = curl_easy_init();
+  if(curl) 
+    {
+    /* Get curl 7.9.2 from sunet.se's FTP site: */
+    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
+    curl_easy_setopt(curl, CURLOPT_HEADER, 1);
+    curl_easy_setopt(curl, CURLOPT_URL,
+                     "ftp://public.kitware.com/pub/cmake/cygwin/setup.hint");
+    res = curl_easy_perform(curl);
+    if ( res != 0 )
+      {
+      printf("Error fetching: ftp://public.kitware.com/pub/cmake/cygwin/setup.hint\n");
+      retVal = 1;
+      }
+
+    /* always cleanup */
+    curl_easy_cleanup(curl);
+    }
+  else
+    {
+    printf("Cannot create curl object\n");
+    retVal = 1;
+    }
+  return retVal;
+}
+
+int GetWebFile(void)
+{
+  int retVal = 0;
+  CURL *curl;
+  CURLcode res;
+
+  char proxy[1024];
+  int proxy_type = 0;
+
+  if ( getenv("HTTP_PROXY") )
+    {
+    proxy_type = 1;
+    if (getenv("HTTP_PROXY_PORT") )
+      {
+      sprintf(proxy, "%s:%s", getenv("HTTP_PROXY"), getenv("HTTP_PROXY_PORT"));
+      }
+    else
+      {
+      sprintf(proxy, "%s", getenv("HTTP_PROXY"));
+      }
+    if ( getenv("HTTP_PROXY_TYPE") )
+      {
+      /* HTTP/SOCKS4/SOCKS5 */
+      if ( strcmp(getenv("HTTP_PROXY_TYPE"), "HTTP") == 0 )
+        {
+        proxy_type = 1;
+        }
+      else if ( strcmp(getenv("HTTP_PROXY_TYPE"), "SOCKS4") == 0 )
+        {
+        proxy_type = 2;
+        }
+      else if ( strcmp(getenv("HTTP_PROXY_TYPE"), "SOCKS5") == 0 )
+        {
+        proxy_type = 3;
+        }
+      }
+    }
+
+  curl = curl_easy_init();
+  if(curl) 
+    {
+    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
+    curl_easy_setopt(curl, CURLOPT_HEADER, 1);
+
+    /* Using proxy */
+    if ( proxy_type > 0 )
+      {
+      curl_easy_setopt(curl, CURLOPT_PROXY, proxy); 
+      switch (proxy_type)
+        {
+        case 2:
+          curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
+          break;
+        case 3:
+          curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
+          break;
+        default:
+          curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);           
+        }
+      }
+
+    /* get the first document */
+    curl_easy_setopt(curl, CURLOPT_URL, "http://www.cmake.org/page1.html");
+    res = curl_easy_perform(curl);
+    if ( res != 0 )
+      {
+      printf("Error fetching: http://www.cmake.org/page1.html\n");
+      retVal = 1;
+      }
+
+    /* get another document from the same server using the same
+       connection */
+    /*
+      curl_easy_setopt(curl, CURLOPT_URL, "http://www.cmake.org/page2.html");
+      res = curl_easy_perform(curl);
+      if ( res != 0 )
+      {
+      printf("Error fetching: http://www.cmake.org/page2.html\n");
+      retVal = 1;
+      }
+    */
+
+    /* always cleanup */
+    curl_easy_cleanup(curl);
+    }
+  else
+    {
+    printf("Cannot create curl object\n");
+    retVal = 1;
+    }
+
+  return retVal;
+}
+
+int main(/*int argc, char **argv*/)
+{
+  int retVal = 0;
+  curl_global_init(CURL_GLOBAL_DEFAULT);
+  retVal += GetWebFile();
+
+  /* Do not check the output of FTP socks5 cannot handle FTP yet */
+  GetFtpFile();
+  curl_global_cleanup();
+  return retVal;
+}
diff --git a/Utilities/cmcurl/Testing/ftpget.c b/Utilities/cmcurl/Testing/ftpget.c
new file mode 100644
index 0000000..db3edfb
--- /dev/null
+++ b/Utilities/cmcurl/Testing/ftpget.c
@@ -0,0 +1,83 @@
+/*****************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * $Id$
+ */
+
+#include "curl/curl.h"
+#include "curl/types.h"
+#include "curl/easy.h"
+
+#include "testconfig.h"
+
+/*
+ * This is an example showing how to get a single file from an FTP server.
+ * It delays the actual destination file creation until the first write
+ * callback so that it won't create an empty file in case the remote file
+ * doesn't exist or something else fails.
+ */
+
+struct FtpFile {
+  char *filename;
+  FILE *stream;
+};
+
+int my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
+{
+  struct FtpFile *out=(struct FtpFile *)stream;
+  if(out && !out->stream) {
+    /* open file for writing */
+    out->stream=fopen(out->filename, "wb");
+    if(!out->stream)
+      return -1; /* failure, can't open file to write */
+  }
+  return fwrite(buffer, size, nmemb, out->stream);
+}
+
+
+int main(void)
+{
+  CURL *curl;
+  CURLcode res;
+  struct FtpFile ftpfile={
+    LIBCURL_BINARY_DIR "/Testing/ftpget-download.txt", /* name to store the file as if succesful */
+    NULL
+  };
+
+  curl_global_init(CURL_GLOBAL_DEFAULT);
+  
+  curl = curl_easy_init();
+  if(curl) {
+    /* Get curl 7.9.2 from sunet.se's FTP site: */
+    curl_easy_setopt(curl, CURLOPT_URL,
+                     "ftp://public.kitware.com/pub/cmake/cygwin/setup.hint");
+    /* Define our callback to get called when there's data to be written */
+    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
+    /* Set a pointer to our struct to pass to the callback */
+    curl_easy_setopt(curl, CURLOPT_FILE, &ftpfile);
+
+    /* Switch on full protocol/debug output */
+    curl_easy_setopt(curl, CURLOPT_VERBOSE, TRUE);
+
+    res = curl_easy_perform(curl);
+
+    /* always cleanup */
+    curl_easy_cleanup(curl);
+
+    if(CURLE_OK != res) {
+      /* we failed */
+      fprintf(stderr, "curl told us %d\n", res);
+    }
+  }
+
+  if(ftpfile.stream)
+    fclose(ftpfile.stream); /* close the local file */
+
+  curl_global_cleanup();
+
+  return 0;
+}
diff --git a/Utilities/cmcurl/Testing/ftpgetresp.c b/Utilities/cmcurl/Testing/ftpgetresp.c
new file mode 100644
index 0000000..d3f5d42
--- /dev/null
+++ b/Utilities/cmcurl/Testing/ftpgetresp.c
@@ -0,0 +1,63 @@
+/*****************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * $Id$
+ */
+
+#include "curl/curl.h"
+#include "curl/types.h"
+#include "curl/easy.h"
+
+#include "testconfig.h"
+
+/*
+ * Similar to ftpget.c but this also stores the received response-lines
+ * in a separate file using our own callback!
+ *
+ * This functionality was introduced in libcurl 7.9.3.
+ */
+
+size_t
+write_response(void *ptr, size_t size, size_t nmemb, void *data)
+{
+  FILE *writehere = (FILE *)data;
+  return fwrite(ptr, size, nmemb, writehere);
+}
+
+int main(int argc, char **argv)
+{
+  CURL *curl;
+  CURLcode res;
+  FILE *ftpfile;
+  FILE *respfile;
+  
+  /* local file name to store the file as */
+  ftpfile = fopen(LIBCURL_BINARY_DIR "/Testing/ftpgetresp-list.txt", "wb"); /* b is binary, needed on win32 */
+
+  /* local file name to store the FTP server's response lines in */
+  respfile = fopen(LIBCURL_BINARY_DIR "/Testing/ftpgetresp-responses.txt", "wb"); /* b is binary, needed on win32 */
+
+  curl_global_init(CURL_GLOBAL_DEFAULT);
+
+  curl = curl_easy_init();
+  if(curl) {
+    /* Get a file listing from sunet */
+    curl_easy_setopt(curl, CURLOPT_URL, "ftp://public.kitware.com/");
+    curl_easy_setopt(curl, CURLOPT_FILE, ftpfile);
+    curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, write_response);
+    curl_easy_setopt(curl, CURLOPT_WRITEHEADER, respfile);
+    res = curl_easy_perform(curl);
+
+    /* always cleanup */
+    curl_easy_cleanup(curl);
+  }
+
+  fclose(ftpfile); /* close the local file */
+  fclose(respfile); /* close the response file */
+
+  return 0;
+}
diff --git a/Utilities/cmcurl/Testing/ftpupload.c b/Utilities/cmcurl/Testing/ftpupload.c
new file mode 100644
index 0000000..bca0a56
--- /dev/null
+++ b/Utilities/cmcurl/Testing/ftpupload.c
@@ -0,0 +1,92 @@
+/*****************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * $Id$
+ */
+
+#include "curl/curl.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "testconfig.h"
+
+/*
+ * This example shows an FTP upload, with a rename of the file just after
+ * a successful upload.
+ *
+ * Example based on source code provided by Erick Nuwendam. Thanks!
+ */
+
+#define LOCAL_FILE      LIBCURL_SOURCE_DIR "/Testing/ftpupload.c"
+#define UPLOAD_FILE_AS  "while-uploading.txt"
+#define REMOTE_URL      "ftp://public.kitware.com/incoming/"  UPLOAD_FILE_AS
+#define RENAME_FILE_TO  "renamed-and-fine.txt"
+
+int main(int argc, char **argv)
+{
+  CURL *curl;
+  CURLcode res;
+  FILE *ftpfile;
+  FILE * hd_src ;
+  int hd ;
+  struct stat file_info;
+
+  struct curl_slist *headerlist=NULL;
+  char buf_1 [] = "RNFR " UPLOAD_FILE_AS;
+  char buf_2 [] = "RNTO " RENAME_FILE_TO;
+
+  /* get the file size of the local file */
+  hd = open(LOCAL_FILE, O_RDONLY) ;
+  fstat(hd, &file_info);
+  close(hd) ;
+
+  /* get a FILE * of the same file, could also be made with
+     fdopen() from the previous descriptor, but hey this is just 
+     an example! */
+  hd_src = fopen(LOCAL_FILE, "rb");
+
+  /* In windows, this will init the winsock stuff */
+  curl_global_init(CURL_GLOBAL_ALL);
+
+  /* get a curl handle */
+  curl = curl_easy_init();
+  if(curl) {
+    /* build a list of commands to pass to libcurl */
+    headerlist = curl_slist_append(headerlist, buf_1);
+    headerlist = curl_slist_append(headerlist, buf_2);
+
+    /* enable uploading */
+    curl_easy_setopt(curl, CURLOPT_UPLOAD, TRUE) ;
+
+    /* specify target */
+    curl_easy_setopt(curl,CURLOPT_URL, REMOTE_URL);
+
+    /* pass in that last of FTP commands to run after the transfer */
+    curl_easy_setopt(curl, CURLOPT_POSTQUOTE, headerlist);
+
+    /* now specify which file to upload */
+    curl_easy_setopt(curl, CURLOPT_INFILE, hd_src);
+
+    /* and give the size of the upload (optional) */
+    curl_easy_setopt(curl, CURLOPT_INFILESIZE, (long)file_info.st_size);
+
+    /* Now run off and do what you've been told! */
+    res = curl_easy_perform(curl);
+
+    /* clean up the FTP commands list */
+    curl_slist_free_all (headerlist);
+
+    /* always cleanup */
+    curl_easy_cleanup(curl);
+  }
+  fclose(hd_src); /* close the local file */
+
+  curl_global_cleanup();
+  return 0;
+}
diff --git a/Utilities/cmcurl/Testing/getinmemory.c b/Utilities/cmcurl/Testing/getinmemory.c
new file mode 100644
index 0000000..a8872da
--- /dev/null
+++ b/Utilities/cmcurl/Testing/getinmemory.c
@@ -0,0 +1,83 @@
+/*****************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * $Id$
+ *
+ * Example source code to show how the callback function can be used to
+ * download data into a chunk of memory instead of storing it in a file.
+ *
+ * This exact source code has not been verified to work.
+ */
+
+/* to make this work under windows, use the win32-functions from the
+   win32socket.c file as well */
+
+#include "curl/curl.h"
+#include "curl/types.h"
+#include "curl/easy.h"
+
+struct MemoryStruct {
+  char *memory;
+  size_t size;
+};
+
+size_t
+WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
+{
+  register int realsize = size * nmemb;
+  struct MemoryStruct *mem = (struct MemoryStruct *)data;
+  
+  mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1);
+  if (mem->memory) {
+    memcpy(&(mem->memory[mem->size]), ptr, realsize);
+    mem->size += realsize;
+    mem->memory[mem->size] = 0;
+  }
+  return realsize;
+}
+
+int main(int argc, char **argv)
+{
+  CURL *curl_handle;
+
+  struct MemoryStruct chunk;
+
+  chunk.memory=NULL; /* we expect realloc(NULL, size) to work */
+  chunk.size = 0;    /* no data at this point */
+
+  curl_global_init(CURL_GLOBAL_DEFAULT);
+
+  /* init the curl session */
+  curl_handle = curl_easy_init();
+
+  /* specify URL to get */
+  curl_easy_setopt(curl_handle, CURLOPT_URL, "http://www.cmake.org/HTML/Index.html");
+
+  /* send all data to this function  */
+  curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
+
+  /* we pass our 'chunk' struct to the callback function */
+  curl_easy_setopt(curl_handle, CURLOPT_FILE, (void *)&chunk);
+
+  /* get it! */
+  curl_easy_perform(curl_handle);
+
+  /* cleanup curl stuff */
+  curl_easy_cleanup(curl_handle);
+
+  /*
+   * Now, our chunk.memory points to a memory block that is chunk.size
+   * bytes big and contains the remote file.
+   *
+   * Do something nice with it!
+   */
+
+  /* For example display it... */
+  write(1, chunk.memory, chunk.size);
+
+  return 0;
+}
diff --git a/Utilities/cmcurl/Testing/http-post.c b/Utilities/cmcurl/Testing/http-post.c
new file mode 100644
index 0000000..1b4154f
--- /dev/null
+++ b/Utilities/cmcurl/Testing/http-post.c
@@ -0,0 +1,35 @@
+/*****************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <curl/curl.h>
+
+int main(void)
+{
+  CURL *curl;
+  CURLcode res;
+
+  curl = curl_easy_init();
+  if(curl) {
+    /* First set the URL that is about to receive our POST. This URL can
+       just as well be a https:// URL if that is what should receive the
+       data. */
+    curl_easy_setopt(curl, CURLOPT_URL, "http://postit.example.com/moo.cgi");
+    /* Now specify the POST data */
+    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "name=daniel&project=curl");
+
+    /* Perform the request, res will get the return code */
+    res = curl_easy_perform(curl);
+
+    /* always cleanup */
+    curl_easy_cleanup(curl);
+  }
+  return 0;
+}
diff --git a/Utilities/cmcurl/Testing/httpput.c b/Utilities/cmcurl/Testing/httpput.c
new file mode 100644
index 0000000..78275c4
--- /dev/null
+++ b/Utilities/cmcurl/Testing/httpput.c
@@ -0,0 +1,100 @@
+/*****************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <curl/curl.h>
+
+/*
+ * This example shows a HTTP PUT operation. PUTs a file given as a command
+ * line argument to the URL also given on the command line.
+ *
+ * This example also uses its own read callback.
+ */
+
+size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+  size_t retcode;
+
+  /* in real-world cases, this would probably get this data differently
+     as this fread() stuff is exactly what the library already would do
+     by default internally */
+  retcode = fread(ptr, size, nmemb, stream);
+
+  fprintf(stderr, "*** We read %d bytes from file\n", retcode);
+
+  return retcode;
+}
+
+int main(int argc, char **argv)
+{
+  CURL *curl;
+  CURLcode res;
+  FILE *ftpfile;
+  FILE * hd_src ;
+  int hd ;
+  struct stat file_info;
+
+  char *file;
+  char *url;
+
+  if(argc < 3)
+    return 1;
+ 
+  file= argv[1];
+  url = argv[2];
+  
+  /* get the file size of the local file */
+  hd = open(file, O_RDONLY) ;
+  fstat(hd, &file_info);
+  close(hd) ;
+
+  /* get a FILE * of the same file, could also be made with
+     fdopen() from the previous descriptor, but hey this is just 
+     an example! */
+  hd_src = fopen(file, "rb");
+
+  /* In windows, this will init the winsock stuff */
+  curl_global_init(CURL_GLOBAL_ALL);
+
+  /* get a curl handle */
+  curl = curl_easy_init();
+  if(curl) {
+    /* we want to use our own read function */
+    curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
+
+    /* enable uploading */
+    curl_easy_setopt(curl, CURLOPT_UPLOAD, TRUE) ;
+
+    /* HTTP PUT please */
+    curl_easy_setopt(curl, CURLOPT_PUT, TRUE);
+
+    /* specify target */
+    curl_easy_setopt(curl,CURLOPT_URL, url);
+
+    /* now specify which file to upload */
+    curl_easy_setopt(curl, CURLOPT_INFILE, hd_src);
+
+    /* and give the size of the upload (optional) */
+    curl_easy_setopt(curl, CURLOPT_INFILESIZE, file_info.st_size);
+
+    /* Now run off and do what you've been told! */
+    res = curl_easy_perform(curl);
+
+    /* always cleanup */
+    curl_easy_cleanup(curl);
+  }
+  fclose(hd_src); /* close the local file */
+
+  curl_global_cleanup();
+  return 0;
+}
diff --git a/Utilities/cmcurl/Testing/multithread.c b/Utilities/cmcurl/Testing/multithread.c
new file mode 100644
index 0000000..c3936ef
--- /dev/null
+++ b/Utilities/cmcurl/Testing/multithread.c
@@ -0,0 +1,70 @@
+/*****************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * $Id$
+ */
+
+/* A multi-threaded example that uses pthreads extensively to fetch
+ * X remote files at once */
+
+#include <stdio.h>
+#include <pthread.h>
+#include <curl/curl.h>
+
+/* silly list of test-URLs */
+char *urls[]= {
+  "http://curl.haxx.se/",
+  "ftp://cool.haxx.se/",
+  "http://www.contactor.se/",
+  "www.haxx.se"
+};
+
+void *pull_one_url(void *url)
+{
+  CURL *curl;
+
+  curl = curl_easy_init();
+
+  curl_easy_setopt(curl, CURLOPT_URL, url);
+  curl_easy_perform(curl);
+
+  curl_easy_cleanup(curl);
+
+  return NULL;
+}
+
+
+/* 
+   int pthread_create(pthread_t *new_thread_ID,
+   const pthread_attr_t *attr,
+   void * (*start_func)(void *), void *arg);
+*/
+
+int main(int argc, char **argv)
+{
+  pthread_t tid[4];
+  int i;
+  int error;
+  for(i=0; i< 4; i++) {
+    error = pthread_create(&tid[i],
+                           NULL, /* default attributes please */
+                           pull_one_url,
+                           urls[i]);
+    if(0 != error)
+      fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error);
+    else 
+      fprintf(stderr, "Thread %d, gets %s\n", i, urls[i]);
+  }
+
+  /* now wait for all threads to terminate */
+  for(i=0; i< 4; i++) {
+    error = pthread_join(tid[i], NULL);
+    fprintf(stderr, "Thread %d terminated\n", i);
+  }
+
+  return 0;
+}
diff --git a/Utilities/cmcurl/Testing/persistant.c b/Utilities/cmcurl/Testing/persistant.c
new file mode 100644
index 0000000..8534703
--- /dev/null
+++ b/Utilities/cmcurl/Testing/persistant.c
@@ -0,0 +1,53 @@
+/*****************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+
+#include "curl/curl.h"
+
+/* to make this work under windows, use the win32-functions from the
+   docs/examples/win32socket.c file as well */
+
+/* This example REQUIRES libcurl 7.7 or later */
+#if (LIBCURL_VERSION_NUM < 0x070700)
+#error Too old libcurl version, upgrade or stay away.
+#endif
+
+int main(int argc, char **argv)
+{
+  CURL *curl;
+  CURLcode res;
+
+#ifdef MALLOCDEBUG
+  /* this sends all memory debug messages to a specified logfile */
+  curl_memdebug("memdump");
+#endif
+
+  curl_global_init(CURL_GLOBAL_DEFAULT);
+  curl = curl_easy_init();
+  if(curl) {
+    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
+    curl_easy_setopt(curl, CURLOPT_HEADER, 1);
+
+    /* get the first document */
+    curl_easy_setopt(curl, CURLOPT_URL, "http://www.cmake.org/");
+    res = curl_easy_perform(curl);
+
+    /* get another document from the same server using the same
+       connection */
+    curl_easy_setopt(curl, CURLOPT_URL, "http://www.cmake.org/HTML/Index.html");
+    res = curl_easy_perform(curl);
+
+    /* always cleanup */
+    curl_easy_cleanup(curl);
+  }
+
+  return 0;
+}
diff --git a/Utilities/cmcurl/Testing/postit2.c b/Utilities/cmcurl/Testing/postit2.c
new file mode 100644
index 0000000..9b7cda0
--- /dev/null
+++ b/Utilities/cmcurl/Testing/postit2.c
@@ -0,0 +1,92 @@
+/*****************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * $Id$
+ *
+ * Example code that uploads a file name 'foo' to a remote script that accepts
+ * "HTML form based" (as described in RFC1738) uploads using HTTP POST.
+ *
+ * The imaginary form we'll fill in looks like:
+ *
+ * <form method="post" enctype="multipart/form-data" action="examplepost.cgi">
+ * Enter file: <input type="file" name="sendfile" size="40">
+ * Enter file name: <input type="text" name="filename" size="30">
+ * <input type="submit" value="send" name="submit">
+ * </form>
+ *
+ * This exact source code has not been verified to work.
+ */
+
+/* to make this work under windows, use the win32-functions from the
+   win32socket.c file as well */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <curl/curl.h>
+#include <curl/types.h>
+#include <curl/easy.h>
+
+#if LIBCURL_VERSION_NUM < 0x070900
+#error "curl_formadd() is not introduced until libcurl 7.9 and later"
+#endif
+
+int main(int argc, char *argv[])
+{
+  CURL *curl;
+  CURLcode res;
+
+  struct HttpPost *formpost=NULL;
+  struct HttpPost *lastptr=NULL;
+  struct curl_slist *headerlist=NULL;
+  char buf[] = "Expect:";
+
+  /* Fill in the file upload field */
+  curl_formadd(&formpost,
+               &lastptr,
+               CURLFORM_COPYNAME, "sendfile",
+               CURLFORM_FILE, "postit2.c",
+               CURLFORM_END);
+
+  /* Fill in the filename field */
+  curl_formadd(&formpost,
+               &lastptr,
+               CURLFORM_COPYNAME, "filename",
+               CURLFORM_COPYCONTENTS, "postit2.c",
+               CURLFORM_END);
+  
+
+  /* Fill in the submit field too, even if this is rarely needed */
+  curl_formadd(&formpost,
+               &lastptr,
+               CURLFORM_COPYNAME, "submit",
+               CURLFORM_COPYCONTENTS, "send",
+               CURLFORM_END);
+
+  curl = curl_easy_init();
+  /* initalize custom header list (stating that Expect: 100-continue is not
+     wanted */
+  headerlist = curl_slist_append(headerlist, buf);
+  if(curl) {
+    /* what URL that receives this POST */
+    curl_easy_setopt(curl, CURLOPT_URL, "http://curl.haxx.se/examplepost.cgi");
+    if ( (argc == 2) && (!strcmp(argv[1], "noexpectheader")) )
+      /* only disable 100-continue header if explicitly requested */
+      curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
+    curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
+    res = curl_easy_perform(curl);
+
+    /* always cleanup */
+    curl_easy_cleanup(curl);
+
+    /* then cleanup the formpost chain */
+    curl_formfree(formpost);
+    /* free slist */
+    curl_slist_free_all (headerlist);
+  }
+  return 0;
+}
diff --git a/Utilities/cmcurl/Testing/sepheaders.c b/Utilities/cmcurl/Testing/sepheaders.c
new file mode 100644
index 0000000..e3ea7be
--- /dev/null
+++ b/Utilities/cmcurl/Testing/sepheaders.c
@@ -0,0 +1,78 @@
+/*****************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * $Id$
+ */
+
+/* to make this work under windows, use the win32-functions from the
+   win32socket.c file as well */
+
+#include "curl/curl.h"
+#include "curl/types.h"
+#include "curl/easy.h"
+
+#include "testconfig.h"
+
+size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+  int written = fwrite(ptr, size, nmemb, (FILE *)stream);
+  return written;
+}
+
+int main(int argc, char **argv)
+{
+  CURL *curl_handle;
+  char *headerfilename = LIBCURL_BINARY_DIR "/Testing/sepheaders-head.out";
+  FILE *headerfile;
+  char *bodyfilename = LIBCURL_BINARY_DIR "/Testing/sepheaders-body.out";
+  FILE *bodyfile;
+
+  curl_global_init(CURL_GLOBAL_DEFAULT);
+  /* init the curl session */
+  curl_handle = curl_easy_init();
+
+  /* set URL to get */
+  curl_easy_setopt(curl_handle, CURLOPT_URL, "http://www.cmake.org/HTML/Index.html");
+
+  /* no progress meter please */
+  curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1);
+
+  /* shut up completely */
+  curl_easy_setopt(curl_handle, CURLOPT_MUTE, 1);
+
+  /* send all data to this function  */
+  curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data);
+
+  /* open the files */
+  headerfile = fopen(headerfilename,"w");
+  if (headerfile == NULL) {
+    curl_easy_cleanup(curl_handle);
+    return -1;
+  }
+  bodyfile = fopen(bodyfilename,"w");
+  if (bodyfile == NULL) {
+    curl_easy_cleanup(curl_handle);
+    return -1;
+  }
+
+  /* we want the headers to this file handle */
+  curl_easy_setopt(curl_handle,   CURLOPT_WRITEHEADER ,headerfile);
+
+  /* we want the body to this file handle */
+  curl_easy_setopt(curl_handle,   CURLOPT_FILE ,bodyfile);
+
+  /* get it! */
+  curl_easy_perform(curl_handle);
+
+  /* close the header file */
+  fclose(headerfile);
+
+  /* cleanup curl stuff */
+  curl_easy_cleanup(curl_handle);
+
+  return 0;
+}
diff --git a/Utilities/cmcurl/Testing/simple.c b/Utilities/cmcurl/Testing/simple.c
new file mode 100644
index 0000000..6dd6050
--- /dev/null
+++ b/Utilities/cmcurl/Testing/simple.c
@@ -0,0 +1,28 @@
+/*****************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * $Id$
+ */
+
+#include "curl/curl.h"
+
+int main(void)
+{
+  CURL *curl;
+  CURLcode res;
+
+  curl_global_init(CURL_GLOBAL_DEFAULT);
+  curl = curl_easy_init();
+  if(curl) {
+    curl_easy_setopt(curl, CURLOPT_URL, "http://www.cmake.org/HTML/Index.html");
+    res = curl_easy_perform(curl);
+
+    /* always cleanup */
+    curl_easy_cleanup(curl);
+  }
+  return 0;
+}
diff --git a/Utilities/cmcurl/Testing/simplessl.c b/Utilities/cmcurl/Testing/simplessl.c
new file mode 100644
index 0000000..9a53603
--- /dev/null
+++ b/Utilities/cmcurl/Testing/simplessl.c
@@ -0,0 +1,118 @@
+/*****************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+
+#include <curl/curl.h>
+#include <curl/types.h>
+#include <curl/easy.h>
+
+
+/* some requirements for this to work:
+   1.   set pCertFile to the file with the client certificate
+   2.   if the key is passphrase protected, set pPassphrase to the
+        passphrase you use
+   3.   if you are using a crypto engine:
+   3.1. set a #define USE_ENGINE
+   3.2. set pEngine to the name of the crypto engine you use
+   3.3. set pKeyName to the key identifier you want to use
+   4.   if you don't use a crypto engine:
+   4.1. set pKeyName to the file name of your client key
+   4.2. if the format of the key file is DER, set pKeyType to "DER"
+
+   !! verify of the server certificate is not implemented here !!
+
+   **** This example only works with libcurl 7.9.3 and later! ****
+
+*/
+
+int main(int argc, char **argv)
+{
+  CURL *curl;
+  CURLcode res;
+  FILE *headerfile;
+
+  const char *pCertFile = "testcert.pem";
+  const char *pCACertFile="cacert.pem"
+
+  const char *pKeyName;
+  const char *pKeyType;
+
+  const char *pEngine;
+
+#if USE_ENGINE
+  pKeyName  = "rsa_test";
+  pKeyType  = "ENG";
+  pEngine   = "chil";            /* for nChiper HSM... */
+#else
+  pKeyName  = "testkey.pem";
+  pKeyType  = "PEM";
+  pEngine   = NULL;
+#endif
+
+  const char *pPassphrase = NULL;
+
+  headerfile = fopen("dumpit", "w");
+
+  curl_global_init(CURL_GLOBAL_DEFAULT);
+
+  curl = curl_easy_init();
+  if(curl) {
+    /* what call to write: */
+    curl_easy_setopt(curl, CURLOPT_URL, "HTTPS://curl.haxx.se");
+    curl_easy_setopt(curl, CURLOPT_WRITEHEADER, headerfile);
+
+    while(1)                    /* do some ugly short cut... */
+    {
+       if (pEngine)             /* use crypto engine */
+       {
+          if (curl_easy_setopt(curl, CURLOPT_SSLENGINE,pEngine) != CURLE_OK)
+          {                     /* load the crypto engine */
+             fprintf(stderr,"can't set crypto engine\n");
+             break;
+          }
+          if (curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT,1) != CURLE_OK)
+          {                     /* set the crypto engine as default */
+                                /* only needed for the first time you load
+                                   a engine in a curl object... */
+             fprintf(stderr,"can't set crypto engine as default\n");
+             break;
+          }
+       }
+                                /* cert is stored PEM coded in file... */
+                                /* since PEM is default, we needn't set it for PEM */
+       curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE,"PEM");
+                                /* set the cert for client authentication */
+       curl_easy_setopt(curl,CURLOPT_SSLCERT,pCertFile);
+                                /* sorry, for engine we must set the passphrase
+                                   (if the key has one...) */
+       if (pPassphrase)
+          curl_easy_setopt(curl,CURLOPT_SSLKEYPASSWD,pPassphrase);
+                                /* if we use a key stored in a crypto engine,
+                                   we must set the key type to "ENG" */
+       curl_easy_setopt(curl,CURLOPT_SSLKEYTYPE,pKeyType);
+                                /* set the private key (file or ID in engine) */
+       curl_easy_setopt(curl,CURLOPT_SSLKEY,pKeyName);
+                                /* set the file with the certs vaildating the server */
+       curl_easy_setopt(curl,CURLOPT_CAINFO,pCACertFile);
+                                /* disconnect if we can't validate server's cert */
+       curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,1);
+       
+       res = curl_easy_perform(curl);
+       break;                   /* we are done... */
+    }
+    /* always cleanup */
+    curl_easy_cleanup(curl);
+  }
+
+  curl_global_cleanup();
+
+  return 0;
+}
diff --git a/Utilities/cmcurl/Testing/testconfig.h.in b/Utilities/cmcurl/Testing/testconfig.h.in
new file mode 100644
index 0000000..faab462
--- /dev/null
+++ b/Utilities/cmcurl/Testing/testconfig.h.in
@@ -0,0 +1,7 @@
+#ifndef __testconfig_h__
+#define __testconfig_h__
+
+#define LIBCURL_SOURCE_DIR "${LIBCURL_SOURCE_DIR}"
+#define LIBCURL_BINARY_DIR "${LIBCURL_BINARY_DIR}"
+
+#endif /* __testconfig_h__ */
diff --git a/Utilities/cmcurl/Testing/win32sockets.c b/Utilities/cmcurl/Testing/win32sockets.c
new file mode 100644
index 0000000..5f791c8
--- /dev/null
+++ b/Utilities/cmcurl/Testing/win32sockets.c
@@ -0,0 +1,49 @@
+
+/*
+ * Note: This is only required if you use curl 7.8 or lower, later 
+ * versions provide an option to curl_global_init() that does the
+ * win32 initialization for you.
+ */
+
+/*
+ * These are example functions doing socket init that Windows
+ * require. If you don't use windows, you can safely ignore this crap.
+ */
+
+#include <windows.h>
+
+void win32_cleanup(void)
+{
+  WSACleanup();
+}
+
+int win32_init(void)
+{
+  WORD wVersionRequested;  
+  WSADATA wsaData; 
+  int err; 
+  wVersionRequested = MAKEWORD(1, 1); 
+    
+  err = WSAStartup(wVersionRequested, &wsaData); 
+    
+  if (err != 0) 
+    /* Tell the user that we couldn't find a useable */ 
+    /* winsock.dll.     */ 
+    return 1;
+    
+  /* Confirm that the Windows Sockets DLL supports 1.1.*/ 
+  /* Note that if the DLL supports versions greater */ 
+  /* than 1.1 in addition to 1.1, it will still return */ 
+  /* 1.1 in wVersion since that is the version we */ 
+  /* requested. */ 
+    
+  if ( LOBYTE( wsaData.wVersion ) != 1 || 
+       HIBYTE( wsaData.wVersion ) != 1 ) { 
+    /* Tell the user that we couldn't find a useable */ 
+
+    /* winsock.dll. */ 
+    WSACleanup(); 
+    return 1; 
+  }
+  return 0; /* 0 is ok */
+}
diff --git a/Utilities/cmcurl/amigaos.c b/Utilities/cmcurl/amigaos.c
new file mode 100644
index 0000000..16a7d5e
--- /dev/null
+++ b/Utilities/cmcurl/amigaos.c
@@ -0,0 +1,49 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "amigaos.h"
+#include <stdio.h> /* for stderr */
+
+struct Library *SocketBase = NULL;
+
+void amiga_cleanup()
+{
+  if(SocketBase)
+    CloseLibrary(SocketBase);
+        
+  SocketBase = NULL;
+}
+
+BOOL amiga_init()
+{
+  if(!SocketBase)
+    SocketBase = OpenLibrary("bsdsocket.library", 4);
+        
+  if(!SocketBase) {
+    fprintf(stderr, "No TCP/IP Stack running!\n\a");
+    return FALSE;
+  }
+        
+  atexit(amiga_cleanup);
+  return TRUE;
+}
diff --git a/Utilities/cmcurl/amigaos.h b/Utilities/cmcurl/amigaos.h
new file mode 100644
index 0000000..0196eec
--- /dev/null
+++ b/Utilities/cmcurl/amigaos.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#ifndef LIBCURL_AMIGAOS_H
+#define LIBCURL_AMIGAOS_H
+
+#ifndef __ixemul__
+
+#include <exec/types.h>
+#include <exec/execbase.h>
+
+#include <proto/exec.h>
+#include <proto/dos.h>
+
+#include <bsdsocket.h>
+
+#include "config-amigaos.h"
+
+#define select(args...) WaitSelect( args, NULL)
+#define inet_ntoa(x)    Inet_NtoA( x ## .s_addr)
+#define ioctl(a,b,c,d)  IoctlSocket( (LONG)a, (ULONG)b, (char*)c)
+#define _AMIGASF        1
+
+extern void amiga_cleanup();
+extern BOOL amiga_init();
+
+#else /* __ixemul__ */
+
+#warning compiling with ixemul...
+
+#endif /* __ixemul__ */
+#endif /* LIBCURL_AMIGAOS_H */
diff --git a/Utilities/cmcurl/arpa_telnet.h b/Utilities/cmcurl/arpa_telnet.h
new file mode 100644
index 0000000..5359ff1
--- /dev/null
+++ b/Utilities/cmcurl/arpa_telnet.h
@@ -0,0 +1,101 @@
+#ifndef __ARPA_TELNET_H
+#define __ARPA_TELNET_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+#ifndef CURL_DISABLE_TELNET
+/*
+ * Telnet option defines. Add more here if in need.
+ */
+#define CURL_TELOPT_BINARY   0  /* binary 8bit data */
+#define CURL_TELOPT_SGA      3  /* Supress Go Ahead */
+#define CURL_TELOPT_EXOPL  255  /* EXtended OPtions List */
+#define CURL_TELOPT_TTYPE   24  /* Terminal TYPE */
+#define CURL_TELOPT_XDISPLOC 35 /* X DISPlay LOCation */
+
+#define CURL_TELOPT_NEW_ENVIRON 39  /* NEW ENVIRONment variables */
+#define CURL_NEW_ENV_VAR   0
+#define CURL_NEW_ENV_VALUE 1
+
+/*
+ * The telnet options represented as strings
+ */
+static const char *telnetoptions[]=
+{
+  "BINARY",      "ECHO",           "RCP",           "SUPPRESS GO AHEAD",
+  "NAME",        "STATUS",         "TIMING MARK",   "RCTE",
+  "NAOL",        "NAOP",           "NAOCRD",        "NAOHTS",
+  "NAOHTD",      "NAOFFD",         "NAOVTS",        "NAOVTD",
+  "NAOLFD",      "EXTEND ASCII",   "LOGOUT",        "BYTE MACRO",
+  "DE TERMINAL", "SUPDUP",         "SUPDUP OUTPUT", "SEND LOCATION",
+  "TERM TYPE",   "END OF RECORD",  "TACACS UID",    "OUTPUT MARKING",
+  "TTYLOC",      "3270 REGIME",    "X3 PAD",        "NAWS",
+  "TERM SPEED",  "LFLOW",          "LINEMODE",      "XDISPLOC",
+  "OLD-ENVIRON", "AUTHENTICATION", "ENCRYPT",       "NEW-ENVIRON"
+};
+
+#define CURL_TELOPT_MAXIMUM CURL_TELOPT_NEW_ENVIRON
+
+#define CURL_TELOPT_OK(x) ((x) <= CURL_TELOPT_MAXIMUM)
+#define CURL_TELOPT(x)    telnetoptions[x]
+
+#define CURL_NTELOPTS 40 
+
+/*
+ * First some defines
+ */
+#define CURL_xEOF 236 /* End Of File */ 
+#define CURL_SE   240 /* Sub negotiation End */
+#define CURL_NOP  241 /* No OPeration */
+#define CURL_DM   242 /* Data Mark */
+#define CURL_GA   249 /* Go Ahead, reverse the line */
+#define CURL_SB   250 /* SuBnegotiation */
+#define CURL_WILL 251 /* Our side WILL use this option */
+#define CURL_WONT 252 /* Our side WON'T use this option */
+#define CURL_DO   253 /* DO use this option! */
+#define CURL_DONT 254 /* DON'T use this option! */
+#define CURL_IAC  255 /* Interpret As Command */
+
+/*
+ * Then those numbers represented as strings:
+ */
+static const char *telnetcmds[]=
+{
+  "EOF",  "SUSP",  "ABORT", "EOR",  "SE",
+  "NOP",  "DMARK", "BRK",   "IP",   "AO",
+  "AYT",  "EC",    "EL",    "GA",   "SB",
+  "WILL", "WONT",  "DO",    "DONT", "IAC"
+};
+
+#define CURL_TELCMD_MINIMUM CURL_xEOF /* the first one */
+#define CURL_TELCMD_MAXIMUM CURL_IAC  /* surprise, 255 is the last one! ;-) */
+
+#define CURL_TELQUAL_IS   0
+#define CURL_TELQUAL_SEND 1
+#define CURL_TELQUAL_INFO 2
+#define CURL_TELQUAL_NAME 3
+
+#define CURL_TELCMD_OK(x) ( ((unsigned int)(x) >= CURL_TELCMD_MINIMUM) && \
+                       ((unsigned int)(x) <= CURL_TELCMD_MAXIMUM) )
+#define CURL_TELCMD(x)    telnetcmds[(x)-CURL_TELCMD_MINIMUM]
+#endif
+#endif
diff --git a/Utilities/cmcurl/base64.c b/Utilities/cmcurl/base64.c
new file mode 100644
index 0000000..7f8ae86
--- /dev/null
+++ b/Utilities/cmcurl/base64.c
@@ -0,0 +1,288 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/* Base64 encoding/decoding
+ *
+ * Test harnesses down the bottom - compile with -DTEST_ENCODE for
+ * a program that will read in raw data from stdin and write out
+ * a base64-encoded version to stdout, and the length returned by the
+ * encoding function to stderr. Compile with -DTEST_DECODE for a program that
+ * will go the other way.
+ *
+ * This code will break if int is smaller than 32 bits
+ */
+
+#include "setup.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "base64.h"
+#include "curl_memory.h"
+
+/* include memdebug.h last */
+#include "memdebug.h"
+
+
+static void decodeQuantum(unsigned char *dest, const char *src)
+{
+  unsigned int x = 0;
+  int i;
+  for(i = 0; i < 4; i++) {
+    if(src[i] >= 'A' && src[i] <= 'Z')
+      x = (x << 6) + (unsigned int)(src[i] - 'A' + 0);
+    else if(src[i] >= 'a' && src[i] <= 'z')
+      x = (x << 6) + (unsigned int)(src[i] - 'a' + 26);
+    else if(src[i] >= '0' && src[i] <= '9')
+      x = (x << 6) + (unsigned int)(src[i] - '0' + 52);
+    else if(src[i] == '+')
+      x = (x << 6) + 62;
+    else if(src[i] == '/')
+      x = (x << 6) + 63;
+    else if(src[i] == '=')
+      x = (x << 6);
+  }
+
+  dest[2] = (unsigned char)(x & 255);
+  x >>= 8;
+  dest[1] = (unsigned char)(x & 255);
+  x >>= 8;
+  dest[0] = (unsigned char)(x & 255);
+}
+
+/*
+ * Curl_base64_decode()
+ *
+ * Given a base64 string at src, decode it into the memory pointed to by
+ * dest. Returns the length of the decoded data.
+ */
+size_t Curl_base64_decode(const char *src, char *dest)
+{
+  int length = 0;
+  int equalsTerm = 0;
+  int i;
+  int numQuantums;
+  unsigned char lastQuantum[3];
+  size_t rawlen;
+
+  while((src[length] != '=') && src[length])
+    length++;
+  while(src[length+equalsTerm] == '=')
+    equalsTerm++;
+
+  numQuantums = (length + equalsTerm) / 4;
+
+  rawlen = (numQuantums * 3) - equalsTerm;
+
+  for(i = 0; i < numQuantums - 1; i++) {
+    decodeQuantum((unsigned char *)dest, src);
+    dest += 3; src += 4;
+  }
+
+  decodeQuantum(lastQuantum, src);
+  for(i = 0; i < 3 - equalsTerm; i++)
+    dest[i] = lastQuantum[i];
+
+  return rawlen;
+}
+
+/* ---- Base64 Encoding --- */
+static char table64[]=
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/*
+ * Curl_base64_encode()
+ *
+ * Returns the length of the newly created base64 string. The third argument
+ * is a pointer to an allocated area holding the base64 data. If something
+ * went wrong, -1 is returned.
+ *
+ */
+size_t Curl_base64_encode(const char *inp, size_t insize, char **outptr)
+{
+  unsigned char ibuf[3];
+  unsigned char obuf[4];
+  int i;
+  int inputparts;
+  char *output;
+  char *base64data;
+
+  char *indata = (char *)inp;
+
+  *outptr = NULL; /* set to NULL in case of failure before we reach the end */
+
+  if(0 == insize)
+    insize = strlen(indata);
+
+  base64data = output = (char*)malloc(insize*4/3+4);
+  if(NULL == output)
+    return 0;
+
+  while(insize > 0) {
+    for (i = inputparts = 0; i < 3; i++) {
+      if(insize > 0) {
+        inputparts++;
+        ibuf[i] = *indata;
+        indata++;
+        insize--;
+      }
+      else
+        ibuf[i] = 0;
+    }
+
+    obuf [0] = (ibuf [0] & 0xFC) >> 2;
+    obuf [1] = ((ibuf [0] & 0x03) << 4) | ((ibuf [1] & 0xF0) >> 4);
+    obuf [2] = ((ibuf [1] & 0x0F) << 2) | ((ibuf [2] & 0xC0) >> 6);
+    obuf [3] = ibuf [2] & 0x3F;
+
+    switch(inputparts) {
+    case 1: /* only one byte read */
+      snprintf(output, 5, "%c%c==",
+               table64[obuf[0]],
+               table64[obuf[1]]);
+      break;
+    case 2: /* two bytes read */
+      snprintf(output, 5, "%c%c%c=",
+               table64[obuf[0]],
+               table64[obuf[1]],
+               table64[obuf[2]]);
+      break;
+    default:
+      snprintf(output, 5, "%c%c%c%c",
+               table64[obuf[0]],
+               table64[obuf[1]],
+               table64[obuf[2]],
+               table64[obuf[3]] );
+      break;
+    }
+    output += 4;
+  }
+  *output=0;
+  *outptr = base64data; /* make it return the actual data memory */
+
+  return strlen(base64data); /* return the length of the new data */
+}
+/* ---- End of Base64 Encoding ---- */
+
+/************* TEST HARNESS STUFF ****************/
+
+
+#ifdef TEST_ENCODE
+/* encoding test harness. Read in standard input and write out the length
+ * returned by Curl_base64_encode, followed by the base64'd data itself
+ */
+#include <stdio.h>
+
+#define TEST_NEED_SUCK
+void *suck(int *);
+
+int main(int argc, char **argv, char **envp)
+{
+  char *base64;
+  size_t base64Len;
+  unsigned char *data;
+  int dataLen;
+
+  data = (unsigned char *)suck(&dataLen);
+  base64Len = Curl_base64_encode(data, dataLen, &base64);
+
+  fprintf(stderr, "%d\n", base64Len);
+  fprintf(stdout, "%s",   base64);
+
+  free(base64); free(data);
+  return 0;
+}
+#endif
+
+#ifdef TEST_DECODE
+/* decoding test harness. Read in a base64 string from stdin and write out the
+ * length returned by Curl_base64_decode, followed by the decoded data itself
+ *
+ * gcc -DTEST_DECODE base64.c -o base64 mprintf.o memdebug.o
+ */
+#include <stdio.h>
+
+#define TEST_NEED_SUCK
+void *suck(int *);
+
+int main(int argc, char **argv, char **envp)
+{
+  char *base64;
+  int base64Len;
+  unsigned char *data;
+  int dataLen;
+  int i, j;
+
+  base64 = (char *)suck(&base64Len);
+  data = (unsigned char *)malloc(base64Len * 3/4 + 8);
+  dataLen = Curl_base64_decode(base64, data);
+
+  fprintf(stderr, "%d\n", dataLen);
+
+  for(i=0; i < dataLen; i+=0x10) {
+    printf("0x%02x: ", i);
+    for(j=0; j < 0x10; j++)
+      if((j+i) < dataLen)
+        printf("%02x ", data[i+j]);
+      else
+        printf("   ");
+
+    printf(" | ");
+
+    for(j=0; j < 0x10; j++)
+      if((j+i) < dataLen)
+        printf("%c", isgraph(data[i+j])?data[i+j]:'.');
+      else
+        break;
+    puts("");
+  }
+
+  free(base64); free(data);
+  return 0;
+}
+#endif
+
+#ifdef TEST_NEED_SUCK
+/* this function 'sucks' in as much as possible from stdin */
+void *suck(int *lenptr)
+{
+  int cursize = 8192;
+  unsigned char *buf = NULL;
+  int lastread;
+  int len = 0;
+
+  do {
+    cursize *= 2;
+    buf = (unsigned char *)realloc(buf, cursize);
+    memset(buf + len, 0, cursize - len);
+    lastread = fread(buf + len, 1, cursize - len, stdin);
+    len += lastread;
+  } while(!feof(stdin));
+
+  lenptr[0] = len;
+  return (void *)buf;
+}
+#endif
diff --git a/Utilities/cmcurl/base64.h b/Utilities/cmcurl/base64.h
new file mode 100644
index 0000000..307148e
--- /dev/null
+++ b/Utilities/cmcurl/base64.h
@@ -0,0 +1,27 @@
+#ifndef __BASE64_H
+#define __BASE64_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+size_t Curl_base64_encode(const char *input, size_t size, char **str);
+size_t Curl_base64_decode(const char *source, char *dest);
+#endif
diff --git a/Utilities/cmcurl/ca-bundle.h b/Utilities/cmcurl/ca-bundle.h
new file mode 100644
index 0000000..12390bc
--- /dev/null
+++ b/Utilities/cmcurl/ca-bundle.h
@@ -0,0 +1 @@
+/* ca bundle path set in here*/
diff --git a/Utilities/cmcurl/config.h.in b/Utilities/cmcurl/config.h.in
new file mode 100644
index 0000000..1086027
--- /dev/null
+++ b/Utilities/cmcurl/config.h.in
@@ -0,0 +1,512 @@
+/* lib/config.h.in.  Generated from configure.in by autoheader.  */
+
+/* to disable DICT */
+#cmakedefine CURL_DISABLE_DICT ${CURL_DISABLE_DICT}
+
+/* to disable FILE */
+#cmakedefine CURL_DISABLE_FILE ${CURL_DISABLE_FILE}
+
+/* to disable FTP */
+#cmakedefine CURL_DISABLE_FTP ${CURL_DISABLE_FTP}
+
+/* to disable GOPHER */
+#cmakedefine CURL_DISABLE_GOPHER ${CURL_DISABLE_GOPHER}
+
+/* to disable HTTP */
+#cmakedefine CURL_DISABLE_HTTP ${CURL_DISABLE_HTTP}
+
+/* to disable LDAP */
+#cmakedefine CURL_DISABLE_LDAP ${CURL_DISABLE_LDAP}
+
+/* to disable TELNET */
+#cmakedefine CURL_DISABLE_TELNET ${CURL_DISABLE_TELNET}
+
+/* Set to explicitly specify we don't want to use thread-safe functions */
+#cmakedefine DISABLED_THREADSAFE ${DISABLED_THREADSAFE}
+
+/* your Entropy Gathering Daemon socket pathname */
+#cmakedefine EGD_SOCKET ${EGD_SOCKET}
+
+/* Define if you want to enable IPv6 support */
+#cmakedefine ENABLE_IPV6 ${ENABLE_IPV6}
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#cmakedefine HAVE_ALLOCA_H ${HAVE_ALLOCA_H}
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#cmakedefine HAVE_ARPA_INET_H ${HAVE_ARPA_INET_H}
+
+/* Define to 1 if you have the <assert.h> header file. */
+#cmakedefine HAVE_ASSERT_H ${HAVE_ASSERT_H}
+
+/* Define to 1 if you have the `closesocket' function. */
+#cmakedefine HAVE_CLOSESOCKET ${HAVE_CLOSESOCKET}
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+#cmakedefine HAVE_CRYPTO_CLEANUP_ALL_EX_DATA ${HAVE_CRYPTO_CLEANUP_ALL_EX_DATA}
+
+/* Define to 1 if you have the <crypto.h> header file. */
+#cmakedefine HAVE_CRYPTO_H ${HAVE_CRYPTO_H}
+
+/* Define to 1 if you have the <des.h> header file. */
+#cmakedefine HAVE_DES_H ${HAVE_DES_H}
+
+/* disabled non-blocking sockets */
+#cmakedefine HAVE_DISABLED_NONBLOCKING ${HAVE_DISABLED_NONBLOCKING}
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#cmakedefine HAVE_DLFCN_H ${HAVE_DLFCN_H}
+
+/* Define to 1 if you have the `dlopen' function. */
+#cmakedefine HAVE_DLOPEN ${HAVE_DLOPEN}
+
+/* Define to 1 if you have the <err.h> header file. */
+#cmakedefine HAVE_ERR_H ${HAVE_ERR_H}
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#cmakedefine HAVE_FCNTL_H ${HAVE_FCNTL_H}
+
+/* use FIONBIO for non-blocking sockets */
+#cmakedefine HAVE_FIONBIO ${HAVE_FIONBIO}
+
+/* Define if getaddrinfo exists and works */
+#cmakedefine HAVE_GETADDRINFO ${HAVE_GETADDRINFO}
+
+/* Define to 1 if you have the `geteuid' function. */
+#cmakedefine HAVE_GETEUID ${HAVE_GETEUID}
+
+/* Define to 1 if you have the `gethostbyaddr' function. */
+#cmakedefine HAVE_GETHOSTBYADDR ${HAVE_GETHOSTBYADDR}
+
+/* If you have gethostbyname */
+#cmakedefine HAVE_GETHOSTBYNAME ${HAVE_GETHOSTBYNAME}
+
+/* Define to 1 if you have the `gethostbyname_r' function. */
+#cmakedefine HAVE_GETHOSTBYNAME_R ${HAVE_GETHOSTBYNAME_R}
+
+/* gethostbyname_r() takes 3 args */
+#cmakedefine HAVE_GETHOSTBYNAME_R_3 ${HAVE_GETHOSTBYNAME_R_3}
+
+/* gethostbyname_r() takes 5 args */
+#cmakedefine HAVE_GETHOSTBYNAME_R_5 ${HAVE_GETHOSTBYNAME_R_5}
+
+/* gethostbyname_r() takes 6 args */
+#cmakedefine HAVE_GETHOSTBYNAME_R_6 ${HAVE_GETHOSTBYNAME_R_6}
+
+/* Define to 1 if you have the `getpass_r' function. */
+#cmakedefine HAVE_GETPASS_R ${HAVE_GETPASS_R}
+
+/* Define to 1 if you have the `getpwuid' function. */
+#cmakedefine HAVE_GETPWUID ${HAVE_GETPWUID}
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#cmakedefine HAVE_GETTIMEOFDAY ${HAVE_GETTIMEOFDAY}
+
+/* we have a glibc-style strerror_r() */
+#cmakedefine HAVE_GLIBC_STRERROR_R ${HAVE_GLIBC_STRERROR_R}
+
+/* Define to 1 if you have the `gmtime_r' function. */
+#cmakedefine HAVE_GMTIME_R ${HAVE_GMTIME_R}
+
+/* if you have the gssapi libraries */
+#cmakedefine HAVE_GSSAPI ${HAVE_GSSAPI}
+
+/* if you have the Heimdal gssapi libraries */
+#cmakedefine HAVE_GSSHEIMDAL ${HAVE_GSSHEIMDAL}
+
+/* if you have the MIT gssapi libraries */
+#cmakedefine HAVE_GSSMIT ${HAVE_GSSMIT}
+
+/* Define to 1 if you have the `idn_free' function. */
+#cmakedefine HAVE_IDN_FREE ${HAVE_IDN_FREE}
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+#cmakedefine HAVE_IDN_FREE_H ${HAVE_IDN_FREE_H}
+
+/* Define to 1 if you have the `inet_addr' function. */
+#cmakedefine HAVE_INET_ADDR ${HAVE_INET_ADDR}
+
+/* Define to 1 if you have the `inet_ntoa' function. */
+#cmakedefine HAVE_INET_NTOA ${HAVE_INET_NTOA}
+
+/* Define to 1 if you have the `inet_ntoa_r' function. */
+#cmakedefine HAVE_INET_NTOA_R ${HAVE_INET_NTOA_R}
+
+/* inet_ntoa_r() is declared */
+#cmakedefine HAVE_INET_NTOA_R_DECL ${HAVE_INET_NTOA_R_DECL}
+
+/* Define to 1 if you have the `inet_pton' function. */
+#cmakedefine HAVE_INET_PTON ${HAVE_INET_PTON}
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#cmakedefine HAVE_INTTYPES_H ${HAVE_INTTYPES_H}
+
+/* use ioctlsocket() for non-blocking sockets */
+#cmakedefine HAVE_IOCTLSOCKET ${HAVE_IOCTLSOCKET}
+
+/* use Ioctlsocket() for non-blocking sockets */
+#cmakedefine HAVE_IOCTLSOCKET_CASE ${HAVE_IOCTLSOCKET_CASE}
+
+/* Define to 1 if you have the <io.h> header file. */
+#cmakedefine HAVE_IO_H ${HAVE_IO_H}
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+#cmakedefine HAVE_KRB4 ${HAVE_KRB4}
+
+/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
+#cmakedefine HAVE_KRB_GET_OUR_IP_FOR_REALM ${HAVE_KRB_GET_OUR_IP_FOR_REALM}
+
+/* Define to 1 if you have the <krb.h> header file. */
+#cmakedefine HAVE_KRB_H ${HAVE_KRB_H}
+
+/* Define to 1 if you have the `crypto' library (-lcrypto). */
+#cmakedefine HAVE_LIBCRYPTO ${HAVE_LIBCRYPTO}
+
+/* Define to 1 if you have the `dl' library (-ldl). */
+#cmakedefine HAVE_LIBDL ${HAVE_LIBDL}
+
+/* Define to 1 if you have the `idn' library (-lidn). */
+#cmakedefine HAVE_LIBIDN ${HAVE_LIBIDN}
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#cmakedefine HAVE_LIBRESOLV ${HAVE_LIBRESOLV}
+
+/* Define to 1 if you have the `resolve' library (-lresolve). */
+#cmakedefine HAVE_LIBRESOLVE ${HAVE_LIBRESOLVE}
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#cmakedefine HAVE_LIBSOCKET ${HAVE_LIBSOCKET}
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+#cmakedefine HAVE_LIBSSL ${HAVE_LIBSSL}
+
+/* if zlib is available */
+#cmakedefine HAVE_LIBZ ${HAVE_LIBZ}
+
+/* Define to 1 if you have the <limits.h> header file. */
+#cmakedefine HAVE_LIMITS_H ${HAVE_LIMITS_H}
+
+/* Define to 1 if you have the `localtime_r' function. */
+#cmakedefine HAVE_LOCALTIME_R ${HAVE_LOCALTIME_R}
+
+/* if your compiler supports 'long long' */
+#cmakedefine HAVE_LONGLONG ${HAVE_LONGLONG}
+
+/* Define to 1 if you have the <malloc.h> header file. */
+#cmakedefine HAVE_MALLOC_H ${HAVE_MALLOC_H}
+
+/* Define to 1 if you have the <memory.h> header file. */
+#cmakedefine HAVE_MEMORY_H ${HAVE_MEMORY_H}
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#cmakedefine HAVE_NETDB_H ${HAVE_NETDB_H}
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#cmakedefine HAVE_NETINET_IN_H ${HAVE_NETINET_IN_H}
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#cmakedefine HAVE_NETINET_TCP_H ${HAVE_NETINET_TCP_H}
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#cmakedefine HAVE_NET_IF_H ${HAVE_NET_IF_H}
+
+/* Define if NI_WITHSCOPEID exists and works */
+#cmakedefine HAVE_NI_WITHSCOPEID ${HAVE_NI_WITHSCOPEID}
+
+/* we have no strerror_r() proto */
+#cmakedefine HAVE_NO_STRERROR_R_DECL ${HAVE_NO_STRERROR_R_DECL}
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+#cmakedefine HAVE_OPENSSL_CRYPTO_H ${HAVE_OPENSSL_CRYPTO_H}
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+#cmakedefine HAVE_OPENSSL_ENGINE_H ${HAVE_OPENSSL_ENGINE_H}
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+#cmakedefine HAVE_OPENSSL_ERR_H ${HAVE_OPENSSL_ERR_H}
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+#cmakedefine HAVE_OPENSSL_PEM_H ${HAVE_OPENSSL_PEM_H}
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+#cmakedefine HAVE_OPENSSL_RSA_H ${HAVE_OPENSSL_RSA_H}
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+#cmakedefine HAVE_OPENSSL_SSL_H ${HAVE_OPENSSL_SSL_H}
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+#cmakedefine HAVE_OPENSSL_X509_H ${HAVE_OPENSSL_X509_H}
+
+/* use O_NONBLOCK for non-blocking sockets */
+#cmakedefine HAVE_O_NONBLOCK ${HAVE_O_NONBLOCK}
+
+/* Define to 1 if you have the <pem.h> header file. */
+#cmakedefine HAVE_PEM_H ${HAVE_PEM_H}
+
+/* Define to 1 if you have the `perror' function. */
+#cmakedefine HAVE_PERROR ${HAVE_PERROR}
+
+/* Define to 1 if you have the `poll' function. */
+#cmakedefine HAVE_POLL ${HAVE_POLL}
+
+/* If you have a fine poll */
+#cmakedefine HAVE_POLL_FINE ${HAVE_POLL_FINE}
+
+/* we have a POSIX-style strerror_r() */
+#cmakedefine HAVE_POSIX_STRERROR_R ${HAVE_POSIX_STRERROR_R}
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#cmakedefine HAVE_PWD_H ${HAVE_PWD_H}
+
+/* Define to 1 if you have the `RAND_egd' function. */
+#cmakedefine HAVE_RAND_EGD ${HAVE_RAND_EGD}
+
+/* Define to 1 if you have the `RAND_screen' function. */
+#cmakedefine HAVE_RAND_SCREEN ${HAVE_RAND_SCREEN}
+
+/* Define to 1 if you have the `RAND_status' function. */
+#cmakedefine HAVE_RAND_STATUS ${HAVE_RAND_STATUS}
+
+/* Define to 1 if you have the <rsa.h> header file. */
+#cmakedefine HAVE_RSA_H ${HAVE_RSA_H}
+
+/* Define to 1 if you have the `select' function. */
+#cmakedefine HAVE_SELECT ${HAVE_SELECT}
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#cmakedefine HAVE_SETJMP_H ${HAVE_SETJMP_H}
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+#cmakedefine HAVE_SGTTY_H ${HAVE_SGTTY_H}
+
+/* Define to 1 if you have the `sigaction' function. */
+#cmakedefine HAVE_SIGACTION ${HAVE_SIGACTION}
+
+/* Define to 1 if you have the `siginterrupt' function. */
+#cmakedefine HAVE_SIGINTERRUPT ${HAVE_SIGINTERRUPT}
+
+/* Define to 1 if you have the `signal' function. */
+#cmakedefine HAVE_SIGNAL ${HAVE_SIGNAL}
+
+/* If you have sigsetjmp */
+#cmakedefine HAVE_SIGSETJMP ${HAVE_SIGSETJMP}
+
+/* Define to 1 if you have the `socket' function. */
+#cmakedefine HAVE_SOCKET ${HAVE_SOCKET}
+
+/* use SO_NONBLOCK for non-blocking sockets */
+#cmakedefine HAVE_SO_NONBLOCK ${HAVE_SO_NONBLOCK}
+
+/* Define this if you have the SPNEGO library fbopenssl */
+#cmakedefine HAVE_SPNEGO ${HAVE_SPNEGO}
+
+/* Define to 1 if you have the <ssl.h> header file. */
+#cmakedefine HAVE_SSL_H ${HAVE_SSL_H}
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#cmakedefine HAVE_STDINT_H ${HAVE_STDINT_H}
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#cmakedefine HAVE_STDLIB_H ${HAVE_STDLIB_H}
+
+/* Define to 1 if you have the `strcasecmp' function. */
+#cmakedefine HAVE_STRCASECMP ${HAVE_STRCASECMP}
+
+/* Define to 1 if you have the `strcmpi' function. */
+#cmakedefine HAVE_STRCMPI ${HAVE_STRCMPI}
+
+/* Define to 1 if you have the `strdup' function. */
+#cmakedefine HAVE_STRDUP ${HAVE_STRDUP}
+
+/* Define to 1 if you have the `strerror_r' function. */
+#cmakedefine HAVE_STRERROR_R ${HAVE_STRERROR_R}
+
+/* Define to 1 if you have the `strftime' function. */
+#cmakedefine HAVE_STRFTIME ${HAVE_STRFTIME}
+
+/* Define to 1 if you have the `stricmp' function. */
+#cmakedefine HAVE_STRICMP ${HAVE_STRICMP}
+
+/* Define to 1 if you have the <strings.h> header file. */
+#cmakedefine HAVE_STRINGS_H ${HAVE_STRINGS_H}
+
+/* Define to 1 if you have the <string.h> header file. */
+#cmakedefine HAVE_STRING_H ${HAVE_STRING_H}
+
+/* Define to 1 if you have the `strlcat' function. */
+#cmakedefine HAVE_STRLCAT ${HAVE_STRLCAT}
+
+/* Define to 1 if you have the `strlcpy' function. */
+#cmakedefine HAVE_STRLCPY ${HAVE_STRLCPY}
+
+/* Define to 1 if you have the `strstr' function. */
+#cmakedefine HAVE_STRSTR ${HAVE_STRSTR}
+
+/* Define to 1 if you have the `strtok_r' function. */
+#cmakedefine HAVE_STRTOK_R ${HAVE_STRTOK_R}
+
+/* Define to 1 if you have the `strtoll' function. */
+#cmakedefine HAVE_STRTOLL ${HAVE_STRTOLL}
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#cmakedefine HAVE_SYS_IOCTL_H ${HAVE_SYS_IOCTL_H}
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#cmakedefine HAVE_SYS_PARAM_H ${HAVE_SYS_PARAM_H}
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#cmakedefine HAVE_SYS_POLL_H ${HAVE_SYS_POLL_H}
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#cmakedefine HAVE_SYS_SELECT_H ${HAVE_SYS_SELECT_H}
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#cmakedefine HAVE_SYS_SOCKET_H ${HAVE_SYS_SOCKET_H}
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#cmakedefine HAVE_SYS_SOCKIO_H ${HAVE_SYS_SOCKIO_H}
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#cmakedefine HAVE_SYS_STAT_H ${HAVE_SYS_STAT_H}
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#cmakedefine HAVE_SYS_TIME_H ${HAVE_SYS_TIME_H}
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#cmakedefine HAVE_SYS_TYPES_H ${HAVE_SYS_TYPES_H}
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+#cmakedefine HAVE_SYS_UTIME_H ${HAVE_SYS_UTIME_H}
+
+/* Define to 1 if you have the `tcgetattr' function. */
+#cmakedefine HAVE_TCGETATTR ${HAVE_TCGETATTR}
+
+/* Define to 1 if you have the `tcsetattr' function. */
+#cmakedefine HAVE_TCSETATTR ${HAVE_TCSETATTR}
+
+/* Define to 1 if you have the <termios.h> header file. */
+#cmakedefine HAVE_TERMIOS_H ${HAVE_TERMIOS_H}
+
+/* Define to 1 if you have the <termio.h> header file. */
+#cmakedefine HAVE_TERMIO_H ${HAVE_TERMIO_H}
+
+/* Define to 1 if you have the <time.h> header file. */
+#cmakedefine HAVE_TIME_H ${HAVE_TIME_H}
+
+/* Define to 1 if you have the `uname' function. */
+#cmakedefine HAVE_UNAME ${HAVE_UNAME}
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H}
+
+/* Define to 1 if you have the `utime' function. */
+#cmakedefine HAVE_UTIME ${HAVE_UTIME}
+
+/* Define to 1 if you have the <utime.h> header file. */
+#cmakedefine HAVE_UTIME_H ${HAVE_UTIME_H}
+
+/* Define to 1 if you have the <winsock.h> header file. */
+#cmakedefine HAVE_WINSOCK_H ${HAVE_WINSOCK_H}
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#cmakedefine HAVE_WRITABLE_ARGV ${HAVE_WRITABLE_ARGV}
+
+/* Define to 1 if you have the <x509.h> header file. */
+#cmakedefine HAVE_X509_H ${HAVE_X509_H}
+
+/* if you have the zlib.h header file */
+#cmakedefine HAVE_ZLIB_H ${HAVE_ZLIB_H}
+
+/* need REENTRANT defined */
+#cmakedefine NEED_REENTRANT ${NEED_REENTRANT}
+
+/* cpu-machine-OS */
+#define OS         "${OPERATING_SYSTEM}"
+
+/* Name of package */
+#cmakedefine PACKAGE            "${PACKAGE}"
+
+/* Define to the address where bug reports for this package should be sent. */
+#cmakedefine PACKAGE_BUGREPORT          "${PACKAGE_BUGREPORT}"
+
+/* Define to the full name of this package. */
+#cmakedefine PACKAGE_NAME               "${PACKAGE_NAME}"
+
+/* Define to the full name and version of this package. */
+#cmakedefine PACKAGE_STRING             "${PACKAGE_STRING}"
+
+/* Define to the one symbol short name of this package. */
+#cmakedefine PACKAGE_TARNAME            "${PACKAGE_TARNAME}"
+
+/* Define to the version of this package. */
+#cmakedefine PACKAGE_VERSION            "${PACKAGE_VERSION}"
+
+/* a suitable file to read random data from */
+#cmakedefine RANDOM_FILE                "${RANDOM_FILE}"
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#cmakedefine RETSIGTYPE ${RETSIGTYPE}
+
+/* Define to the type of arg 1 for `select'. */
+#cmakedefine SELECT_TYPE_ARG1 ${SELECT_TYPE_ARG1}
+
+/* Define to the type of args 2, 3 and 4 for `select'. */
+#cmakedefine SELECT_TYPE_ARG234 ${SELECT_TYPE_ARG234}
+
+/* Define to the type of arg 5 for `select'. */
+#cmakedefine SELECT_TYPE_ARG5 ${SELECT_TYPE_ARG5}
+
+/* The size of a `curl_off_t', as computed by sizeof. */
+#cmakedefine SIZEOF_CURL_OFF_T ${SIZEOF_CURL_OFF_T}
+
+/* The size of a `size_t', as computed by sizeof. */
+#cmakedefine SIZEOF_SIZE_T ${SIZEOF_SIZE_T}
+
+/* Define to 1 if you have the ANSI C header files. */
+#cmakedefine STDC_HEADERS ${STDC_HEADERS}
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#cmakedefine TIME_WITH_SYS_TIME ${TIME_WITH_SYS_TIME}
+
+/* Define if you want to enable ares support */
+#cmakedefine USE_ARES ${USE_ARES}
+
+/* If you want to build curl with the built-in manual */
+#cmakedefine USE_MANUAL ${USE_MANUAL}
+
+/* Version number of package */
+#cmakedefine VERSION            "${VERSION}"
+
+/* Define to 1 if on AIX 3.
+   System headers sometimes define this.
+   We just want to avoid a redefinition error message.  */
+#ifndef _ALL_SOURCE
+#cmakedefine _ALL_SOURCE ${_ALL_SOURCE}
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS}
+
+/* Define for large files, on AIX-style hosts. */
+#cmakedefine _LARGE_FILES ${_LARGE_FILES}
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#cmakedefine const ${const}
+
+/* type to use in place of in_addr_t if not defined */
+#cmakedefine in_addr_t ${in_addr_t}
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#cmakedefine size_t ${size_t}
+
+/* type to use in place of socklen_t if not defined */
+#cmakedefine socklen_t ${socklen_t}
+
+/* the signed version of size_t */
+#cmakedefine ssize_t ${ssize_t}
+
+/* define if the compiler supports number 0x3627676LL */
+#cmakedefine HAVE_LONG_LONG_CONSTANT ${HAVE_LONG_LONG_CONSTANT}
+
+/* Special handling of zlib library */
+#cmakedefine CURL_SPECIAL_ZLIB_H "${CURL_SPECIAL_ZLIB_H}"
diff --git a/Utilities/cmcurl/connect.c b/Utilities/cmcurl/connect.c
new file mode 100644
index 0000000..c107354
--- /dev/null
+++ b/Utilities/cmcurl/connect.c
@@ -0,0 +1,788 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#ifndef WIN32
+/* headers for non-win32 */
+#include <sys/time.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h> /* <netinet/tcp.h> may need it */
+#endif
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h> /* for TCP_NODELAY */
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h> /* required for free() prototype, without it, this crashes
+                       on macos 68K */
+#endif
+#if (defined(HAVE_FIONBIO) && defined(__NOVELL_LIBC__))
+#include <sys/filio.h>
+#endif
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+#ifdef  VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#endif
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#ifdef WIN32
+#include <windows.h>
+#define EINPROGRESS WSAEINPROGRESS
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define EISCONN     WSAEISCONN
+#define ENOTSOCK    WSAENOTSOCK
+#define ECONNREFUSED WSAECONNREFUSED
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "if2ip.h"
+#include "strerror.h"
+#include "connect.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+static bool verifyconnect(curl_socket_t sockfd, int *error);
+
+static curl_socket_t
+singleipconnect(struct connectdata *conn,
+                Curl_addrinfo *ai, /* start connecting to this */
+                long timeout_ms,
+                bool *connected);
+
+/*
+ * Curl_ourerrno() returns the errno (or equivalent) on this platform to
+ * hide platform specific for the function that calls this.
+ */
+int Curl_ourerrno(void)
+{
+#ifdef WIN32
+  return (int)GetLastError();
+#else
+  return errno;
+#endif
+}
+
+/*
+ * Curl_nonblock() set the given socket to either blocking or non-blocking
+ * mode based on the 'nonblock' boolean argument. This function is highly
+ * portable.
+ */
+int Curl_nonblock(curl_socket_t sockfd,    /* operate on this */
+                  int nonblock   /* TRUE or FALSE */)
+{
+#undef SETBLOCK
+#ifdef HAVE_O_NONBLOCK
+    {
+    /* most recent unix versions */
+    int flags;
+
+    flags = fcntl(sockfd, F_GETFL, 0);
+    if (TRUE == nonblock)
+      return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
+    else
+      return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
+    }
+#define SETBLOCK 1
+#endif
+
+#ifdef HAVE_FIONBIO
+    {
+    /* older unix versions */
+    int flags;
+
+    flags = nonblock;
+    return ioctl(sockfd, FIONBIO, &flags);
+    }
+#ifdef SETBLOCK
+# undef SETBLOCK
+#endif
+#define SETBLOCK 2
+#endif
+
+#ifdef HAVE_IOCTLSOCKET
+  /* Windows? */
+  unsigned long flags;
+  flags = nonblock;
+  return ioctlsocket(sockfd, FIONBIO, &flags);
+#define SETBLOCK 3
+#endif
+
+#ifdef HAVE_IOCTLSOCKET_CASE
+  /* presumably for Amiga */
+  return IoctlSocket(sockfd, FIONBIO, (long)nonblock);
+#ifdef SETBLOCK
+# undef SETBLOCK
+#endif
+#define SETBLOCK 4
+#endif
+
+#ifdef HAVE_SO_NONBLOCK
+  /* BeOS */
+  long b = nonblock ? 1 : 0;
+  return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
+#ifdef SETBLOCK
+# undef SETBLOCK
+#endif
+#define SETBLOCK 5
+#endif
+
+#ifdef HAVE_DISABLED_NONBLOCKING
+  (void)nonblock;
+  (void)sockfd;
+  return 0; /* returns success */
+#ifdef SETBLOCK
+# undef SETBLOCK
+#endif
+#define SETBLOCK 6
+#endif
+
+#ifndef SETBLOCK
+#error "no non-blocking method was found/used/set"
+#endif
+}
+
+/*
+ * waitconnect() waits for a TCP connect on the given socket for the specified
+ * number if milliseconds. It returns:
+ * 0    fine connect
+ * -1   select() error
+ * 1    select() timeout
+ * 2    select() returned with an error condition fd_set
+ */
+
+#define WAITCONN_CONNECTED     0
+#define WAITCONN_SELECT_ERROR -1
+#define WAITCONN_TIMEOUT       1
+#define WAITCONN_FDSET_ERROR   2
+
+static
+int waitconnect(curl_socket_t sockfd, /* socket */
+                long timeout_msec)
+{
+  fd_set fd;
+  fd_set errfd;
+  struct timeval interval;
+  int rc;
+#ifdef mpeix
+  /* Call this function once now, and ignore the results. We do this to
+     "clear" the error state on the socket so that we can later read it
+     reliably. This is reported necessary on the MPE/iX operating system. */
+  verifyconnect(sockfd, NULL);
+#endif
+
+  /* now select() until we get connect or timeout */
+  FD_ZERO(&fd);
+  FD_SET(sockfd, &fd);
+
+  FD_ZERO(&errfd);
+  FD_SET(sockfd, &errfd);
+
+  interval.tv_sec = (int)(timeout_msec/1000);
+  timeout_msec -= interval.tv_sec*1000;
+
+  interval.tv_usec = timeout_msec*1000;
+
+  rc = select(sockfd+1, NULL, &fd, &errfd, &interval);
+  if(-1 == rc)
+    /* error, no connect here, try next */
+    return WAITCONN_SELECT_ERROR;
+
+  else if(0 == rc)
+    /* timeout, no connect today */
+    return WAITCONN_TIMEOUT;
+
+  if(FD_ISSET(sockfd, &errfd))
+    /* error condition caught */
+    return WAITCONN_FDSET_ERROR;
+
+  /* we have a connect! */
+  return WAITCONN_CONNECTED;
+}
+
+static CURLcode bindlocal(struct connectdata *conn,
+                          curl_socket_t sockfd)
+{
+#ifdef HAVE_INET_NTOA
+  bool bindworked = FALSE;
+  struct SessionHandle *data = conn->data;
+
+  /*************************************************************
+   * Select device to bind socket to
+   *************************************************************/
+  if (strlen(data->set.device)<255) {
+    struct Curl_dns_entry *h=NULL;
+    char myhost[256] = "";
+    in_addr_t in;
+    int rc;
+    bool was_iface = FALSE;
+
+    /* First check if the given name is an IP address */
+    in=inet_addr(data->set.device);
+
+    if((in == CURL_INADDR_NONE) &&
+       Curl_if2ip(data->set.device, myhost, sizeof(myhost))) {
+      /*
+       * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer
+       */
+      rc = Curl_resolv(conn, myhost, 0, &h);
+      if(rc == CURLRESOLV_PENDING)
+        (void)Curl_wait_for_resolv(conn, &h);
+
+      if(h)
+        was_iface = TRUE;
+    }
+
+    if(!was_iface) {
+      /*
+       * This was not an interface, resolve the name as a host name
+       * or IP number
+       */
+      rc = Curl_resolv(conn, data->set.device, 0, &h);
+      if(rc == CURLRESOLV_PENDING)
+        (void)Curl_wait_for_resolv(conn, &h);
+
+      if(h)
+        /* we know data->set.device is shorter than the myhost array */
+        strcpy(myhost, data->set.device);
+    }
+
+    if(! *myhost) {
+      /* need to fix this
+         h=Curl_gethost(data,
+         getmyhost(*myhost,sizeof(myhost)),
+         hostent_buf,
+         sizeof(hostent_buf));
+      */
+      failf(data, "Couldn't bind to '%s'", data->set.device);
+      return CURLE_HTTP_PORT_FAILED;
+    }
+
+    infof(data, "We bind local end to %s\n", myhost);
+
+#ifdef SO_BINDTODEVICE
+    /* I am not sure any other OSs than Linux that provide this feature, and
+     * at the least I cannot test. --Ben
+     *
+     * This feature allows one to tightly bind the local socket to a
+     * particular interface.  This will force even requests to other local
+     * interfaces to go out the external interface.
+     *
+     */
+    if (was_iface) {
+      /* Only bind to the interface when specified as interface, not just as a
+       * hostname or ip address.
+       */
+      if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
+                     data->set.device, strlen(data->set.device)+1) != 0) {
+        /* printf("Failed to BINDTODEVICE, socket: %d  device: %s error: %s\n",
+           sockfd, data->set.device, Curl_strerror(Curl_ourerrno())); */
+        infof(data, "SO_BINDTODEVICE %s failed\n",
+              data->set.device);
+        /* This is typically "errno 1, error: Operation not permitted" if
+           you're not running as root or another suitable privileged user */
+      }
+    }
+#endif
+
+    in=inet_addr(myhost);
+    if (CURL_INADDR_NONE != in) {
+
+      if ( h ) {
+        Curl_addrinfo *addr = h->addr;
+
+        Curl_resolv_unlock(data, h);
+        /* we don't need it anymore after this function has returned */
+
+        if( bind(sockfd, addr->ai_addr, (socklen_t)addr->ai_addrlen) >= 0) {
+          /* we succeeded to bind */
+#ifdef ENABLE_IPV6
+          struct sockaddr_in6 add;
+#else
+          struct sockaddr_in add;
+#endif
+
+#ifdef __hpux
+          int gsize = sizeof(add);
+#else
+          socklen_t gsize = sizeof(add);
+#endif
+          bindworked = TRUE;
+
+          if(getsockname(sockfd, (struct sockaddr *) &add,
+                         &gsize)<0) {
+            failf(data, "getsockname() failed");
+            return CURLE_HTTP_PORT_FAILED;
+          }
+        }
+
+        if(!bindworked) {
+          failf(data, "%s", Curl_strerror(conn, Curl_ourerrno()));
+          return CURLE_HTTP_PORT_FAILED;
+        }
+
+      } /* end of if  h */
+      else {
+        failf(data,"could't find my own IP address (%s)", myhost);
+        return CURLE_HTTP_PORT_FAILED;
+      }
+    } /* end of inet_addr */
+
+    else {
+      failf(data, "could't find my own IP address (%s)", myhost);
+      return CURLE_HTTP_PORT_FAILED;
+    }
+
+    return CURLE_OK;
+
+  } /* end of device selection support */
+#endif /* end of HAVE_INET_NTOA */
+
+  return CURLE_HTTP_PORT_FAILED;
+}
+
+/*
+ * verifyconnect() returns TRUE if the connect really has happened.
+ */
+static bool verifyconnect(curl_socket_t sockfd, int *error)
+{
+  bool rc;
+#ifdef SO_ERROR
+  int err = 0;
+#ifdef __hpux
+  int errSize = sizeof(err);
+#else
+  socklen_t errSize = sizeof(err);
+#endif
+
+
+#ifdef WIN32
+  /*
+   * In October 2003 we effectively nullified this function on Windows due to
+   * problems with it using all CPU in multi-threaded cases.
+   *
+   * In May 2004, we bring it back to offer more info back on connect failures.
+   * Gisle Vanem could reproduce the former problems with this function, but
+   * could avoid them by adding this SleepEx() call below:
+   *
+   *    "I don't have Rational Quantify, but the hint from his post was
+   *    ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
+   *    just Sleep(0) would be enough?) would release whatever
+   *    mutex/critical-section the ntdll call is waiting on.
+   *
+   *    Someone got to verify this on Win-NT 4.0, 2000."
+   */
+  SleepEx(0, FALSE);
+#endif
+
+  if( -1 == getsockopt(sockfd, SOL_SOCKET, SO_ERROR,
+                       (void *)&err, &errSize))
+    err = Curl_ourerrno();
+
+  if ((0 == err) || (EISCONN == err))
+    /* we are connected, awesome! */
+    rc = TRUE;
+  else
+    /* This wasn't a successful connect */
+    rc = FALSE;
+  if (error)
+    *error = err;
+#else
+  (void)sockfd;
+  if (error)
+    *error = Curl_ourerrno();
+#endif
+  return rc;
+}
+
+/* Used within the multi interface. Try next IP address, return TRUE if no
+   more address exists */
+static bool trynextip(struct connectdata *conn,
+                      int sockindex,
+                      bool *connected)
+{
+  curl_socket_t sockfd;
+  Curl_addrinfo *ai;
+
+  if(sockindex != FIRSTSOCKET)
+    return TRUE; /* no next */
+
+  /* try the next address */
+  ai = conn->ip_addr->ai_next;
+
+  while (ai) {
+    sockfd = singleipconnect(conn, ai, 0L, connected);
+    if(sockfd != CURL_SOCKET_BAD) {
+      /* store the new socket descriptor */
+      conn->sock[sockindex] = sockfd;
+      conn->ip_addr = ai;
+      return FALSE;
+    }
+    ai = ai->ai_next;
+  }
+  return TRUE;
+}
+
+/*
+ * Curl_is_connected() is used from the multi interface to check if the
+ * firstsocket has connected.
+ */
+
+CURLcode Curl_is_connected(struct connectdata *conn,
+                           int sockindex,
+                           bool *connected)
+{
+  int rc;
+  struct SessionHandle *data = conn->data;
+  CURLcode code = CURLE_OK;
+  curl_socket_t sockfd = conn->sock[sockindex];
+  long allow = DEFAULT_CONNECT_TIMEOUT;
+  long has_passed;
+
+  curlassert(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
+
+  *connected = FALSE; /* a very negative world view is best */
+
+  /* Evaluate in milliseconds how much time that has passed */
+  has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);
+
+  /* subtract the most strict timeout of the ones */
+  if(data->set.timeout && data->set.connecttimeout) {
+    if (data->set.timeout < data->set.connecttimeout)
+      allow = data->set.timeout*1000;
+    else
+      allow = data->set.connecttimeout*1000;
+  }
+  else if(data->set.timeout) {
+    allow = data->set.timeout*1000;
+  }
+  else if(data->set.connecttimeout) {
+    allow = data->set.connecttimeout*1000;
+  }
+
+  if(has_passed > allow ) {
+    /* time-out, bail out, go home */
+    failf(data, "Connection time-out after %ld ms", has_passed);
+    return CURLE_OPERATION_TIMEOUTED;
+  }
+  if(conn->bits.tcpconnect) {
+    /* we are connected already! */
+    *connected = TRUE;
+    return CURLE_OK;
+  }
+
+  /* check for connect without timeout as we want to return immediately */
+  rc = waitconnect(sockfd, 0);
+
+  if(WAITCONN_CONNECTED == rc) {
+    if (verifyconnect(sockfd, NULL)) {
+      /* we are connected, awesome! */
+      *connected = TRUE;
+      return CURLE_OK;
+    }
+    /* nope, not connected for real */
+    infof(data, "Connection failed\n");
+    if(trynextip(conn, sockindex, connected)) {
+      code = CURLE_COULDNT_CONNECT;
+    }
+  }
+  else if(WAITCONN_TIMEOUT != rc) {
+    /* nope, not connected  */
+    infof(data, "Connection failed\n");
+    if(trynextip(conn, sockindex, connected)) {
+      int error = Curl_ourerrno();
+      failf(data, "Failed connect to %s:%d; %s",
+            conn->host.name, conn->port, Curl_strerror(conn,error));
+      code = CURLE_COULDNT_CONNECT;
+    }
+  }
+  /*
+   * If the connection failed here, we should attempt to connect to the "next
+   * address" for the given host.
+   */
+
+  return code;
+}
+
+static void tcpnodelay(struct connectdata *conn,
+                       curl_socket_t sockfd)
+{
+#ifdef TCP_NODELAY
+  struct SessionHandle *data= conn->data;
+  socklen_t onoff = (socklen_t) data->set.tcp_nodelay;
+  if(setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void *)&onoff,
+                sizeof(onoff)) < 0)
+    infof(data, "Could not set TCP_NODELAY: %s\n",
+          Curl_strerror(conn, Curl_ourerrno()));
+  else
+    infof(data,"TCP_NODELAY set\n");
+#else
+  (void)conn;
+  (void)sockfd;
+#endif
+}
+
+/* singleipconnect() connects to the given IP only, and it may return without
+   having connected if used from the multi interface. */
+static curl_socket_t
+singleipconnect(struct connectdata *conn,
+                Curl_addrinfo *ai,
+                long timeout_ms,
+                bool *connected)
+{
+  char addr_buf[128];
+  int rc;
+  int error;
+  bool conected;
+  struct SessionHandle *data = conn->data;
+  curl_socket_t sockfd = socket(ai->ai_family, ai->ai_socktype,
+                                ai->ai_protocol);
+  if (sockfd == CURL_SOCKET_BAD)
+    return CURL_SOCKET_BAD;
+
+  *connected = FALSE; /* default is not connected */
+
+  Curl_printable_address(ai, addr_buf, sizeof(addr_buf));
+  infof(data, "  Trying %s... ", addr_buf);
+
+  if(data->set.tcp_nodelay)
+    tcpnodelay(conn, sockfd);
+
+  if(conn->data->set.device) {
+    /* user selected to bind the outgoing socket to a specified "device"
+       before doing connect */
+    CURLcode res = bindlocal(conn, sockfd);
+    if(res)
+      return res;
+  }
+
+  /* set socket non-blocking */
+  Curl_nonblock(sockfd, TRUE);
+
+  rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen);
+
+  if(-1 == rc) {
+    error = Curl_ourerrno();
+
+    switch (error) {
+    case EINPROGRESS:
+    case EWOULDBLOCK:
+#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
+      /* On some platforms EAGAIN and EWOULDBLOCK are the
+       * same value, and on others they are different, hence
+       * the odd #if
+       */
+    case EAGAIN:
+#endif
+      rc = waitconnect(sockfd, timeout_ms);
+      break;
+    default:
+      /* unknown error, fallthrough and try another address! */
+      failf(data, "Failed to connect to %s: %s",
+            addr_buf, Curl_strerror(conn,error));
+      break;
+    }
+  }
+
+  /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
+     connect(). We can be sure of this since connect() cannot return 1. */
+  if((WAITCONN_TIMEOUT == rc) &&
+     (data->state.used_interface == Curl_if_multi)) {
+    /* Timeout when running the multi interface */
+    return sockfd;
+  }
+
+  conected = verifyconnect(sockfd, &error);
+
+  if(!rc && conected) {
+    /* we are connected, awesome! */
+    *connected = TRUE; /* this is a true connect */
+    infof(data, "connected\n");
+    return sockfd;
+  }
+  else if(WAITCONN_TIMEOUT == rc)
+    infof(data, "Timeout\n");
+  else
+    infof(data, "%s\n", Curl_strerror(conn, error));
+
+  /* connect failed or timed out */
+  sclose(sockfd);
+
+  return CURL_SOCKET_BAD;
+}
+
+/*
+ * TCP connect to the given host with timeout, proxy or remote doesn't matter.
+ * There might be more than one IP address to try out. Fill in the passed
+ * pointer with the connected socket.
+ */
+
+CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
+                          struct Curl_dns_entry *remotehost, /* use this one */
+                          curl_socket_t *sockconn,   /* the connected socket */
+                          Curl_addrinfo **addr,      /* the one we used */
+                          bool *connected)           /* really connected? */
+{
+  struct SessionHandle *data = conn->data;
+  curl_socket_t sockfd = CURL_SOCKET_BAD;
+  int aliasindex;
+  int num_addr;
+  Curl_addrinfo *ai;
+  Curl_addrinfo *curr_addr;
+
+  struct timeval after;
+  struct timeval before = Curl_tvnow();
+
+  /*************************************************************
+   * Figure out what maximum time we have left
+   *************************************************************/
+  long timeout_ms= DEFAULT_CONNECT_TIMEOUT;
+  long timeout_per_addr;
+
+  *connected = FALSE; /* default to not connected */
+
+  if(data->set.timeout || data->set.connecttimeout) {
+    long has_passed;
+
+    /* Evaluate in milliseconds how much time that has passed */
+    has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);
+
+#ifndef min
+#define min(a, b)   ((a) < (b) ? (a) : (b))
+#endif
+
+    /* get the most strict timeout of the ones converted to milliseconds */
+    if(data->set.timeout && data->set.connecttimeout) {
+      if (data->set.timeout < data->set.connecttimeout)
+        timeout_ms = data->set.timeout*1000;
+      else
+        timeout_ms = data->set.connecttimeout*1000;
+    }
+    else if(data->set.timeout)
+      timeout_ms = data->set.timeout*1000;
+    else
+      timeout_ms = data->set.connecttimeout*1000;
+
+    /* subtract the passed time */
+    timeout_ms -= has_passed;
+
+    if(timeout_ms < 0) {
+      /* a precaution, no need to continue if time already is up */
+      failf(data, "Connection time-out");
+      return CURLE_OPERATION_TIMEOUTED;
+    }
+  }
+
+  /* Max time for each address */
+  num_addr = Curl_num_addresses(remotehost->addr);
+  timeout_per_addr = timeout_ms / num_addr;
+
+  ai = remotehost->addr;
+
+  /* Below is the loop that attempts to connect to all IP-addresses we
+   * know for the given host. One by one until one IP succeeds.
+   */
+
+  if(data->state.used_interface == Curl_if_multi)
+    /* don't hang when doing multi */
+    timeout_per_addr = timeout_ms = 0;
+
+  /*
+   * Connecting with a Curl_addrinfo chain
+   */
+  for (curr_addr = ai, aliasindex=0; curr_addr;
+       curr_addr = curr_addr->ai_next, aliasindex++) {
+
+    /* start connecting to the IP curr_addr points to */
+    sockfd = singleipconnect(conn, curr_addr, timeout_per_addr, connected);
+
+    if(sockfd != CURL_SOCKET_BAD)
+      break;
+
+    /* get a new timeout for next attempt */
+    after = Curl_tvnow();
+    timeout_ms -= Curl_tvdiff(after, before);
+    if(timeout_ms < 0) {
+      failf(data, "connect() timed out!");
+      return CURLE_OPERATION_TIMEOUTED;
+    }
+    before = after;
+  }  /* end of connect-to-each-address loop */
+
+  if (sockfd == CURL_SOCKET_BAD) {
+    /* no good connect was made */
+    *sockconn = CURL_SOCKET_BAD;
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  /* leave the socket in non-blocking mode */
+
+  /* store the address we use */
+  if(addr)
+    *addr = curr_addr;
+
+  /* allow NULL-pointers to get passed in */
+  if(sockconn)
+    *sockconn = sockfd;    /* the socket descriptor we've connected */
+
+  return CURLE_OK;
+}
diff --git a/Utilities/cmcurl/connect.h b/Utilities/cmcurl/connect.h
new file mode 100644
index 0000000..d39495c
--- /dev/null
+++ b/Utilities/cmcurl/connect.h
@@ -0,0 +1,44 @@
+#ifndef __CONNECT_H
+#define __CONNECT_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+int Curl_nonblock(curl_socket_t sockfd,    /* operate on this */
+                  int nonblock   /* TRUE or FALSE */);
+
+CURLcode Curl_is_connected(struct connectdata *conn,
+                           int sockindex,
+                           bool *connected);
+
+CURLcode Curl_connecthost(struct connectdata *conn,
+                          struct Curl_dns_entry *host, /* connect to this */
+                          curl_socket_t *sockconn, /* not set if error */
+                          Curl_addrinfo **addr, /* the one we used */
+                          bool *connected /* truly connected? */
+                          );
+
+int Curl_ourerrno(void);
+
+#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
+
+#endif
diff --git a/Utilities/cmcurl/content_encoding.c b/Utilities/cmcurl/content_encoding.c
new file mode 100644
index 0000000..b8c68bd
--- /dev/null
+++ b/Utilities/cmcurl/content_encoding.c
@@ -0,0 +1,363 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#ifdef HAVE_LIBZ
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "sendf.h"
+#include "content_encoding.h"
+#include "curl_memory.h"
+
+#include "memdebug.h"
+
+#define DSIZ 0x10000             /* buffer size for decompressed data */
+
+#define GZIP_MAGIC_0 0x1f
+#define GZIP_MAGIC_1 0x8b
+
+/* gzip flag byte */
+#define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define COMMENT      0x10 /* bit 4 set: file comment present */
+#define RESERVED     0xE0 /* bits 5..7: reserved */
+
+static CURLcode
+process_zlib_error(struct SessionHandle *data, z_stream *z)
+{
+  if (z->msg)
+    failf (data, "Error while processing content unencoding.\n%s",
+           z->msg);
+  else
+    failf (data, "Error while processing content unencoding.\n"
+           "Unknown failure within decompression software.");
+
+  return CURLE_BAD_CONTENT_ENCODING;
+}
+
+static CURLcode
+exit_zlib(z_stream *z, bool *zlib_init, CURLcode result)
+{
+  inflateEnd(z);
+  *zlib_init = 0;
+  return result;
+}
+
+CURLcode
+Curl_unencode_deflate_write(struct SessionHandle *data,
+                            struct Curl_transfer_keeper *k,
+                            ssize_t nread)
+{
+  int status;                   /* zlib status */
+  CURLcode result = CURLE_OK;   /* Curl_client_write status */
+  char decomp[DSIZ];            /* Put the decompressed data here. */
+  z_stream *z = &k->z;          /* zlib state structure */
+
+  /* Initialize zlib? */
+  if (!k->zlib_init) {
+    z->zalloc = (alloc_func)Z_NULL;
+    z->zfree = (free_func)Z_NULL;
+    z->opaque = 0;
+    z->next_in = NULL;
+    z->avail_in = 0;
+    if (inflateInit(z) != Z_OK)
+      return process_zlib_error(data, z);
+    k->zlib_init = 1;
+  }
+
+  /* Set the compressed input when this function is called */
+  z->next_in = (Bytef *)k->str;
+  z->avail_in = (uInt)nread;
+
+  /* because the buffer size is fixed, iteratively decompress
+     and transfer to the client via client_write. */
+  for (;;) {
+    /* (re)set buffer for decompressed output for every iteration */
+    z->next_out = (Bytef *)&decomp[0];
+    z->avail_out = DSIZ;
+
+    status = inflate(z, Z_SYNC_FLUSH);
+    if (status == Z_OK || status == Z_STREAM_END) {
+      if (DSIZ - z->avail_out) {
+        result = Curl_client_write(data, CLIENTWRITE_BODY, decomp,
+                                   DSIZ - z->avail_out);
+        /* if !CURLE_OK, clean up, return */
+        if (result)
+          return exit_zlib(z, &k->zlib_init, result);
+      }
+
+      /* Done?; clean up, return */
+      if (status == Z_STREAM_END) {
+        if (inflateEnd(z) == Z_OK)
+          return exit_zlib(z, &k->zlib_init, result);
+        else
+          return exit_zlib(z, &k->zlib_init, process_zlib_error(data, z));
+      }
+
+      /* Done with these bytes, exit */
+      if (status == Z_OK && z->avail_in == 0 && z->avail_out > 0)
+        return result;
+    }
+    else {                      /* Error; exit loop, handle below */
+      return exit_zlib(z, &k->zlib_init, process_zlib_error(data, z));
+    }
+  }
+}
+
+/* Skip over the gzip header */
+static enum {
+  GZIP_OK,
+  GZIP_BAD,
+  GZIP_UNDERFLOW
+} check_gzip_header(unsigned char const *data, ssize_t len, ssize_t *headerlen)
+{
+  int method, flags;
+  const ssize_t totallen = len;
+
+  /* The shortest header is 10 bytes */
+  if (len < 10)
+    return GZIP_UNDERFLOW;
+
+  if ((data[0] != GZIP_MAGIC_0) || (data[1] != GZIP_MAGIC_1))
+    return GZIP_BAD;
+
+  method = data[2];
+  flags = data[3];
+
+  if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
+    /* Can't handle this compression method or unknown flag */
+    return GZIP_BAD;
+  }
+
+  /* Skip over time, xflags, OS code and all previous bytes */
+  len -= 10;
+  data += 10;
+
+  if (flags & EXTRA_FIELD) {
+    ssize_t extra_len;
+
+    if (len < 2)
+      return GZIP_UNDERFLOW;
+
+    extra_len = (data[1] << 8) | data[0];
+
+    if (len < (extra_len+2))
+      return GZIP_UNDERFLOW;
+
+    len -= (extra_len + 2);
+  }
+
+  if (flags & ORIG_NAME) {
+    /* Skip over NUL-terminated file name */
+    while (len && *data) {
+      --len;
+      ++data;
+    }
+    if (!len || *data)
+      return GZIP_UNDERFLOW;
+
+    /* Skip over the NUL */
+    --len;
+    ++data;
+  }
+
+  if (flags & COMMENT) {
+    /* Skip over NUL-terminated comment */
+    while (len && *data) {
+      --len;
+      ++data;
+    }
+    if (!len || *data)
+      return GZIP_UNDERFLOW;
+
+    /* Skip over the NUL */
+    --len;
+    ++data;
+  }
+
+  if (flags & HEAD_CRC) {
+    if (len < 2)
+      return GZIP_UNDERFLOW;
+
+    len -= 2;
+    data += 2;
+  }
+
+  *headerlen = totallen - len;
+  return GZIP_OK;
+}
+
+CURLcode
+Curl_unencode_gzip_write(struct SessionHandle *data,
+                         struct Curl_transfer_keeper *k,
+                         ssize_t nread)
+{
+  int status;                   /* zlib status */
+  CURLcode result = CURLE_OK;   /* Curl_client_write status */
+  char decomp[DSIZ];            /* Put the decompressed data here. */
+  z_stream *z = &k->z;          /* zlib state structure */
+
+  /* Initialize zlib? */
+  if (!k->zlib_init) {
+    z->zalloc = (alloc_func)Z_NULL;
+    z->zfree = (free_func)Z_NULL;
+    z->opaque = 0;
+    z->next_in = NULL;
+    z->avail_in = 0;
+    if (inflateInit2(z, -MAX_WBITS) != Z_OK)
+      return process_zlib_error(data, z);
+    k->zlib_init = 1;   /* Initial call state */
+  }
+
+  /* This next mess is to get around the potential case where there isn't
+   * enough data passed in to skip over the gzip header.  If that happens, we
+   * malloc a block and copy what we have then wait for the next call.  If
+   * there still isn't enough (this is definitely a worst-case scenario), we
+   * make the block bigger, copy the next part in and keep waiting.
+   */
+
+  /* Skip over gzip header? */
+  if (k->zlib_init == 1) {
+    /* Initial call state */
+    ssize_t hlen;
+
+    switch (check_gzip_header((unsigned char *)k->str, nread, &hlen)) {
+    case GZIP_OK:
+      z->next_in = (Bytef *)k->str + hlen;
+      z->avail_in = (uInt)(nread - hlen);
+      k->zlib_init = 3; /* Inflating stream state */
+      break;
+
+    case GZIP_UNDERFLOW:
+      /* We need more data so we can find the end of the gzip header.  It's
+       * possible that the memory block we malloc here will never be freed if
+       * the transfer abruptly aborts after this point.  Since it's unlikely
+       * that circumstances will be right for this code path to be followed in
+       * the first place, and it's even more unlikely for a transfer to fail
+       * immediately afterwards, it should seldom be a problem.
+       */
+      z->avail_in = (uInt)nread;
+      z->next_in = malloc(z->avail_in);
+      if (z->next_in == NULL) {
+        return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
+      }
+      memcpy(z->next_in, k->str, z->avail_in);
+      k->zlib_init = 2;   /* Need more gzip header data state */
+      /* We don't have any data to inflate yet */
+      return CURLE_OK;
+
+    case GZIP_BAD:
+    default:
+      return exit_zlib(z, &k->zlib_init, process_zlib_error(data, z));
+    }
+
+  }
+  else if (k->zlib_init == 2) {
+    /* Need more gzip header data state */
+    ssize_t hlen;
+    unsigned char *oldblock = z->next_in;
+
+    z->avail_in += nread;
+    z->next_in = realloc(z->next_in, z->avail_in);
+    if (z->next_in == NULL) {
+      free(oldblock);
+      return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
+    }
+    /* Append the new block of data to the previous one */
+    memcpy(z->next_in + z->avail_in - nread, k->str, nread);
+
+    switch (check_gzip_header(z->next_in, z->avail_in, &hlen)) {
+    case GZIP_OK:
+      /* This is the zlib stream data */
+      free(z->next_in);
+      /* Don't point into the malloced block since we just freed it */
+      z->next_in = (Bytef *)k->str + hlen + nread - z->avail_in;
+      z->avail_in = (uInt)(z->avail_in - hlen);
+      k->zlib_init = 3;   /* Inflating stream state */
+      break;
+
+    case GZIP_UNDERFLOW:
+      /* We still don't have any data to inflate! */
+      return CURLE_OK;
+
+    case GZIP_BAD:
+    default:
+      free(z->next_in);
+      return exit_zlib(z, &k->zlib_init, process_zlib_error(data, z));
+    }
+
+  }
+  else {
+    /* Inflating stream state */
+    z->next_in = (Bytef *)k->str;
+    z->avail_in = (uInt)nread;
+  }
+
+  if (z->avail_in == 0) {
+    /* We don't have any data to inflate; wait until next time */
+    return CURLE_OK;
+  }
+
+  /* because the buffer size is fixed, iteratively decompress and transfer to
+     the client via client_write. */
+  for (;;) {
+    /* (re)set buffer for decompressed output for every iteration */
+    z->next_out = (Bytef *)&decomp[0];
+    z->avail_out = DSIZ;
+
+    status = inflate(z, Z_SYNC_FLUSH);
+    if (status == Z_OK || status == Z_STREAM_END) {
+      if(DSIZ - z->avail_out) {
+        result = Curl_client_write(data, CLIENTWRITE_BODY, decomp,
+                                   DSIZ - z->avail_out);
+        /* if !CURLE_OK, clean up, return */
+        if (result)
+          return exit_zlib(z, &k->zlib_init, result);
+      }
+
+      /* Done?; clean up, return */
+      /* We should really check the gzip CRC here */
+      if (status == Z_STREAM_END) {
+        if (inflateEnd(z) == Z_OK)
+          return exit_zlib(z, &k->zlib_init, result);
+        else
+          return exit_zlib(z, &k->zlib_init, process_zlib_error(data, z));
+      }
+
+      /* Done with these bytes, exit */
+      if (status == Z_OK && z->avail_in == 0 && z->avail_out > 0)
+        return result;
+    }
+    else {                      /* Error; exit loop, handle below */
+      return exit_zlib(z, &k->zlib_init, process_zlib_error(data, z));
+    }
+  }
+}
+#endif /* HAVE_LIBZ */
diff --git a/Utilities/cmcurl/content_encoding.h b/Utilities/cmcurl/content_encoding.h
new file mode 100644
index 0000000..a65dbd2
--- /dev/null
+++ b/Utilities/cmcurl/content_encoding.h
@@ -0,0 +1,41 @@
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+#include "setup.h"
+
+/*
+ * Comma-separated list all supported Content-Encodings ('identity' is implied)
+ */
+#ifdef HAVE_LIBZ
+#define ALL_CONTENT_ENCODINGS "deflate, gzip"
+#else
+#define ALL_CONTENT_ENCODINGS "identity"
+#endif
+
+CURLcode Curl_unencode_deflate_write(struct SessionHandle *data, 
+                                     struct Curl_transfer_keeper *k, 
+                                     ssize_t nread);
+
+CURLcode
+Curl_unencode_gzip_write(struct SessionHandle *data, 
+                         struct Curl_transfer_keeper *k,
+                         ssize_t nread);
diff --git a/Utilities/cmcurl/cookie.c b/Utilities/cmcurl/cookie.c
new file mode 100644
index 0000000..3ba5627
--- /dev/null
+++ b/Utilities/cmcurl/cookie.c
@@ -0,0 +1,879 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/***
+
+
+RECEIVING COOKIE INFORMATION
+============================
+
+struct CookieInfo *cookie_init(char *file);
+
+        Inits a cookie struct to store data in a local file. This is always
+        called before any cookies are set.
+
+int cookies_set(struct CookieInfo *cookie, char *cookie_line);
+
+        The 'cookie_line' parameter is a full "Set-cookie:" line as
+        received from a server.
+
+        The function need to replace previously stored lines that this new
+        line superceeds.
+
+        It may remove lines that are expired.
+
+        It should return an indication of success/error.
+
+
+SENDING COOKIE INFORMATION
+==========================
+
+struct Cookies *cookie_getlist(struct CookieInfo *cookie,
+                               char *host, char *path, bool secure);
+
+        For a given host and path, return a linked list of cookies that
+        the client should send to the server if used now. The secure
+        boolean informs the cookie if a secure connection is achieved or
+        not.
+
+        It shall only return cookies that haven't expired.
+
+
+Example set of cookies:
+
+    Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure
+    Set-cookie: PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
+    domain=.fidelity.com; path=/ftgw; secure
+    Set-cookie: FidHist=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
+    domain=.fidelity.com; path=/; secure
+    Set-cookie: FidOrder=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
+    domain=.fidelity.com; path=/; secure
+    Set-cookie: DisPend=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
+    domain=.fidelity.com; path=/; secure
+    Set-cookie: FidDis=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
+    domain=.fidelity.com; path=/; secure
+    Set-cookie:
+    Session_Key@6791a9e0-901a-11d0-a1c8-9b012c88aa77=none;expires=Monday,
+    13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure
+****/
+
+
+#include "setup.h"
+
+#ifndef CURL_DISABLE_HTTP
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "urldata.h"
+#include "cookie.h"
+#include "getdate.h"
+#include "strequal.h"
+#include "strtok.h"
+#include "sendf.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#ifdef CURLDEBUG
+#include "memdebug.h"
+#endif
+
+static void freecookie(struct Cookie *co)
+{
+  if(co->expirestr)
+    free(co->expirestr);
+  if(co->domain)
+    free(co->domain);
+  if(co->path)
+    free(co->path);
+  if(co->name)
+    free(co->name);
+  if(co->value)
+    free(co->value);
+
+  free(co);
+}
+
+static bool tailmatch(const char *little, const char *bigone)
+{
+  size_t littlelen = strlen(little);
+  size_t biglen = strlen(bigone);
+
+  if(littlelen > biglen)
+    return FALSE;
+
+  return (bool)strequal(little, bigone+biglen-littlelen);
+}
+
+/****************************************************************************
+ *
+ * Curl_cookie_add()
+ *
+ * Add a single cookie line to the cookie keeping object.
+ *
+ ***************************************************************************/
+
+struct Cookie *
+Curl_cookie_add(struct SessionHandle *data,
+                /* The 'data' pointer here may be NULL at times, and thus
+                   must only be used very carefully for things that can deal
+                   with data being NULL. Such as infof() and similar */
+
+                struct CookieInfo *c,
+                bool httpheader, /* TRUE if HTTP header-style line */
+                char *lineptr,   /* first character of the line */
+                char *domain,    /* default domain */
+                char *path)      /* full path used when this cookie is set,
+                                    used to get default path for the cookie
+                                    unless set */
+{
+  struct Cookie *clist;
+  char *what;
+  char name[MAX_NAME];
+  char *ptr;
+  char *semiptr;
+  struct Cookie *co;
+  struct Cookie *lastc=NULL;
+  time_t now = time(NULL);
+  bool replace_old;
+  bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
+
+  /* First, alloc and init a new struct for it */
+  co = (struct Cookie *)calloc(sizeof(struct Cookie), 1);
+  if(!co)
+    return NULL; /* bail out if we're this low on memory */
+
+  if(httpheader) {
+    /* This line was read off a HTTP-header */
+    char *sep;
+
+    what = malloc(MAX_COOKIE_LINE);
+    if(!what) {
+      free(co);
+      return NULL;
+    }
+
+    semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
+
+    while(*lineptr && isspace((int)*lineptr))
+      lineptr++;
+
+    ptr = lineptr;
+    do {
+      /* we have a <what>=<this> pair or a 'secure' word here */
+      sep = strchr(ptr, '=');
+      if(sep && (!semiptr || (semiptr>sep)) ) {
+        /*
+         * There is a = sign and if there was a semicolon too, which make sure
+         * that the semicolon comes _after_ the equal sign.
+         */
+
+        name[0]=what[0]=0; /* init the buffers */
+        if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;=]=%"
+                       MAX_COOKIE_LINE_TXT "[^;\r\n]",
+                       name, what)) {
+          /* this is a <name>=<what> pair */
+
+          char *whatptr;
+
+          /* Strip off trailing whitespace from the 'what' */
+          size_t len=strlen(what);
+          while(len && isspace((int)what[len-1])) {
+            what[len-1]=0;
+            len--;
+          }
+
+          /* Skip leading whitespace from the 'what' */
+          whatptr=what;
+          while(isspace((int)*whatptr)) {
+            whatptr++;
+          }
+
+          if(strequal("path", name)) {
+            co->path=strdup(whatptr);
+            if(!co->path) {
+              badcookie = TRUE; /* out of memory bad */
+              break;
+            }
+          }
+          else if(strequal("domain", name)) {
+            /* note that this name may or may not have a preceeding dot, but
+               we don't care about that, we treat the names the same anyway */
+
+            const char *domptr=whatptr;
+            int dotcount=1;
+
+            /* Count the dots, we need to make sure that there are enough
+               of them. */
+
+            if('.' == whatptr[0])
+              /* don't count the initial dot, assume it */
+              domptr++;
+
+            do {
+              domptr = strchr(domptr, '.');
+              if(domptr) {
+                domptr++;
+                dotcount++;
+              }
+            } while(domptr);
+
+            /* The original Netscape cookie spec defined that this domain name
+               MUST have three dots (or two if one of the seven holy TLDs),
+               but it seems that these kinds of cookies are in use "out there"
+               so we cannot be that strict. I've therefore lowered the check
+               to not allow less than two dots. */
+
+            if(dotcount < 2) {
+              /* Received and skipped a cookie with a domain using too few
+                 dots. */
+              badcookie=TRUE; /* mark this as a bad cookie */
+              infof(data, "skipped cookie with illegal dotcount domain: %s\n",
+                    whatptr);
+            }
+            else {
+              /* Now, we make sure that our host is within the given domain,
+                 or the given domain is not valid and thus cannot be set. */
+
+              if('.' == whatptr[0])
+                whatptr++; /* ignore preceeding dot */
+
+              if(!domain || tailmatch(whatptr, domain)) {
+                const char *tailptr=whatptr;
+                if(tailptr[0] == '.')
+                  tailptr++;
+                co->domain=strdup(tailptr); /* don't prefix w/dots
+                                               internally */
+                if(!co->domain) {
+                  badcookie = TRUE;
+                  break;
+                }
+                co->tailmatch=TRUE; /* we always do that if the domain name was
+                                       given */
+              }
+              else {
+                /* we did not get a tailmatch and then the attempted set domain
+                   is not a domain to which the current host belongs. Mark as
+                   bad. */
+                badcookie=TRUE;
+                infof(data, "skipped cookie with bad tailmatch domain: %s\n",
+                      whatptr);
+              }
+            }
+          }
+          else if(strequal("version", name)) {
+            co->version=strdup(whatptr);
+            if(!co->version) {
+              badcookie = TRUE;
+              break;
+            }
+          }
+          else if(strequal("max-age", name)) {
+            /* Defined in RFC2109:
+
+               Optional.  The Max-Age attribute defines the lifetime of the
+               cookie, in seconds.  The delta-seconds value is a decimal non-
+               negative integer.  After delta-seconds seconds elapse, the
+               client should discard the cookie.  A value of zero means the
+               cookie should be discarded immediately.
+
+             */
+            co->maxage = strdup(whatptr);
+            if(!co->maxage) {
+              badcookie = TRUE;
+              break;
+            }
+            co->expires =
+              atoi((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0]) + now;
+          }
+          else if(strequal("expires", name)) {
+            co->expirestr=strdup(whatptr);
+            if(!co->expirestr) {
+              badcookie = TRUE;
+              break;
+            }
+            co->expires = curl_getdate(what, &now);
+          }
+          else if(!co->name) {
+            co->name = strdup(name);
+            co->value = strdup(whatptr);
+            if(!co->name || !co->value) {
+              badcookie = TRUE;
+              break;
+            }
+          }
+          /*
+            else this is the second (or more) name we don't know
+            about! */
+        }
+        else {
+          /* this is an "illegal" <what>=<this> pair */
+        }
+      }
+      else {
+        if(sscanf(ptr, "%" MAX_COOKIE_LINE_TXT "[^;\r\n]",
+                  what)) {
+          if(strequal("secure", what))
+            co->secure = TRUE;
+          /* else,
+             unsupported keyword without assign! */
+
+        }
+      }
+      if(!semiptr || !*semiptr) {
+        /* we already know there are no more cookies */
+        semiptr = NULL;
+        continue;
+      }
+
+      ptr=semiptr+1;
+      while(ptr && *ptr && isspace((int)*ptr))
+        ptr++;
+      semiptr=strchr(ptr, ';'); /* now, find the next semicolon */
+
+      if(!semiptr && *ptr)
+        /* There are no more semicolons, but there's a final name=value pair
+           coming up */
+        semiptr=strchr(ptr, '\0');
+    } while(semiptr);
+
+    if(!badcookie && !co->domain) {
+      if(domain) {
+        /* no domain was given in the header line, set the default */
+        co->domain=strdup(domain);
+        if(!co->domain)
+          badcookie = TRUE;
+      }
+    }
+
+    if(!badcookie && !co->path && path) {
+      /* no path was given in the header line, set the default  */
+      char *endslash = strrchr(path, '/');
+      if(endslash) {
+        size_t pathlen = endslash-path+1; /* include the ending slash */
+        co->path=malloc(pathlen+1); /* one extra for the zero byte */
+        if(co->path) {
+          memcpy(co->path, path, pathlen);
+          co->path[pathlen]=0; /* zero terminate */
+        }
+        else
+          badcookie = TRUE;
+      }
+    }
+
+    free(what);
+
+    if(badcookie || !co->name) {
+      /* we didn't get a cookie name or a bad one,
+         this is an illegal line, bail out */
+      freecookie(co);
+      return NULL;
+    }
+
+  }
+  else {
+    /* This line is NOT a HTTP header style line, we do offer support for
+       reading the odd netscape cookies-file format here */
+    char *firstptr;
+    char *tok_buf;
+    int fields;
+
+    if(lineptr[0]=='#') {
+      /* don't even try the comments */
+      free(co);
+      return NULL;
+    }
+    /* strip off the possible end-of-line characters */
+    ptr=strchr(lineptr, '\r');
+    if(ptr)
+      *ptr=0; /* clear it */
+    ptr=strchr(lineptr, '\n');
+    if(ptr)
+      *ptr=0; /* clear it */
+
+    firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
+
+    /* Here's a quick check to eliminate normal HTTP-headers from this */
+    if(!firstptr || strchr(firstptr, ':')) {
+      free(co);
+      return NULL;
+    }
+
+    /* Now loop through the fields and init the struct we already have
+       allocated */
+    for(ptr=firstptr, fields=0; ptr && !badcookie;
+        ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
+      switch(fields) {
+      case 0:
+        if(ptr[0]=='.') /* skip preceeding dots */
+          ptr++;
+        co->domain = strdup(ptr);
+        if(!co->domain)
+          badcookie = TRUE;
+        break;
+      case 1:
+        /* This field got its explanation on the 23rd of May 2001 by
+           Andr�s Garc�a:
+
+           flag: A TRUE/FALSE value indicating if all machines within a given
+           domain can access the variable. This value is set automatically by
+           the browser, depending on the value you set for the domain.
+
+           As far as I can see, it is set to true when the cookie says
+           .domain.com and to false when the domain is complete www.domain.com
+        */
+        co->tailmatch=(bool)strequal(ptr, "TRUE"); /* store information */
+        break;
+      case 2:
+        /* It turns out, that sometimes the file format allows the path
+           field to remain not filled in, we try to detect this and work
+           around it! Andr�s Garc�a made us aware of this... */
+        if (strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
+          /* only if the path doesn't look like a boolean option! */
+          co->path = strdup(ptr);
+          if(!co->path)
+            badcookie = TRUE;
+          break;
+        }
+        /* this doesn't look like a path, make one up! */
+        co->path = strdup("/");
+        if(!co->path)
+          badcookie = TRUE;
+        fields++; /* add a field and fall down to secure */
+        /* FALLTHROUGH */
+      case 3:
+        co->secure = (bool)strequal(ptr, "TRUE");
+        break;
+      case 4:
+        co->expires = atoi(ptr);
+        break;
+      case 5:
+        co->name = strdup(ptr);
+        if(!co->name)
+          badcookie = TRUE;
+        break;
+      case 6:
+        co->value = strdup(ptr);
+        if(!co->value)
+          badcookie = TRUE;
+        break;
+      }
+    }
+    if(6 == fields) {
+      /* we got a cookie with blank contents, fix it */
+      co->value = strdup("");
+      if(!co->value)
+        badcookie = TRUE;
+      else
+        fields++;
+    }
+
+    if(!badcookie && (7 != fields))
+      /* we did not find the sufficient number of fields */
+      badcookie = TRUE;
+
+    if(badcookie) {
+      freecookie(co);
+      return NULL;
+    }
+
+  }
+
+  if(!c->running &&    /* read from a file */
+     c->newsession &&  /* clean session cookies */
+     !co->expires) {   /* this is a session cookie since it doesn't expire! */
+    freecookie(co);
+    return NULL;
+  }
+
+  co->livecookie = c->running;
+
+  /* now, we have parsed the incoming line, we must now check if this
+     superceeds an already existing cookie, which it may if the previous have
+     the same domain and path as this */
+
+  clist = c->cookies;
+  replace_old = FALSE;
+  while(clist) {
+    if(strequal(clist->name, co->name)) {
+      /* the names are identical */
+
+      if(clist->domain && co->domain) {
+        if(strequal(clist->domain, co->domain))
+          /* The domains are identical */
+          replace_old=TRUE;
+      }
+      else if(!clist->domain && !co->domain)
+        replace_old = TRUE;
+
+      if(replace_old) {
+        /* the domains were identical */
+
+        if(clist->path && co->path) {
+          if(strequal(clist->path, co->path)) {
+            replace_old = TRUE;
+          }
+          else
+            replace_old = FALSE;
+        }
+        else if(!clist->path && !co->path)
+          replace_old = TRUE;
+        else
+          replace_old = FALSE;
+
+      }
+
+      if(replace_old && !co->livecookie && clist->livecookie) {
+        /* Both cookies matched fine, except that the already present
+           cookie is "live", which means it was set from a header, while
+           the new one isn't "live" and thus only read from a file. We let
+           live cookies stay alive */
+
+        /* Free the newcomer and get out of here! */
+        freecookie(co);
+        return NULL;
+      }
+
+      if(replace_old) {
+        co->next = clist->next; /* get the next-pointer first */
+
+        /* then free all the old pointers */
+        if(clist->name)
+          free(clist->name);
+        if(clist->value)
+          free(clist->value);
+        if(clist->domain)
+          free(clist->domain);
+        if(clist->path)
+          free(clist->path);
+        if(clist->expirestr)
+          free(clist->expirestr);
+
+        if(clist->version)
+          free(clist->version);
+        if(clist->maxage)
+          free(clist->maxage);
+
+        *clist = *co;  /* then store all the new data */
+
+        free(co);   /* free the newly alloced memory */
+        co = clist; /* point to the previous struct instead */
+
+        /* We have replaced a cookie, now skip the rest of the list but
+           make sure the 'lastc' pointer is properly set */
+        do {
+          lastc = clist;
+          clist = clist->next;
+        } while(clist);
+        break;
+      }
+    }
+    lastc = clist;
+    clist = clist->next;
+  }
+
+  if(c->running)
+    /* Only show this when NOT reading the cookies from a file */
+    infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, expire %d\n",
+          replace_old?"Replaced":"Added", co->name, co->value,
+          co->domain, co->path, co->expires);
+
+  if(!replace_old) {
+    /* then make the last item point on this new one */
+    if(lastc)
+      lastc->next = co;
+    else
+      c->cookies = co;
+  }
+
+  c->numcookies++; /* one more cookie in the jar */
+  return co;
+}
+
+/*****************************************************************************
+ *
+ * Curl_cookie_init()
+ *
+ * Inits a cookie struct to read data from a local file. This is always
+ * called before any cookies are set. File may be NULL.
+ *
+ * If 'newsession' is TRUE, discard all "session cookies" on read from file.
+ *
+ ****************************************************************************/
+struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
+                                    char *file,
+                                    struct CookieInfo *inc,
+                                    bool newsession)
+{
+  struct CookieInfo *c;
+  FILE *fp;
+  bool fromfile=TRUE;
+
+  if(NULL == inc) {
+    /* we didn't get a struct, create one */
+    c = (struct CookieInfo *)calloc(1, sizeof(struct CookieInfo));
+    if(!c)
+      return NULL; /* failed to get memory */
+    c->filename = strdup(file?file:"none"); /* copy the name just in case */
+  }
+  else {
+    /* we got an already existing one, use that */
+    c = inc;
+  }
+  c->running = FALSE; /* this is not running, this is init */
+
+  if(file && strequal(file, "-")) {
+    fp = stdin;
+    fromfile=FALSE;
+  }
+  else
+    fp = file?fopen(file, "r"):NULL;
+
+  c->newsession = newsession; /* new session? */
+
+  if(fp) {
+    char *lineptr;
+    bool headerline;
+
+    char *line = (char *)malloc(MAX_COOKIE_LINE);
+    if(line) {
+      while(fgets(line, MAX_COOKIE_LINE, fp)) {
+        if(checkprefix("Set-Cookie:", line)) {
+          /* This is a cookie line, get it! */
+          lineptr=&line[11];
+          headerline=TRUE;
+        }
+        else {
+          lineptr=line;
+          headerline=FALSE;
+        }
+        while(*lineptr && isspace((int)*lineptr))
+          lineptr++;
+
+        Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL);
+      }
+      free(line); /* free the line buffer */
+    }
+    if(fromfile)
+      fclose(fp);
+  }
+
+  c->running = TRUE;          /* now, we're running */
+
+  return c;
+}
+
+/*****************************************************************************
+ *
+ * Curl_cookie_getlist()
+ *
+ * For a given host and path, return a linked list of cookies that the
+ * client should send to the server if used now. The secure boolean informs
+ * the cookie if a secure connection is achieved or not.
+ *
+ * It shall only return cookies that haven't expired.
+ *
+ ****************************************************************************/
+
+struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
+                                   char *host, char *path, bool secure)
+{
+   struct Cookie *newco;
+   struct Cookie *co;
+   time_t now = time(NULL);
+   struct Cookie *mainco=NULL;
+
+   if(!c || !c->cookies)
+      return NULL; /* no cookie struct or no cookies in the struct */
+
+   co = c->cookies;
+
+   while(co) {
+     /* only process this cookie if it is not expired or had no expire
+        date AND that if the cookie requires we're secure we must only
+        continue if we are! */
+     if( (co->expires<=0 || (co->expires> now)) &&
+         (co->secure?secure:TRUE) ) {
+
+       /* now check if the domain is correct */
+       if(!co->domain ||
+          (co->tailmatch && tailmatch(co->domain, host)) ||
+          (!co->tailmatch && strequal(host, co->domain)) ) {
+         /* the right part of the host matches the domain stuff in the
+            cookie data */
+
+         /* now check the left part of the path with the cookies path
+            requirement */
+         if(!co->path ||
+            checkprefix(co->path, path) ) {
+
+           /* and now, we know this is a match and we should create an
+              entry for the return-linked-list */
+
+           newco = (struct Cookie *)malloc(sizeof(struct Cookie));
+           if(newco) {
+             /* first, copy the whole source cookie: */
+             memcpy(newco, co, sizeof(struct Cookie));
+
+             /* then modify our next */
+             newco->next = mainco;
+
+             /* point the main to us */
+             mainco = newco;
+           }
+           else {
+              /* failure, clear up the allocated chain and return NULL */
+             while(mainco) {
+               co = mainco->next;
+               free(mainco);
+               mainco = co;
+             }
+
+             return NULL;
+           }
+         }
+       }
+     }
+     co = co->next;
+   }
+
+   return mainco; /* return the new list */
+}
+
+
+/*****************************************************************************
+ *
+ * Curl_cookie_freelist()
+ *
+ * Free a list of cookies previously returned by Curl_cookie_getlist();
+ *
+ ****************************************************************************/
+
+void Curl_cookie_freelist(struct Cookie *co)
+{
+   struct Cookie *next;
+   if(co) {
+      while(co) {
+         next = co->next;
+         free(co); /* we only free the struct since the "members" are all
+                      just copied! */
+         co = next;
+      }
+   }
+}
+
+/*****************************************************************************
+ *
+ * Curl_cookie_cleanup()
+ *
+ * Free a "cookie object" previous created with cookie_init().
+ *
+ ****************************************************************************/
+void Curl_cookie_cleanup(struct CookieInfo *c)
+{
+   struct Cookie *co;
+   struct Cookie *next;
+   if(c) {
+      if(c->filename)
+         free(c->filename);
+      co = c->cookies;
+
+      while(co) {
+         next = co->next;
+         freecookie(co);
+         co = next;
+      }
+      free(c); /* free the base struct as well */
+   }
+}
+
+/*
+ * Curl_cookie_output()
+ *
+ * Writes all internally known cookies to the specified file. Specify
+ * "-" as file name to write to stdout.
+ *
+ * The function returns non-zero on write failure.
+ */
+int Curl_cookie_output(struct CookieInfo *c, char *dumphere)
+{
+  struct Cookie *co;
+  FILE *out;
+  bool use_stdout=FALSE;
+
+  if((NULL == c) || (0 == c->numcookies))
+    /* If there are no known cookies, we don't write or even create any
+       destination file */
+    return 0;
+
+  if(strequal("-", dumphere)) {
+    /* use stdout */
+    out = stdout;
+    use_stdout=TRUE;
+  }
+  else {
+    out = fopen(dumphere, "w");
+    if(!out)
+      return 1; /* failure */
+  }
+
+  if(c) {
+    fputs("# Netscape HTTP Cookie File\n"
+          "# http://www.netscape.com/newsref/std/cookie_spec.html\n"
+          "# This file was generated by libcurl! Edit at your own risk.\n\n",
+          out);
+    co = c->cookies;
+
+    while(co) {
+      fprintf(out,
+              "%s%s\t" /* domain */
+              "%s\t" /* tailmatch */
+              "%s\t" /* path */
+              "%s\t" /* secure */
+              "%u\t" /* expires */
+              "%s\t" /* name */
+              "%s\n", /* value */
+
+              /* Make sure all domains are prefixed with a dot if they allow
+                 tailmatching. This is Mozilla-style. */
+              (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
+              co->domain?co->domain:"unknown",
+              co->tailmatch?"TRUE":"FALSE",
+              co->path?co->path:"/",
+              co->secure?"TRUE":"FALSE",
+              (unsigned int)co->expires,
+              co->name,
+              co->value?co->value:"");
+
+      co=co->next;
+    }
+  }
+
+  if(!use_stdout)
+    fclose(out);
+
+  return 0;
+}
+
+#endif /* CURL_DISABLE_HTTP */
diff --git a/Utilities/cmcurl/cookie.h b/Utilities/cmcurl/cookie.h
new file mode 100644
index 0000000..6f8e8e5
--- /dev/null
+++ b/Utilities/cmcurl/cookie.h
@@ -0,0 +1,95 @@
+#ifndef __COOKIE_H
+#define __COOKIE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include <stdio.h>
+#ifdef WIN32
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif
+
+#include <curl/curl.h>
+
+struct Cookie {
+  struct Cookie *next; /* next in the chain */
+  char *name;        /* <this> = value */
+  char *value;       /* name = <this> */
+  char *path;         /* path = <this> */
+  char *domain;      /* domain = <this> */
+  long expires;    /* expires = <this> */
+  char *expirestr;   /* the plain text version */
+  bool tailmatch;    /* weather we do tail-matchning of the domain name */
+
+  /* RFC 2109 keywords. Version=1 means 2109-compliant cookie sending */
+  char *version;     /* Version = <value> */
+  char *maxage;      /* Max-Age = <value> */
+
+  bool secure;       /* whether the 'secure' keyword was used */
+  bool livecookie;   /* updated from a server, not a stored file */
+};
+
+struct CookieInfo {
+  /* linked list of cookies we know of */
+  struct Cookie *cookies;
+
+  char *filename;  /* file we read from/write to */
+  bool running;    /* state info, for cookie adding information */
+  long numcookies; /* number of cookies in the "jar" */
+  bool newsession; /* new session, discard session cookies on load */
+};
+
+/* This is the maximum line length we accept for a cookie line. RFC 2109
+   section 6.3 says:
+
+   "at least 4096 bytes per cookie (as measured by the size of the characters
+   that comprise the cookie non-terminal in the syntax description of the
+   Set-Cookie header)"
+
+*/
+#define MAX_COOKIE_LINE 5000
+#define MAX_COOKIE_LINE_TXT "4999"
+
+/* This is the maximum length of a cookie name we deal with: */
+#define MAX_NAME 1024
+#define MAX_NAME_TXT "1023"
+
+struct SessionHandle;
+/*
+ * Add a cookie to the internal list of cookies. The domain and path arguments
+ * are only used if the header boolean is TRUE.
+ */
+
+struct Cookie *Curl_cookie_add(struct SessionHandle *data,
+                               struct CookieInfo *, bool header, char *line,
+                               char *domain, char *path);
+
+struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
+                                    char *, struct CookieInfo *, bool);
+struct Cookie *Curl_cookie_getlist(struct CookieInfo *, char *, char *, bool);
+void Curl_cookie_freelist(struct Cookie *);
+void Curl_cookie_cleanup(struct CookieInfo *);
+int Curl_cookie_output(struct CookieInfo *, char *);
+
+#endif
diff --git a/Utilities/cmcurl/curl.copyright b/Utilities/cmcurl/curl.copyright
new file mode 100644
index 0000000..16ea773
--- /dev/null
+++ b/Utilities/cmcurl/curl.copyright
@@ -0,0 +1,25 @@
+This package was cmakified by Andy Cedilnik <andy . cedilnik @ kitware.com> 
+
+It was downloaded from http://curl.haxx.se
+
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright (c) 1996 - 2004, Daniel Stenberg, <daniel@haxx.se>.
+
+All rights reserved.
+
+Permission to use, copy, modify, and distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright
+notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
+NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder shall not
+be used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization of the copyright holder.
diff --git a/Utilities/cmcurl/curl/curl.h b/Utilities/cmcurl/curl/curl.h
new file mode 100644
index 0000000..96c8fcc
--- /dev/null
+++ b/Utilities/cmcurl/curl/curl.h
@@ -0,0 +1,1340 @@
+#ifndef __CURL_CURL_H
+#define __CURL_CURL_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/* If you have problems, all libcurl docs and details are found here:
+   http://curl.haxx.se/libcurl/
+*/
+
+#include "curlver.h" /* the libcurl version defines */
+
+#include <stdio.h>
+#include <limits.h>
+
+/* The include stuff here below is mainly for time_t! */
+#ifdef vms
+# include <types.h>
+# include <time.h>
+#else
+# include <sys/types.h>
+# include <time.h>
+#endif /* defined (vms) */
+
+typedef void CURL;
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/*
+ * We want the typedef curl_off_t setup for large file support on all
+ * platforms. We also provide a CURL_FORMAT_OFF_T define to use in *printf
+ * format strings when outputting a variable of type curl_off_t.
+ */
+#if defined(_MSC_VER) || defined(__LCC__)
+/* MSVC */
+  typedef signed __int64 curl_off_t;
+#define CURL_FORMAT_OFF_T "%I64d"
+#else /* _MSC_VER || __LCC__ */
+#if (defined(__GNUC__) && defined(WIN32)) || defined(__WATCOMC__)
+/* gcc on windows or Watcom */
+  typedef long long curl_off_t;
+#define CURL_FORMAT_OFF_T "%I64d"
+#else /* GCC or Watcom on Windows  */
+
+/* "normal" POSIX approach, do note that this does not necessarily mean that
+   the type is >32 bits, see the SIZEOF_CURL_OFF_T define for that! */
+  typedef off_t curl_off_t;
+
+/* Check a range of defines to detect large file support. On Linux it seems
+   none of these are set by default, so if you don't explicitly switches on
+   large file support, this define will be made for "small file" support. */
+#ifndef _FILE_OFFSET_BITS
+#define _FILE_OFFSET_BITS 0 /* to prevent warnings in the check below */
+#define UNDEF_FILE_OFFSET_BITS
+#endif
+#ifndef FILESIZEBITS
+#define FILESIZEBITS 0 /* to prevent warnings in the check below */
+#define UNDEF_FILESIZEBITS
+#endif
+
+#if defined(_LARGE_FILES) || (_FILE_OFFSET_BITS > 32) || (FILESIZEBITS > 32) \
+   || defined(_LARGEFILE_SOURCE) || defined(_LARGEFILE64_SOURCE)
+  /* For now, we assume at least one of these to be set for large files to
+     work! */
+#define CURL_FORMAT_OFF_T "%lld"
+#else /* LARGE_FILE support */
+#define CURL_FORMAT_OFF_T "%ld"
+#endif
+#endif /* GCC or Watcom on Windows */
+#endif /* _MSC_VER || __LCC__ */
+
+#ifdef UNDEF_FILE_OFFSET_BITS
+/* this was defined above for our checks, undefine it again */
+#undef _FILE_OFFSET_BITS
+#endif
+
+#ifdef UNDEF_FILESIZEBITS
+/* this was defined above for our checks, undefine it again */
+#undef FILESIZEBITS
+#endif
+
+struct curl_httppost {
+  struct curl_httppost *next;       /* next entry in the list */
+  char *name;                       /* pointer to allocated name */
+  long namelength;                  /* length of name length */
+  char *contents;                   /* pointer to allocated data contents */
+  long contentslength;              /* length of contents field */
+  char *buffer;                     /* pointer to allocated buffer contents */
+  long bufferlength;                /* length of buffer field */
+  char *contenttype;                /* Content-Type */
+  struct curl_slist* contentheader; /* list of extra headers for this form */
+  struct curl_httppost *more;       /* if one field name has more than one
+                                       file, this link should link to following
+                                       files */
+  long flags;                       /* as defined below */
+#define HTTPPOST_FILENAME (1<<0)    /* specified content is a file name */
+#define HTTPPOST_READFILE (1<<1)    /* specified content is a file name */
+#define HTTPPOST_PTRNAME (1<<2)     /* name is only stored pointer
+                                       do not free in formfree */
+#define HTTPPOST_PTRCONTENTS (1<<3) /* contents is only stored pointer
+                                       do not free in formfree */
+#define HTTPPOST_BUFFER (1<<4)      /* upload file from buffer */
+#define HTTPPOST_PTRBUFFER (1<<5)   /* upload file from pointer contents */
+
+  char *showfilename;               /* The file name to show. If not set, the
+                                       actual file name will be used (if this
+                                       is a file part) */
+};
+
+typedef int (*curl_progress_callback)(void *clientp,
+                                      double dltotal,
+                                      double dlnow,
+                                      double ultotal,
+                                      double ulnow);
+
+  /* Tests have proven that 20K is a very bad buffer size for uploads on
+     Windows, while 16K for some odd reason performed a lot better. */
+#define CURL_MAX_WRITE_SIZE 16384
+
+typedef size_t (*curl_write_callback)(char *buffer,
+                                      size_t size,
+                                      size_t nitems,
+                                      void *outstream);
+
+/* This is a brand new return code for the read callback that will signal
+   the caller to immediately abort the current transfer. */
+#define CURL_READFUNC_ABORT 0x10000000
+typedef size_t (*curl_read_callback)(char *buffer,
+                                     size_t size,
+                                     size_t nitems,
+                                     void *instream);
+
+  /* not used since 7.10.8, will be removed in a future release */
+typedef int (*curl_passwd_callback)(void *clientp,
+                                    const char *prompt,
+                                    char *buffer,
+                                    int buflen);
+
+/*
+ * The following typedef's are signatures of malloc, free, realloc, strdup and
+ * calloc respectively.  Function pointers of these types can be passed to the
+ * curl_global_init_mem() function to set user defined memory management
+ * callback routines.
+ */
+typedef void *(*curl_malloc_callback)(size_t size);
+typedef void (*curl_free_callback)(void *ptr);
+typedef void *(*curl_realloc_callback)(void *ptr, size_t size);
+typedef char *(*curl_strdup_callback)(const char *str);
+typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size);
+
+/* the kind of data that is passed to information_callback*/
+typedef enum {
+  CURLINFO_TEXT = 0,
+  CURLINFO_HEADER_IN,    /* 1 */
+  CURLINFO_HEADER_OUT,   /* 2 */
+  CURLINFO_DATA_IN,      /* 3 */
+  CURLINFO_DATA_OUT,     /* 4 */
+  CURLINFO_SSL_DATA_IN,  /* 5 */
+  CURLINFO_SSL_DATA_OUT, /* 6 */
+  CURLINFO_END
+} curl_infotype;
+
+typedef int (*curl_debug_callback)
+       (CURL *handle,      /* the handle/transfer this concerns */
+        curl_infotype type, /* what kind of data */
+        char *data,        /* points to the data */
+        size_t size,       /* size of the data pointed to */
+        void *userptr);    /* whatever the user please */
+
+/* All possible error codes from all sorts of curl functions. Future versions
+   may return other values, stay prepared.
+
+   Always add new return codes last. Never *EVER* remove any. The return
+   codes must remain the same!
+ */
+
+typedef enum {
+  CURLE_OK = 0,
+  CURLE_UNSUPPORTED_PROTOCOL,    /* 1 */
+  CURLE_FAILED_INIT,             /* 2 */
+  CURLE_URL_MALFORMAT,           /* 3 */
+  CURLE_URL_MALFORMAT_USER,      /* 4 (NOT USED) */
+  CURLE_COULDNT_RESOLVE_PROXY,   /* 5 */
+  CURLE_COULDNT_RESOLVE_HOST,    /* 6 */
+  CURLE_COULDNT_CONNECT,         /* 7 */
+  CURLE_FTP_WEIRD_SERVER_REPLY,  /* 8 */
+  CURLE_FTP_ACCESS_DENIED,       /* 9 */
+  CURLE_FTP_USER_PASSWORD_INCORRECT, /* 10 */
+  CURLE_FTP_WEIRD_PASS_REPLY,    /* 11 */
+  CURLE_FTP_WEIRD_USER_REPLY,    /* 12 */
+  CURLE_FTP_WEIRD_PASV_REPLY,    /* 13 */
+  CURLE_FTP_WEIRD_227_FORMAT,    /* 14 */
+  CURLE_FTP_CANT_GET_HOST,       /* 15 */
+  CURLE_FTP_CANT_RECONNECT,      /* 16 */
+  CURLE_FTP_COULDNT_SET_BINARY,  /* 17 */
+  CURLE_PARTIAL_FILE,            /* 18 */
+  CURLE_FTP_COULDNT_RETR_FILE,   /* 19 */
+  CURLE_FTP_WRITE_ERROR,         /* 20 */
+  CURLE_FTP_QUOTE_ERROR,         /* 21 */
+  CURLE_HTTP_RETURNED_ERROR,     /* 22 */
+  CURLE_WRITE_ERROR,             /* 23 */
+  CURLE_MALFORMAT_USER,          /* 24 - NOT USED */
+  CURLE_FTP_COULDNT_STOR_FILE,   /* 25 - failed FTP upload */
+  CURLE_READ_ERROR,              /* 26 - could open/read from file */
+  CURLE_OUT_OF_MEMORY,           /* 27 */
+  CURLE_OPERATION_TIMEOUTED,     /* 28 - the timeout time was reached */
+  CURLE_FTP_COULDNT_SET_ASCII,   /* 29 - TYPE A failed */
+  CURLE_FTP_PORT_FAILED,         /* 30 - FTP PORT operation failed */
+  CURLE_FTP_COULDNT_USE_REST,    /* 31 - the REST command failed */
+  CURLE_FTP_COULDNT_GET_SIZE,    /* 32 - the SIZE command failed */
+  CURLE_HTTP_RANGE_ERROR,        /* 33 - RANGE "command" didn't work */
+  CURLE_HTTP_POST_ERROR,         /* 34 */
+  CURLE_SSL_CONNECT_ERROR,       /* 35 - wrong when connecting with SSL */
+  CURLE_BAD_DOWNLOAD_RESUME,     /* 36 - couldn't resume download */
+  CURLE_FILE_COULDNT_READ_FILE,  /* 37 */
+  CURLE_LDAP_CANNOT_BIND,        /* 38 */
+  CURLE_LDAP_SEARCH_FAILED,      /* 39 */
+  CURLE_LIBRARY_NOT_FOUND,       /* 40 */
+  CURLE_FUNCTION_NOT_FOUND,      /* 41 */
+  CURLE_ABORTED_BY_CALLBACK,     /* 42 */
+  CURLE_BAD_FUNCTION_ARGUMENT,   /* 43 */
+  CURLE_BAD_CALLING_ORDER,       /* 44 - NOT USED */
+  CURLE_INTERFACE_FAILED,        /* 45 - CURLOPT_INTERFACE failed */
+  CURLE_BAD_PASSWORD_ENTERED,    /* 46 - NOT USED */
+  CURLE_TOO_MANY_REDIRECTS ,     /* 47 - catch endless re-direct loops */
+  CURLE_UNKNOWN_TELNET_OPTION,   /* 48 - User specified an unknown option */
+  CURLE_TELNET_OPTION_SYNTAX ,   /* 49 - Malformed telnet option */
+  CURLE_OBSOLETE,                /* 50 - NOT USED */
+  CURLE_SSL_PEER_CERTIFICATE,    /* 51 - peer's certificate wasn't ok */
+  CURLE_GOT_NOTHING,             /* 52 - when this is a specific error */
+  CURLE_SSL_ENGINE_NOTFOUND,     /* 53 - SSL crypto engine not found */
+  CURLE_SSL_ENGINE_SETFAILED,    /* 54 - can not set SSL crypto engine as
+                                    default */
+  CURLE_SEND_ERROR,              /* 55 - failed sending network data */
+  CURLE_RECV_ERROR,              /* 56 - failure in receiving network data */
+  CURLE_SHARE_IN_USE,            /* 57 - share is in use */
+  CURLE_SSL_CERTPROBLEM,         /* 58 - problem with the local certificate */
+  CURLE_SSL_CIPHER,              /* 59 - couldn't use specified cipher */
+  CURLE_SSL_CACERT,              /* 60 - problem with the CA cert (path?) */
+  CURLE_BAD_CONTENT_ENCODING,    /* 61 - Unrecognized transfer encoding */
+  CURLE_LDAP_INVALID_URL,        /* 62 - Invalid LDAP URL */
+  CURLE_FILESIZE_EXCEEDED,       /* 63 - Maximum file size exceeded */
+  CURLE_FTP_SSL_FAILED,          /* 64 - Requested FTP SSL level failed */
+
+  CURL_LAST /* never use! */
+} CURLcode;
+
+typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl,    /* easy handle */
+                                          void *ssl_ctx, /* actually an
+                                                            OpenSSL SSL_CTX */
+                                          void *userptr);
+
+/* Make a spelling correction for the operation timed-out define */
+#define CURLE_OPERATION_TIMEDOUT CURLE_OPERATION_TIMEOUTED
+
+/* backwards compatibility with older names */
+#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR
+#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED
+
+typedef enum {
+  CURLPROXY_HTTP = 0,
+  CURLPROXY_SOCKS4 = 4,
+  CURLPROXY_SOCKS5 = 5
+} curl_proxytype;
+
+#define CURLAUTH_NONE         0       /* nothing */
+#define CURLAUTH_BASIC        (1<<0)  /* Basic (default) */
+#define CURLAUTH_DIGEST       (1<<1)  /* Digest */
+#define CURLAUTH_GSSNEGOTIATE (1<<2)  /* GSS-Negotiate */
+#define CURLAUTH_NTLM         (1<<3)  /* NTLM */
+#define CURLAUTH_ANY ~0               /* all types set */
+#define CURLAUTH_ANYSAFE (~CURLAUTH_BASIC)
+
+/* this was the error code 50 in 7.7.3 and a few earlier versions, this
+   is no longer used by libcurl but is instead #defined here only to not
+   make programs break */
+#define CURLE_ALREADY_COMPLETE 99999
+
+/* This is just to make older programs not break: */
+#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE
+#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME
+
+#define CURL_ERROR_SIZE 256
+
+typedef enum {
+  CURLFTPSSL_NONE,    /* do not attempt to use SSL */
+  CURLFTPSSL_TRY,     /* try using SSL, proceed anyway otherwise */
+  CURLFTPSSL_CONTROL, /* SSL for the control connection or fail */
+  CURLFTPSSL_ALL,     /* SSL for all communication or fail */
+  CURLFTPSSL_LAST     /* not an option, never use */
+} curl_ftpssl;
+
+/* long may be 32 or 64 bits, but we should never depend on anything else
+   but 32 */
+#define CURLOPTTYPE_LONG          0
+#define CURLOPTTYPE_OBJECTPOINT   10000
+#define CURLOPTTYPE_FUNCTIONPOINT 20000
+#define CURLOPTTYPE_OFF_T         30000
+
+/* name is uppercase CURLOPT_<name>,
+   type is one of the defined CURLOPTTYPE_<type>
+   number is unique identifier */
+#ifdef CINIT
+#undef CINIT
+#endif
+/*
+ * Figure out if we can use the ## operator, which is supported by ISO/ANSI C
+ * and C++. Some compilers support it without setting __STDC__ or __cplusplus
+ * so we need to carefully check for them too. We don't use configure-checks
+ * for these since we want these headers to remain generic and working for all
+ * platforms.
+ */
+#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \
+  defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__)
+  /* This compiler is believed to have an ISO compatible preprocessor */
+#define CURL_ISOCPP
+#else
+  /* This compiler is believed NOT to have an ISO compatible preprocessor */
+#undef CURL_ISOCPP
+#endif
+
+#ifdef CURL_ISOCPP
+#define CINIT(name,type,number) CURLOPT_ ## name = CURLOPTTYPE_ ## type + number
+#else
+/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
+#define LONG          CURLOPTTYPE_LONG
+#define OBJECTPOINT   CURLOPTTYPE_OBJECTPOINT
+#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT
+#define OFF_T         CURLOPTTYPE_OFF_T
+#define CINIT(name,type,number) CURLOPT_/**/name = type + number
+#endif
+
+/*
+ * This macro-mania below setups the CURLOPT_[what] enum, to be used with
+ * curl_easy_setopt(). The first argument in the CINIT() macro is the [what]
+ * word.
+ */
+
+typedef enum {
+  /* This is the FILE * or void * the regular output should be written to. */
+  CINIT(FILE, OBJECTPOINT, 1),
+
+  /* The full URL to get/put */
+  CINIT(URL,  OBJECTPOINT, 2),
+
+  /* Port number to connect to, if other than default. */
+  CINIT(PORT, LONG, 3),
+
+  /* Name of proxy to use. */
+  CINIT(PROXY, OBJECTPOINT, 4),
+
+  /* "name:password" to use when fetching. */
+  CINIT(USERPWD, OBJECTPOINT, 5),
+
+  /* "name:password" to use with proxy. */
+  CINIT(PROXYUSERPWD, OBJECTPOINT, 6),
+
+  /* Range to get, specified as an ASCII string. */
+  CINIT(RANGE, OBJECTPOINT, 7),
+
+  /* not used */
+
+  /* Specified file stream to upload from (use as input): */
+  CINIT(INFILE, OBJECTPOINT, 9),
+
+  /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE
+   * bytes big. If this is not used, error messages go to stderr instead: */
+  CINIT(ERRORBUFFER, OBJECTPOINT, 10),
+
+  /* Function that will be called to store the output (instead of fwrite). The
+   * parameters will use fwrite() syntax, make sure to follow them. */
+  CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11),
+
+  /* Function that will be called to read the input (instead of fread). The
+   * parameters will use fread() syntax, make sure to follow them. */
+  CINIT(READFUNCTION, FUNCTIONPOINT, 12),
+
+  /* Time-out the read operation after this amount of seconds */
+  CINIT(TIMEOUT, LONG, 13),
+
+  /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about
+   * how large the file being sent really is. That allows better error
+   * checking and better verifies that the upload was succcessful. -1 means
+   * unknown size.
+   *
+   * For large file support, there is also a _LARGE version of the key
+   * which takes an off_t type, allowing platforms with larger off_t
+   * sizes to handle larger files.  See below for INFILESIZE_LARGE.
+   */
+  CINIT(INFILESIZE, LONG, 14),
+
+  /* POST input fields. */
+  CINIT(POSTFIELDS, OBJECTPOINT, 15),
+
+  /* Set the referer page (needed by some CGIs) */
+  CINIT(REFERER, OBJECTPOINT, 16),
+
+  /* Set the FTP PORT string (interface name, named or numerical IP address)
+     Use i.e '-' to use default address. */
+  CINIT(FTPPORT, OBJECTPOINT, 17),
+
+  /* Set the User-Agent string (examined by some CGIs) */
+  CINIT(USERAGENT, OBJECTPOINT, 18),
+
+  /* If the download receives less than "low speed limit" bytes/second
+   * during "low speed time" seconds, the operations is aborted.
+   * You could i.e if you have a pretty high speed connection, abort if
+   * it is less than 2000 bytes/sec during 20 seconds.
+   */
+
+  /* Set the "low speed limit" */
+  CINIT(LOW_SPEED_LIMIT, LONG , 19),
+
+  /* Set the "low speed time" */
+  CINIT(LOW_SPEED_TIME, LONG, 20),
+
+  /* Set the continuation offset.
+   *
+   * Note there is also a _LARGE version of this key which uses
+   * off_t types, allowing for large file offsets on platforms which
+   * use larger-than-32-bit off_t's.  Look below for RESUME_FROM_LARGE.
+   */
+  CINIT(RESUME_FROM, LONG, 21),
+
+  /* Set cookie in request: */
+  CINIT(COOKIE, OBJECTPOINT, 22),
+
+  /* This points to a linked list of headers, struct curl_slist kind */
+  CINIT(HTTPHEADER, OBJECTPOINT, 23),
+
+  /* This points to a linked list of post entries, struct HttpPost */
+  CINIT(HTTPPOST, OBJECTPOINT, 24),
+
+  /* name of the file keeping your private SSL-certificate */
+  CINIT(SSLCERT, OBJECTPOINT, 25),
+
+  /* password for the SSL-private key, keep this for compatibility */
+  CINIT(SSLCERTPASSWD, OBJECTPOINT, 26),
+  /* password for the SSL private key */
+  CINIT(SSLKEYPASSWD, OBJECTPOINT, 26),
+
+  /* send TYPE parameter? */
+  CINIT(CRLF, LONG, 27),
+
+  /* send linked-list of QUOTE commands */
+  CINIT(QUOTE, OBJECTPOINT, 28),
+
+  /* send FILE * or void * to store headers to, if you use a callback it
+     is simply passed to the callback unmodified */
+  CINIT(WRITEHEADER, OBJECTPOINT, 29),
+
+  /* point to a file to read the initial cookies from, also enables
+     "cookie awareness" */
+  CINIT(COOKIEFILE, OBJECTPOINT, 31),
+
+  /* What version to specifly try to use.
+     See CURL_SSLVERSION defines below. */
+  CINIT(SSLVERSION, LONG, 32),
+
+  /* What kind of HTTP time condition to use, see defines */
+  CINIT(TIMECONDITION, LONG, 33),
+
+  /* Time to use with the above condition. Specified in number of seconds
+     since 1 Jan 1970 */
+  CINIT(TIMEVALUE, LONG, 34),
+
+  /* 35 = OBSOLETE */
+
+  /* Custom request, for customizing the get command like
+     HTTP: DELETE, TRACE and others
+     FTP: to use a different list command
+     */
+  CINIT(CUSTOMREQUEST, OBJECTPOINT, 36),
+
+  /* HTTP request, for odd commands like DELETE, TRACE and others */
+  CINIT(STDERR, OBJECTPOINT, 37),
+
+  /* 38 is not used */
+
+  /* send linked-list of post-transfer QUOTE commands */
+  CINIT(POSTQUOTE, OBJECTPOINT, 39),
+
+  /* Pass a pointer to string of the output using full variable-replacement
+     as described elsewhere. */
+  CINIT(WRITEINFO, OBJECTPOINT, 40),
+
+  CINIT(VERBOSE, LONG, 41),      /* talk a lot */
+  CINIT(HEADER, LONG, 42),       /* throw the header out too */
+  CINIT(NOPROGRESS, LONG, 43),   /* shut off the progress meter */
+  CINIT(NOBODY, LONG, 44),       /* use HEAD to get http document */
+  CINIT(FAILONERROR, LONG, 45),  /* no output on http error codes >= 300 */
+  CINIT(UPLOAD, LONG, 46),       /* this is an upload */
+  CINIT(POST, LONG, 47),         /* HTTP POST method */
+  CINIT(FTPLISTONLY, LONG, 48),  /* Use NLST when listing ftp dir */
+
+  CINIT(FTPAPPEND, LONG, 50),    /* Append instead of overwrite on upload! */
+
+  /* Specify whether to read the user+password from the .netrc or the URL.
+   * This must be one of the CURL_NETRC_* enums below. */
+  CINIT(NETRC, LONG, 51),
+
+  CINIT(FOLLOWLOCATION, LONG, 52),  /* use Location: Luke! */
+
+  CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */
+  CINIT(PUT, LONG, 54),          /* HTTP PUT */
+
+  /* 55 = OBSOLETE */
+
+  /* Function that will be called instead of the internal progress display
+   * function. This function should be defined as the curl_progress_callback
+   * prototype defines. */
+  CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56),
+
+  /* Data passed to the progress callback */
+  CINIT(PROGRESSDATA, OBJECTPOINT, 57),
+
+  /* We want the referer field set automatically when following locations */
+  CINIT(AUTOREFERER, LONG, 58),
+
+  /* Port of the proxy, can be set in the proxy string as well with:
+     "[host]:[port]" */
+  CINIT(PROXYPORT, LONG, 59),
+
+  /* size of the POST input data, if strlen() is not good to use */
+  CINIT(POSTFIELDSIZE, LONG, 60),
+
+  /* tunnel non-http operations through a HTTP proxy */
+  CINIT(HTTPPROXYTUNNEL, LONG, 61),
+
+  /* Set the interface string to use as outgoing network interface */
+  CINIT(INTERFACE, OBJECTPOINT, 62),
+
+  /* Set the krb4 security level, this also enables krb4 awareness.  This is a
+   * string, 'clear', 'safe', 'confidential' or 'private'.  If the string is
+   * set but doesn't match one of these, 'private' will be used.  */
+  CINIT(KRB4LEVEL, OBJECTPOINT, 63),
+
+  /* Set if we should verify the peer in ssl handshake, set 1 to verify. */
+  CINIT(SSL_VERIFYPEER, LONG, 64),
+
+  /* The CApath or CAfile used to validate the peer certificate
+     this option is used only if SSL_VERIFYPEER is true */
+  CINIT(CAINFO, OBJECTPOINT, 65),
+
+  /* 66 = OBSOLETE */
+  /* 67 = OBSOLETE */
+
+  /* Maximum number of http redirects to follow */
+  CINIT(MAXREDIRS, LONG, 68),
+
+  /* Pass a long set to 1 to get the date of the requested document (if
+     possible)! Pass a zero to shut it off. */
+  CINIT(FILETIME, LONG, 69),
+
+  /* This points to a linked list of telnet options */
+  CINIT(TELNETOPTIONS, OBJECTPOINT, 70),
+
+  /* Max amount of cached alive connections */
+  CINIT(MAXCONNECTS, LONG, 71),
+
+  /* What policy to use when closing connections when the cache is filled
+     up */
+  CINIT(CLOSEPOLICY, LONG, 72),
+
+  /* 73 = OBSOLETE */
+
+  /* Set to explicitly use a new connection for the upcoming transfer.
+     Do not use this unless you're absolutely sure of this, as it makes the
+     operation slower and is less friendly for the network. */
+  CINIT(FRESH_CONNECT, LONG, 74),
+
+  /* Set to explicitly forbid the upcoming transfer's connection to be re-used
+     when done. Do not use this unless you're absolutely sure of this, as it
+     makes the operation slower and is less friendly for the network. */
+  CINIT(FORBID_REUSE, LONG, 75),
+
+  /* Set to a file name that contains random data for libcurl to use to
+     seed the random engine when doing SSL connects. */
+  CINIT(RANDOM_FILE, OBJECTPOINT, 76),
+
+  /* Set to the Entropy Gathering Daemon socket pathname */
+  CINIT(EGDSOCKET, OBJECTPOINT, 77),
+
+  /* Time-out connect operations after this amount of seconds, if connects
+     are OK within this time, then fine... This only aborts the connect
+     phase. [Only works on unix-style/SIGALRM operating systems] */
+  CINIT(CONNECTTIMEOUT, LONG, 78),
+
+  /* Function that will be called to store headers (instead of fwrite). The
+   * parameters will use fwrite() syntax, make sure to follow them. */
+  CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79),
+
+  /* Set this to force the HTTP request to get back to GET. Only really usable
+     if POST, PUT or a custom request have been used first.
+   */
+  CINIT(HTTPGET, LONG, 80),
+
+  /* Set if we should verify the Common name from the peer certificate in ssl
+   * handshake, set 1 to check existence, 2 to ensure that it matches the
+   * provided hostname. */
+  CINIT(SSL_VERIFYHOST, LONG, 81),
+
+  /* Specify which file name to write all known cookies in after completed
+     operation. Set file name to "-" (dash) to make it go to stdout. */
+  CINIT(COOKIEJAR, OBJECTPOINT, 82),
+
+  /* Specify which SSL ciphers to use */
+  CINIT(SSL_CIPHER_LIST, OBJECTPOINT, 83),
+
+  /* Specify which HTTP version to use! This must be set to one of the
+     CURL_HTTP_VERSION* enums set below. */
+  CINIT(HTTP_VERSION, LONG, 84),
+
+  /* Specificly switch on or off the FTP engine's use of the EPSV command. By
+     default, that one will always be attempted before the more traditional
+     PASV command. */
+  CINIT(FTP_USE_EPSV, LONG, 85),
+
+  /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */
+  CINIT(SSLCERTTYPE, OBJECTPOINT, 86),
+
+  /* name of the file keeping your private SSL-key */
+  CINIT(SSLKEY, OBJECTPOINT, 87),
+
+  /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */
+  CINIT(SSLKEYTYPE, OBJECTPOINT, 88),
+
+  /* crypto engine for the SSL-sub system */
+  CINIT(SSLENGINE, OBJECTPOINT, 89),
+
+  /* set the crypto engine for the SSL-sub system as default
+     the param has no meaning...
+   */
+  CINIT(SSLENGINE_DEFAULT, LONG, 90),
+
+  /* Non-zero value means to use the global dns cache */
+  CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* To become OBSOLETE soon */
+
+  /* DNS cache timeout */
+  CINIT(DNS_CACHE_TIMEOUT, LONG, 92),
+
+  /* send linked-list of pre-transfer QUOTE commands (Wesley Laxton)*/
+  CINIT(PREQUOTE, OBJECTPOINT, 93),
+
+  /* set the debug function */
+  CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94),
+
+  /* set the data for the debug function */
+  CINIT(DEBUGDATA, OBJECTPOINT, 95),
+
+  /* mark this as start of a cookie session */
+  CINIT(COOKIESESSION, LONG, 96),
+
+  /* The CApath directory used to validate the peer certificate
+     this option is used only if SSL_VERIFYPEER is true */
+  CINIT(CAPATH, OBJECTPOINT, 97),
+
+  /* Instruct libcurl to use a smaller receive buffer */
+  CINIT(BUFFERSIZE, LONG, 98),
+
+  /* Instruct libcurl to not use any signal/alarm handlers, even when using
+     timeouts. This option is useful for multi-threaded applications.
+     See libcurl-the-guide for more background information. */
+  CINIT(NOSIGNAL, LONG, 99),
+
+  /* Provide a CURLShare for mutexing non-ts data */
+  CINIT(SHARE, OBJECTPOINT, 100),
+
+  /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default),
+     CURLPROXY_SOCKS4 and CURLPROXY_SOCKS5. */
+  CINIT(PROXYTYPE, LONG, 101),
+
+  /* Set the Accept-Encoding string. Use this to tell a server you would like
+     the response to be compressed. */
+  CINIT(ENCODING, OBJECTPOINT, 102),
+
+  /* Set pointer to private data */
+  CINIT(PRIVATE, OBJECTPOINT, 103),
+
+  /* Set aliases for HTTP 200 in the HTTP Response header */
+  CINIT(HTTP200ALIASES, OBJECTPOINT, 104),
+
+  /* Continue to send authentication (user+password) when following locations,
+     even when hostname changed. This can potentionally send off the name
+     and password to whatever host the server decides. */
+  CINIT(UNRESTRICTED_AUTH, LONG, 105),
+
+  /* Specificly switch on or off the FTP engine's use of the EPRT command ( it
+     also disables the LPRT attempt). By default, those ones will always be
+     attempted before the good old traditional PORT command. */
+  CINIT(FTP_USE_EPRT, LONG, 106),
+
+  /* Set this to a bitmask value to enable the particular authentications
+     methods you like. Use this in combination with CURLOPT_USERPWD.
+     Note that setting multiple bits may cause extra network round-trips. */
+  CINIT(HTTPAUTH, LONG, 107),
+
+  /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx
+     in second argument. The function must be matching the
+     curl_ssl_ctx_callback proto. */
+  CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108),
+
+  /* Set the userdata for the ssl context callback function's third
+     argument */
+  CINIT(SSL_CTX_DATA, OBJECTPOINT, 109),
+
+  /* FTP Option that causes missing dirs to be created on the remote server */
+  CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110),
+
+  /* Set this to a bitmask value to enable the particular authentications
+     methods you like. Use this in combination with CURLOPT_PROXYUSERPWD.
+     Note that setting multiple bits may cause extra network round-trips. */
+  CINIT(PROXYAUTH, LONG, 111),
+
+  /* FTP option that changes the timeout, in seconds, associated with
+     getting a response.  This is different from transfer timeout time and
+     essentially places a demand on the FTP server to acknowledge commands
+     in a timely manner. */
+  CINIT(FTP_RESPONSE_TIMEOUT, LONG , 112),
+
+  /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to
+     tell libcurl to resolve names to those IP versions only. This only has
+     affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */
+  CINIT(IPRESOLVE, LONG, 113),
+
+  /* Set this option to limit the size of a file that will be downloaded from
+     an HTTP or FTP server.
+
+     Note there is also _LARGE version which adds large file support for
+     platforms which have larger off_t sizes.  See MAXFILESIZE_LARGE below. */
+  CINIT(MAXFILESIZE, LONG, 114),
+
+  /* See the comment for INFILESIZE above, but in short, specifies
+   * the size of the file being uploaded.  -1 means unknown.
+   */
+  CINIT(INFILESIZE_LARGE, OFF_T, 115),
+
+  /* Sets the continuation offset.  There is also a LONG version of this;
+   * look above for RESUME_FROM.
+   */
+  CINIT(RESUME_FROM_LARGE, OFF_T, 116),
+
+  /* Sets the maximum size of data that will be downloaded from
+   * an HTTP or FTP server.  See MAXFILESIZE above for the LONG version.
+   */
+  CINIT(MAXFILESIZE_LARGE, OFF_T, 117),
+
+  /* Set this option to the file name of your .netrc file you want libcurl
+     to parse (using the CURLOPT_NETRC option). If not set, libcurl will do
+     a poor attempt to find the user's home directory and check for a .netrc
+     file in there. */
+  CINIT(NETRC_FILE, OBJECTPOINT, 118),
+
+  /* Enable SSL/TLS for FTP, pick one of:
+     CURLFTPSSL_TRY     - try using SSL, proceed anyway otherwise
+     CURLFTPSSL_CONTROL - SSL for the control connection or fail
+     CURLFTPSSL_ALL     - SSL for all communication or fail
+  */
+  CINIT(FTP_SSL, LONG, 119),
+
+  /* The _LARGE version of the standard POSTFIELDSIZE option */
+  CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120),
+
+  /* Enable/disable the TCP Nagle algorithm */
+  CINIT(TCP_NODELAY, LONG, 121),
+
+  /* When doing 3rd party transfer, set the source host name with this */
+  CINIT(SOURCE_HOST, OBJECTPOINT, 122),
+
+  /* When doing 3rd party transfer, set the source user and password with
+     this */
+  CINIT(SOURCE_USERPWD, OBJECTPOINT, 123),
+
+  /* When doing 3rd party transfer, set the source file path with this */
+  CINIT(SOURCE_PATH, OBJECTPOINT, 124),
+
+  /* When doing 3rd party transfer, set the source server's port number
+     with this */
+  CINIT(SOURCE_PORT, LONG, 125),
+
+  /* When doing 3rd party transfer, decide which server that should get the
+     PASV command (and the other gets the PORT).
+     0 (default) - The target host issues PASV.
+     1           - The source host issues PASV */
+  CINIT(PASV_HOST, LONG, 126),
+
+  /* When doing 3rd party transfer, set the source pre-quote linked list
+     of commands with this */
+  CINIT(SOURCE_PREQUOTE, OBJECTPOINT, 127),
+
+  /* When doing 3rd party transfer, set the source post-quote linked list
+     of commands with this */
+  CINIT(SOURCE_POSTQUOTE, OBJECTPOINT, 128),
+
+  CURLOPT_LASTENTRY /* the last unused */
+} CURLoption;
+
+  /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host
+     name resolves addresses using more than one IP protocol version, this
+     option might be handy to force libcurl to use a specific IP version. */
+#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP
+                                     versions that your system allows */
+#define CURL_IPRESOLVE_V4       1 /* resolve to ipv4 addresses */
+#define CURL_IPRESOLVE_V6       2 /* resolve to ipv6 addresses */
+
+  /* three convenient "aliases" that follow the name scheme better */
+#define CURLOPT_WRITEDATA CURLOPT_FILE
+#define CURLOPT_READDATA  CURLOPT_INFILE
+#define CURLOPT_HEADERDATA CURLOPT_WRITEHEADER
+
+#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
+                          the obsolete stuff removed! */
+#define CURLOPT_HTTPREQUEST    -1
+#define CURLOPT_FTPASCII       CURLOPT_TRANSFERTEXT
+#define CURLOPT_MUTE           -2
+#define CURLOPT_PASSWDFUNCTION -3
+#define CURLOPT_PASSWDDATA     -4
+#define CURLOPT_CLOSEFUNCTION  -5
+
+#else
+/* This is set if CURL_NO_OLDIES is defined at compile-time */
+#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */
+#endif
+
+
+  /* These enums are for use with the CURLOPT_HTTP_VERSION option. */
+enum {
+  CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd
+                             like the library to choose the best possible
+                             for us! */
+  CURL_HTTP_VERSION_1_0,  /* please use HTTP 1.0 in the request */
+  CURL_HTTP_VERSION_1_1,  /* please use HTTP 1.1 in the request */
+
+  CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */
+};
+
+  /* These enums are for use with the CURLOPT_NETRC option. */
+enum CURL_NETRC_OPTION {
+  CURL_NETRC_IGNORED,     /* The .netrc will never be read.
+                           * This is the default. */
+  CURL_NETRC_OPTIONAL,    /* A user:password in the URL will be preferred
+                           * to one in the .netrc. */
+  CURL_NETRC_REQUIRED,    /* A user:password in the URL will be ignored.
+                           * Unless one is set programmatically, the .netrc
+                           * will be queried. */
+  CURL_NETRC_LAST
+};
+
+enum {
+  CURL_SSLVERSION_DEFAULT,
+  CURL_SSLVERSION_TLSv1,
+  CURL_SSLVERSION_SSLv2,
+  CURL_SSLVERSION_SSLv3,
+
+  CURL_SSLVERSION_LAST /* never use, keep last */
+};
+
+
+typedef enum {
+  CURL_TIMECOND_NONE,
+
+  CURL_TIMECOND_IFMODSINCE,
+  CURL_TIMECOND_IFUNMODSINCE,
+  CURL_TIMECOND_LASTMOD,
+
+  CURL_TIMECOND_LAST
+} curl_TimeCond;
+
+#ifdef __BEOS__
+#include <support/SupportDefs.h>
+#endif
+
+
+/* curl_strequal() and curl_strnequal() are subject for removal in a future
+   libcurl, see lib/README.curlx for details */
+extern int (curl_strequal)(const char *s1, const char *s2);
+extern int (curl_strnequal)(const char *s1, const char *s2, size_t n);
+
+/* name is uppercase CURLFORM_<name> */
+#ifdef CFINIT
+#undef CFINIT
+#endif
+
+#ifdef CURL_ISOCPP
+#define CFINIT(name) CURLFORM_ ## name
+#else
+/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
+#define CFINIT(name) CURLFORM_/**/name
+#endif
+
+typedef enum {
+  CFINIT(NOTHING),        /********* the first one is unused ************/
+
+  /*  */
+  CFINIT(COPYNAME),
+  CFINIT(PTRNAME),
+  CFINIT(NAMELENGTH),
+  CFINIT(COPYCONTENTS),
+  CFINIT(PTRCONTENTS),
+  CFINIT(CONTENTSLENGTH),
+  CFINIT(FILECONTENT),
+  CFINIT(ARRAY),
+  CFINIT(OBSOLETE),
+  CFINIT(FILE),
+
+  CFINIT(BUFFER),
+  CFINIT(BUFFERPTR),
+  CFINIT(BUFFERLENGTH),
+
+  CFINIT(CONTENTTYPE),
+  CFINIT(CONTENTHEADER),
+  CFINIT(FILENAME),
+  CFINIT(END),
+  CFINIT(OBSOLETE2),
+
+  CURLFORM_LASTENTRY /* the last unusued */
+} CURLformoption;
+
+#undef CFINIT /* done */
+
+/* structure to be used as parameter for CURLFORM_ARRAY */
+struct curl_forms {
+  CURLformoption    option;
+  const char    *value;
+};
+
+/* use this for multipart formpost building */
+/* Returns code for curl_formadd()
+ *
+ * Returns:
+ * CURL_FORMADD_OK             on success
+ * CURL_FORMADD_MEMORY         if the FormInfo allocation fails
+ * CURL_FORMADD_OPTION_TWICE   if one option is given twice for one Form
+ * CURL_FORMADD_NULL           if a null pointer was given for a char
+ * CURL_FORMADD_MEMORY         if the allocation of a FormInfo struct failed
+ * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
+ * CURL_FORMADD_INCOMPLETE     if the some FormInfo is not complete (or error)
+ * CURL_FORMADD_MEMORY         if a HttpPost struct cannot be allocated
+ * CURL_FORMADD_MEMORY         if some allocation for string copying failed.
+ * CURL_FORMADD_ILLEGAL_ARRAY  if an illegal option is used in an array
+ *
+ ***************************************************************************/
+typedef enum {
+  CURL_FORMADD_OK, /* first, no error */
+
+  CURL_FORMADD_MEMORY,
+  CURL_FORMADD_OPTION_TWICE,
+  CURL_FORMADD_NULL,
+  CURL_FORMADD_UNKNOWN_OPTION,
+  CURL_FORMADD_INCOMPLETE,
+  CURL_FORMADD_ILLEGAL_ARRAY,
+  CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */
+
+  CURL_FORMADD_LAST /* last */
+} CURLFORMcode;
+
+/*
+ * NAME curl_formadd()
+ *
+ * DESCRIPTION
+ *
+ * Pretty advanved function for building multi-part formposts. Each invoke
+ * adds one part that together construct a full post. Then use
+ * CURLOPT_HTTPPOST to send it off to libcurl.
+ */
+CURLFORMcode curl_formadd(struct curl_httppost **httppost,
+                          struct curl_httppost **last_post,
+                          ...);
+
+/*
+ * NAME curl_formfree()
+ *
+ * DESCRIPTION
+ *
+ * Free a multipart formpost previously built with curl_formadd().
+ */
+void curl_formfree(struct curl_httppost *form);
+
+/*
+ * NAME curl_getenv()
+ *
+ * DESCRIPTION
+ *
+ * Returns a malloc()'ed string that MUST be curl_free()ed after usage is
+ * complete. DEPRECATED - see lib/README.curlx
+ */
+char *curl_getenv(const char *variable);
+
+/*
+ * NAME curl_version()
+ *
+ * DESCRIPTION
+ *
+ * Returns a static ascii string of the libcurl version.
+ */
+char *curl_version(void);
+
+/*
+ * NAME curl_escape()
+ *
+ * DESCRIPTION
+ *
+ * Escapes URL strings (converts all letters consider illegal in URLs to their
+ * %XX versions). This function returns a new allocated string or NULL if an
+ * error occurred.
+ */
+char *curl_escape(const char *string, int length);
+
+/*
+ * NAME curl_unescape()
+ *
+ * DESCRIPTION
+ *
+ * Unescapes URL encoding in strings (converts all %XX codes to their 8bit
+ * versions). This function returns a new allocated string or NULL if an error
+ * occurred.
+ */
+char *curl_unescape(const char *string, int length);
+
+/*
+ * NAME curl_free()
+ *
+ * DESCRIPTION
+ *
+ * Provided for de-allocation in the same translation unit that did the
+ * allocation. Added in libcurl 7.10
+ */
+void curl_free(void *p);
+
+/*
+ * NAME curl_global_init()
+ *
+ * DESCRIPTION
+ *
+ * curl_global_init() should be invoked exactly once for each application that
+ * uses libcurl
+ */
+CURLcode curl_global_init(long flags);
+
+/*
+ * NAME curl_global_init_mem()
+ *
+ * DESCRIPTION
+ *
+ * curl_global_init() or curl_global_init_mem() should be invoked exactly once
+ * for each application that uses libcurl.  This function can be used to
+ * initialize libcurl and set user defined memory management callback
+ * functions.  Users can implement memory management routines to check for
+ * memory leaks, check for mis-use of the curl library etc.  User registered
+ * callback routines with be invoked by this library instead of the system
+ * memory management routines like malloc, free etc.
+ */
+CURLcode curl_global_init_mem(long flags,
+                              curl_malloc_callback m,
+                              curl_free_callback f,
+                              curl_realloc_callback r,
+                              curl_strdup_callback s,
+                              curl_calloc_callback c);
+
+/*
+ * NAME curl_global_cleanup()
+ *
+ * DESCRIPTION
+ *
+ * curl_global_cleanup() should be invoked exactly once for each application
+ * that uses libcurl
+ */
+void curl_global_cleanup(void);
+
+/* linked-list structure for the CURLOPT_QUOTE option (and other) */
+struct curl_slist {
+  char *data;
+  struct curl_slist *next;
+};
+
+/*
+ * NAME curl_slist_append()
+ *
+ * DESCRIPTION
+ *
+ * Appends a string to a linked list. If no list exists, it will be created
+ * first. Returns the new list, after appending.
+ */
+struct curl_slist *curl_slist_append(struct curl_slist *, const char *);
+
+/*
+ * NAME curl_slist_free_all()
+ *
+ * DESCRIPTION
+ *
+ * free a previously built curl_slist.
+ */
+void curl_slist_free_all(struct curl_slist *);
+
+/*
+ * NAME curl_getdate()
+ *
+ * DESCRIPTION
+ *
+ * Returns the time, in seconds since 1 Jan 1970 of the time string given in
+ * the first argument. The time argument in the second parameter is for cases
+ * where the specified time is relative now, like 'two weeks' or 'tomorrow'
+ * etc.
+ */
+time_t curl_getdate(const char *p, const time_t *now);
+
+#define CURLINFO_STRING   0x100000
+#define CURLINFO_LONG     0x200000
+#define CURLINFO_DOUBLE   0x300000
+#define CURLINFO_MASK     0x0fffff
+#define CURLINFO_TYPEMASK 0xf00000
+
+typedef enum {
+  CURLINFO_NONE, /* first, never use this */
+  CURLINFO_EFFECTIVE_URL    = CURLINFO_STRING + 1,
+  CURLINFO_RESPONSE_CODE    = CURLINFO_LONG   + 2,
+  CURLINFO_TOTAL_TIME       = CURLINFO_DOUBLE + 3,
+  CURLINFO_NAMELOOKUP_TIME  = CURLINFO_DOUBLE + 4,
+  CURLINFO_CONNECT_TIME     = CURLINFO_DOUBLE + 5,
+  CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6,
+  CURLINFO_SIZE_UPLOAD      = CURLINFO_DOUBLE + 7,
+  CURLINFO_SIZE_DOWNLOAD    = CURLINFO_DOUBLE + 8,
+  CURLINFO_SPEED_DOWNLOAD   = CURLINFO_DOUBLE + 9,
+  CURLINFO_SPEED_UPLOAD     = CURLINFO_DOUBLE + 10,
+  CURLINFO_HEADER_SIZE      = CURLINFO_LONG   + 11,
+  CURLINFO_REQUEST_SIZE     = CURLINFO_LONG   + 12,
+  CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG   + 13,
+  CURLINFO_FILETIME         = CURLINFO_LONG   + 14,
+  CURLINFO_CONTENT_LENGTH_DOWNLOAD   = CURLINFO_DOUBLE + 15,
+  CURLINFO_CONTENT_LENGTH_UPLOAD     = CURLINFO_DOUBLE + 16,
+  CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17,
+  CURLINFO_CONTENT_TYPE     = CURLINFO_STRING + 18,
+  CURLINFO_REDIRECT_TIME    = CURLINFO_DOUBLE + 19,
+  CURLINFO_REDIRECT_COUNT   = CURLINFO_LONG   + 20,
+  CURLINFO_PRIVATE          = CURLINFO_STRING + 21,
+  CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG   + 22,
+  CURLINFO_HTTPAUTH_AVAIL   = CURLINFO_LONG   + 23,
+  CURLINFO_PROXYAUTH_AVAIL  = CURLINFO_LONG   + 24,
+  /* Fill in new entries below here! */
+
+  CURLINFO_LASTONE          = 23
+} CURLINFO;
+
+/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
+   CURLINFO_HTTP_CODE */
+#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE
+
+typedef enum {
+  CURLCLOSEPOLICY_NONE, /* first, never use this */
+
+  CURLCLOSEPOLICY_OLDEST,
+  CURLCLOSEPOLICY_LEAST_RECENTLY_USED,
+  CURLCLOSEPOLICY_LEAST_TRAFFIC,
+  CURLCLOSEPOLICY_SLOWEST,
+  CURLCLOSEPOLICY_CALLBACK,
+
+  CURLCLOSEPOLICY_LAST /* last, never use this */
+} curl_closepolicy;
+
+#define CURL_GLOBAL_SSL (1<<0)
+#define CURL_GLOBAL_WIN32 (1<<1)
+#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32)
+#define CURL_GLOBAL_NOTHING 0
+#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL
+
+
+/*****************************************************************************
+ * Setup defines, protos etc for the sharing stuff.
+ */
+
+/* Different data locks for a single share */
+typedef enum {
+  CURL_LOCK_DATA_NONE = 0,
+  /*  CURL_LOCK_DATA_SHARE is used internaly to say that
+   *  the locking is just made to change the internal state of the share
+   *  itself.
+   */
+  CURL_LOCK_DATA_SHARE,
+  CURL_LOCK_DATA_COOKIE,
+  CURL_LOCK_DATA_DNS,
+  CURL_LOCK_DATA_SSL_SESSION,
+  CURL_LOCK_DATA_CONNECT,
+  CURL_LOCK_DATA_LAST
+} curl_lock_data;
+
+/* Different lock access types */
+typedef enum {
+  CURL_LOCK_ACCESS_NONE = 0,   /* unspecified action */
+  CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */
+  CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */
+  CURL_LOCK_ACCESS_LAST        /* never use */
+} curl_lock_access;
+
+typedef void (*curl_lock_function)(CURL *handle,
+                                   curl_lock_data data,
+                                   curl_lock_access locktype,
+                                   void *userptr);
+typedef void (*curl_unlock_function)(CURL *handle,
+                                     curl_lock_data data,
+                                     void *userptr);
+
+typedef void CURLSH;
+
+typedef enum {
+  CURLSHE_OK,  /* all is fine */
+  CURLSHE_BAD_OPTION, /* 1 */
+  CURLSHE_IN_USE,     /* 2 */
+  CURLSHE_INVALID,    /* 3 */
+  CURLSHE_NOMEM,      /* out of memory */
+  CURLSHE_LAST /* never use */
+} CURLSHcode;
+
+typedef enum {
+  CURLSHOPT_NONE,  /* don't use */
+  CURLSHOPT_SHARE,   /* specify a data type to share */
+  CURLSHOPT_UNSHARE, /* specify shich data type to stop sharing */
+  CURLSHOPT_LOCKFUNC,   /* pass in a 'curl_lock_function' pointer */
+  CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */
+  CURLSHOPT_USERDATA,   /* pass in a user data pointer used in the lock/unlock
+                           callback functions */
+  CURLSHOPT_LAST  /* never use */
+} CURLSHoption;
+
+CURLSH *curl_share_init(void);
+CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...);
+CURLSHcode curl_share_cleanup(CURLSH *);
+
+/****************************************************************************
+ * Structures for querying information about the curl library at runtime.
+ */
+
+typedef enum {
+  CURLVERSION_FIRST,
+  CURLVERSION_SECOND,
+  CURLVERSION_THIRD,
+  CURLVERSION_LAST /* never actually use this */
+} CURLversion;
+
+/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by
+   basicly all programs ever, that want to get version information. It is
+   meant to be a built-in version number for what kind of struct the caller
+   expects. If the struct ever changes, we redfine the NOW to another enum
+   from above. */
+#define CURLVERSION_NOW CURLVERSION_THIRD
+
+typedef struct {
+  CURLversion age;          /* age of the returned struct */
+  const char *version;      /* LIBCURL_VERSION */
+  unsigned int version_num; /* LIBCURL_VERSION_NUM */
+  const char *host;         /* OS/host/cpu/machine when configured */
+  int features;             /* bitmask, see defines below */
+  char *ssl_version;        /* human readable string */
+  long ssl_version_num;     /* number */
+  const char *libz_version;       /* human readable string */
+  /* protocols is terminated by an entry with a NULL protoname */
+  const char **protocols;
+
+  /* The fields below this were added in CURLVERSION_SECOND */
+  const char *ares;
+  int ares_num;
+
+  /* This field was aded in CURLVERSION_THIRD */
+  const char *libidn;
+} curl_version_info_data;
+
+#define CURL_VERSION_IPV6      (1<<0)  /* IPv6-enabled */
+#define CURL_VERSION_KERBEROS4 (1<<1)  /* kerberos auth is supported */
+#define CURL_VERSION_SSL       (1<<2)  /* SSL options are present */
+#define CURL_VERSION_LIBZ      (1<<3)  /* libz features are present */
+#define CURL_VERSION_NTLM      (1<<4)  /* NTLM auth is supported */
+#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth support */
+#define CURL_VERSION_DEBUG     (1<<6)  /* built with debug capabilities */
+#define CURL_VERSION_ASYNCHDNS (1<<7)  /* asynchronous dns resolves */
+#define CURL_VERSION_SPNEGO    (1<<8)  /* SPNEGO auth */
+#define CURL_VERSION_LARGEFILE (1<<9)  /* supports files bigger than 2GB */
+#define CURL_VERSION_IDN       (1<<10) /* International Domain Names support */
+
+/*
+ * NAME curl_version_info()
+ *
+ * DESCRIPTION
+ *
+ * This function returns a pointer to a static copy of the version info
+ * struct. See above.
+ */
+curl_version_info_data *curl_version_info(CURLversion);
+
+/*
+ * NAME curl_easy_strerror()
+ *
+ * DESCRIPTION
+ *
+ * The curl_easy_strerror function may be used to turn a CURLcode value
+ * into the equivalent human readable error string.  This is useful
+ * for printing meaningful error messages.
+ */
+const char *curl_easy_strerror(CURLcode);
+
+/*
+ * NAME curl_share_strerror()
+ *
+ * DESCRIPTION
+ *
+ * The curl_share_strerror function may be used to turn a CURLSHcode value
+ * into the equivalent human readable error string.  This is useful
+ * for printing meaningful error messages.
+ */
+const char *curl_share_strerror(CURLSHcode);
+
+#ifdef  __cplusplus
+}
+#endif
+
+/* unfortunately, the easy.h and multi.h include files need options and info
+  stuff before they can be included! */
+#include "easy.h" /* nothing in curl is fun without the easy stuff */
+#include "multi.h"
+
+#endif /* __CURL_CURL_H */
diff --git a/Utilities/cmcurl/curl/curlver.h b/Utilities/cmcurl/curl/curlver.h
new file mode 100644
index 0000000..ef0a4c5
--- /dev/null
+++ b/Utilities/cmcurl/curl/curlver.h
@@ -0,0 +1,55 @@
+#ifndef __CURL_CURLVER_H
+#define __CURL_CURLVER_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/* This header file contains nothing but libcurl version info, generated by
+   a script at release-time. This was made its own header file in 7.11.2 */
+
+/* This is the version number of the libcurl package from which this header
+   file origins: */
+#define LIBCURL_VERSION "7.12.1"
+
+/* This is the numeric version of the libcurl version number, meant for easier
+   parsing and comparions by programs. The LIBCURL_VERSION_NUM define will
+   always follow this syntax:
+
+         0xXXYYZZ
+
+   Where XX, YY and ZZ are the main version, release and patch numbers in
+   hexadecimal. All three numbers are always represented using two digits.  1.2
+   would appear as "0x010200" while version 9.11.7 appears as "0x090b07".
+
+   This 6-digit hexadecimal number does not show pre-release number, and it is
+   always a greater number in a more recent release. It makes comparisons with
+   greater than and less than work.
+*/
+#define LIBCURL_VERSION_NUM 0x70C01
+
+/* The numeric version number is also available "in parts" by using these
+   defines: */
+#define LIBCURL_VERSION_MAJOR 7
+#define LIBCURL_VERSION_MINOR 12
+#define LIBCURL_VERSION_PATCH 1
+
+#endif /* __CURL_CURLVER_H */
diff --git a/Utilities/cmcurl/curl/easy.h b/Utilities/cmcurl/curl/easy.h
new file mode 100644
index 0000000..336e542
--- /dev/null
+++ b/Utilities/cmcurl/curl/easy.h
@@ -0,0 +1,81 @@
+#ifndef __CURL_EASY_H
+#define __CURL_EASY_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+CURL *curl_easy_init(void);
+CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...);
+CURLcode curl_easy_perform(CURL *curl);
+void curl_easy_cleanup(CURL *curl);
+
+/*
+ * NAME curl_easy_getinfo()
+ *
+ * DESCRIPTION
+ *
+ * Request internal information from the curl session with this function.  The
+ * third argument MUST be a pointer to a long, a pointer to a char * or a
+ * pointer to a double (as the documentation describes elsewhere).  The data
+ * pointed to will be filled in accordingly and can be relied upon only if the
+ * function returns CURLE_OK.  This function is intended to get used *AFTER* a
+ * performed transfer, all results from this function are undefined until the
+ * transfer is completed.
+ */
+CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...);
+
+
+/*
+ * NAME curl_easy_duphandle()
+ *
+ * DESCRIPTION
+ *
+ * Creates a new curl session handle with the same options set for the handle
+ * passed in. Duplicating a handle could only be a matter of cloning data and
+ * options, internal state info and things like persistant connections cannot
+ * be transfered. It is useful in multithreaded applications when you can run
+ * curl_easy_duphandle() for each new thread to avoid a series of identical
+ * curl_easy_setopt() invokes in every thread.
+ */
+CURL* curl_easy_duphandle(CURL *curl);
+
+/*
+ * NAME curl_easy_reset()
+ *
+ * DESCRIPTION
+ *
+ * Re-initializes a CURL handle to the default values. This puts back the
+ * handle to the same state as it was in when it was just created.
+ *
+ * It does keep: live connections, the Session ID cache, the DNS cache and the
+ * cookies.
+ */
+void curl_easy_reset(CURL *curl);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/Utilities/cmcurl/curl/mprintf.h b/Utilities/cmcurl/curl/mprintf.h
new file mode 100644
index 0000000..65dc114
--- /dev/null
+++ b/Utilities/cmcurl/curl/mprintf.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#ifndef H_MPRINTF
+#define H_MPRINTF
+
+#include <stdarg.h>
+#include <stdio.h> /* needed for FILE */
+
+int curl_mprintf(const char *format, ...);
+int curl_mfprintf(FILE *fd, const char *format, ...);
+int curl_msprintf(char *buffer, const char *format, ...);
+int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...);
+int curl_mvprintf(const char *format, va_list args);
+int curl_mvfprintf(FILE *fd, const char *format, va_list args);
+int curl_mvsprintf(char *buffer, const char *format, va_list args);
+int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, va_list args);
+char *curl_maprintf(const char *format, ...);
+char *curl_mvaprintf(const char *format, va_list args);
+
+#ifdef _MPRINTF_REPLACE
+# define printf curl_mprintf
+# define fprintf curl_mfprintf
+# define sprintf curl_msprintf
+# define snprintf curl_msnprintf
+# define vprintf curl_mvprintf
+# define vfprintf curl_mvfprintf
+# define vsprintf curl_mvsprintf
+# define vsnprintf curl_mvsnprintf
+# define aprintf curl_maprintf
+# define vaprintf curl_mvaprintf
+#endif
+
+#endif /* H_MPRINTF */
diff --git a/Utilities/cmcurl/curl/multi.h b/Utilities/cmcurl/curl/multi.h
new file mode 100644
index 0000000..3a867ab
--- /dev/null
+++ b/Utilities/cmcurl/curl/multi.h
@@ -0,0 +1,221 @@
+#ifndef __CURL_MULTI_H
+#define __CURL_MULTI_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+/*
+  This is meant to be the "external" header file. Don't give away any
+  internals here!
+
+  This document presents a mixture of ideas from at least:
+  - Daniel Stenberg
+  - Steve Dekorte
+  - Sterling Hughes
+  - Ben Greear
+
+  -------------------------------------------
+  GOALS
+
+  o Enable a "pull" interface. The application that uses libcurl decides where
+    and when to ask libcurl to get/send data.
+
+  o Enable multiple simultaneous transfers in the same thread without making it
+    complicated for the application.
+
+  o Enable the application to select() on its own file descriptors and curl's
+    file descriptors simultaneous easily.
+  
+*/
+#if defined(_WIN32) && !defined(WIN32)
+/* Chris Lewis mentioned that he doesn't get WIN32 defined, only _WIN32 so we
+   make this adjustment to catch this. */
+#define WIN32 1
+#endif
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#include <winsock2.h>
+#else
+
+/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish
+   libc5-based Linux systems. Only include it on system that are known to
+   require it! */
+#if defined(_AIX) || defined(NETWARE)
+#include <sys/select.h>
+#endif
+
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#endif
+
+#include "curl.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef void CURLM;
+
+typedef enum {
+  CURLM_CALL_MULTI_PERFORM=-1, /* please call curl_multi_perform() soon */
+  CURLM_OK,
+  CURLM_BAD_HANDLE,      /* the passed-in handle is not a valid CURLM handle */
+  CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */
+  CURLM_OUT_OF_MEMORY,   /* if you ever get this, you're in deep sh*t */
+  CURLM_INTERNAL_ERROR,  /* this is a libcurl bug */
+  CURLM_LAST
+} CURLMcode;
+
+typedef enum {
+  CURLMSG_NONE, /* first, not used */
+  CURLMSG_DONE, /* This easy handle has completed. 'result' contains
+                   the CURLcode of the transfer */
+  CURLMSG_LAST /* last, not used */
+} CURLMSG;
+
+struct CURLMsg {
+  CURLMSG msg;       /* what this message means */
+  CURL *easy_handle; /* the handle it concerns */
+  union {
+    void *whatever;    /* message-specific data */
+    CURLcode result;   /* return code for transfer */
+  } data;
+};
+typedef struct CURLMsg CURLMsg;
+
+/*
+ * Name:    curl_multi_init()
+ *
+ * Desc:    inititalize multi-style curl usage
+ * Returns: a new CURLM handle to use in all 'curl_multi' functions.
+ */
+CURLM *curl_multi_init(void);
+
+/*
+ * Name:    curl_multi_add_handle()
+ *
+ * Desc:    add a standard curl handle to the multi stack
+ * Returns: CURLMcode type, general multi error code.
+ */
+CURLMcode curl_multi_add_handle(CURLM *multi_handle,
+                                CURL *curl_handle);
+
+ /*
+  * Name:    curl_multi_remove_handle()
+  *
+  * Desc:    removes a curl handle from the multi stack again
+  * Returns: CURLMcode type, general multi error code.
+  */
+CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
+                                   CURL *curl_handle);
+
+ /*
+  * Name:    curl_multi_fdset()
+  *
+  * Desc:    Ask curl for its fd_set sets. The app can use these to select() or
+  *          poll() on. We want curl_multi_perform() called as soon as one of
+  *          them are ready.
+  * Returns: CURLMcode type, general multi error code.
+  */
+CURLMcode curl_multi_fdset(CURLM *multi_handle,
+                           fd_set *read_fd_set,
+                           fd_set *write_fd_set,
+                           fd_set *exc_fd_set,
+                           int *max_fd);
+
+ /*
+  * Name:    curl_multi_perform()
+  *
+  * Desc:    When the app thinks there's data available for curl it calls this
+  *          function to read/write whatever there is right now. This returns
+  *          as soon as the reads and writes are done. This function does not
+  *          require that there actually is data available for reading or that
+  *          data can be written, it can be called just in case. It returns
+  *          the number of handles that still transfer data in the second
+  *          argument's integer-pointer.
+  *
+  * Returns: CURLMcode type, general multi error code. *NOTE* that this only
+  *          returns errors etc regarding the whole multi stack. There might
+  *          still have occurred problems on invidual transfers even when this
+  *          returns OK.
+  */
+CURLMcode curl_multi_perform(CURLM *multi_handle,
+                             int *running_handles);
+
+ /*
+  * Name:    curl_multi_cleanup()
+  *
+  * Desc:    Cleans up and removes a whole multi stack. It does not free or
+  *          touch any individual easy handles in any way. We need to define
+  *          in what state those handles will be if this function is called
+  *          in the middle of a transfer.
+  * Returns: CURLMcode type, general multi error code.
+  */
+CURLMcode curl_multi_cleanup(CURLM *multi_handle);
+
+/*
+ * Name:    curl_multi_info_read()
+ *
+ * Desc:    Ask the multi handle if there's any messages/informationals from
+ *          the individual transfers. Messages include informationals such as
+ *          error code from the transfer or just the fact that a transfer is
+ *          completed. More details on these should be written down as well.
+ *
+ *          Repeated calls to this function will return a new struct each
+ *          time, until a special "end of msgs" struct is returned as a signal
+ *          that there is no more to get at this point.
+ *
+ *          The data the returned pointer points to will not survive calling
+ *          curl_multi_cleanup().
+ *
+ *          The 'CURLMsg' struct is meant to be very simple and only contain
+ *          very basic informations. If more involved information is wanted,
+ *          we will provide the particular "transfer handle" in that struct
+ *          and that should/could/would be used in subsequent
+ *          curl_easy_getinfo() calls (or similar). The point being that we
+ *          must never expose complex structs to applications, as then we'll
+ *          undoubtably get backwards compatibility problems in the future.
+ *
+ * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out
+ *          of structs. It also writes the number of messages left in the
+ *          queue (after this read) in the integer the second argument points
+ *          to.
+ */
+CURLMsg *curl_multi_info_read(CURLM *multi_handle,
+                              int *msgs_in_queue);
+
+/*
+ * NAME curl_multi_strerror()
+ *
+ * DESCRIPTION
+ *
+ * The curl_multi_strerror function may be used to turn a CURLMcode value
+ * into the equivalent human readable error string.  This is useful
+ * for printing meaningful error messages.
+ */
+const char *curl_multi_strerror(CURLMcode);
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+  
+#endif
diff --git a/Utilities/cmcurl/curl/stdcheaders.h b/Utilities/cmcurl/curl/stdcheaders.h
new file mode 100644
index 0000000..11c1e2f
--- /dev/null
+++ b/Utilities/cmcurl/curl/stdcheaders.h
@@ -0,0 +1,34 @@
+#ifndef __STDC_HEADERS_H
+#define __STDC_HEADERS_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include <sys/types.h>
+
+size_t fread (void *, size_t, size_t, FILE *);
+size_t fwrite (const void *, size_t, size_t, FILE *);
+
+int strcasecmp(const char *, const char *);
+int strncasecmp(const char *, const char *, size_t);
+
+#endif
diff --git a/Utilities/cmcurl/curl/types.h b/Utilities/cmcurl/curl/types.h
new file mode 100644
index 0000000..d37d6ae
--- /dev/null
+++ b/Utilities/cmcurl/curl/types.h
@@ -0,0 +1 @@
+/* not used */
diff --git a/Utilities/cmcurl/curl_memory.h b/Utilities/cmcurl/curl_memory.h
new file mode 100644
index 0000000..4e32a67
--- /dev/null
+++ b/Utilities/cmcurl/curl_memory.h
@@ -0,0 +1,50 @@
+#ifndef _CURL_MEMORY_H
+#define _CURL_MEMORY_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include <curl/curl.h> /* for the typedefs */
+
+extern curl_malloc_callback Curl_cmalloc;
+extern curl_free_callback Curl_cfree;
+extern curl_realloc_callback Curl_crealloc;
+extern curl_strdup_callback Curl_cstrdup;
+extern curl_calloc_callback Curl_ccalloc;
+
+#ifndef CURLDEBUG
+/* Only do this define-mania if we're not using the memdebug system, as that
+   has preference on this magic. */
+#undef strdup
+#define strdup(ptr) Curl_cstrdup(ptr)
+#undef malloc
+#define malloc(size) Curl_cmalloc(size)
+#undef calloc
+#define calloc(nbelem,size) Curl_ccalloc(nbelem, size)
+#undef realloc
+#define realloc(ptr,size) Curl_crealloc(ptr, size)
+#undef free
+#define free(ptr) Curl_cfree(ptr)
+
+#endif
+
+#endif /* _CURL_MEMORY_H */
diff --git a/Utilities/cmcurl/curlx.h b/Utilities/cmcurl/curlx.h
new file mode 100644
index 0000000..0dd9a09
--- /dev/null
+++ b/Utilities/cmcurl/curlx.h
@@ -0,0 +1,95 @@
+#ifndef __CURLX_H
+#define __CURLX_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/*
+ * Defines protos and includes all header files that provide the curlx_*
+ * functions. The curlx_* functions are not part of the libcurl API, but are
+ * stand-alone functions whose sources can be built and linked by apps if need
+ * be.
+ */
+
+#include <curl/mprintf.h>
+/* this is still a public header file that provides the curl_mprintf()
+   functions while they still are offered publicly. They will be made library-
+   private one day */
+
+#include "strequal.h"
+/* "strequal.h" provides the strequal protos */
+
+#include "strtoofft.h"
+/* "strtoofft.h" provides this function: curlx_strtoofft(), returns a
+   curl_off_t number from a given string.
+*/
+
+#include "timeval.h"
+/*
+  "timeval.h" sets up a 'struct timeval' even for platforms that otherwise
+  don't have one and has protos for these functions:
+
+  curlx_tvnow()
+  curlx_tvdiff()
+  curlx_tvdiff_secs()
+*/
+
+/* Now setup curlx_ * names for the functions that are to become curlx_ and
+   be removed from a future libcurl official API:
+   curlx_getenv
+   curlx_mprintf (and its variations)
+   curlx_strequal
+   curlx_strnequal
+
+*/
+
+#define curlx_getenv curl_getenv
+#define curlx_strequal curl_strequal
+#define curlx_strnequal curl_strnequal
+#define curlx_mvsnprintf curl_mvsnprintf
+#define curlx_msnprintf curl_msnprintf
+#define curlx_maprintf curl_maprintf
+#define curlx_mvaprintf curl_mvaprintf
+#define curlx_msprintf curl_msprintf
+#define curlx_mprintf curl_mprintf
+#define curlx_mfprintf curl_mfprintf
+#define curlx_mvsprintf curl_mvsprintf
+#define curlx_mvprintf curl_mvprintf
+#define curlx_mvfprintf curl_mvfprintf
+
+#ifdef ENABLE_CURLX_PRINTF
+/* If this define is set, we define all "standard" printf() functions to use
+   the curlx_* version instead. It makes the source code transparant and
+   easier to understand/patch. */
+# define printf curlx_mprintf
+# define fprintf curlx_mfprintf
+# define sprintf curlx_msprintf
+# define snprintf curlx_msnprintf
+# define vprintf curlx_mvprintf
+# define vfprintf curlx_mvfprintf
+# define vsprintf curlx_mvsprintf
+# define vsnprintf curlx_mvsnprintf
+# define aprintf curlx_maprintf
+# define vaprintf curlx_mvaprintf
+#endif /* ENABLE_CURLX_PRINTF */
+
+#endif /* __CURLX_H */
diff --git a/Utilities/cmcurl/dict.c b/Utilities/cmcurl/dict.c
new file mode 100644
index 0000000..06cb6b6
--- /dev/null
+++ b/Utilities/cmcurl/dict.c
@@ -0,0 +1,221 @@
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#include <time.h>
+#include <io.h>
+#else
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <netinet/in.h>
+#include <sys/time.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <netdb.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#include <sys/ioctl.h>
+#include <signal.h>
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+
+#include "progress.h"
+#include "strequal.h"
+#include "dict.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+CURLcode Curl_dict(struct connectdata *conn)
+{
+  char *word;
+  char *ppath;
+  char *database = NULL;
+  char *strategy = NULL;
+  char *nthdef = NULL; /* This is not part of the protocol, but required
+                          by RFC 2229 */
+  CURLcode result;
+  struct SessionHandle *data=conn->data;
+  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+
+  char *path = conn->path;
+  curl_off_t *bytecount = &conn->bytecount;
+
+  if(conn->bits.user_passwd) {
+    /* AUTH is missing */
+  }
+
+  if (strnequal(path, DICT_MATCH, sizeof(DICT_MATCH)-1) ||
+      strnequal(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) ||
+      strnequal(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) {
+      
+    word = strchr(path, ':');
+    if (word) {
+      word++;
+      database = strchr(word, ':');
+      if (database) {
+        *database++ = (char)0;
+        strategy = strchr(database, ':');
+        if (strategy) {
+          *strategy++ = (char)0;
+          nthdef = strchr(strategy, ':');
+          if (nthdef) {
+            *nthdef++ = (char)0;
+          }
+        }
+      }
+    }
+      
+    if ((word == NULL) || (*word == (char)0)) {
+      failf(data, "lookup word is missing");
+    }
+    if ((database == NULL) || (*database == (char)0)) {
+      database = (char *)"!";
+    }
+    if ((strategy == NULL) || (*strategy == (char)0)) {
+      strategy = (char *)".";
+    }
+      
+    result = Curl_sendf(sockfd, conn,
+                        "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n"
+                        "MATCH "
+                        "%s "    /* database */
+                        "%s "    /* strategy */
+                        "%s\n"   /* word */
+                        "QUIT\n",
+                        
+                        database,
+                        strategy,
+                        word
+                        );
+    if(result)
+      failf(data, "Failed sending DICT request");
+    else
+      result = Curl_Transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
+                             -1, NULL); /* no upload */      
+    if(result)
+      return result;
+  }
+  else if (strnequal(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
+           strnequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
+           strnequal(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) {
+    
+    word = strchr(path, ':');
+    if (word) {
+      word++;
+      database = strchr(word, ':');
+      if (database) {
+        *database++ = (char)0;
+        nthdef = strchr(database, ':');
+        if (nthdef) {
+          *nthdef++ = (char)0;
+        }
+      }
+    }
+      
+    if ((word == NULL) || (*word == (char)0)) {
+      failf(data, "lookup word is missing");
+    }
+    if ((database == NULL) || (*database == (char)0)) {
+      database = (char *)"!";
+    }
+      
+    result = Curl_sendf(sockfd, conn,
+                        "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n"
+                        "DEFINE "
+                        "%s "     /* database */
+                        "%s\n"    /* word */
+                        "QUIT\n",
+                        database,
+                        word);
+    if(result)
+      failf(data, "Failed sending DICT request");
+    else
+      result = Curl_Transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
+                             -1, NULL); /* no upload */
+    
+    if(result)
+      return result;
+      
+  }
+  else {
+      
+    ppath = strchr(path, '/');
+    if (ppath) {
+      int i;
+        
+      ppath++;
+      for (i = 0; ppath[i]; i++) {
+        if (ppath[i] == ':')
+          ppath[i] = ' ';
+      }
+      result = Curl_sendf(sockfd, conn,
+                          "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n"
+                          "%s\n"
+                          "QUIT\n", ppath);
+      if(result)
+        failf(data, "Failed sending DICT request");
+      else
+        result = Curl_Transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
+                               -1, NULL);
+      if(result)
+        return result;
+    }
+  }
+  (void)nthdef;
+
+  return CURLE_OK;
+}
diff --git a/Utilities/cmcurl/dict.h b/Utilities/cmcurl/dict.h
new file mode 100644
index 0000000..4301f01
--- /dev/null
+++ b/Utilities/cmcurl/dict.h
@@ -0,0 +1,30 @@
+#ifndef __DICT_H
+#define __DICT_H
+
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+#ifndef CURL_DISABLE_DICT
+CURLcode Curl_dict(struct connectdata *conn);
+CURLcode Curl_dict_done(struct connectdata *conn);
+#endif
+#endif
diff --git a/Utilities/cmcurl/easy.c b/Utilities/cmcurl/easy.c
new file mode 100644
index 0000000..fb116fd
--- /dev/null
+++ b/Utilities/cmcurl/easy.c
@@ -0,0 +1,583 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+
+#include "strequal.h"
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#include <time.h>
+#include <io.h>
+#else
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <netinet/in.h>
+#include <sys/time.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <netdb.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#include <sys/ioctl.h>
+#include <signal.h>
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#endif  /* WIN32 ... */
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "ssluse.h"
+#include "url.h"
+#include "getinfo.h"
+#include "hostip.h"
+#include "share.h"
+#include "curl_memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+/* win32_cleanup() is for win32 socket cleanup functionality, the opposite
+   of win32_init() */
+static void win32_cleanup(void)
+{
+  WSACleanup();
+}
+
+/* win32_init() performs win32 socket initialization to properly setup the
+   stack to allow networking */
+static CURLcode win32_init(void)
+{
+  WORD wVersionRequested;
+  WSADATA wsaData;
+  int err;
+
+#ifdef ENABLE_IPV6
+  wVersionRequested = MAKEWORD(2, 0);
+#else
+  wVersionRequested = MAKEWORD(1, 1);
+#endif
+
+  err = WSAStartup(wVersionRequested, &wsaData);
+
+  if (err != 0)
+    /* Tell the user that we couldn't find a useable */
+    /* winsock.dll.     */
+    return CURLE_FAILED_INIT;
+
+  /* Confirm that the Windows Sockets DLL supports what we need.*/
+  /* Note that if the DLL supports versions greater */
+  /* than wVersionRequested, it will still return */
+  /* wVersionRequested in wVersion. wHighVersion contains the */
+  /* highest supported version. */
+
+  if ( LOBYTE( wsaData.wVersion ) != LOBYTE(wVersionRequested) ||
+       HIBYTE( wsaData.wVersion ) != HIBYTE(wVersionRequested) ) {
+    /* Tell the user that we couldn't find a useable */
+
+    /* winsock.dll. */
+    WSACleanup();
+    return CURLE_FAILED_INIT;
+  }
+  /* The Windows Sockets DLL is acceptable. Proceed. */
+  return CURLE_OK;
+}
+
+#else
+/* These functions exist merely to prevent compiler warnings */
+static CURLcode win32_init(void) { return CURLE_OK; }
+static void win32_cleanup(void) { }
+#endif
+
+#ifdef USE_LIBIDN
+/*
+ * Initialise use of IDNA library.
+ * It falls back to ASCII if $CHARSET isn't defined. This doesn't work for
+ * idna_to_ascii_lz().
+ */
+static void idna_init (void)
+{
+#ifdef WIN32
+  char buf[60];
+  UINT cp = GetACP();
+
+  if (!getenv("CHARSET") && cp > 0) {
+    snprintf(buf, sizeof(buf), "CHARSET=cp%u", cp);
+    putenv(buf);
+  }
+#else
+  /* to do? */
+#endif
+}
+#endif  /* USE_LIBIDN */
+
+/* true globals -- for curl_global_init() and curl_global_cleanup() */
+static unsigned int  initialized = 0;
+static long          init_flags  = 0;
+
+/*
+ * If a memory-using function (like curl_getenv) is used before
+ * curl_global_init() is called, we need to have these pointers set already.
+ */
+curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc;
+curl_free_callback Curl_cfree = (curl_free_callback)free;
+curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
+curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)strdup;
+curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
+
+/**
+ * curl_global_init() globally initializes cURL given a bitwise set of the
+ * different features of what to initialize.
+ */
+CURLcode curl_global_init(long flags)
+{
+  if (initialized)
+    return CURLE_OK;
+
+  /* Setup the default memory functions here (again) */
+  Curl_cmalloc = (curl_malloc_callback)malloc;
+  Curl_cfree = (curl_free_callback)free;
+  Curl_crealloc = (curl_realloc_callback)realloc;
+  Curl_cstrdup = (curl_strdup_callback)strdup;
+  Curl_ccalloc = (curl_calloc_callback)calloc;
+
+  if (flags & CURL_GLOBAL_SSL)
+    Curl_SSL_init();
+
+  if (flags & CURL_GLOBAL_WIN32)
+    if (win32_init() != CURLE_OK)
+      return CURLE_FAILED_INIT;
+
+#ifdef _AMIGASF
+  if(!amiga_init())
+    return CURLE_FAILED_INIT;
+#endif
+
+#ifdef USE_LIBIDN
+  idna_init();
+#endif
+
+  initialized = 1;
+  init_flags  = flags;
+
+  return CURLE_OK;
+}
+
+/*
+ * curl_global_init_mem() globally initializes cURL and also registers the
+ * user provided callback routines.
+ */
+CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
+                              curl_free_callback f, curl_realloc_callback r,
+                              curl_strdup_callback s, curl_calloc_callback c)
+{
+  CURLcode code;
+
+  /* Invalid input, return immediately */
+  if (!m || !f || !r || !s || !c)
+    return CURLE_FAILED_INIT;
+
+  /* Already initialized, don't do it again */
+  if ( initialized )
+    return CURLE_OK;
+
+  /* Call the actual init function first */
+  code = curl_global_init(flags);
+  if (code == CURLE_OK) {
+    Curl_cmalloc = m;
+    Curl_cfree = f;
+    Curl_cstrdup = s;
+    Curl_crealloc = r;
+    Curl_ccalloc = c;
+  }
+
+  return code;
+}
+
+/**
+ * curl_global_cleanup() globally cleanups cURL, uses the value of
+ * "init_flags" to determine what needs to be cleaned up and what doesn't.
+ */
+void curl_global_cleanup(void)
+{
+  if (!initialized)
+    return;
+
+  Curl_global_host_cache_dtor();
+
+  if (init_flags & CURL_GLOBAL_SSL)
+    Curl_SSL_cleanup();
+
+  if (init_flags & CURL_GLOBAL_WIN32)
+    win32_cleanup();
+
+#ifdef _AMIGASF
+  amiga_cleanup();
+#endif
+
+  initialized = 0;
+  init_flags  = 0;
+}
+
+/*
+ * curl_easy_init() is the external interface to alloc, setup and init an
+ * easy handle that is returned. If anything goes wrong, NULL is returned.
+ */
+CURL *curl_easy_init(void)
+{
+  CURLcode res;
+  struct SessionHandle *data;
+
+  /* Make sure we inited the global SSL stuff */
+  if (!initialized) {
+    res = curl_global_init(CURL_GLOBAL_DEFAULT);
+    if(res)
+      /* something in the global init failed, return nothing */
+      return NULL;
+  }
+
+  /* We use curl_open() with undefined URL so far */
+  res = Curl_open(&data);
+  if(res != CURLE_OK)
+    return NULL;
+
+  return data;
+}
+
+/*
+ * curl_easy_setopt() is the external interface for setting options on an
+ * easy handle.
+ */
+typedef int (*func_T)(void);
+CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
+{
+  va_list arg;
+  func_T param_func;
+  long param_long;
+  void *param_obj;
+  curl_off_t param_offset;
+  struct SessionHandle *data = curl;
+  CURLcode ret;
+
+  if(!curl)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  va_start(arg, tag);
+
+  /* PORTING NOTE:
+     Object pointers can't necessarily be casted to function pointers and
+     therefore we need to know what type it is and read the correct type
+     at once. This should also correct problems with different sizes of
+     the types.
+  */
+
+  if(tag < CURLOPTTYPE_OBJECTPOINT) {
+    /* This is a LONG type */
+    param_long = va_arg(arg, long);
+    ret = Curl_setopt(data, tag, param_long);
+  }
+  else if(tag < CURLOPTTYPE_FUNCTIONPOINT) {
+    /* This is a object pointer type */
+    param_obj = va_arg(arg, void *);
+    ret = Curl_setopt(data, tag, param_obj);
+  }
+  else if(tag < CURLOPTTYPE_OFF_T) {
+    /* This is a function pointer type */
+    param_func = va_arg(arg, func_T );
+    ret = Curl_setopt(data, tag, param_func);
+  }
+  else {
+    /* This is a curl_off_t type */
+    param_offset = va_arg(arg, curl_off_t);
+    ret = Curl_setopt(data, tag, param_offset);
+  }
+
+  va_end(arg);
+  return ret;
+}
+
+/*
+ * curl_easy_perform() is the external interface that performs a transfer
+ * previously setup.
+ */
+CURLcode curl_easy_perform(CURL *curl)
+{
+  struct SessionHandle *data = (struct SessionHandle *)curl;
+
+  if(!data)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  if ( ! (data->share && data->share->hostcache) ) {
+
+    if (Curl_global_host_cache_use(data) &&
+        data->hostcache != Curl_global_host_cache_get()) {
+      if (data->hostcache)
+        Curl_hash_destroy(data->hostcache);
+      data->hostcache = Curl_global_host_cache_get();
+    }
+
+    if (!data->hostcache) {
+      data->hostcache = Curl_mk_dnscache();
+
+      if(!data->hostcache)
+        /* While we possibly could survive and do good without a host cache,
+           the fact that creating it failed indicates that things are truly
+           screwed up and we should bail out! */
+        return CURLE_OUT_OF_MEMORY;
+    }
+
+  }
+
+  return Curl_perform(data);
+}
+
+/*
+ * curl_easy_cleanup() is the external interface to cleaning/freeing the given
+ * easy handle.
+ */
+void curl_easy_cleanup(CURL *curl)
+{
+  struct SessionHandle *data = (struct SessionHandle *)curl;
+
+  if(!data)
+    return;
+
+  if ( ! (data->share && data->share->hostcache) ) {
+    if ( !Curl_global_host_cache_use(data)) {
+      Curl_hash_destroy(data->hostcache);
+    }
+  }
+  Curl_close(data);
+}
+
+/*
+ * curl_easy_getinfo() is an external interface that allows an app to retrieve
+ * information from a performed transfer and similar.
+ */
+CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...)
+{
+  va_list arg;
+  void *paramp;
+  struct SessionHandle *data = (struct SessionHandle *)curl;
+
+  va_start(arg, info);
+  paramp = va_arg(arg, void *);
+
+  return Curl_getinfo(data, info, paramp);
+}
+
+/*
+ * curl_easy_duphandle() is an external interface to allow duplication of a
+ * given input easy handle. The returned handle will be a new working handle
+ * with all options set exactly as the input source handle.
+ */
+CURL *curl_easy_duphandle(CURL *incurl)
+{
+  bool fail = TRUE;
+  struct SessionHandle *data=(struct SessionHandle *)incurl;
+
+  struct SessionHandle *outcurl = (struct SessionHandle *)
+    calloc(sizeof(struct SessionHandle), 1);
+
+  if(NULL == outcurl)
+    return NULL; /* failure */
+
+  do {
+
+    /*
+     * We setup a few buffers we need. We should probably make them
+     * get setup on-demand in the code, as that would probably decrease
+     * the likeliness of us forgetting to init a buffer here in the future.
+     */
+    outcurl->state.headerbuff=(char*)malloc(HEADERSIZE);
+    if(!outcurl->state.headerbuff) {
+      break;
+    }
+    outcurl->state.headersize=HEADERSIZE;
+
+    /* copy all userdefined values */
+    outcurl->set = data->set;
+    outcurl->state.numconnects = data->state.numconnects;
+    outcurl->state.connects = (struct connectdata **)
+      malloc(sizeof(struct connectdata *) * outcurl->state.numconnects);
+
+    if(!outcurl->state.connects) {
+      break;
+    }
+
+    memset(outcurl->state.connects, 0,
+           sizeof(struct connectdata *)*outcurl->state.numconnects);
+
+    outcurl->progress.flags    = data->progress.flags;
+    outcurl->progress.callback = data->progress.callback;
+
+#ifndef CURL_DISABLE_HTTP
+    if(data->cookies) {
+      /* If cookies are enabled in the parent handle, we enable them
+         in the clone as well! */
+      outcurl->cookies = Curl_cookie_init(data,
+                                            data->cookies->filename,
+                                            outcurl->cookies,
+                                            data->set.cookiesession);
+      if(!outcurl->cookies) {
+        break;
+      }
+    }
+#endif   /* CURL_DISABLE_HTTP */
+
+    /* duplicate all values in 'change' */
+    if(data->change.url) {
+      outcurl->change.url = strdup(data->change.url);
+      if(!outcurl->change.url)
+        break;
+      outcurl->change.url_alloc = TRUE;
+    }
+    if(data->change.proxy) {
+      outcurl->change.proxy = strdup(data->change.proxy);
+      if(!outcurl->change.proxy)
+        break;
+      outcurl->change.proxy_alloc = TRUE;
+    }
+    if(data->change.referer) {
+      outcurl->change.referer = strdup(data->change.referer);
+      if(!outcurl->change.referer)
+        break;
+      outcurl->change.referer_alloc = TRUE;
+    }
+
+#ifdef USE_ARES
+    /* If we use ares, we setup a new ares channel for the new handle */
+    if(ARES_SUCCESS != ares_init(&outcurl->state.areschannel))
+      break;
+#endif
+
+    fail = FALSE; /* we reach this point and thus we are OK */
+
+  } while(0);
+
+  if(fail) {
+    if(outcurl) {
+      if(outcurl->state.connects)
+        free(outcurl->state.connects);
+      if(outcurl->state.headerbuff)
+        free(outcurl->state.headerbuff);
+      if(outcurl->change.proxy)
+        free(outcurl->change.proxy);
+      if(outcurl->change.url)
+        free(outcurl->change.url);
+      if(outcurl->change.referer)
+        free(outcurl->change.referer);
+      free(outcurl); /* free the memory again */
+      outcurl = NULL;
+    }
+  }
+
+  return outcurl;
+}
+
+/*
+ * curl_easy_reset() is an external interface that allows an app to re-
+ * initialize a session handle to the default values.
+ */
+void curl_easy_reset(CURL *curl)
+{
+  struct SessionHandle *data = (struct SessionHandle *)curl;
+
+  /* zero out UserDefined data: */
+  memset(&data->set, 0, sizeof(struct UserDefined));
+
+  /* zero out Progress data: */
+  memset(&data->progress, 0, sizeof(struct Progress));
+
+  /* The remainder of these calls have been taken from Curl_open() */
+
+  data->set.out = stdout; /* default output to stdout */
+  data->set.in  = stdin;  /* default input from stdin */
+  data->set.err  = stderr;  /* default stderr to stderr */
+
+  /* use fwrite as default function to store output */
+  data->set.fwrite = (curl_write_callback)fwrite;
+
+  /* use fread as default function to read input */
+  data->set.fread = (curl_read_callback)fread;
+
+  data->set.infilesize = -1; /* we don't know any size */
+
+  data->state.current_speed = -1; /* init to negative == impossible */
+
+  data->set.httpreq = HTTPREQ_GET; /* Default HTTP request */
+  data->set.ftp_use_epsv = TRUE;   /* FTP defaults to EPSV operations */
+  data->set.ftp_use_eprt = TRUE;   /* FTP defaults to EPRT operations */
+
+  data->set.dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
+
+  /* make libcurl quiet by default: */
+  data->set.hide_progress = TRUE;  /* CURLOPT_NOPROGRESS changes these */
+
+  /* Set the default size of the SSL session ID cache */
+  data->set.ssl.numsessions = 5;
+
+  data->set.proxyport = 1080;
+  data->set.proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
+  data->set.httpauth = CURLAUTH_BASIC;  /* defaults to basic */
+  data->set.proxyauth = CURLAUTH_BASIC; /* defaults to basic */
+
+  /*
+   * libcurl 7.10 introduced SSL verification *by default*! This needs to be
+   * switched off unless wanted.
+   */
+  data->set.ssl.verifypeer = TRUE;
+  data->set.ssl.verifyhost = 2;
+#ifdef CURL_CA_BUNDLE
+  /* This is our prefered CA cert bundle since install time */
+  data->set.ssl.CAfile = (char *)CURL_CA_BUNDLE;
+#endif
+}
diff --git a/Utilities/cmcurl/escape.c b/Utilities/cmcurl/escape.c
new file mode 100644
index 0000000..2b9a883
--- /dev/null
+++ b/Utilities/cmcurl/escape.c
@@ -0,0 +1,135 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/* Escape and unescape URL encoding in strings. The functions return a new
+ * allocated string or NULL if an error occurred.  */
+
+#include "setup.h"
+#include <ctype.h>
+#include <curl/curl.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "curl_memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+char *curl_escape(const char *string, int inlength)
+{
+  size_t alloc = (inlength?(size_t)inlength:strlen(string))+1;
+  char *ns;
+  char *testing_ptr;
+  unsigned char in;
+  size_t newlen = alloc;
+  int strindex=0;
+  size_t length;
+
+  ns = malloc(alloc);
+  if(!ns)
+    return NULL;
+
+  length = alloc-1;
+  while(length--) {
+    in = *string;
+    if(!(in >= 'a' && in <= 'z') &&
+       !(in >= 'A' && in <= 'Z') &&
+       !(in >= '0' && in <= '9')) {
+      /* encode it */
+      newlen += 2; /* the size grows with two, since this'll become a %XX */
+      if(newlen > alloc) {
+        alloc *= 2;
+        testing_ptr = realloc(ns, alloc);
+        if(!testing_ptr) {
+          free( ns );
+          return NULL;
+        }
+        else {
+          ns = testing_ptr;
+        }
+      }
+      snprintf(&ns[strindex], 4, "%%%02X", in);
+
+      strindex+=3;
+    }
+    else {
+      /* just copy this */
+      ns[strindex++]=in;
+    }
+    string++;
+  }
+  ns[strindex]=0; /* terminate it */
+  return ns;
+}
+
+#define ishex(in) ((in >= 'a' && in <= 'f') || \
+                   (in >= 'A' && in <= 'F') || \
+                   (in >= '0' && in <= '9'))
+
+char *curl_unescape(const char *string, int length)
+{
+  int alloc = (length?length:(int)strlen(string))+1;
+  char *ns = malloc(alloc);
+  unsigned char in;
+  int strindex=0;
+  long hex;
+
+  if( !ns )
+    return NULL;
+
+  while(--alloc > 0) {
+    in = *string;
+    if(('%' == in) && ishex(string[1]) && ishex(string[2])) {
+      /* this is two hexadecimal digits following a '%' */
+      char hexstr[3];
+      char *ptr;
+      hexstr[0] = string[1];
+      hexstr[1] = string[2];
+      hexstr[2] = 0;
+
+      hex = strtol(hexstr, &ptr, 16);
+
+      in = (unsigned char)hex; /* this long is never bigger than 255 anyway */
+      string+=2;
+      alloc-=2;
+    }
+
+    ns[strindex++] = in;
+    string++;
+  }
+  ns[strindex]=0; /* terminate it */
+  return ns;
+}
+
+/* For operating systems/environments that use different malloc/free
+   ssystems for the app and for this library, we provide a free that uses
+   the library's memory system */
+void curl_free(void *p)
+{
+  if(p)
+    free(p);
+}
diff --git a/Utilities/cmcurl/escape.h b/Utilities/cmcurl/escape.h
new file mode 100644
index 0000000..4d29236
--- /dev/null
+++ b/Utilities/cmcurl/escape.h
@@ -0,0 +1,32 @@
+#ifndef __ESCAPE_H
+#define __ESCAPE_H
+
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+/* Escape and unescape URL encoding in strings. The functions return a new
+ * allocated string or NULL if an error occurred.  */
+
+char *curl_escape(const char *string, int length);
+char *curl_unescape(const char *string, int length);
+
+#endif
diff --git a/Utilities/cmcurl/file.c b/Utilities/cmcurl/file.c
new file mode 100644
index 0000000..cd4366c
--- /dev/null
+++ b/Utilities/cmcurl/file.c
@@ -0,0 +1,390 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#ifndef CURL_DISABLE_FILE
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#include <time.h>
+#include <io.h>
+#include <fcntl.h>
+#else
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#include <sys/time.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#include <sys/ioctl.h>
+#include <signal.h>
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "progress.h"
+#include "sendf.h"
+#include "escape.h"
+#include "file.h"
+#include "speedcheck.h"
+#include "getinfo.h"
+#include "transfer.h"
+#include "url.h"
+#include "curl_memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * Curl_file_connect() gets called from Curl_protocol_connect() to allow us to
+ * do protocol-specific actions at connect-time.  We emulate a
+ * connect-then-transfer protocol and "connect" to the file here
+ */
+CURLcode Curl_file_connect(struct connectdata *conn)
+{
+  char *real_path = curl_unescape(conn->path, 0);
+  struct FILEPROTO *file;
+  int fd;
+#if defined(WIN32) || defined(__EMX__)
+  int i;
+  char *actual_path;
+#endif
+
+  if(!real_path)
+    return CURLE_OUT_OF_MEMORY;
+
+  file = (struct FILEPROTO *)calloc(sizeof(struct FILEPROTO), 1);
+  if(!file) {
+    free(real_path);
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  conn->proto.file = file;
+
+#if defined(WIN32) || defined(__EMX__)
+  /* If the first character is a slash, and there's
+     something that looks like a drive at the beginning of
+     the path, skip the slash.  If we remove the initial
+     slash in all cases, paths without drive letters end up
+     relative to the current directory which isn't how
+     browsers work.
+
+     Some browsers accept | instead of : as the drive letter
+     separator, so we do too.
+
+     On other platforms, we need the slash to indicate an
+     absolute pathname.  On Windows, absolute paths start
+     with a drive letter.
+  */
+  actual_path = real_path;
+  if ((actual_path[0] == '/') &&
+      actual_path[1] &&
+      (actual_path[2] == ':' || actual_path[2] == '|'))
+  {
+    actual_path[2] = ':';
+    actual_path++;
+  }
+
+  /* change path separators from '/' to '\\' for Windows and OS/2 */
+  for (i=0; actual_path[i] != '\0'; ++i)
+    if (actual_path[i] == '/')
+      actual_path[i] = '\\';
+
+  fd = open(actual_path, O_RDONLY | O_BINARY);  /* no CR/LF translation! */
+  file->path = actual_path;
+#else
+  fd = open(real_path, O_RDONLY);
+  file->path = real_path;
+#endif
+  file->freepath = real_path; /* free this when done */
+
+  if(!conn->data->set.upload && (fd == -1)) {
+    failf(conn->data, "Couldn't open file %s", conn->path);
+    Curl_file_done(conn, CURLE_FILE_COULDNT_READ_FILE);
+    return CURLE_FILE_COULDNT_READ_FILE;
+  }
+  file->fd = fd;
+
+  return CURLE_OK;
+}
+
+#if defined(WIN32) && (SIZEOF_CURL_OFF_T > 4)
+#define lseek(x,y,z) _lseeki64(x, y, z)
+#endif
+
+CURLcode Curl_file_done(struct connectdata *conn,
+                        CURLcode status)
+{
+  struct FILEPROTO *file = conn->proto.file;
+  (void)status; /* not used */
+  Curl_safefree(file->freepath);
+
+  return CURLE_OK;
+}
+
+#if defined(WIN32) || defined(__EMX__)
+#define DIRSEP '\\'
+#else
+#define DIRSEP '/'
+#endif
+
+static CURLcode file_upload(struct connectdata *conn)
+{
+  struct FILEPROTO *file = conn->proto.file;
+  char *dir = strchr(file->path, DIRSEP);
+  FILE *fp;
+  CURLcode res=CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  char *buf = data->state.buffer;
+  size_t nread;
+  size_t nwrite;
+  curl_off_t bytecount = 0;
+  struct timeval now = Curl_tvnow();
+
+  /*
+   * Since FILE: doesn't do the full init, we need to provide some extra
+   * assignments here.
+   */
+  conn->fread = data->set.fread;
+  conn->fread_in = data->set.in;
+  conn->upload_fromhere = buf;
+
+  if(!dir)
+    return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */
+
+  if(!dir[1])
+     return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */
+
+  fp = fopen(file->path, "wb");
+  if(!fp) {
+    failf(data, "Can't open %s for writing", file->path);
+    return CURLE_WRITE_ERROR;
+  }
+
+  if(-1 != data->set.infilesize)
+    /* known size of data to "upload" */
+    Curl_pgrsSetUploadSize(data, data->set.infilesize);
+
+  while (res == CURLE_OK) {
+    int readcount;
+    res = Curl_fillreadbuffer(conn, BUFSIZE, &readcount);
+    if(res)
+      return res;
+
+    nread = (size_t)readcount;
+
+    if (nread <= 0)
+      break;
+
+    /* write the data to the target */
+    nwrite = fwrite(buf, 1, nread, fp);
+    if(nwrite != nread) {
+      res = CURLE_SEND_ERROR;
+      break;
+    }
+
+    bytecount += nread;
+
+    Curl_pgrsSetUploadCounter(data, bytecount);
+
+    if(Curl_pgrsUpdate(conn))
+      res = CURLE_ABORTED_BY_CALLBACK;
+    else
+      res = Curl_speedcheck(data, now);
+  }
+  if(!res && Curl_pgrsUpdate(conn))
+    res = CURLE_ABORTED_BY_CALLBACK;
+
+  fclose(fp);
+
+  return res;
+}
+
+/*
+ * Curl_file() is the protocol-specific function for the do-phase, separated
+ * from the connect-phase above. Other protocols merely setup the transfer in
+ * the do-phase, to have it done in the main transfer loop but since some
+ * platforms we support don't allow select()ing etc on file handles (as
+ * opposed to sockets) we instead perform the whole do-operation in this
+ * function.
+ */
+CURLcode Curl_file(struct connectdata *conn)
+{
+  /* This implementation ignores the host name in conformance with
+     RFC 1738. Only local files (reachable via the standard file system)
+     are supported. This means that files on remotely mounted directories
+     (via NFS, Samba, NT sharing) can be accessed through a file:// URL
+  */
+  CURLcode res = CURLE_OK;
+  struct stat statbuf;
+  curl_off_t expected_size=0;
+  bool fstated=FALSE;
+  ssize_t nread;
+  struct SessionHandle *data = conn->data;
+  char *buf = data->state.buffer;
+  curl_off_t bytecount = 0;
+  int fd;
+  struct timeval now = Curl_tvnow();
+
+  Curl_readwrite_init(conn);
+  Curl_initinfo(data);
+  Curl_pgrsStartNow(data);
+
+  if(data->set.upload)
+    return file_upload(conn);
+
+  /* get the fd from the connection phase */
+  fd = conn->proto.file->fd;
+
+  /* VMS: This only works reliable for STREAMLF files */
+  if( -1 != fstat(fd, &statbuf)) {
+    /* we could stat it, then read out the size */
+    expected_size = statbuf.st_size;
+    fstated = TRUE;
+  }
+
+  /* If we have selected NOBODY and HEADER, it means that we only want file
+     information. Which for FILE can't be much more than the file size and
+     date. */
+  if(conn->bits.no_body && data->set.include_header && fstated) {
+    CURLcode result;
+    snprintf(buf, sizeof(data->state.buffer),
+             "Content-Length: %" FORMAT_OFF_T "\r\n", expected_size);
+    result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
+    if(result)
+      return result;
+
+    result = Curl_client_write(data, CLIENTWRITE_BOTH,
+                               (char *)"Accept-ranges: bytes\r\n", 0);
+    if(result)
+      return result;
+
+#ifdef HAVE_STRFTIME
+    if(fstated) {
+      struct tm *tm;
+      time_t cuClock = (time_t)statbuf.st_mtime;
+#ifdef HAVE_GMTIME_R
+      struct tm buffer;
+      tm = (struct tm *)gmtime_r(&cuClock, &buffer);
+#else
+      tm = gmtime(&cuClock);
+#endif
+      /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
+      strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S GMT\r\n",
+               tm);
+      result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
+    }
+#endif
+    return result;
+  }
+
+  /* Added by Dolbneff A.V & Spiridonoff A.V */
+  if (conn->resume_from <= expected_size)
+    expected_size -= conn->resume_from;
+  else
+    /* Is this error code suitable in such situation? */
+    return CURLE_FTP_BAD_DOWNLOAD_RESUME;
+
+  if (fstated && (expected_size == 0))
+    return CURLE_OK;
+
+  /* The following is a shortcut implementation of file reading
+     this is both more efficient than the former call to download() and
+     it avoids problems with select() and recv() on file descriptors
+     in Winsock */
+  if(fstated)
+    Curl_pgrsSetDownloadSize(data, expected_size);
+
+  if(conn->resume_from)
+    lseek(fd, conn->resume_from, SEEK_SET);
+
+  Curl_pgrsTime(data, TIMER_STARTTRANSFER);
+
+  while (res == CURLE_OK) {
+    nread = read(fd, buf, BUFSIZE-1);
+
+    if ( nread > 0)
+      buf[nread] = 0;
+
+    if (nread <= 0)
+      break;
+
+    bytecount += nread;
+
+    res = Curl_client_write(data, CLIENTWRITE_BODY, buf, nread);
+    if(res)
+      return res;
+
+    Curl_pgrsSetDownloadCounter(data, bytecount);
+
+    if(Curl_pgrsUpdate(conn))
+      res = CURLE_ABORTED_BY_CALLBACK;
+    else
+      res = Curl_speedcheck(data, now);
+  }
+  if(Curl_pgrsUpdate(conn))
+    res = CURLE_ABORTED_BY_CALLBACK;
+
+  close(fd);
+
+  return res;
+}
+#endif
diff --git a/Utilities/cmcurl/file.h b/Utilities/cmcurl/file.h
new file mode 100644
index 0000000..689b8ae
--- /dev/null
+++ b/Utilities/cmcurl/file.h
@@ -0,0 +1,31 @@
+#ifndef __FILE_H
+#define __FILE_H
+
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+#ifndef CURL_DISABLE_FILE
+CURLcode Curl_file(struct connectdata *);
+CURLcode Curl_file_done(struct connectdata *, CURLcode);
+CURLcode Curl_file_connect(struct connectdata *);
+#endif
+#endif
diff --git a/Utilities/cmcurl/formdata.c b/Utilities/cmcurl/formdata.c
new file mode 100644
index 0000000..5abff6e
--- /dev/null
+++ b/Utilities/cmcurl/formdata.c
@@ -0,0 +1,1484 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/*
+  Debug the form generator stand-alone by compiling this source file with:
+
+  gcc -DHAVE_CONFIG_H -I../ -g -D_FORM_DEBUG -o formdata -I../include formdata.c strequal.c
+
+  run the 'formdata' executable the output should end with:
+  All Tests seem to have worked ...
+  and the following parts should be there:
+
+Content-Disposition: form-data; name="simple_COPYCONTENTS"
+value for simple COPYCONTENTS
+
+Content-Disposition: form-data; name="COPYCONTENTS_+_CONTENTTYPE"
+Content-Type: image/gif
+value for COPYCONTENTS + CONTENTTYPE
+
+Content-Disposition: form-data; name="PRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH"
+vlue for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH
+(or you might see P^@RNAME and v^@lue at the start)
+
+Content-Disposition: form-data; name="simple_PTRCONTENTS"
+value for simple PTRCONTENTS
+
+Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH"
+vlue for PTRCONTENTS + CONTENTSLENGTH
+(or you might see v^@lue at the start)
+
+Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE"
+Content-Type: text/plain
+vlue for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE
+(or you might see v^@lue at the start)
+
+Content-Disposition: form-data; name="FILE1_+_CONTENTTYPE"; filename="inet_ntoa_r.h"
+Content-Type: text/html
+...
+
+Content-Disposition: form-data; name="FILE1_+_FILE2"
+Content-Type: multipart/mixed, boundary=curlz1s0dkticx49MV1KGcYP5cvfSsz
+...
+Content-Disposition: attachment; filename="inet_ntoa_r.h"
+Content-Type: text/plain
+...
+Content-Disposition: attachment; filename="Makefile.b32.resp"
+Content-Type: text/plain
+...
+
+Content-Disposition: form-data; name="FILE1_+_FILE2_+_FILE3"
+Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1
+...
+Content-Disposition: attachment; filename="inet_ntoa_r.h"
+Content-Type: text/plain
+...
+Content-Disposition: attachment; filename="Makefile.b32.resp"
+Content-Type: text/plain
+...
+Content-Disposition: attachment; filename="inet_ntoa_r.h"
+Content-Type: text/plain
+...
+
+
+Content-Disposition: form-data; name="ARRAY: FILE1_+_FILE2_+_FILE3"
+Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1
+...
+Content-Disposition: attachment; filename="inet_ntoa_r.h"
+Content-Type: text/plain
+...
+Content-Disposition: attachment; filename="Makefile.b32.resp"
+Content-Type: text/plain
+...
+Content-Disposition: attachment; filename="inet_ntoa_r.h"
+Content-Type: text/plain
+...
+
+Content-Disposition: form-data; name="FILECONTENT"
+...
+
+ */
+
+#include "setup.h"
+#include <curl/curl.h>
+
+/* Length of the random boundary string. */
+#define BOUNDARY_LENGTH 40
+
+#ifndef CURL_DISABLE_HTTP
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <time.h>
+#include <sys/stat.h>
+#include "formdata.h"
+#include "strequal.h"
+#include "curl_memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* What kind of Content-Type to use on un-specified files with unrecognized
+   extensions. */
+#define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream"
+
+#define FORM_FILE_SEPARATOR ','
+#define FORM_TYPE_SEPARATOR ';'
+
+/***************************************************************************
+ *
+ * AddHttpPost()
+ *
+ * Adds a HttpPost structure to the list, if parent_post is given becomes
+ * a subpost of parent_post instead of a direct list element.
+ *
+ * Returns newly allocated HttpPost on success and NULL if malloc failed.
+ *
+ ***************************************************************************/
+static struct curl_httppost *
+AddHttpPost(char * name, size_t namelength,
+            char * value, size_t contentslength,
+            char * buffer, size_t bufferlength,
+            char *contenttype,
+            long flags,
+            struct curl_slist* contentHeader,
+            char *showfilename,
+            struct curl_httppost *parent_post,
+            struct curl_httppost **httppost,
+            struct curl_httppost **last_post)
+{
+  struct curl_httppost *post;
+  post = (struct curl_httppost *)calloc(sizeof(struct curl_httppost), 1);
+  if(post) {
+    post->name = name;
+    post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
+    post->contents = value;
+    post->contentslength = (long)contentslength;
+    post->buffer = buffer;
+    post->bufferlength = (long)bufferlength;
+    post->contenttype = contenttype;
+    post->contentheader = contentHeader;
+    post->showfilename = showfilename;
+    post->flags = flags;
+  }
+  else
+    return NULL;
+
+  if (parent_post) {
+    /* now, point our 'more' to the original 'more' */
+    post->more = parent_post->more;
+
+    /* then move the original 'more' to point to ourselves */
+    parent_post->more = post;
+  }
+  else {
+    /* make the previous point to this */
+    if(*last_post)
+      (*last_post)->next = post;
+    else
+      (*httppost) = post;
+
+    (*last_post) = post;
+  }
+  return post;
+}
+
+/***************************************************************************
+ *
+ * AddFormInfo()
+ *
+ * Adds a FormInfo structure to the list presented by parent_form_info.
+ *
+ * Returns newly allocated FormInfo on success and NULL if malloc failed/
+ * parent_form_info is NULL.
+ *
+ ***************************************************************************/
+static FormInfo * AddFormInfo(char *value,
+                              char *contenttype,
+                              FormInfo *parent_form_info)
+{
+  FormInfo *form_info;
+  form_info = (FormInfo *)malloc(sizeof(FormInfo));
+  if(form_info) {
+    memset(form_info, 0, sizeof(FormInfo));
+    if (value)
+      form_info->value = value;
+    if (contenttype)
+      form_info->contenttype = contenttype;
+    form_info->flags = HTTPPOST_FILENAME;
+  }
+  else
+    return NULL;
+
+  if (parent_form_info) {
+    /* now, point our 'more' to the original 'more' */
+    form_info->more = parent_form_info->more;
+
+    /* then move the original 'more' to point to ourselves */
+    parent_form_info->more = form_info;
+  }
+  else
+    return NULL;
+
+  return form_info;
+}
+
+/***************************************************************************
+ *
+ * ContentTypeForFilename()
+ *
+ * Provides content type for filename if one of the known types (else
+ * (either the prevtype or the default is returned).
+ *
+ * Returns some valid contenttype for filename.
+ *
+ ***************************************************************************/
+static const char * ContentTypeForFilename (const char *filename,
+                                            const char *prevtype)
+{
+  const char *contenttype;
+  unsigned int i;
+  /*
+   * No type was specified, we scan through a few well-known
+   * extensions and pick the first we match!
+   */
+  struct ContentType {
+    const char *extension;
+    const char *type;
+  };
+  static struct ContentType ctts[]={
+    {".gif",  "image/gif"},
+    {".jpg",  "image/jpeg"},
+    {".jpeg", "image/jpeg"},
+    {".txt",  "text/plain"},
+    {".html", "text/html"}
+  };
+
+  if(prevtype)
+    /* default to the previously set/used! */
+    contenttype = prevtype;
+  else
+    /* It seems RFC1867 defines no Content-Type to default to
+       text/plain so we don't actually need to set this: */
+    contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
+
+  for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
+    if(strlen(filename) >= strlen(ctts[i].extension)) {
+      if(strequal(filename +
+                  strlen(filename) - strlen(ctts[i].extension),
+                  ctts[i].extension)) {
+        contenttype = ctts[i].type;
+        break;
+      }
+    }
+  }
+  /* we have a contenttype by now */
+  return contenttype;
+}
+
+/***************************************************************************
+ *
+ * memdup()
+ *
+ * Copies the 'source' data to a newly allocated buffer buffer (that is
+ * returned). Uses buffer_length if not null, else uses strlen to determine
+ * the length of the buffer to be copied
+ *
+ * Returns the new pointer or NULL on failure.
+ *
+ ***************************************************************************/
+static char *memdup(const char *src, size_t buffer_length)
+{
+  size_t length;
+  bool add = FALSE;
+  char *buffer;
+
+  if (buffer_length)
+    length = buffer_length;
+  else {
+    length = strlen(src);
+    add = TRUE;
+  }
+  buffer = (char*)malloc(length+add);
+  if (!buffer)
+    return NULL; /* fail */
+
+  memcpy(buffer, src, length);
+
+  /* if length unknown do null termination */
+  if (add)
+    buffer[length] = '\0';
+
+  return buffer;
+}
+
+/***************************************************************************
+ *
+ * FormAdd()
+ *
+ * Stores a formpost parameter and builds the appropriate linked list.
+ *
+ * Has two principal functionalities: using files and byte arrays as
+ * post parts. Byte arrays are either copied or just the pointer is stored
+ * (as the user requests) while for files only the filename and not the
+ * content is stored.
+ *
+ * While you may have only one byte array for each name, multiple filenames
+ * are allowed (and because of this feature CURLFORM_END is needed after
+ * using CURLFORM_FILE).
+ *
+ * Examples:
+ *
+ * Simple name/value pair with copied contents:
+ * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
+ * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
+ *
+ * name/value pair where only the content pointer is remembered:
+ * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
+ * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
+ * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
+ *
+ * storing a filename (CONTENTTYPE is optional!):
+ * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
+ * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
+ * CURLFORM_END);
+ *
+ * storing multiple filenames:
+ * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
+ * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
+ *
+ * Returns:
+ * CURL_FORMADD_OK             on success
+ * CURL_FORMADD_MEMORY         if the FormInfo allocation fails
+ * CURL_FORMADD_OPTION_TWICE   if one option is given twice for one Form
+ * CURL_FORMADD_NULL           if a null pointer was given for a char
+ * CURL_FORMADD_MEMORY         if the allocation of a FormInfo struct failed
+ * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
+ * CURL_FORMADD_INCOMPLETE     if the some FormInfo is not complete (or an error)
+ * CURL_FORMADD_MEMORY         if a HttpPost struct cannot be allocated
+ * CURL_FORMADD_MEMORY         if some allocation for string copying failed.
+ * CURL_FORMADD_ILLEGAL_ARRAY  if an illegal option is used in an array
+ *
+ ***************************************************************************/
+
+static
+CURLFORMcode FormAdd(struct curl_httppost **httppost,
+                     struct curl_httppost **last_post,
+                     va_list params)
+{
+  FormInfo *first_form, *current_form, *form = NULL;
+  CURLFORMcode return_value = CURL_FORMADD_OK;
+  const char *prevtype = NULL;
+  struct curl_httppost *post;
+  CURLformoption option;
+  struct curl_forms *forms = NULL;
+  char *array_value=NULL; /* value read from an array */
+
+  /* This is a state variable, that if TRUE means that we're parsing an
+     array that we got passed to us. If FALSE we're parsing the input
+     va_list arguments. */
+  bool array_state = FALSE;
+
+  /*
+   * We need to allocate the first struct to fill in.
+   */
+  first_form = (FormInfo *)calloc(sizeof(struct FormInfo), 1);
+  if(!first_form)
+    return CURL_FORMADD_MEMORY;
+
+  current_form = first_form;
+
+  /*
+   * Loop through all the options set. Break if we have an error to report.
+   */
+  while (return_value == CURL_FORMADD_OK) {
+
+    /* first see if we have more parts of the array param */
+    if ( array_state ) {
+      /* get the upcoming option from the given array */
+      option = forms->option;
+      array_value = (char *)forms->value;
+
+      forms++; /* advance this to next entry */
+      if (CURLFORM_END == option) {
+        /* end of array state */
+        array_state = FALSE;
+        continue;
+      }
+    }
+    else {
+      /* This is not array-state, get next option */
+      option = va_arg(params, CURLformoption);
+      if (CURLFORM_END == option)
+        break;
+    }
+
+    switch (option) {
+    case CURLFORM_ARRAY:
+      if(array_state)
+        /* we don't support an array from within an array */
+        return_value = CURL_FORMADD_ILLEGAL_ARRAY;
+      else {
+        forms = va_arg(params, struct curl_forms *);
+        if (forms)
+          array_state = TRUE;
+        else
+          return_value = CURL_FORMADD_NULL;
+      }
+      break;
+
+      /*
+       * Set the Name property.
+       */
+    case CURLFORM_PTRNAME:
+      current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
+    case CURLFORM_COPYNAME:
+      if (current_form->name)
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else {
+        char *name = array_state?
+          array_value:va_arg(params, char *);
+        if (name)
+          current_form->name = name; /* store for the moment */
+        else
+          return_value = CURL_FORMADD_NULL;
+      }
+      break;
+    case CURLFORM_NAMELENGTH:
+      if (current_form->namelength)
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else
+        current_form->namelength =
+          array_state?(long)array_value:va_arg(params, long);
+      break;
+
+      /*
+       * Set the contents property.
+       */
+    case CURLFORM_PTRCONTENTS:
+      current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */
+    case CURLFORM_COPYCONTENTS:
+      if (current_form->value)
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else {
+        char *value =
+          array_state?array_value:va_arg(params, char *);
+        if (value)
+          current_form->value = value; /* store for the moment */
+        else
+          return_value = CURL_FORMADD_NULL;
+      }
+      break;
+    case CURLFORM_CONTENTSLENGTH:
+      if (current_form->contentslength)
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else
+        current_form->contentslength =
+          array_state?(long)array_value:va_arg(params, long);
+      break;
+
+      /* Get contents from a given file name */
+    case CURLFORM_FILECONTENT:
+      if (current_form->flags != 0)
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else {
+        char *filename = array_state?
+          array_value:va_arg(params, char *);
+        if (filename) {
+          current_form->value = strdup(filename);
+          if(!current_form->value)
+            return_value = CURL_FORMADD_MEMORY;
+          else {
+            current_form->flags |= HTTPPOST_READFILE;
+            current_form->value_alloc = TRUE;
+          }
+        }
+        else
+          return_value = CURL_FORMADD_NULL;
+      }
+      break;
+
+      /* We upload a file */
+    case CURLFORM_FILE:
+      {
+        char *filename = array_state?array_value:
+          va_arg(params, char *);
+
+        if (current_form->value) {
+          if (current_form->flags & HTTPPOST_FILENAME) {
+            if (filename) {
+              if (!(current_form = AddFormInfo(strdup(filename),
+                                               NULL, current_form)))
+                return_value = CURL_FORMADD_MEMORY;
+            }
+            else
+              return_value = CURL_FORMADD_NULL;
+          }
+          else
+            return_value = CURL_FORMADD_OPTION_TWICE;
+        }
+        else {
+          if (filename) {
+            current_form->value = strdup(filename);
+            if(!current_form->value)
+              return_value = CURL_FORMADD_MEMORY;
+            else {
+              current_form->flags |= HTTPPOST_FILENAME;
+              current_form->value_alloc = TRUE;
+            }
+          }
+          else
+            return_value = CURL_FORMADD_NULL;
+        }
+        break;
+      }
+
+    case CURLFORM_BUFFER:
+      {
+        char *filename = array_state?array_value:
+          va_arg(params, char *);
+
+        if (current_form->value) {
+          if (current_form->flags & HTTPPOST_BUFFER) {
+            if (filename) {
+              if (!(current_form = AddFormInfo(strdup(filename),
+                                               NULL, current_form)))
+                return_value = CURL_FORMADD_MEMORY;
+            }
+            else
+              return_value = CURL_FORMADD_NULL;
+          }
+          else
+            return_value = CURL_FORMADD_OPTION_TWICE;
+        }
+        else {
+          if (filename) {
+            current_form->value = strdup(filename);
+            if(!current_form->value)
+              return_value = CURL_FORMADD_MEMORY;
+          }
+          else
+            return_value = CURL_FORMADD_NULL;
+          current_form->flags |= HTTPPOST_BUFFER;
+        }
+        break;
+      }
+
+    case CURLFORM_BUFFERPTR:
+        current_form->flags |= HTTPPOST_PTRBUFFER;
+      if (current_form->buffer)
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else {
+        char *buffer =
+          array_state?array_value:va_arg(params, char *);
+        if (buffer)
+          current_form->buffer = buffer; /* store for the moment */
+        else
+          return_value = CURL_FORMADD_NULL;
+      }
+      break;
+
+    case CURLFORM_BUFFERLENGTH:
+      if (current_form->bufferlength)
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else
+        current_form->bufferlength =
+          array_state?(long)array_value:va_arg(params, long);
+      break;
+
+    case CURLFORM_CONTENTTYPE:
+      {
+        char *contenttype =
+          array_state?array_value:va_arg(params, char *);
+        if (current_form->contenttype) {
+          if (current_form->flags & HTTPPOST_FILENAME) {
+            if (contenttype) {
+              if (!(current_form = AddFormInfo(NULL,
+                                               strdup(contenttype),
+                                               current_form)))
+                return_value = CURL_FORMADD_MEMORY;
+            }
+            else
+              return_value = CURL_FORMADD_NULL;
+          }
+          else
+            return_value = CURL_FORMADD_OPTION_TWICE;
+        }
+        else {
+          if (contenttype) {
+            current_form->contenttype = strdup(contenttype);
+            if(!current_form->contenttype)
+              return_value = CURL_FORMADD_MEMORY;
+            else
+              current_form->contenttype_alloc = TRUE;
+          }
+          else
+            return_value = CURL_FORMADD_NULL;
+        }
+        break;
+      }
+    case CURLFORM_CONTENTHEADER:
+      {
+        /* this "cast increases required alignment of target type" but
+           we consider it OK anyway */
+        struct curl_slist* list = 0;
+        if ( array_state )
+          {
+          memcpy(&list, &array_value, sizeof(struct curl_slist*));
+          }
+        else
+          {
+          list = va_arg(params, struct curl_slist*);
+          }
+
+        if( current_form->contentheader )
+          return_value = CURL_FORMADD_OPTION_TWICE;
+        else
+          current_form->contentheader = list;
+
+        break;
+      }
+    case CURLFORM_FILENAME:
+      {
+        char *filename = array_state?array_value:
+          va_arg(params, char *);
+        if( current_form->showfilename )
+          return_value = CURL_FORMADD_OPTION_TWICE;
+        else {
+          current_form->showfilename = strdup(filename);
+          if(!current_form->showfilename)
+            return_value = CURL_FORMADD_MEMORY;
+          else
+            current_form->showfilename_alloc = TRUE;
+        }
+        break;
+      }
+    default:
+      return_value = CURL_FORMADD_UNKNOWN_OPTION;
+    }
+  }
+
+  if(CURL_FORMADD_OK == return_value) {
+    /* go through the list, check for copleteness and if everything is
+     * alright add the HttpPost item otherwise set return_value accordingly */
+
+    post = NULL;
+    for(form = first_form;
+        form != NULL;
+        form = form->more) {
+      if ( ((!form->name || !form->value) && !post) ||
+           ( (form->contentslength) &&
+             (form->flags & HTTPPOST_FILENAME) ) ||
+           ( (form->flags & HTTPPOST_FILENAME) &&
+             (form->flags & HTTPPOST_PTRCONTENTS) ) ||
+
+           ( (!form->buffer) &&
+             (form->flags & HTTPPOST_BUFFER) &&
+             (form->flags & HTTPPOST_PTRBUFFER) ) ||
+
+           ( (form->flags & HTTPPOST_READFILE) &&
+             (form->flags & HTTPPOST_PTRCONTENTS) )
+           ) {
+        return_value = CURL_FORMADD_INCOMPLETE;
+        break;
+      }
+      else {
+        if ( ((form->flags & HTTPPOST_FILENAME) ||
+              (form->flags & HTTPPOST_BUFFER)) &&
+             !form->contenttype ) {
+          /* our contenttype is missing */
+          form->contenttype
+            = strdup(ContentTypeForFilename(form->value, prevtype));
+          if(!form->contenttype) {
+            return_value = CURL_FORMADD_MEMORY;
+            break;
+          }
+          form->contenttype_alloc = TRUE;
+        }
+        if ( !(form->flags & HTTPPOST_PTRNAME) &&
+             (form == first_form) ) {
+          /* copy name (without strdup; possibly contains null characters) */
+          form->name = memdup(form->name, form->namelength);
+          if (!form->name) {
+            return_value = CURL_FORMADD_MEMORY;
+            break;
+          }
+          form->name_alloc = TRUE;
+        }
+        if ( !(form->flags & HTTPPOST_FILENAME) &&
+             !(form->flags & HTTPPOST_READFILE) &&
+             !(form->flags & HTTPPOST_PTRCONTENTS) &&
+             !(form->flags & HTTPPOST_PTRBUFFER) ) {
+          /* copy value (without strdup; possibly contains null characters) */
+          form->value = memdup(form->value, form->contentslength);
+          if (!form->value) {
+            return_value = CURL_FORMADD_MEMORY;
+            break;
+          }
+          form->value_alloc = TRUE;
+        }
+        post = AddHttpPost(form->name, form->namelength,
+                           form->value, form->contentslength,
+                           form->buffer, form->bufferlength,
+                           form->contenttype, form->flags,
+                           form->contentheader, form->showfilename,
+                           post, httppost,
+                           last_post);
+
+        if(!post) {
+          return_value = CURL_FORMADD_MEMORY;
+          break;
+        }
+
+        if (form->contenttype)
+          prevtype = form->contenttype;
+      }
+    }
+  }
+
+  if(return_value) {
+    /* we return on error, free possibly allocated fields */
+    if(!form)
+      form = current_form;
+    if(form) {
+      if(form->name_alloc)
+        free(form->name);
+      if(form->value_alloc)
+        free(form->value);
+      if(form->contenttype_alloc)
+        free(form->contenttype);
+      if(form->showfilename_alloc)
+        free(form->showfilename);
+    }
+  }
+
+  /* always delete the allocated memory before returning */
+  form = first_form;
+  while (form != NULL) {
+    FormInfo *delete_form;
+
+    delete_form = form;
+    form = form->more;
+    free (delete_form);
+  }
+
+  return return_value;
+}
+
+/*
+ * curl_formadd() is a public API to add a section to the multipart formpost.
+ */
+
+CURLFORMcode curl_formadd(struct curl_httppost **httppost,
+                          struct curl_httppost **last_post,
+                          ...)
+{
+  va_list arg;
+  CURLFORMcode result;
+  va_start(arg, last_post);
+  result = FormAdd(httppost, last_post, arg);
+  va_end(arg);
+  return result;
+}
+
+/*
+ * AddFormData() adds a chunk of data to the FormData linked list.
+ *
+ * size is incremented by the chunk length, unless it is NULL
+ */
+static CURLcode AddFormData(struct FormData **formp,
+                            enum formtype type,
+                            const void *line,
+                            size_t length,
+                            curl_off_t *size)
+{
+  struct FormData *newform = (struct FormData *)
+    malloc(sizeof(struct FormData));
+  if (!newform)
+    return CURLE_OUT_OF_MEMORY;
+  newform->next = NULL;
+
+  /* we make it easier for plain strings: */
+  if(!length)
+    length = strlen((char *)line);
+
+  newform->line = (char *)malloc(length+1);
+  if (!newform->line) {
+    free(newform);
+    return CURLE_OUT_OF_MEMORY;
+  }
+  memcpy(newform->line, line, length);
+  newform->length = length;
+  newform->line[length]=0; /* zero terminate for easier debugging */
+  newform->type = type;
+
+  if(*formp) {
+    (*formp)->next = newform;
+    *formp = newform;
+  }
+  else
+    *formp = newform;
+
+  if (size) {
+    if(type == FORM_DATA)
+      *size += length;
+    else {
+      /* Since this is a file to be uploaded here, add the size of the actual
+         file */
+      if(!strequal("-", newform->line)) {
+        struct stat file;
+        if(!stat(newform->line, &file)) {
+          *size += file.st_size;
+        }
+      }
+    }
+  }
+  return CURLE_OK;
+}
+
+/*
+ * AddFormDataf() adds printf()-style formatted data to the formdata chain.
+ */
+
+static CURLcode AddFormDataf(struct FormData **formp,
+                             curl_off_t *size,
+                             const char *fmt, ...)
+{
+  char s[4096];
+  va_list ap;
+  va_start(ap, fmt);
+  vsnprintf(s, sizeof(s), fmt, ap);
+  va_end(ap);
+
+  return AddFormData(formp, FORM_DATA, s, 0, size);
+}
+
+/*
+ * Curl_formclean() is used from http.c, this cleans a built FormData linked
+ * list
+ */
+void Curl_formclean(struct FormData *form)
+{
+  struct FormData *next;
+
+  if(!form)
+    return;
+
+  do {
+    next=form->next;  /* the following form line */
+    free(form->line); /* free the line */
+    free(form);       /* free the struct */
+
+  } while((form=next)); /* continue */
+}
+
+/*
+ * curl_formfree() is an external function to free up a whole form post
+ * chain
+ */
+void curl_formfree(struct curl_httppost *form)
+{
+  struct curl_httppost *next;
+
+  if(!form)
+    /* no form to free, just get out of this */
+    return;
+
+  do {
+    next=form->next;  /* the following form line */
+
+    /* recurse to sub-contents */
+    if(form->more)
+      curl_formfree(form->more);
+
+    if( !(form->flags & HTTPPOST_PTRNAME) && form->name)
+      free(form->name); /* free the name */
+    if( !(form->flags & HTTPPOST_PTRCONTENTS) && form->contents)
+      free(form->contents); /* free the contents */
+    if(form->contenttype)
+      free(form->contenttype); /* free the content type */
+    if(form->showfilename)
+      free(form->showfilename); /* free the faked file name */
+    free(form);       /* free the struct */
+
+  } while((form=next)); /* continue */
+}
+
+/*
+ * Curl_getFormData() converts a linked list of "meta data" into a complete
+ * (possibly huge) multipart formdata. The input list is in 'post', while the
+ * output resulting linked lists gets stored in '*finalform'. *sizep will get
+ * the total size of the whole POST.
+ */
+
+CURLcode Curl_getFormData(struct FormData **finalform,
+                          struct curl_httppost *post,
+                          curl_off_t *sizep)
+{
+  struct FormData *form = NULL;
+  struct FormData *firstform;
+  struct curl_httppost *file;
+  CURLcode result = CURLE_OK;
+
+  curl_off_t size=0; /* support potentially ENORMOUS formposts */
+  char *boundary;
+  char *fileboundary=NULL;
+  struct curl_slist* curList;
+
+  *finalform=NULL; /* default form is empty */
+
+  if(!post)
+    return result; /* no input => no output! */
+
+  boundary = Curl_FormBoundary();
+  if(!boundary)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Make the first line of the output */
+  result = AddFormDataf(&form, NULL,
+                        "Content-Type: multipart/form-data;"
+                        " boundary=%s\r\n",
+                        boundary);
+  if (result) {
+    free(boundary);
+    return result;
+  }
+  /* we DO NOT include that line in the total size of the POST, since it'll be
+     part of the header! */
+
+  firstform = form;
+
+  do {
+
+    if(size) {
+      result = AddFormDataf(&form, &size, "\r\n");
+      if (result)
+        break;
+    }
+
+    /* boundary */
+    result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
+    if (result)
+      break;
+
+    result = AddFormDataf(&form, &size,
+                          "Content-Disposition: form-data; name=\"");
+    if (result)
+      break;
+
+    result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
+                         &size);
+    if (result)
+      break;
+
+    result = AddFormDataf(&form, &size, "\"");
+    if (result)
+      break;
+
+    if(post->more) {
+      /* If used, this is a link to more file names, we must then do
+         the magic to include several files with the same field name */
+
+      fileboundary = Curl_FormBoundary();
+
+      result = AddFormDataf(&form, &size,
+                            "\r\nContent-Type: multipart/mixed,"
+                            " boundary=%s\r\n",
+                            fileboundary);
+      if (result)
+        break;
+    }
+
+    file = post;
+
+    do {
+
+      /* If 'showfilename' is set, that is a faked name passed on to us
+         to use to in the formpost. If that is not set, the actually used
+         local file name should be added. */
+
+      if(post->more) {
+        /* if multiple-file */
+        result = AddFormDataf(&form, &size,
+                              "\r\n--%s\r\nContent-Disposition: "
+                              "attachment; filename=\"%s\"",
+                              fileboundary,
+                              (file->showfilename?file->showfilename:
+                               file->contents));
+        if (result)
+          break;
+      }
+      else if((post->flags & HTTPPOST_FILENAME) ||
+              (post->flags & HTTPPOST_BUFFER)) {
+
+        result = AddFormDataf(&form, &size,
+                              "; filename=\"%s\"",
+                              (post->showfilename?post->showfilename:
+                               post->contents));
+        if (result)
+          break;
+      }
+
+      if(file->contenttype) {
+        /* we have a specified type */
+        result = AddFormDataf(&form, &size,
+                              "\r\nContent-Type: %s",
+                              file->contenttype);
+        if (result)
+          break;
+      }
+
+      curList = file->contentheader;
+      while( curList ) {
+        /* Process the additional headers specified for this form */
+        result = AddFormDataf( &form, &size, "\r\n%s", curList->data );
+        if (result)
+          break;
+        curList = curList->next;
+      }
+      if (result) {
+        Curl_formclean(firstform);
+        free(boundary);
+        return result;
+      }
+
+#if 0
+      /* The header Content-Transfer-Encoding: seems to confuse some receivers
+       * (like the built-in PHP engine). While I can't see any reason why it
+       * should, I can just as well skip this to the benefit of the users who
+       * are using such confused receivers.
+       */
+
+      if(file->contenttype &&
+         !checkprefix("text/", file->contenttype)) {
+        /* this is not a text content, mention our binary encoding */
+        size += AddFormData(&form, "\r\nContent-Transfer-Encoding: binary", 0);
+      }
+#endif
+
+      result = AddFormDataf(&form, &size, "\r\n\r\n");
+      if (result)
+        break;
+
+      if((post->flags & HTTPPOST_FILENAME) ||
+         (post->flags & HTTPPOST_READFILE)) {
+        /* we should include the contents from the specified file */
+        FILE *fileread;
+
+        fileread = strequal("-", file->contents)?
+          stdin:fopen(file->contents, "rb"); /* binary read for win32  */
+
+        /*
+         * VMS: This only allows for stream files on VMS.  Stream files are
+         * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
+         * every record needs to have a \n appended & 1 added to SIZE
+         */
+
+        if(fileread) {
+          if(fileread != stdin) {
+            /* close the file again */
+            fclose(fileread);
+            /* add the file name only - for later reading from this */
+            result = AddFormData(&form, FORM_FILE, file->contents, 0, &size);
+          }
+          else {
+            /* When uploading from stdin, we can't know the size of the file,
+             * thus must read the full file as before. We *could* use chunked
+             * transfer-encoding, but that only works for HTTP 1.1 and we
+             * can't be sure we work with such a server.
+             */
+            size_t nread;
+            char buffer[512];
+            while((nread = fread(buffer, 1, sizeof(buffer), fileread))) {
+              result = AddFormData(&form, FORM_DATA, buffer, nread, &size);
+              if (result)
+                break;
+            }
+          }
+
+          if (result) {
+            Curl_formclean(firstform);
+            free(boundary);
+            return result;
+          }
+
+        }
+        else {
+          Curl_formclean(firstform);
+          free(boundary);
+          *finalform = NULL;
+          return CURLE_READ_ERROR;
+        }
+
+      }
+      else if (post->flags & HTTPPOST_BUFFER) {
+        /* include contents of buffer */
+        result = AddFormData(&form, FORM_DATA, post->buffer,
+                             post->bufferlength, &size);
+          if (result)
+            break;
+      }
+
+      else {
+        /* include the contents we got */
+        result = AddFormData(&form, FORM_DATA, post->contents,
+                             post->contentslength, &size);
+        if (result)
+          break;
+      }
+    } while((file = file->more)); /* for each specified file for this field */
+    if (result) {
+      Curl_formclean(firstform);
+      free(boundary);
+      return result;
+    }
+
+    if(post->more) {
+      /* this was a multiple-file inclusion, make a termination file
+         boundary: */
+      result = AddFormDataf(&form, &size,
+                           "\r\n--%s--",
+                           fileboundary);
+      free(fileboundary);
+      if (result)
+        break;
+    }
+
+  } while((post=post->next)); /* for each field */
+  if (result) {
+    Curl_formclean(firstform);
+    free(boundary);
+    return result;
+  }
+
+  /* end-boundary for everything */
+  result = AddFormDataf(&form, &size,
+                       "\r\n--%s--\r\n",
+                       boundary);
+  if (result) {
+    Curl_formclean(firstform);
+    free(boundary);
+    return result;
+  }
+
+  *sizep = size;
+
+  free(boundary);
+
+  *finalform=firstform;
+
+  return result;
+}
+
+/*
+ * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
+ * and resets the 'sent' counter.
+ */
+int Curl_FormInit(struct Form *form, struct FormData *formdata )
+{
+  if(!formdata)
+    return 1; /* error */
+
+  form->data = formdata;
+  form->sent = 0;
+  form->fp = NULL;
+
+  return 0;
+}
+
+static size_t readfromfile(struct Form *form, char *buffer, size_t size)
+{
+  size_t nread;
+  if(!form->fp) {
+    /* this file hasn't yet been opened */
+    form->fp = fopen(form->data->line, "rb"); /* b is for binary */
+    if(!form->fp)
+      return -1; /* failure */
+  }
+  nread = fread(buffer, 1, size, form->fp);
+
+  if(nread != size) {
+    /* this is the last chunk form the file, move on */
+    fclose(form->fp);
+    form->fp = NULL;
+    form->data = form->data->next;
+  }
+
+  return nread;
+}
+
+/*
+ * Curl_FormReader() is the fread() emulation function that will be used to
+ * deliver the formdata to the transfer loop and then sent away to the peer.
+ */
+size_t Curl_FormReader(char *buffer,
+                       size_t size,
+                       size_t nitems,
+                       FILE *mydata)
+{
+  struct Form *form;
+  size_t wantedsize;
+  size_t gotsize = 0;
+
+  form=(struct Form *)mydata;
+
+  wantedsize = size * nitems;
+
+  if(!form->data)
+    return 0; /* nothing, error, empty */
+
+  if(form->data->type == FORM_FILE)
+    return readfromfile(form, buffer, wantedsize);
+
+  do {
+
+    if( (form->data->length - form->sent ) > wantedsize - gotsize) {
+
+      memcpy(buffer + gotsize , form->data->line + form->sent,
+             wantedsize - gotsize);
+
+      form->sent += wantedsize-gotsize;
+
+      return wantedsize;
+    }
+
+    memcpy(buffer+gotsize,
+           form->data->line + form->sent,
+           (form->data->length - form->sent) );
+    gotsize += form->data->length - form->sent;
+
+    form->sent = 0;
+
+    form->data = form->data->next; /* advance */
+
+  } while(form->data && (form->data->type == FORM_DATA));
+  /* If we got an empty line and we have more data, we proceed to the next
+     line immediately to avoid returning zero before we've reached the end.
+     This is the bug reported November 22 1999 on curl 6.3. (Daniel) */
+
+  return gotsize;
+}
+
+/*
+ * Curl_formpostheader() returns the first line of the formpost, the
+ * request-header part (which is not part of the request-body like the rest of
+ * the post).
+ */
+char *Curl_formpostheader(void *formp, size_t *len)
+{
+  char *header;
+  struct Form *form=(struct Form *)formp;
+
+  if(!form->data)
+    return 0; /* nothing, ERROR! */
+
+  header = form->data->line;
+  *len = form->data->length;
+
+  form->data = form->data->next; /* advance */
+
+  return header;
+}
+
+
+#ifdef _FORM_DEBUG
+int FormAddTest(const char * errormsg,
+                 struct curl_httppost **httppost,
+                 struct curl_httppost **last_post,
+                 ...)
+{
+  int result;
+  va_list arg;
+  va_start(arg, last_post);
+  if ((result = FormAdd(httppost, last_post, arg)))
+    fprintf (stderr, "ERROR doing FormAdd ret: %d action: %s\n", result,
+             errormsg);
+  va_end(arg);
+  return result;
+}
+
+
+int main()
+{
+  char name1[] = "simple_COPYCONTENTS";
+  char name2[] = "COPYCONTENTS_+_CONTENTTYPE";
+  char name3[] = "PTRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH";
+  char name4[] = "simple_PTRCONTENTS";
+  char name5[] = "PTRCONTENTS_+_CONTENTSLENGTH";
+  char name6[] = "PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE";
+  char name7[] = "FILE1_+_CONTENTTYPE";
+  char name8[] = "FILE1_+_FILE2";
+  char name9[] = "FILE1_+_FILE2_+_FILE3";
+  char name10[] = "ARRAY: FILE1_+_FILE2_+_FILE3";
+  char name11[] = "FILECONTENT";
+  char value1[] = "value for simple COPYCONTENTS";
+  char value2[] = "value for COPYCONTENTS + CONTENTTYPE";
+  char value3[] = "value for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH";
+  char value4[] = "value for simple PTRCONTENTS";
+  char value5[] = "value for PTRCONTENTS + CONTENTSLENGTH";
+  char value6[] = "value for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE";
+  char value7[] = "inet_ntoa_r.h";
+  char value8[] = "Makefile.b32.resp";
+  char type2[] = "image/gif";
+  char type6[] = "text/plain";
+  char type7[] = "text/html";
+  int name3length = strlen(name3);
+  int value3length = strlen(value3);
+  int value5length = strlen(value4);
+  int value6length = strlen(value5);
+  int errors = 0;
+  int size;
+  size_t nread;
+  char buffer[4096];
+  struct curl_httppost *httppost=NULL;
+  struct curl_httppost *last_post=NULL;
+  struct curl_forms forms[4];
+
+  struct FormData *form;
+  struct Form formread;
+
+  if (FormAddTest("simple COPYCONTENTS test", &httppost, &last_post,
+                  CURLFORM_COPYNAME, name1, CURLFORM_COPYCONTENTS, value1,
+                  CURLFORM_END))
+    ++errors;
+  if (FormAddTest("COPYCONTENTS  + CONTENTTYPE test", &httppost, &last_post,
+                  CURLFORM_COPYNAME, name2, CURLFORM_COPYCONTENTS, value2,
+                  CURLFORM_CONTENTTYPE, type2, CURLFORM_END))
+    ++errors;
+  /* make null character at start to check that contentslength works
+     correctly */
+  name3[1] = '\0';
+  value3[1] = '\0';
+  if (FormAddTest("PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH test",
+                  &httppost, &last_post,
+                  CURLFORM_PTRNAME, name3, CURLFORM_COPYCONTENTS, value3,
+                  CURLFORM_CONTENTSLENGTH, value3length,
+                  CURLFORM_NAMELENGTH, name3length, CURLFORM_END))
+    ++errors;
+  if (FormAddTest("simple PTRCONTENTS test", &httppost, &last_post,
+                  CURLFORM_COPYNAME, name4, CURLFORM_PTRCONTENTS, value4,
+                  CURLFORM_END))
+    ++errors;
+  /* make null character at start to check that contentslength works
+     correctly */
+  value5[1] = '\0';
+  if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH test", &httppost, &last_post,
+                  CURLFORM_COPYNAME, name5, CURLFORM_PTRCONTENTS, value5,
+                  CURLFORM_CONTENTSLENGTH, value5length, CURLFORM_END))
+    ++errors;
+  /* make null character at start to check that contentslength works
+     correctly */
+  value6[1] = '\0';
+  if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE test",
+                  &httppost, &last_post,
+                  CURLFORM_COPYNAME, name6, CURLFORM_PTRCONTENTS, value6,
+                  CURLFORM_CONTENTSLENGTH, value6length,
+                  CURLFORM_CONTENTTYPE, type6, CURLFORM_END))
+    ++errors;
+  if (FormAddTest("FILE + CONTENTTYPE test", &httppost, &last_post,
+                  CURLFORM_COPYNAME, name7, CURLFORM_FILE, value7,
+                  CURLFORM_CONTENTTYPE, type7, CURLFORM_END))
+    ++errors;
+  if (FormAddTest("FILE1 + FILE2 test", &httppost, &last_post,
+                  CURLFORM_COPYNAME, name8, CURLFORM_FILE, value7,
+                  CURLFORM_FILE, value8, CURLFORM_END))
+    ++errors;
+  if (FormAddTest("FILE1 + FILE2 + FILE3 test", &httppost, &last_post,
+                  CURLFORM_COPYNAME, name9, CURLFORM_FILE, value7,
+                  CURLFORM_FILE, value8, CURLFORM_FILE, value7, CURLFORM_END))
+    ++errors;
+  forms[0].option = CURLFORM_FILE;
+  forms[0].value  = value7;
+  forms[1].option = CURLFORM_FILE;
+  forms[1].value  = value8;
+  forms[2].option = CURLFORM_FILE;
+  forms[2].value  = value7;
+  forms[3].option  = CURLFORM_END;
+  if (FormAddTest("FILE1 + FILE2 + FILE3 ARRAY test", &httppost, &last_post,
+                  CURLFORM_COPYNAME, name10, CURLFORM_ARRAY, forms,
+                  CURLFORM_END))
+    ++errors;
+  if (FormAddTest("FILECONTENT test", &httppost, &last_post,
+                  CURLFORM_COPYNAME, name11, CURLFORM_FILECONTENT, value7,
+                  CURLFORM_END))
+    ++errors;
+
+  form=Curl_getFormData(httppost, &size);
+
+  Curl_FormInit(&formread, form);
+
+  do {
+    nread = Curl_FormReader(buffer, 1, sizeof(buffer),
+                            (FILE *)&formread);
+
+    if(-1 == nread)
+      break;
+    fwrite(buffer, nread, 1, stdout);
+  } while(1);
+
+  fprintf(stdout, "size: %d\n", size);
+  if (errors)
+    fprintf(stdout, "\n==> %d Test(s) failed!\n", errors);
+  else
+    fprintf(stdout, "\nAll Tests seem to have worked (please check output)\n");
+
+  return 0;
+}
+
+#endif
+
+#else  /* CURL_DISABLE_HTTP */
+CURLFORMcode curl_formadd(struct curl_httppost **httppost,
+                          struct curl_httppost **last_post,
+                          ...)
+{
+  (void)httppost;
+  (void)last_post;
+  return CURL_FORMADD_DISABLED;
+}
+
+void curl_formfree(struct curl_httppost *form)
+{
+  (void)form;
+  /* does nothing HTTP is disabled */
+}
+
+#endif  /* CURL_DISABLE_HTTP */
+
+/*
+ * Curl_FormBoundary() creates a suitable boundary string and returns an
+ * allocated one. This is also used by SSL-code so it must be present even
+ * if HTTP is disabled!
+ */
+char *Curl_FormBoundary(void)
+{
+  char *retstring;
+  static int randomizer=0; /* this is just so that two boundaries within
+                              the same form won't be identical */
+  size_t i;
+
+  static char table16[]="abcdef0123456789";
+
+  retstring = (char *)malloc(BOUNDARY_LENGTH+1);
+
+  if(!retstring)
+    return NULL; /* failed */
+
+  srand(time(NULL)+randomizer++); /* seed */
+
+  strcpy(retstring, "----------------------------");
+
+  for(i=strlen(retstring); i<BOUNDARY_LENGTH; i++)
+    retstring[i] = table16[rand()%16];
+
+  /* 28 dashes and 12 hexadecimal digits makes 12^16 (184884258895036416)
+     combinations */
+  retstring[BOUNDARY_LENGTH]=0; /* zero terminate */
+
+  return retstring;
+}
diff --git a/Utilities/cmcurl/formdata.h b/Utilities/cmcurl/formdata.h
new file mode 100644
index 0000000..c6a78cd
--- /dev/null
+++ b/Utilities/cmcurl/formdata.h
@@ -0,0 +1,92 @@
+#ifndef __FORMDATA_H
+#define __FORMDATA_H
+
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+enum formtype {
+  FORM_DATA, /* regular data */
+  FORM_FILE  /* 'line' points to a file name we should read from */
+};
+
+/* plain and simple linked list with lines to send */
+struct FormData {
+  struct FormData *next;
+  enum formtype type;
+  char *line;
+  size_t length;
+};
+
+struct Form {
+  struct FormData *data; /* current form line to send */
+  size_t sent;           /* number of bytes of the current line that has
+                            already been sent in a previous invoke */
+  FILE *fp;              /* file to read from */
+};
+
+/* used by FormAdd for temporary storage */
+typedef struct FormInfo {
+  char *name;
+  bool name_alloc;
+  size_t namelength;
+  char *value;
+  bool value_alloc;
+  size_t contentslength;
+  char *contenttype;
+  bool contenttype_alloc;
+  long flags;
+  char *buffer;      /* pointer to existing buffer used for file upload */
+  size_t bufferlength;
+  char *showfilename; /* The file name to show. If not set, the actual
+                         file name will be used */
+  bool showfilename_alloc;
+  struct curl_slist* contentheader;
+  struct FormInfo *more;
+} FormInfo;
+
+int Curl_FormInit(struct Form *form, struct FormData *formdata );
+
+CURLcode
+Curl_getFormData(struct FormData **,
+                 struct curl_httppost *post,
+                 curl_off_t *size);
+
+/* fread() emulation */
+size_t Curl_FormReader(char *buffer,
+                       size_t size,
+                       size_t nitems,
+                       FILE *mydata);
+
+/*
+ * Curl_formpostheader() returns the first line of the formpost, the
+ * request-header part (which is not part of the request-body like the rest of
+ * the post).
+ */
+char *Curl_formpostheader(void *formp, size_t *len);
+
+char *Curl_FormBoundary(void);
+
+void Curl_formclean(struct FormData *);
+
+#endif
+
diff --git a/Utilities/cmcurl/ftp.c b/Utilities/cmcurl/ftp.c
new file mode 100644
index 0000000..2501412
--- /dev/null
+++ b/Utilities/cmcurl/ftp.c
@@ -0,0 +1,2774 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#ifndef CURL_DISABLE_FTP
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+
+#else /* some kind of unix */
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <sys/types.h>
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#include <sys/utsname.h>
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef  VMS
+#include <in.h>
+#include <inet.h>
+#endif
+#endif
+
+#if defined(WIN32) && defined(__GNUC__) || defined(__MINGW32__)
+#include <errno.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+
+#include "if2ip.h"
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "ftp.h"
+
+#ifdef HAVE_KRB4
+#include "security.h"
+#include "krb4.h"
+#endif
+
+#include "strtoofft.h"
+#include "strequal.h"
+#include "ssluse.h"
+#include "connect.h"
+#include "strerror.h"
+#include "curl_memory.h"
+#include "inet_ntop.h"
+
+#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
+#include "inet_ntoa_r.h"
+#endif
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#ifdef CURLDEBUG
+#include "memdebug.h"
+#endif
+
+#ifdef HAVE_NI_WITHSCOPEID
+#define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID
+#else
+#define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV
+#endif
+
+/* Local API functions */
+static CURLcode ftp_sendquote(struct connectdata *conn,
+                              struct curl_slist *quote);
+static CURLcode ftp_cwd(struct connectdata *conn, char *path);
+static CURLcode ftp_mkd(struct connectdata *conn, char *path);
+static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path);
+static CURLcode ftp_quit(struct connectdata *conn);
+static CURLcode ftp_3rdparty_pretransfer(struct connectdata *conn);
+static CURLcode ftp_3rdparty_transfer(struct connectdata *conn);
+static CURLcode ftp_regular_transfer(struct connectdata *conn);
+static CURLcode ftp_3rdparty(struct connectdata *conn);
+
+/* easy-to-use macro: */
+#define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z))) return result
+
+static void freedirs(struct FTP *ftp)
+{
+  int i;
+  if(ftp->dirs) {
+    for (i=0; i < ftp->dirdepth; i++){
+      if(ftp->dirs[i]) {
+        free(ftp->dirs[i]);
+        ftp->dirs[i]=NULL;
+      }
+    }
+    free(ftp->dirs);
+    ftp->dirs = NULL;
+  }
+  if(ftp->file) {
+    free(ftp->file);
+    ftp->file = NULL;
+  }
+}
+
+/***********************************************************************
+ *
+ * AllowServerConnect()
+ *
+ * When we've issue the PORT command, we have told the server to connect
+ * to us. This function will sit and wait here until the server has
+ * connected.
+ *
+ */
+static CURLcode AllowServerConnect(struct connectdata *conn)
+{
+  fd_set rdset;
+  struct timeval dt;
+  struct SessionHandle *data = conn->data;
+  curl_socket_t sock = conn->sock[SECONDARYSOCKET];
+  struct timeval now = Curl_tvnow();
+  long timespent = Curl_tvdiff(Curl_tvnow(), now)/1000;
+  long timeout = data->set.connecttimeout?data->set.connecttimeout:
+    (data->set.timeout?data->set.timeout: 0);
+
+  FD_ZERO(&rdset);
+
+  FD_SET(sock, &rdset);
+
+  if(timeout) {
+    timeout -= timespent;
+    if(timeout<=0) {
+      failf(data, "Timed out before server could connect to us");
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+  }
+
+  /* we give the server 60 seconds to connect to us, or a custom timeout */
+  dt.tv_sec = (int)(timeout?timeout:60);
+  dt.tv_usec = 0;
+
+  switch (select(sock+1, &rdset, NULL, NULL, &dt)) {
+  case -1: /* error */
+    /* let's die here */
+    failf(data, "Error while waiting for server connect");
+    return CURLE_FTP_PORT_FAILED;
+  case 0:  /* timeout */
+    /* let's die here */
+    failf(data, "Timeout while waiting for server connect");
+    return CURLE_FTP_PORT_FAILED;
+  default:
+    /* we have received data here */
+    {
+      curl_socket_t s;
+#ifdef __hpux
+      int size = sizeof(struct sockaddr_in);
+#else
+      socklen_t size = sizeof(struct sockaddr_in);
+#endif
+      struct sockaddr_in add;
+
+      getsockname(sock, (struct sockaddr *) &add, &size);
+      s=accept(sock, (struct sockaddr *) &add, &size);
+
+      sclose(sock); /* close the first socket */
+
+      if (CURL_SOCKET_BAD == s) {
+        /* DIE! */
+        failf(data, "Error accept()ing server connect");
+        return CURLE_FTP_PORT_FAILED;
+      }
+      infof(data, "Connection accepted from server\n");
+
+      conn->sock[SECONDARYSOCKET] = s;
+      Curl_nonblock(s, TRUE); /* enable non-blocking */
+    }
+    break;
+  }
+
+  return CURLE_OK;
+}
+
+
+/* --- parse FTP server responses --- */
+
+/*
+ * Curl_GetFTPResponse() is supposed to be invoked after each command sent to
+ * a remote FTP server. This function will wait and read all lines of the
+ * response and extract the relevant return code for the invoking function.
+ */
+
+CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
+                             struct connectdata *conn,
+                             int *ftpcode) /* return the ftp-code */
+{
+  /* Brand new implementation.
+   * We cannot read just one byte per read() and then go back to select()
+   * as it seems that the OpenSSL read() stuff doesn't grok that properly.
+   *
+   * Alas, read as much as possible, split up into lines, use the ending
+   * line in a response or continue reading.  */
+
+  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+  int perline; /* count bytes per line */
+  bool keepon=TRUE;
+  ssize_t gotbytes;
+  char *ptr;
+  long timeout;              /* timeout in seconds */
+  struct timeval interval;
+  fd_set rkeepfd;
+  fd_set readfd;
+  struct SessionHandle *data = conn->data;
+  char *line_start;
+  int code=0; /* default ftp "error code" to return */
+  char *buf = data->state.buffer;
+  CURLcode result = CURLE_OK;
+  struct FTP *ftp = conn->proto.ftp;
+  struct timeval now = Curl_tvnow();
+
+  if (ftpcode)
+    *ftpcode = 0; /* 0 for errors */
+
+  FD_ZERO (&readfd);            /* clear it */
+  FD_SET (sockfd, &readfd);     /* read socket */
+
+  /* get this in a backup variable to be able to restore it on each lap in the
+     select() loop */
+  rkeepfd = readfd;
+
+  ptr=buf;
+  line_start = buf;
+
+  *nreadp=0;
+  perline=0;
+
+  while((*nreadp<BUFSIZE) && (keepon && !result)) {
+    /* check and reset timeout value every lap */
+    if(data->set.ftp_response_timeout )
+      /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine
+         remaining time.  Also, use "now" as opposed to "conn->now"
+         because ftp_response_timeout is only supposed to govern
+         the response for any given ftp response, not for the time
+         from connect to the given ftp response. */
+      timeout = data->set.ftp_response_timeout - /* timeout time */
+        Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
+    else if(data->set.timeout)
+      /* if timeout is requested, find out how much remaining time we have */
+      timeout = data->set.timeout - /* timeout time */
+        Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
+    else
+      /* Even without a requested timeout, we only wait response_time
+         seconds for the full response to arrive before we bail out */
+      timeout = ftp->response_time -
+        Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
+
+    if(timeout <=0 ) {
+      failf(data, "FTP response timeout");
+      return CURLE_OPERATION_TIMEDOUT; /* already too little time */
+    }
+
+    if(!ftp->cache) {
+      readfd = rkeepfd;            /* set every lap */
+      interval.tv_sec = 1; /* use 1 second timeout intervals */
+      interval.tv_usec = 0;
+
+      switch (select (sockfd+1, &readfd, NULL, NULL, &interval)) {
+      case -1: /* select() error, stop reading */
+        result = CURLE_RECV_ERROR;
+        failf(data, "FTP response aborted due to select() error: %d", errno);
+        break;
+      case 0: /* timeout */
+        if(Curl_pgrsUpdate(conn))
+          return CURLE_ABORTED_BY_CALLBACK;
+        continue; /* just continue in our loop for the timeout duration */
+
+      default:
+        break;
+      }
+    }
+    if(CURLE_OK == result) {
+      /*
+       * This code previously didn't use the kerberos sec_read() code
+       * to read, but when we use Curl_read() it may do so. Do confirm
+       * that this is still ok and then remove this comment!
+       */
+      if(ftp->cache) {
+        /* we had data in the "cache", copy that instead of doing an actual
+         * read
+         *
+         * Dave Meyer, December 2003:
+         * ftp->cache_size is cast to int here.  This should be safe,
+         * because it would have been populated with something of size
+         * int to begin with, even though its datatype may be larger
+         * than an int.
+         */
+        memcpy(ptr, ftp->cache, (int)ftp->cache_size);
+        gotbytes = (int)ftp->cache_size;
+        free(ftp->cache);    /* free the cache */
+        ftp->cache = NULL;   /* clear the pointer */
+        ftp->cache_size = 0; /* zero the size just in case */
+      }
+      else {
+        int res = Curl_read(conn, sockfd, ptr, BUFSIZE-*nreadp, &gotbytes);
+        if(res < 0)
+          /* EWOULDBLOCK */
+          continue; /* go looping again */
+
+        if(CURLE_OK != res)
+          keepon = FALSE;
+      }
+
+      if(!keepon)
+        ;
+      else if(gotbytes <= 0) {
+        keepon = FALSE;
+        result = CURLE_RECV_ERROR;
+        failf(data, "FTP response reading failed");
+      }
+      else {
+        /* we got a whole chunk of data, which can be anything from one
+         * byte to a set of lines and possible just a piece of the last
+         * line */
+        int i;
+
+        conn->headerbytecount += gotbytes;
+
+        *nreadp += gotbytes;
+        for(i = 0; i < gotbytes; ptr++, i++) {
+          perline++;
+          if(*ptr=='\n') {
+            /* a newline is CRLF in ftp-talk, so the CR is ignored as
+               the line isn't really terminated until the LF comes */
+
+            /* output debug output if that is requested */
+            if(data->set.verbose)
+              Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline, conn->host.dispname);
+
+            /*
+             * We pass all response-lines to the callback function registered
+             * for "headers". The response lines can be seen as a kind of
+             * headers.
+             */
+            result = Curl_client_write(data, CLIENTWRITE_HEADER,
+                                       line_start, perline);
+            if(result)
+              return result;
+
+#define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \
+                        isdigit((int)line[2]) && (' ' == line[3]))
+
+            if(perline>3 && lastline(line_start)) {
+              /* This is the end of the last line, copy the last
+               * line to the start of the buffer and zero terminate,
+               * for old times sake (and krb4)! */
+              char *meow;
+              int n;
+              for(meow=line_start, n=0; meow<ptr; meow++, n++)
+                buf[n] = *meow;
+              *meow=0; /* zero terminate */
+              keepon=FALSE;
+              line_start = ptr+1; /* advance pointer */
+              i++; /* skip this before getting out */
+              break;
+            }
+            perline=0; /* line starts over here */
+            line_start = ptr+1;
+          }
+        }
+        if(!keepon && (i != gotbytes)) {
+          /* We found the end of the response lines, but we didn't parse the
+             full chunk of data we have read from the server. We therefore
+             need to store the rest of the data to be checked on the next
+             invoke as it may actually contain another end of response
+             already!  Cleverly figured out by Eric Lavigne in December
+             2001. */
+          ftp->cache_size = gotbytes - i;
+          ftp->cache = (char *)malloc((int)ftp->cache_size);
+          if(ftp->cache)
+            memcpy(ftp->cache, line_start, (int)ftp->cache_size);
+          else
+            return CURLE_OUT_OF_MEMORY; /**BANG**/
+        }
+      } /* there was data */
+    } /* if(no error) */
+  } /* while there's buffer left and loop is requested */
+
+  if(!result)
+    code = atoi(buf);
+
+#ifdef HAVE_KRB4
+  /* handle the security-oriented responses 6xx ***/
+  /* FIXME: some errorchecking perhaps... ***/
+  switch(code) {
+  case 631:
+    Curl_sec_read_msg(conn, buf, prot_safe);
+    break;
+  case 632:
+    Curl_sec_read_msg(conn, buf, prot_private);
+    break;
+  case 633:
+    Curl_sec_read_msg(conn, buf, prot_confidential);
+    break;
+  default:
+    /* normal ftp stuff we pass through! */
+    break;
+  }
+#endif
+
+  if(ftpcode)
+    *ftpcode=code; /* return the initial number like this */
+
+  /* store the latest code for later retrieval */
+  conn->data->info.httpcode=code;
+
+  return result;
+}
+
+static const char *ftpauth[]= {
+  "SSL", "TLS", NULL
+};
+
+/*
+ * Curl_ftp_connect() should do everything that is to be considered a part of
+ * the connection phase.
+ */
+CURLcode Curl_ftp_connect(struct connectdata *conn)
+{
+  /* this is FTP and no proxy */
+  ssize_t nread;
+  struct SessionHandle *data=conn->data;
+  char *buf = data->state.buffer; /* this is our buffer */
+  struct FTP *ftp;
+  CURLcode result;
+  int ftpcode, try;
+
+  ftp = (struct FTP *)malloc(sizeof(struct FTP));
+  if(!ftp)
+    return CURLE_OUT_OF_MEMORY;
+
+  memset(ftp, 0, sizeof(struct FTP));
+  conn->proto.ftp = ftp;
+
+  /* We always support persistant connections on ftp */
+  conn->bits.close = FALSE;
+
+  /* get some initial data into the ftp struct */
+  ftp->bytecountp = &conn->bytecount;
+
+  /* no need to duplicate them, this connectdata struct won't change */
+  ftp->user = conn->user;
+  ftp->passwd = conn->passwd;
+  ftp->response_time = 3600; /* set default response time-out */
+
+#ifndef CURL_DISABLE_HTTP
+  if (conn->bits.tunnel_proxy) {
+    /* We want "seamless" FTP operations through HTTP proxy tunnel */
+    result = Curl_ConnectHTTPProxyTunnel(conn, FIRSTSOCKET,
+                                         conn->host.name, conn->remote_port);
+    if(CURLE_OK != result)
+      return result;
+  }
+#endif   /* CURL_DISABLE_HTTP */
+
+  if(conn->protocol & PROT_FTPS) {
+    /* FTPS is simply ftp with SSL for the control channel */
+    /* now, perform the SSL initialization for this socket */
+    result = Curl_SSLConnect(conn, FIRSTSOCKET);
+    if(result)
+      return result;
+  }
+
+  /* The first thing we do is wait for the "220*" line: */
+  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+  if(result)
+    return result;
+
+  if(ftpcode != 220) {
+    failf(data, "This doesn't seem like a nice ftp-server response");
+    return CURLE_FTP_WEIRD_SERVER_REPLY;
+  }
+
+#ifdef HAVE_KRB4
+  /* if not anonymous login, try a secure login */
+  if(data->set.krb4) {
+
+    /* request data protection level (default is 'clear') */
+    Curl_sec_request_prot(conn, "private");
+
+    /* We set private first as default, in case the line below fails to
+       set a valid level */
+    Curl_sec_request_prot(conn, data->set.krb4_level);
+
+    if(Curl_sec_login(conn) != 0)
+      infof(data, "Logging in with password in cleartext!\n");
+    else
+      infof(data, "Authentication successful\n");
+  }
+#endif
+
+  if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
+    /* we don't have a SSL/TLS connection, try a FTPS connection now */
+
+    for (try = 0; ftpauth[try]; try++) {
+
+      FTPSENDF(conn, "AUTH %s", ftpauth[try]);
+
+      result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+
+      if(result)
+        return result;
+
+      /* RFC2228 (page 5) says:
+       *
+       * If the server is willing to accept the named security mechanism, and
+       * does not require any security data, it must respond with reply code
+       * 234/334.
+       */
+
+      if((ftpcode == 234) || (ftpcode == 334)) {
+        result = Curl_SSLConnect(conn, FIRSTSOCKET);
+        if(result)
+          return result;
+        conn->protocol |= PROT_FTPS;
+        conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
+        break;
+      }
+    }
+  }
+
+  /* send USER */
+  FTPSENDF(conn, "USER %s", ftp->user?ftp->user:"");
+
+  /* wait for feedback */
+  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+  if(result)
+    return result;
+
+  if(ftpcode == 530) {
+    /* 530 User ... access denied
+       (the server denies to log the specified user) */
+    failf(data, "Access denied: %s", &buf[4]);
+    return CURLE_FTP_ACCESS_DENIED;
+  }
+  else if(ftpcode == 331) {
+    /* 331 Password required for ...
+       (the server requires to send the user's password too) */
+    FTPSENDF(conn, "PASS %s", ftp->passwd?ftp->passwd:"");
+    result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+    if(result)
+      return result;
+
+    if(ftpcode == 530) {
+      /* 530 Login incorrect.
+         (the username and/or the password are incorrect) */
+      failf(data, "the username and/or the password are incorrect");
+      return CURLE_FTP_USER_PASSWORD_INCORRECT;
+    }
+    else if(ftpcode == 230) {
+      /* 230 User ... logged in.
+         (user successfully logged in) */
+
+      infof(data, "We have successfully logged in\n");
+    }
+    else {
+      failf(data, "Odd return code after PASS");
+      return CURLE_FTP_WEIRD_PASS_REPLY;
+    }
+  }
+  else if(buf[0] == '2') {
+    /* 230 User ... logged in.
+       (the user logged in without password) */
+    infof(data, "We have successfully logged in\n");
+    if (conn->ssl[FIRSTSOCKET].use) {
+#ifdef HAVE_KRB4
+      /* We are logged in with Kerberos, now set the requested protection
+       * level
+       */
+      if(conn->sec_complete)
+        Curl_sec_set_protection_level(conn);
+
+      /* We may need to issue a KAUTH here to have access to the files
+       * do it if user supplied a password
+       */
+      if(conn->passwd && *conn->passwd) {
+        result = Curl_krb_kauth(conn);
+        if(result)
+          return result;
+      }
+#endif
+    }
+  }
+  else {
+    failf(data, "Odd return code after USER");
+    return CURLE_FTP_WEIRD_USER_REPLY;
+  }
+
+  if(conn->ssl[FIRSTSOCKET].use) {
+    /* PBSZ = PROTECTION BUFFER SIZE.
+
+       The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
+
+       Specifically, the PROT command MUST be preceded by a PBSZ command
+       and a PBSZ command MUST be preceded by a successful security data
+       exchange (the TLS negotiation in this case)
+
+       ... (and on page 8):
+
+       Thus the PBSZ command must still be issued, but must have a parameter
+       of '0' to indicate that no buffering is taking place and the data
+       connection should not be encapsulated.
+    */
+    FTPSENDF(conn, "PBSZ %d", 0);
+    result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+    if(result)
+      return result;
+
+    /* For TLS, the data connection can have one of two security levels.
+
+       1)Clear (requested by 'PROT C')
+
+       2)Private (requested by 'PROT P')
+    */
+    if(!conn->ssl[SECONDARYSOCKET].use) {
+      FTPSENDF(conn, "PROT %c", 'P');
+      result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+      if(result)
+        return result;
+
+      if(ftpcode == 200)
+        /* We have enabled SSL for the data connection! */
+        conn->ssl[SECONDARYSOCKET].use = TRUE;
+
+      /* FTP servers typically responds with 500 if they decide to reject
+         our 'P' request */
+    }
+  }
+
+  /* send PWD to discover our entry point */
+  FTPSENDF(conn, "PWD", NULL);
+
+  /* wait for feedback */
+  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+  if(result)
+    return result;
+
+  if(ftpcode == 257) {
+    char *dir = (char *)malloc(nread+1);
+    char *store=dir;
+    char *ptr=&buf[4]; /* start on the first letter */
+
+    if(!dir)
+      return CURLE_OUT_OF_MEMORY;
+
+    /* Reply format is like
+       257<space>"<directory-name>"<space><commentary> and the RFC959 says
+
+       The directory name can contain any character; embedded double-quotes
+       should be escaped by double-quotes (the "quote-doubling" convention).
+    */
+    if('\"' == *ptr) {
+      /* it started good */
+      ptr++;
+      while(ptr && *ptr) {
+        if('\"' == *ptr) {
+          if('\"' == ptr[1]) {
+            /* "quote-doubling" */
+            *store = ptr[1];
+            ptr++;
+          }
+          else {
+            /* end of path */
+            *store = '\0'; /* zero terminate */
+            break; /* get out of this loop */
+          }
+        }
+        else
+          *store = *ptr;
+        store++;
+        ptr++;
+      }
+      ftp->entrypath =dir; /* remember this */
+      infof(data, "Entry path is '%s'\n", ftp->entrypath);
+    }
+    else {
+      /* couldn't get the path */
+      free(dir);
+      infof(data, "Failed to figure out path\n");
+    }
+
+  }
+  else {
+    /* We couldn't read the PWD response! */
+  }
+
+  return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * Curl_ftp_done()
+ *
+ * The DONE function. This does what needs to be done after a single DO has
+ * performed.
+ *
+ * Input argument is already checked for validity.
+ */
+CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status)
+{
+  struct SessionHandle *data = conn->data;
+  struct FTP *ftp = conn->proto.ftp;
+  ssize_t nread;
+  int ftpcode;
+  CURLcode result=CURLE_OK;
+
+  bool was_ctl_valid = ftp->ctl_valid;
+
+  /* free the dir tree and file parts */
+  freedirs(ftp);
+
+  ftp->ctl_valid = FALSE;
+
+  if(data->set.upload) {
+    if((-1 != data->set.infilesize) &&
+       (data->set.infilesize != *ftp->bytecountp) &&
+       !data->set.crlf) {
+      failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T
+            " out of %" FORMAT_OFF_T " bytes)",
+            *ftp->bytecountp, data->set.infilesize);
+      conn->bits.close = TRUE; /* close this connection since we don't
+                                  know what state this error leaves us in */
+      return CURLE_PARTIAL_FILE;
+    }
+  }
+  else {
+    if((-1 != conn->size) && (conn->size != *ftp->bytecountp) &&
+       (conn->maxdownload != *ftp->bytecountp)) {
+      failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
+            *ftp->bytecountp);
+      conn->bits.close = TRUE; /* close this connection since we don't
+                                  know what state this error leaves us in */
+      return CURLE_PARTIAL_FILE;
+    }
+    else if(!ftp->dont_check &&
+            !*ftp->bytecountp &&
+            (conn->size>0)) {
+      /* We consider this an error, but there's no true FTP error received
+         why we need to continue to "read out" the server response too.
+         We don't want to leave a "waiting" server reply if we'll get told
+         to make a second request on this same connection! */
+      failf(data, "No data was received!");
+      result = CURLE_FTP_COULDNT_RETR_FILE;
+    }
+  }
+
+  switch(status) {
+  case CURLE_BAD_DOWNLOAD_RESUME:
+  case CURLE_FTP_WEIRD_PASV_REPLY:
+  case CURLE_FTP_PORT_FAILED:
+  case CURLE_FTP_COULDNT_SET_BINARY:
+  case CURLE_FTP_COULDNT_RETR_FILE:
+  case CURLE_FTP_ACCESS_DENIED:
+    /* the connection stays alive fine even though this happened */
+    /* fall-through */
+  case CURLE_OK: /* doesn't affect the control connection's status */
+    ftp->ctl_valid = was_ctl_valid;
+    break;
+  default:       /* by default, an error means the control connection is
+                    wedged and should not be used anymore */
+    ftp->ctl_valid = FALSE;
+    break;
+  }
+
+#ifdef HAVE_KRB4
+  Curl_sec_fflush_fd(conn, conn->sock[SECONDARYSOCKET]);
+#endif
+  /* shut down the socket to inform the server we're done */
+  sclose(conn->sock[SECONDARYSOCKET]);
+  conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
+
+  if(!ftp->no_transfer && !status) {
+    /* Let's see what the server says about the transfer we just performed,
+     * but lower the timeout as sometimes this connection has died while the
+     * data has been transfered. This happens when doing through NATs etc that
+     * abandon old silent connections.
+     */
+    ftp->response_time = 60; /* give it only a minute for now */
+
+    result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+
+    ftp->response_time = 3600; /* set this back to one hour waits */
+
+    if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
+      failf(data, "control connection looks dead");
+      return result;
+    }
+
+    if(result)
+      return result;
+
+    if(!ftp->dont_check) {
+      /* 226 Transfer complete, 250 Requested file action okay, completed. */
+      if((ftpcode != 226) && (ftpcode != 250)) {
+        failf(data, "server did not report OK, got %d", ftpcode);
+        return CURLE_FTP_WRITE_ERROR;
+      }
+    }
+  }
+
+  /* clear these for next connection */
+  ftp->no_transfer = FALSE;
+  ftp->dont_check = FALSE;
+
+  if (!result && conn->sec_conn) {   /* 3rd party transfer */
+    /* "done" with the secondary connection */
+    result = Curl_ftp_done(conn->sec_conn, status);
+  }
+
+  /* Send any post-transfer QUOTE strings? */
+  if(!status && !result && data->set.postquote)
+    result = ftp_sendquote(conn, data->set.postquote);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_sendquote()
+ *
+ * Where a 'quote' means a list of custom commands to send to the server.
+ * The quote list is passed as an argument.
+ */
+
+static
+CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
+{
+  struct curl_slist *item;
+  ssize_t nread;
+  int ftpcode;
+  CURLcode result;
+
+  item = quote;
+  while (item) {
+    if (item->data) {
+      FTPSENDF(conn, "%s", item->data);
+
+      result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+      if (result)
+        return result;
+
+      if (ftpcode >= 400) {
+        failf(conn->data, "QUOT string not accepted: %s", item->data);
+        return CURLE_FTP_QUOTE_ERROR;
+      }
+    }
+
+    item = item->next;
+  }
+
+  return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * ftp_getfiletime()
+ *
+ * Get the timestamp of the given file.
+ */
+static
+CURLcode ftp_getfiletime(struct connectdata *conn, char *file)
+{
+  CURLcode result;
+  int ftpcode; /* for ftp status */
+  ssize_t nread;
+  char *buf = conn->data->state.buffer;
+
+  /* we have requested to get the modified-time of the file, this is yet
+     again a grey area as the MDTM is not kosher RFC959 */
+  FTPSENDF(conn, "MDTM %s", file);
+
+  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+  if(result)
+    return result;
+
+  switch(ftpcode) {
+  case 213:
+    {
+      /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
+         last .sss part is optional and means fractions of a second */
+      int year, month, day, hour, minute, second;
+      if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
+                     &year, &month, &day, &hour, &minute, &second)) {
+        /* we have a time, reformat it */
+        time_t secs=time(NULL);
+        snprintf(buf, sizeof(conn->data->state.buffer),
+                 "%04d%02d%02d %02d:%02d:%02d GMT",
+                 year, month, day, hour, minute, second);
+        /* now, convert this into a time() value: */
+        conn->data->info.filetime = curl_getdate(buf, &secs);
+      }
+    }
+    break;
+  default:
+    infof(conn->data, "unsupported MDTM reply format\n");
+    break;
+  case 550: /* "No such file or directory" */
+    failf(conn->data, "Given file does not exist");
+    result = CURLE_FTP_COULDNT_RETR_FILE;
+    break;
+  }
+  return  result;
+}
+
+/***********************************************************************
+ *
+ * ftp_transfertype()
+ *
+ * Set transfer type. We only deal with ASCII or BINARY so this function
+ * sets one of them.
+ */
+static CURLcode ftp_transfertype(struct connectdata *conn,
+                                  bool ascii)
+{
+  struct SessionHandle *data = conn->data;
+  int ftpcode;
+  ssize_t nread;
+  CURLcode result;
+
+  FTPSENDF(conn, "TYPE %s", ascii?"A":"I");
+
+  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+  if(result)
+    return result;
+
+  if(ftpcode != 200) {
+    failf(data, "Couldn't set %s mode",
+          ascii?"ASCII":"binary");
+    return ascii? CURLE_FTP_COULDNT_SET_ASCII:CURLE_FTP_COULDNT_SET_BINARY;
+  }
+
+  return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * ftp_getsize()
+ *
+ * Returns the file size (in bytes) of the given remote file.
+ */
+
+static
+CURLcode ftp_getsize(struct connectdata *conn, char *file,
+                     curl_off_t *size)
+{
+  struct SessionHandle *data = conn->data;
+  int ftpcode;
+  ssize_t nread;
+  char *buf=data->state.buffer;
+  CURLcode result;
+
+  FTPSENDF(conn, "SIZE %s", file);
+  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+  if(result)
+    return result;
+
+  if(ftpcode == 213) {
+    /* get the size from the ascii string: */
+    *size = curlx_strtoofft(buf+4, NULL, 0);
+  }
+  else
+    return CURLE_FTP_COULDNT_GET_SIZE;
+
+  return CURLE_OK;
+}
+
+/***************************************************************************
+ *
+ * ftp_pasv_verbose()
+ *
+ * This function only outputs some informationals about this second connection
+ * when we've issued a PASV command before and thus we have connected to a
+ * possibly new IP address.
+ *
+ */
+static void
+ftp_pasv_verbose(struct connectdata *conn,
+                 Curl_addrinfo *ai,
+                 char *newhost, /* ascii version */
+                 int port)
+{
+  char buf[256];
+  Curl_printable_address(ai, buf, sizeof(buf));
+  infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
+}
+
+/***********************************************************************
+ *
+ * ftp_use_port()
+ *
+ * Send the proper PORT command. PORT is the ftp client's way of telling the
+ * server that *WE* open a port that we listen on an awaits the server to
+ * connect to. This is the opposite of PASV.
+ */
+
+static
+CURLcode ftp_use_port(struct connectdata *conn)
+{
+  struct SessionHandle *data=conn->data;
+  curl_socket_t portsock;
+  ssize_t nread;
+  int ftpcode; /* receive FTP response codes in this */
+  CURLcode result;
+
+#ifdef ENABLE_IPV6
+  /******************************************************************
+   *
+   * Here's a piece of IPv6-specific code coming up
+   *
+   */
+
+  struct addrinfo hints, *res, *ai;
+  struct sockaddr_storage ss;
+  socklen_t sslen;
+  char hbuf[NI_MAXHOST];
+
+  struct sockaddr *sa=(struct sockaddr *)&ss;
+  unsigned char *ap;
+  unsigned char *pp;
+  char portmsgbuf[1024], tmp[1024];
+
+  const char *mode[] = { "EPRT", "LPRT", "PORT", NULL };
+  char **modep;
+  int rc;
+  int error;
+
+  /*
+   * we should use Curl_if2ip?  given pickiness of recent ftpd,
+   * I believe we should use the same address as the control connection.
+   */
+  sslen = sizeof(ss);
+  rc = getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)&ss, &sslen);
+  if(rc < 0) {
+    failf(data, "getsockname() returned %d\n", rc);
+    return CURLE_FTP_PORT_FAILED;
+  }
+
+  rc = getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL, 0,
+                   NIFLAGS);
+  if(rc) {
+    failf(data, "getnameinfo() returned %d\n", rc);
+    return CURLE_FTP_PORT_FAILED;
+  }
+
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = sa->sa_family;
+  /*hints.ai_family = ss.ss_family;
+    this way can be used if sockaddr_storage is properly defined, as glibc
+    2.1.X doesn't do*/
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_flags = AI_PASSIVE;
+
+  rc = getaddrinfo(hbuf, NULL, &hints, &res);
+  if(rc) {
+    failf(data, "getaddrinfo() returned %d\n", rc);
+    return CURLE_FTP_PORT_FAILED;
+  }
+
+  portsock = CURL_SOCKET_BAD;
+  error = 0;
+  for (ai = res; ai; ai = ai->ai_next) {
+    /*
+     * Workaround for AIX5 getaddrinfo() problem (it doesn't set ai_socktype):
+     */
+    if (ai->ai_socktype == 0)
+      ai->ai_socktype = hints.ai_socktype;
+
+    portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+    if (portsock == CURL_SOCKET_BAD) {
+      error = Curl_ourerrno();
+      continue;
+    }
+
+    if (bind(portsock, ai->ai_addr, ai->ai_addrlen) < 0) {
+      error = Curl_ourerrno();
+      sclose(portsock);
+      portsock = CURL_SOCKET_BAD;
+      continue;
+    }
+
+    if (listen(portsock, 1) < 0) {
+      error = Curl_ourerrno();
+      sclose(portsock);
+      portsock = CURL_SOCKET_BAD;
+      continue;
+    }
+
+    break;
+  }
+  freeaddrinfo(res);
+  if (portsock == CURL_SOCKET_BAD) {
+    failf(data, "%s", Curl_strerror(conn,error));
+    return CURLE_FTP_PORT_FAILED;
+  }
+
+  sslen = sizeof(ss);
+  if (getsockname(portsock, sa, &sslen) < 0) {
+    failf(data, "%s", Curl_strerror(conn,Curl_ourerrno()));
+    return CURLE_FTP_PORT_FAILED;
+  }
+
+  for (modep = (char **)(data->set.ftp_use_eprt?&mode[0]:&mode[2]);
+       modep && *modep; modep++) {
+    int lprtaf, eprtaf;
+    int alen=0, plen=0;
+
+    switch (sa->sa_family) {
+    case AF_INET:
+      ap = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_addr;
+      alen = sizeof(((struct sockaddr_in *)&ss)->sin_addr);
+      pp = (unsigned char *)&((struct sockaddr_in *)&ss)->sin_port;
+      plen = sizeof(((struct sockaddr_in *)&ss)->sin_port);
+      lprtaf = 4;
+      eprtaf = 1;
+      break;
+    case AF_INET6:
+      ap = (unsigned char *)&((struct sockaddr_in6 *)&ss)->sin6_addr;
+      alen = sizeof(((struct sockaddr_in6 *)&ss)->sin6_addr);
+      pp = (unsigned char *)&((struct sockaddr_in6 *)&ss)->sin6_port;
+      plen = sizeof(((struct sockaddr_in6 *)&ss)->sin6_port);
+      lprtaf = 6;
+      eprtaf = 2;
+      break;
+    default:
+      ap = pp = NULL;
+      lprtaf = eprtaf = -1;
+      break;
+    }
+
+    if (strcmp(*modep, "EPRT") == 0) {
+      if (eprtaf < 0)
+        continue;
+      if (getnameinfo((struct sockaddr *)&ss, sslen,
+                      portmsgbuf, sizeof(portmsgbuf), tmp, sizeof(tmp),
+                      NIFLAGS))
+        continue;
+
+      /* do not transmit IPv6 scope identifier to the wire */
+      if (sa->sa_family == AF_INET6) {
+        char *q = strchr(portmsgbuf, '%');
+        if (q)
+          *q = '\0';
+      }
+
+      result = Curl_ftpsendf(conn, "%s |%d|%s|%s|", *modep, eprtaf,
+                             portmsgbuf, tmp);
+      if(result)
+        return result;
+    }
+    else if (strcmp(*modep, "LPRT") == 0 ||
+             strcmp(*modep, "PORT") == 0) {
+      int i;
+
+      if (strcmp(*modep, "LPRT") == 0 && lprtaf < 0)
+        continue;
+      if (strcmp(*modep, "PORT") == 0 && sa->sa_family != AF_INET)
+        continue;
+
+      portmsgbuf[0] = '\0';
+      if (strcmp(*modep, "LPRT") == 0) {
+        snprintf(tmp, sizeof(tmp), "%d,%d", lprtaf, alen);
+        if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
+            sizeof(portmsgbuf)) {
+          continue;
+        }
+      }
+
+      for (i = 0; i < alen; i++) {
+        if (portmsgbuf[0])
+          snprintf(tmp, sizeof(tmp), ",%u", ap[i]);
+        else
+          snprintf(tmp, sizeof(tmp), "%u", ap[i]);
+
+        if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
+            sizeof(portmsgbuf)) {
+          continue;
+        }
+      }
+
+      if (strcmp(*modep, "LPRT") == 0) {
+        snprintf(tmp, sizeof(tmp), ",%d", plen);
+
+        if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >= sizeof(portmsgbuf))
+          continue;
+      }
+
+      for (i = 0; i < plen; i++) {
+        snprintf(tmp, sizeof(tmp), ",%u", pp[i]);
+
+        if (strlcat(portmsgbuf, tmp, sizeof(portmsgbuf)) >=
+            sizeof(portmsgbuf)) {
+          continue;
+        }
+      }
+
+      result = Curl_ftpsendf(conn, "%s %s", *modep, portmsgbuf);
+      if(result)
+        return result;
+    }
+
+    result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+    if(result)
+      return result;
+
+    if (ftpcode != 200) {
+      continue;
+    }
+    else
+      break;
+  }
+
+  if (!*modep) {
+    sclose(portsock);
+    failf(data, "PORT command attempts failed");
+    return CURLE_FTP_PORT_FAILED;
+  }
+  /* we set the secondary socket variable to this for now, it
+     is only so that the cleanup function will close it in case
+     we fail before the true secondary stuff is made */
+  conn->sock[SECONDARYSOCKET] = portsock;
+
+#else
+  /******************************************************************
+   *
+   * Here's a piece of IPv4-specific code coming up
+   *
+   */
+  struct sockaddr_in sa;
+  unsigned short porttouse;
+  char myhost[256] = "";
+  bool sa_filled_in = FALSE;
+  Curl_addrinfo *addr = NULL;
+  unsigned short ip[4];
+
+  if(data->set.ftpport) {
+    in_addr_t in;
+
+    /* First check if the given name is an IP address */
+    in=inet_addr(data->set.ftpport);
+
+    if(in != CURL_INADDR_NONE)
+      /* this is an IPv4 address */
+      addr = Curl_ip2addr(in, data->set.ftpport, 0);
+    else {
+      if(Curl_if2ip(data->set.ftpport, myhost, sizeof(myhost))) {
+        /* The interface to IP conversion provided a dotted address */
+        in=inet_addr(myhost);
+        addr = Curl_ip2addr(in, myhost, 0);
+      }
+      else if(strlen(data->set.ftpport)> 1) {
+        /* might be a host name! */
+        struct Curl_dns_entry *h=NULL;
+        int rc = Curl_resolv(conn, myhost, 0, &h);
+        if(rc == CURLRESOLV_PENDING)
+          rc = Curl_wait_for_resolv(conn, &h);
+        (void)rc;
+        if(h) {
+          addr = h->addr;
+          /* when we return from this function, we can forget about this entry
+             to we can unlock it now already */
+          Curl_resolv_unlock(data, h);
+        } /* (h) */
+      } /* strlen */
+    } /* CURL_INADDR_NONE */
+  } /* data->set.ftpport */
+
+  if(!addr) {
+    /* pick a suitable default here */
+
+#ifdef __hpux
+    int sslen;
+#else
+    socklen_t sslen;
+#endif
+
+    sslen = sizeof(sa);
+    if (getsockname(conn->sock[FIRSTSOCKET],
+                    (struct sockaddr *)&sa, &sslen) < 0) {
+      failf(data, "getsockname() failed");
+      return CURLE_FTP_PORT_FAILED;
+    }
+
+    sa_filled_in = TRUE; /* the sa struct is filled in */
+  }
+
+  if (addr || sa_filled_in) {
+    portsock = socket(AF_INET, SOCK_STREAM, 0);
+    if(CURL_SOCKET_BAD != portsock) {
+      socklen_t size;
+
+      /* we set the secondary socket variable to this for now, it
+         is only so that the cleanup function will close it in case
+         we fail before the true secondary stuff is made */
+      conn->sock[SECONDARYSOCKET] = portsock;
+
+      if(!sa_filled_in) {
+        memcpy(&sa, addr->ai_addr, sizeof(sa));
+        sa.sin_addr.s_addr = INADDR_ANY;
+      }
+
+      sa.sin_port = 0;
+      size = sizeof(sa);
+
+      if(bind(portsock, (struct sockaddr *)&sa, size) >= 0) {
+        /* we succeeded to bind */
+        struct sockaddr_in add;
+#ifdef __hpux
+        int socksize = sizeof(add);
+#else
+        socklen_t socksize = sizeof(add);
+#endif
+
+        if(getsockname(portsock, (struct sockaddr *) &add,
+                       &socksize)<0) {
+          failf(data, "getsockname() failed");
+          return CURLE_FTP_PORT_FAILED;
+        }
+        porttouse = ntohs(add.sin_port);
+
+        if ( listen(portsock, 1) < 0 ) {
+          failf(data, "listen(2) failed on socket");
+          return CURLE_FTP_PORT_FAILED;
+        }
+      }
+      else {
+        failf(data, "bind(2) failed on socket");
+        return CURLE_FTP_PORT_FAILED;
+      }
+    }
+    else {
+      failf(data, "socket(2) failed (%s)");
+      return CURLE_FTP_PORT_FAILED;
+    }
+  }
+  else {
+    failf(data, "could't find IP address to use");
+    return CURLE_FTP_PORT_FAILED;
+  }
+
+  if(sa_filled_in)
+    Curl_inet_ntop(AF_INET, &((struct sockaddr_in *)&sa)->sin_addr,
+                   myhost, sizeof(myhost));
+  else
+    Curl_printable_address(addr, myhost, sizeof(myhost));
+
+  if(4 == sscanf(myhost, "%hu.%hu.%hu.%hu",
+                 &ip[0], &ip[1], &ip[2], &ip[3])) {
+
+    infof(data, "Telling server to connect to %d.%d.%d.%d:%d\n",
+          ip[0], ip[1], ip[2], ip[3], porttouse);
+
+    result=Curl_ftpsendf(conn, "PORT %d,%d,%d,%d,%d,%d",
+                         ip[0], ip[1], ip[2], ip[3],
+                         porttouse >> 8,
+                         porttouse & 255);
+    if(result)
+      return result;
+
+  }
+  else
+    return CURLE_FTP_PORT_FAILED;
+
+  Curl_freeaddrinfo(addr);
+
+  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+  if(result)
+    return result;
+
+  if(ftpcode != 200) {
+    failf(data, "Server does not grok PORT, try without it!");
+    return CURLE_FTP_PORT_FAILED;
+  }
+#endif /* end of ipv4-specific code */
+
+  return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * ftp_use_pasv()
+ *
+ * Send the PASV command. PASV is the ftp client's way of asking the server to
+ * open a second port that we can connect to (for the data transfer). This is
+ * the opposite of PORT.
+ */
+
+static
+CURLcode ftp_use_pasv(struct connectdata *conn,
+                      bool *connected)
+{
+  struct SessionHandle *data = conn->data;
+  ssize_t nread;
+  char *buf = data->state.buffer; /* this is our buffer */
+  int ftpcode; /* receive FTP response codes in this */
+  CURLcode result;
+  struct Curl_dns_entry *addr=NULL;
+  Curl_addrinfo *conninfo;
+  int rc;
+
+  /*
+    Here's the excecutive summary on what to do:
+
+    PASV is RFC959, expect:
+    227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
+
+    LPSV is RFC1639, expect:
+    228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
+
+    EPSV is RFC2428, expect:
+    229 Entering Extended Passive Mode (|||port|)
+
+  */
+
+  const char *mode[] = { "EPSV", "PASV", NULL };
+  int results[] = { 229, 227, 0 };
+  int modeoff;
+  unsigned short connectport; /* the local port connect() should use! */
+  unsigned short newport=0; /* remote port, not necessary the local one */
+
+  /* newhost must be able to hold a full IP-style address in ASCII, which
+     in the IPv6 case means 5*8-1 = 39 letters */
+  char newhost[48];
+  char *newhostp=NULL;
+
+  for (modeoff = (data->set.ftp_use_epsv?0:1);
+       mode[modeoff]; modeoff++) {
+    result = Curl_ftpsendf(conn, "%s", mode[modeoff]);
+    if(result)
+      return result;
+    result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+    if(result)
+      return result;
+    if (ftpcode == results[modeoff])
+      break;
+  }
+
+  if (!mode[modeoff]) {
+    failf(data, "Odd return code after PASV");
+    return CURLE_FTP_WEIRD_PASV_REPLY;
+  }
+  else if (227 == results[modeoff]) {
+    int ip[4];
+    int port[2];
+    char *str=buf;
+
+    /*
+     * New 227-parser June 3rd 1999.
+     * It now scans for a sequence of six comma-separated numbers and
+     * will take them as IP+port indicators.
+     *
+     * Found reply-strings include:
+     * "227 Entering Passive Mode (127,0,0,1,4,51)"
+     * "227 Data transfer will passively listen to 127,0,0,1,4,51"
+     * "227 Entering passive mode. 127,0,0,1,4,51"
+     */
+
+    while(*str) {
+      if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
+                      &ip[0], &ip[1], &ip[2], &ip[3],
+                      &port[0], &port[1]))
+        break;
+      str++;
+    }
+
+    if(!*str) {
+      failf(data, "Couldn't interpret this 227-reply: %s", buf);
+      return CURLE_FTP_WEIRD_227_FORMAT;
+    }
+
+    snprintf(newhost, sizeof(newhost),
+             "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
+    newhostp = newhost;
+    newport = (port[0]<<8) + port[1];
+  }
+  else if (229 == results[modeoff]) {
+    char *ptr = strchr(buf, '(');
+    if(ptr) {
+      unsigned int num;
+      char separator[4];
+      ptr++;
+      if(5  == sscanf(ptr, "%c%c%c%u%c",
+                      &separator[0],
+                      &separator[1],
+                      &separator[2],
+                      &num,
+                      &separator[3])) {
+        char sep1 = separator[0];
+        int i;
+
+        /* The four separators should be identical, or else this is an oddly
+           formatted reply and we bail out immediately. */
+        for(i=1; i<4; i++) {
+          if(separator[i] != sep1) {
+            ptr=NULL; /* set to NULL to signal error */
+            break;
+          }
+        }
+        if(ptr) {
+          newport = num;
+
+          /* we should use the same host we already are connected to */
+          newhostp = conn->host.name;
+        }
+      }
+      else
+        ptr=NULL;
+    }
+    if(!ptr) {
+      failf(data, "Weirdly formatted EPSV reply");
+      return CURLE_FTP_WEIRD_PASV_REPLY;
+    }
+  }
+  else
+    return CURLE_FTP_CANT_RECONNECT;
+
+  if(data->change.proxy && *data->change.proxy) {
+    /*
+     * This is a tunnel through a http proxy and we need to connect to the
+     * proxy again here.
+     *
+     * We don't want to rely on a former host lookup that might've expired
+     * now, instead we remake the lookup here and now!
+     */
+    rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
+    if(rc == CURLRESOLV_PENDING)
+      rc = Curl_wait_for_resolv(conn, &addr);
+
+    connectport =
+      (unsigned short)conn->port; /* we connect to the proxy's port */
+
+  }
+  else {
+    /* normal, direct, ftp connection */
+    rc = Curl_resolv(conn, newhostp, newport, &addr);
+    if(rc == CURLRESOLV_PENDING)
+      rc = Curl_wait_for_resolv(conn, &addr);
+
+    if(!addr) {
+      failf(data, "Can't resolve new host %s:%d", newhostp, newport);
+      return CURLE_FTP_CANT_GET_HOST;
+    }
+    connectport = newport; /* we connect to the remote port */
+  }
+
+  result = Curl_connecthost(conn,
+                            addr,
+                            &conn->sock[SECONDARYSOCKET],
+                            &conninfo,
+                            connected);
+
+  Curl_resolv_unlock(data, addr); /* we're done using this address */
+
+  if(result)
+    return result;
+
+  /*
+   * When this is used from the multi interface, this might've returned with
+   * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
+   * connect to connect and we should not be "hanging" here waiting.
+   */
+
+  if(data->set.verbose)
+    /* this just dumps information about this second connection */
+    ftp_pasv_verbose(conn, conninfo, newhostp, connectport);
+
+#ifndef CURL_DISABLE_HTTP
+  if(conn->bits.tunnel_proxy) {
+    /* We want "seamless" FTP operations through HTTP proxy tunnel */
+    result = Curl_ConnectHTTPProxyTunnel(conn, SECONDARYSOCKET,
+                                         newhostp, newport);
+    if(CURLE_OK != result)
+      return result;
+  }
+#endif   /* CURL_DISABLE_HTTP */
+
+  (void)rc;
+  return CURLE_OK;
+}
+
+/*
+ * Curl_ftp_nextconnect()
+ *
+ * This function shall be called when the second FTP connection has been
+ * established and is confirmed connected.
+ */
+
+CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
+{
+  struct SessionHandle *data=conn->data;
+  char *buf = data->state.buffer; /* this is our buffer */
+  CURLcode result;
+  ssize_t nread;
+  int ftpcode; /* for ftp status */
+
+  /* the ftp struct is already inited in Curl_ftp_connect() */
+  struct FTP *ftp = conn->proto.ftp;
+  curl_off_t *bytecountp = ftp->bytecountp;
+
+  if(data->set.upload) {
+
+    /* Set type to binary (unless specified ASCII) */
+    result = ftp_transfertype(conn, data->set.ftp_ascii);
+    if(result)
+      return result;
+
+    /* Send any PREQUOTE strings after transfer type is set? (Wesley Laxton)*/
+    if(data->set.prequote) {
+      if ((result = ftp_sendquote(conn, data->set.prequote)) != CURLE_OK)
+        return result;
+    }
+
+    if(conn->resume_from) {
+      /* we're about to continue the uploading of a file */
+      /* 1. get already existing file's size. We use the SIZE
+         command for this which may not exist in the server!
+         The SIZE command is not in RFC959. */
+
+      /* 2. This used to set REST. But since we can do append, we
+         don't another ftp command. We just skip the source file
+         offset and then we APPEND the rest on the file instead */
+
+      /* 3. pass file-size number of bytes in the source file */
+      /* 4. lower the infilesize counter */
+      /* => transfer as usual */
+
+      if(conn->resume_from < 0 ) {
+        /* we could've got a specified offset from the command line,
+           but now we know we didn't */
+        curl_off_t gottensize;
+
+        if(CURLE_OK != ftp_getsize(conn, ftp->file, &gottensize)) {
+          failf(data, "Couldn't get remote file size");
+          return CURLE_FTP_COULDNT_GET_SIZE;
+        }
+        conn->resume_from = gottensize;
+      }
+
+      if(conn->resume_from) {
+        /* do we still game? */
+        curl_off_t passed=0;
+        /* enable append instead */
+        data->set.ftp_append = 1;
+
+        /* Now, let's read off the proper amount of bytes from the
+           input. If we knew it was a proper file we could've just
+           fseek()ed but we only have a stream here */
+        do {
+          curl_off_t readthisamountnow = (conn->resume_from - passed);
+          curl_off_t actuallyread;
+
+          if(readthisamountnow > BUFSIZE)
+            readthisamountnow = BUFSIZE;
+
+          actuallyread = (curl_off_t)
+            conn->fread(data->state.buffer, 1, (size_t)readthisamountnow,
+                        conn->fread_in);
+
+          passed += actuallyread;
+          if(actuallyread != readthisamountnow) {
+            failf(data, "Could only read %" FORMAT_OFF_T
+                  " bytes from the input", passed);
+            return CURLE_FTP_COULDNT_USE_REST;
+          }
+        }
+        while(passed != conn->resume_from);
+
+        /* now, decrease the size of the read */
+        if(data->set.infilesize>0) {
+          data->set.infilesize -= conn->resume_from;
+
+          if(data->set.infilesize <= 0) {
+            infof(data, "File already completely uploaded\n");
+
+            /* no data to transfer */
+            result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+            (void)result;
+
+            /* Set no_transfer so that we won't get any error in
+             * Curl_ftp_done() because we didn't transfer anything! */
+            ftp->no_transfer = TRUE;
+
+            return CURLE_OK;
+          }
+        }
+        /* we've passed, proceed as normal */
+      }
+    }
+
+    /* Send everything on data->state.in to the socket */
+    if(data->set.ftp_append) {
+      /* we append onto the file instead of rewriting it */
+      FTPSENDF(conn, "APPE %s", ftp->file);
+    }
+    else {
+      FTPSENDF(conn, "STOR %s", ftp->file);
+    }
+
+    result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+    if(result)
+      return result;
+
+    if(ftpcode>=400) {
+      failf(data, "Failed FTP upload:%s", buf+3);
+      /* oops, we never close the sockets! */
+      return CURLE_FTP_COULDNT_STOR_FILE;
+    }
+
+    if(data->set.ftp_use_port) {
+      /* PORT means we are now awaiting the server to connect to us. */
+      result = AllowServerConnect(conn);
+      if( result )
+        return result;
+    }
+
+    if(conn->ssl[SECONDARYSOCKET].use) {
+      /* since we only have a plaintext TCP connection here, we must now
+         do the TLS stuff */
+      infof(data, "Doing the SSL/TLS handshake on the data stream\n");
+      result = Curl_SSLConnect(conn, SECONDARYSOCKET);
+      if(result)
+        return result;
+    }
+
+    *bytecountp=0;
+
+    /* When we know we're uploading a specified file, we can get the file
+       size prior to the actual upload. */
+
+    Curl_pgrsSetUploadSize(data, data->set.infilesize);
+
+    result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */
+                           SECONDARYSOCKET, bytecountp);
+    if(result)
+      return result;
+
+  }
+  else if(!conn->bits.no_body) {
+    /* Retrieve file or directory */
+    bool dirlist=FALSE;
+    curl_off_t downloadsize=-1;
+
+    if(conn->bits.use_range && conn->range) {
+      curl_off_t from, to;
+      curl_off_t totalsize;
+      char *ptr;
+      char *ptr2;
+
+      from=curlx_strtoofft(conn->range, &ptr, 0);
+      while(ptr && *ptr && (isspace((int)*ptr) || (*ptr=='-')))
+        ptr++;
+      to=curlx_strtoofft(ptr, &ptr2, 0);
+      if(ptr == ptr2) {
+        /* we didn't get any digit */
+        to=-1;
+      }
+      if((-1 == to) && (from>=0)) {
+        /* X - */
+        conn->resume_from = from;
+        infof(data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n", from);
+      }
+      else if(from < 0) {
+        /* -Y */
+        totalsize = -from;
+        conn->maxdownload = -from;
+        conn->resume_from = from;
+        infof(data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n", totalsize);
+      }
+      else {
+        /* X-Y */
+        totalsize = to-from;
+        conn->maxdownload = totalsize+1; /* include the last mentioned byte */
+        conn->resume_from = from;
+        infof(data, "FTP RANGE from %" FORMAT_OFF_T
+              " getting %" FORMAT_OFF_T " bytes\n", from, conn->maxdownload);
+      }
+      infof(data, "range-download from %" FORMAT_OFF_T
+            " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
+            from, to, conn->maxdownload);
+      ftp->dont_check = TRUE; /* dont check for successful transfer */
+    }
+
+    if((data->set.ftp_list_only) || !ftp->file) {
+      /* The specified path ends with a slash, and therefore we think this
+         is a directory that is requested, use LIST. But before that we
+         need to set ASCII transfer mode. */
+      dirlist = TRUE;
+
+      /* Set type to ASCII */
+      result = ftp_transfertype(conn, TRUE /* ASCII enforced */);
+      if(result)
+        return result;
+
+      /* if this output is to be machine-parsed, the NLST command will be
+         better used since the LIST command output is not specified or
+         standard in any way */
+
+      FTPSENDF(conn, "%s",
+            data->set.customrequest?data->set.customrequest:
+            (data->set.ftp_list_only?"NLST":"LIST"));
+    }
+    else {
+      curl_off_t foundsize;
+
+      /* Set type to binary (unless specified ASCII) */
+      result = ftp_transfertype(conn, data->set.ftp_ascii);
+      if(result)
+        return result;
+
+      /* Send any PREQUOTE strings after transfer type is set? */
+      if(data->set.prequote) {
+        if ((result = ftp_sendquote(conn, data->set.prequote)) != CURLE_OK)
+          return result;
+      }
+
+      /* Attempt to get the size, it'll be useful in some cases: for resumed
+         downloads and when talking to servers that don't give away the size
+         in the RETR response line. */
+      result = ftp_getsize(conn, ftp->file, &foundsize);
+      if(CURLE_OK == result) {
+        if (data->set.max_filesize && foundsize > data->set.max_filesize) {
+          failf(data, "Maximum file size exceeded");
+          return CURLE_FILESIZE_EXCEEDED;
+        }
+        downloadsize = foundsize;
+      }
+
+      if(conn->resume_from) {
+
+        /* Daniel: (August 4, 1999)
+         *
+         * We start with trying to use the SIZE command to figure out the size
+         * of the file we're gonna get. If we can get the size, this is by far
+         * the best way to know if we're trying to resume beyond the EOF.
+         *
+         * Daniel, November 28, 2001. We *always* get the size on downloads
+         * now, so it is done before this even when not doing resumes. I saved
+         * the comment above for nostalgical reasons! ;-)
+         */
+        if(CURLE_OK != result) {
+          infof(data, "ftp server doesn't support SIZE\n");
+          /* We couldn't get the size and therefore we can't know if there
+             really is a part of the file left to get, although the server
+             will just close the connection when we start the connection so it
+             won't cause us any harm, just not make us exit as nicely. */
+        }
+        else {
+          /* We got a file size report, so we check that there actually is a
+             part of the file left to get, or else we go home.  */
+          if(conn->resume_from< 0) {
+            /* We're supposed to download the last abs(from) bytes */
+            if(foundsize < -conn->resume_from) {
+              failf(data, "Offset (%" FORMAT_OFF_T
+                    ") was beyond file size (%" FORMAT_OFF_T ")",
+                    conn->resume_from, foundsize);
+              return CURLE_FTP_BAD_DOWNLOAD_RESUME;
+            }
+            /* convert to size to download */
+            downloadsize = -conn->resume_from;
+            /* download from where? */
+            conn->resume_from = foundsize - downloadsize;
+          }
+          else {
+            if(foundsize < conn->resume_from) {
+              failf(data, "Offset (%" FORMAT_OFF_T
+                    ") was beyond file size (%" FORMAT_OFF_T ")",
+                    conn->resume_from, foundsize);
+              return CURLE_FTP_BAD_DOWNLOAD_RESUME;
+            }
+            /* Now store the number of bytes we are expected to download */
+            downloadsize = foundsize-conn->resume_from;
+          }
+        }
+
+        if (downloadsize == 0) {
+          /* no data to transfer */
+          result=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+          (void)result;
+          infof(data, "File already completely downloaded\n");
+
+          /* Set no_transfer so that we won't get any error in Curl_ftp_done()
+           * because we didn't transfer the any file */
+          ftp->no_transfer = TRUE;
+          return CURLE_OK;
+        }
+
+        /* Set resume file transfer offset */
+        infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
+              "\n",
+              conn->resume_from);
+
+        FTPSENDF(conn, "REST %" FORMAT_OFF_T, conn->resume_from);
+
+        result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+        if(result)
+          return result;
+
+        if(ftpcode != 350) {
+          failf(data, "Couldn't use REST: %s", buf+4);
+          return CURLE_FTP_COULDNT_USE_REST;
+        }
+      }
+
+      FTPSENDF(conn, "RETR %s", ftp->file);
+    }
+
+    result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+    if(result)
+      return result;
+
+    if((ftpcode == 150) || (ftpcode == 125)) {
+
+      /*
+        A;
+        150 Opening BINARY mode data connection for /etc/passwd (2241
+        bytes).  (ok, the file is being transfered)
+
+        B:
+        150 Opening ASCII mode data connection for /bin/ls
+
+        C:
+        150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
+
+        D:
+        150 Opening ASCII mode data connection for /linux/fisk/kpanelrc (0.0.0.0,0) (545 bytes).
+
+        E:
+        125 Data connection already open; Transfer starting. */
+
+      curl_off_t size=-1; /* default unknown size */
+
+
+      /*
+       * It appears that there are FTP-servers that return size 0 for files
+       * when SIZE is used on the file while being in BINARY mode. To work
+       * around that (stupid) behavior, we attempt to parse the RETR response
+       * even if the SIZE returned size zero.
+       *
+       * Debugging help from Salvatore Sorrentino on February 26, 2003.
+       */
+
+      if(!dirlist &&
+         !data->set.ftp_ascii &&
+         (downloadsize < 1)) {
+        /*
+         * It seems directory listings either don't show the size or very
+         * often uses size 0 anyway. ASCII transfers may very well turn out
+         * that the transfered amount of data is not the same as this line
+         * tells, why using this number in those cases only confuses us.
+         *
+         * Example D above makes this parsing a little tricky */
+        char *bytes;
+        bytes=strstr(buf, " bytes");
+        if(bytes--) {
+          long in=bytes-buf;
+          /* this is a hint there is size information in there! ;-) */
+          while(--in) {
+            /* scan for the parenthesis and break there */
+            if('(' == *bytes)
+              break;
+            /* if only skip digits, or else we're in deep trouble */
+            if(!isdigit((int)*bytes)) {
+              bytes=NULL;
+              break;
+            }
+            /* one more estep backwards */
+            bytes--;
+          }
+          /* only if we have nothing but digits: */
+          if(bytes++) {
+            /* get the number! */
+            size = curlx_strtoofft(bytes, NULL, 0);
+          }
+
+        }
+      }
+      else if(downloadsize > -1)
+        size = downloadsize;
+
+      if(data->set.ftp_use_port) {
+        result = AllowServerConnect(conn);
+        if( result )
+          return result;
+      }
+
+      if(conn->ssl[SECONDARYSOCKET].use) {
+        /* since we only have a plaintext TCP connection here, we must now
+           do the TLS stuff */
+        infof(data, "Doing the SSL/TLS handshake on the data stream\n");
+        result = Curl_SSLConnect(conn, SECONDARYSOCKET);
+        if(result)
+          return result;
+      }
+
+      if(size > conn->maxdownload && conn->maxdownload > 0)
+        size = conn->size = conn->maxdownload;
+
+      infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
+
+      /* FTP download: */
+      result=Curl_Transfer(conn, SECONDARYSOCKET, size, FALSE,
+                           bytecountp,
+                           -1, NULL); /* no upload here */
+      if(result)
+        return result;
+    }
+    else {
+      if(dirlist && (ftpcode == 450)) {
+        /* simply no matching files */
+        ftp->no_transfer = TRUE; /* don't think we should download anything */
+      }
+      else {
+        failf(data, "%s", buf+4);
+        return CURLE_FTP_COULDNT_RETR_FILE;
+      }
+    }
+
+  }
+  /* end of transfer */
+
+  return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * ftp_perform()
+ *
+ * This is the actual DO function for FTP. Get a file/directory according to
+ * the options previously setup.
+ */
+
+static
+CURLcode ftp_perform(struct connectdata *conn,
+                     bool *connected)  /* for the TCP connect status after
+                                          PASV / PORT */
+{
+  /* this is FTP and no proxy */
+  CURLcode result=CURLE_OK;
+  struct SessionHandle *data=conn->data;
+  char *buf = data->state.buffer; /* this is our buffer */
+
+  /* the ftp struct is already inited in Curl_ftp_connect() */
+  struct FTP *ftp = conn->proto.ftp;
+
+  /* Send any QUOTE strings? */
+  if(data->set.quote) {
+    if ((result = ftp_sendquote(conn, data->set.quote)) != CURLE_OK)
+      return result;
+  }
+
+  /* This is a re-used connection. Since we change directory to where the
+     transfer is taking place, we must now get back to the original dir
+     where we ended up after login: */
+  if (conn->bits.reuse && ftp->entrypath) {
+    if ((result = ftp_cwd_and_mkd(conn, ftp->entrypath)) != CURLE_OK)
+      return result;
+  }
+
+  {
+    int i; /* counter for loop */
+    for (i=0; i < ftp->dirdepth; i++) {
+      /* RFC 1738 says empty components should be respected too, but
+         that is plain stupid since CWD can't be used with an empty argument */
+      if ((result = ftp_cwd_and_mkd(conn, ftp->dirs[i])) != CURLE_OK)
+        return result;
+    }
+  }
+
+  /* Requested time of file or time-depended transfer? */
+  if((data->set.get_filetime || data->set.timecondition) &&
+     ftp->file) {
+    result = ftp_getfiletime(conn, ftp->file);
+    switch( result )
+      {
+      case CURLE_FTP_COULDNT_RETR_FILE:
+      case CURLE_OK:
+        if(data->set.timecondition) {
+          if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
+            switch(data->set.timecondition) {
+            case CURL_TIMECOND_IFMODSINCE:
+            default:
+              if(data->info.filetime < data->set.timevalue) {
+                infof(data, "The requested document is not new enough\n");
+                ftp->no_transfer = TRUE; /* mark this to not transfer data */
+                return CURLE_OK;
+              }
+              break;
+            case CURL_TIMECOND_IFUNMODSINCE:
+              if(data->info.filetime > data->set.timevalue) {
+                infof(data, "The requested document is not old enough\n");
+                ftp->no_transfer = TRUE; /* mark this to not transfer data */
+                return CURLE_OK;
+              }
+              break;
+            } /* switch */
+          }
+          else {
+            infof(data, "Skipping time comparison\n");
+          }
+        }
+        break;
+      default:
+        return result;
+      } /* switch */
+  }
+
+  /* If we have selected NOBODY and HEADER, it means that we only want file
+     information. Which in FTP can't be much more than the file size and
+     date. */
+  if(conn->bits.no_body && data->set.include_header && ftp->file) {
+    /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
+       may not support it! It is however the only way we have to get a file's
+       size! */
+    curl_off_t filesize;
+    ssize_t nread;
+    int ftpcode;
+
+    ftp->no_transfer = TRUE; /* this means no actual transfer is made */
+
+    /* Some servers return different sizes for different modes, and thus we
+       must set the proper type before we check the size */
+    result = ftp_transfertype(conn, data->set.ftp_ascii);
+    if(result)
+      return result;
+
+    /* failing to get size is not a serious error */
+    result = ftp_getsize(conn, ftp->file, &filesize);
+
+    if(CURLE_OK == result) {
+      snprintf(buf, sizeof(data->state.buffer),
+               "Content-Length: %" FORMAT_OFF_T "\r\n", filesize);
+      result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
+      if(result)
+        return result;
+    }
+
+    /* Determine if server can respond to REST command and therefore
+       whether it can do a range */
+    FTPSENDF(conn, "REST 0", NULL);
+    result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+
+    if ((CURLE_OK == result) && (ftpcode == 350)) {
+      result = Curl_client_write(data, CLIENTWRITE_BOTH,
+                                 (char *)"Accept-ranges: bytes\r\n", 0);
+      if(result)
+        return result;
+    }
+
+    /* If we asked for a time of the file and we actually got one as
+       well, we "emulate" a HTTP-style header in our output. */
+
+#ifdef HAVE_STRFTIME
+    if(data->set.get_filetime && (data->info.filetime>=0) ) {
+      struct tm *tm;
+      time_t cuClock = (time_t)data->info.filetime;
+#ifdef HAVE_GMTIME_R
+      struct tm buffer;
+      tm = (struct tm *)gmtime_r(&cuClock, &buffer);
+#else
+      tm = gmtime(&cuClock);
+#endif
+      /* format: "Tue, 15 Nov 1994 12:45:26" */
+      strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S GMT\r\n",
+               tm);
+      result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
+      if(result)
+        return result;
+    }
+#endif
+
+    return CURLE_OK;
+  }
+
+  if(conn->bits.no_body)
+    /* doesn't really transfer any data */
+    ftp->no_transfer = TRUE;
+  /* Get us a second connection up and connected */
+  else if(data->set.ftp_use_port) {
+    /* We have chosen to use the PORT command */
+    result = ftp_use_port(conn);
+    if(CURLE_OK == result) {
+      /* we have the data connection ready */
+      infof(data, "Ordered connect of the data stream with PORT!\n");
+      *connected = TRUE; /* mark us "still connected" */
+    }
+  }
+  else {
+    /* We have chosen (this is default) to use the PASV command */
+    result = ftp_use_pasv(conn, connected);
+    if(CURLE_OK == result && *connected)
+      infof(data, "Connected the data stream with PASV!\n");
+  }
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * Curl_ftp()
+ *
+ * This function is registered as 'curl_do' function. It decodes the path
+ * parts etc as a wrapper to the actual DO function (ftp_perform).
+ *
+ * The input argument is already checked for validity.
+ */
+CURLcode Curl_ftp(struct connectdata *conn)
+{
+  CURLcode retcode;
+
+  if (conn->sec_conn) /* 3rd party transfer */
+    retcode = ftp_3rdparty(conn);
+  else
+    retcode = ftp_regular_transfer(conn);
+
+  return retcode;
+}
+
+/***********************************************************************
+ *
+ * Curl_ftpsendf()
+ *
+ * Sends the formated string as a ftp command to a ftp server
+ *
+ * NOTE: we build the command in a fixed-length buffer, which sets length
+ * restrictions on the command!
+ */
+CURLcode Curl_ftpsendf(struct connectdata *conn,
+                       const char *fmt, ...)
+{
+  ssize_t bytes_written;
+  char s[256];
+  size_t write_len;
+  char *sptr=s;
+  CURLcode res;
+
+  va_list ap;
+  va_start(ap, fmt);
+  vsnprintf(s, 250, fmt, ap);
+  va_end(ap);
+
+  strcat(s, "\r\n"); /* append a trailing CRLF */
+
+  bytes_written=0;
+  write_len = strlen(s);
+
+  while(1) {
+    res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
+                     &bytes_written);
+
+    if(CURLE_OK != res)
+      break;
+
+    if(conn->data->set.verbose)
+      Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, bytes_written, conn->host.dispname);
+
+    if(bytes_written != (ssize_t)write_len) {
+      write_len -= bytes_written;
+      sptr += bytes_written;
+    }
+    else
+      break;
+  }
+
+  return res;
+}
+
+/***********************************************************************
+ *
+ * ftp_quit()
+ *
+ * This should be called before calling sclose() on an ftp control connection
+ * (not data connections). We should then wait for the response from the
+ * server before returning. The calling code should then try to close the
+ * connection.
+ *
+ */
+static CURLcode ftp_quit(struct connectdata *conn)
+{
+  ssize_t nread;
+  int ftpcode;
+  CURLcode ret = CURLE_OK;
+
+  if(conn->proto.ftp->ctl_valid) {
+    ret = Curl_ftpsendf(conn, "%s", "QUIT");
+    if(CURLE_OK == ret)
+      ret = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+  }
+
+  return ret;
+}
+
+/***********************************************************************
+ *
+ * Curl_ftp_disconnect()
+ *
+ * Disconnect from an FTP server. Cleanup protocol-specific per-connection
+ * resources
+ */
+CURLcode Curl_ftp_disconnect(struct connectdata *conn)
+{
+  struct FTP *ftp= conn->proto.ftp;
+
+  /* We cannot send quit unconditionally. If this connection is stale or
+     bad in any way, sending quit and waiting around here will make the
+     disconnect wait in vain and cause more problems than we need to.
+
+     ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
+     will try to send the QUIT command, otherwise it will just return.
+  */
+
+  /* The FTP session may or may not have been allocated/setup at this point! */
+  if(ftp) {
+    (void)ftp_quit(conn); /* ignore errors on the QUIT */
+
+    if(ftp->entrypath)
+      free(ftp->entrypath);
+    if(ftp->cache) {
+      free(ftp->cache);
+      ftp->cache = NULL;
+    }
+    freedirs(ftp);
+  }
+  return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * ftp_mkd()
+ *
+ * Makes a directory on the FTP server.
+ *
+ * Calls failf()
+ */
+static CURLcode ftp_mkd(struct connectdata *conn, char *path)
+{
+  CURLcode result;
+  int ftpcode; /* for ftp status */
+  ssize_t nread;
+
+  /* Create a directory on the remote server */
+  FTPSENDF(conn, "MKD %s", path);
+
+  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+  if(result)
+    return result;
+
+  switch(ftpcode) {
+  case 257:
+    /* success! */
+    infof( conn->data , "Created remote directory %s\n" , path );
+    break;
+  case 550:
+    failf(conn->data, "Permission denied to make directory %s", path);
+    result = CURLE_FTP_ACCESS_DENIED;
+    break;
+  default:
+    failf(conn->data, "unrecognized MKD response: %d", ftpcode );
+    result = CURLE_FTP_ACCESS_DENIED;
+    break;
+  }
+  return  result;
+}
+
+/***********************************************************************
+ *
+ * ftp_cwd()
+ *
+ * Send 'CWD' to the remote server to Change Working Directory.  It is the ftp
+ * version of the unix 'cd' command. This function is only called from the
+ * ftp_cwd_and_mkd() function these days.
+ *
+ * This function does NOT call failf().
+ */
+static
+CURLcode ftp_cwd(struct connectdata *conn, char *path)
+{
+  ssize_t nread;
+  int     ftpcode;
+  CURLcode result;
+
+  FTPSENDF(conn, "CWD %s", path);
+  result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+  if (!result) {
+    /* According to RFC959, CWD is supposed to return 250 on success, but
+       there seem to be non-compliant FTP servers out there that return 200,
+       so we accept any '2xy' code here. */
+    if (ftpcode/100 != 2)
+      result = CURLE_FTP_ACCESS_DENIED;
+  }
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_cwd_and_mkd()
+ *
+ * Change to the given directory.  If the directory is not present, and we
+ * have been told to allow it, then create the directory and cd to it.
+ *
+ */
+static CURLcode ftp_cwd_and_mkd(struct connectdata *conn, char *path)
+{
+  CURLcode result;
+
+  result = ftp_cwd(conn, path);
+  if (result) {
+    if(conn->data->set.ftp_create_missing_dirs) {
+      result = ftp_mkd(conn, path);
+      if (result)
+        /* ftp_mkd() calls failf() itself */
+        return result;
+      result = ftp_cwd(conn, path);
+    }
+    if(result)
+      failf(conn->data, "Couldn't cd to %s", path);
+  }
+  return result;
+}
+
+
+
+/***********************************************************************
+ *
+ * ftp_3rdparty_pretransfer()
+ *
+ * Preparation for 3rd party transfer.
+ *
+ */
+static CURLcode ftp_3rdparty_pretransfer(struct connectdata *conn)
+{
+  CURLcode result;
+  struct SessionHandle *data = conn->data;
+  struct connectdata *sec_conn = conn->sec_conn;
+
+  /* sets transfer type */
+  result = ftp_transfertype(conn, data->set.ftp_ascii);
+  if (result)
+    return result;
+
+  result = ftp_transfertype(sec_conn, data->set.ftp_ascii);
+  if (result)
+    return result;
+
+  /* Send any PREQUOTE strings after transfer type is set? */
+  if (data->set.source_prequote) {
+    /* sends command(s) to source server before file transfer */
+    result = ftp_sendquote(sec_conn, data->set.source_prequote);
+  }
+  if (!result && data->set.prequote)
+    result = ftp_sendquote(conn, data->set.prequote);
+
+  return result;
+}
+
+
+
+/***********************************************************************
+ *
+ * ftp_3rdparty_transfer()
+ *
+ * Performs 3rd party transfer.
+ *
+ */
+static CURLcode ftp_3rdparty_transfer(struct connectdata *conn)
+{
+  CURLcode result;
+  ssize_t nread;
+  int ftpcode, ip[4], port[2];
+  struct SessionHandle *data = conn->data;
+  struct connectdata *sec_conn = conn->sec_conn;
+  char *buf = data->state.buffer;   /* this is our buffer */
+  char *str = buf;
+  char pasv_port[50];
+  const char *stor_cmd;
+  struct connectdata *pasv_conn;
+  struct connectdata *port_conn;
+
+  if (data->set.pasvHost == CURL_TARGET_PASV) {
+    pasv_conn = conn;
+    port_conn = sec_conn;
+  }
+  else {
+    pasv_conn = sec_conn;
+    port_conn = conn;
+  }
+
+  /* sets the passive mode */
+  FTPSENDF(pasv_conn, "%s", "PASV");
+  result = Curl_GetFTPResponse(&nread, pasv_conn, &ftpcode);
+  if (result) return result;
+  if (ftpcode != 227) {
+    failf(data, "Odd return code after PASV:%s", buf + 3);
+    return CURLE_FTP_WEIRD_PASV_REPLY;
+  }
+
+  while (*str) {
+    if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
+                    &ip[0], &ip[1], &ip[2], &ip[3], &port[0], &port[1]))
+      break;
+    str++;
+  }
+
+  if (!*str) {
+    failf(pasv_conn->data, "Couldn't interpret this 227-reply: %s", buf);
+    return CURLE_FTP_WEIRD_227_FORMAT;
+  }
+
+  snprintf(pasv_port, sizeof(pasv_port), "%d,%d,%d,%d,%d,%d", ip[0], ip[1],
+           ip[2], ip[3], port[0], port[1]);
+
+  /* sets data connection between remote hosts */
+  FTPSENDF(port_conn, "PORT %s", pasv_port);
+  result = Curl_GetFTPResponse(&nread, port_conn, &ftpcode);
+  if (result)
+    return result;
+
+  if (ftpcode != 200) {
+    failf(data, "PORT command attempts failed:%s", buf + 3);
+    return CURLE_FTP_PORT_FAILED;
+  }
+
+  /* we might append onto the file instead of overwriting it */
+  stor_cmd = data->set.ftp_append?"APPE":"STOR";
+
+  /* transfers file between remote hosts */
+  FTPSENDF(sec_conn, "RETR %s", data->set.source_path);
+
+  if(data->set.pasvHost == CURL_TARGET_PASV) {
+
+    result = Curl_GetFTPResponse(&nread, sec_conn, &ftpcode);
+    if (result)
+      return result;
+
+    if (ftpcode != 150) {
+      failf(data, "Failed RETR: %s", buf + 4);
+      return CURLE_FTP_COULDNT_RETR_FILE;
+    }
+
+    result = Curl_ftpsendf(conn, "%s %s", stor_cmd, conn->path);
+    if(CURLE_OK == result)
+      result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+    if (result)
+      return result;
+
+    if (ftpcode != 150) {
+      failf(data, "Failed FTP upload: %s", buf + 4);
+      return CURLE_FTP_COULDNT_STOR_FILE;
+    }
+
+  }
+  else {
+
+    result = Curl_ftpsendf(conn, "%s %s", stor_cmd, conn->path);
+    if(CURLE_OK == result)
+      result = Curl_GetFTPResponse(&nread, sec_conn, &ftpcode);
+    if (result)
+      return result;
+
+    if (ftpcode != 150) {
+      failf(data, "Failed FTP upload: %s", buf + 4);
+      return CURLE_FTP_COULDNT_STOR_FILE;
+    }
+
+    result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+    if (result)
+      return result;
+
+    if (ftpcode != 150) {
+      failf(data, "Failed FTP upload: %s", buf + 4);
+      return CURLE_FTP_COULDNT_STOR_FILE;
+    }
+  }
+
+  return CURLE_OK;
+}
+
+
+
+/***********************************************************************
+ *
+ * ftp_regular_transfer()
+ *
+ * The input argument is already checked for validity.
+ * Performs a regular transfer between local and remote hosts.
+ *
+ * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
+ * Curl_ftp_done() function without finding any major problem.
+ */
+static
+CURLcode ftp_regular_transfer(struct connectdata *conn)
+{
+  CURLcode retcode=CURLE_OK;
+  bool connected=0;
+  struct SessionHandle *data = conn->data;
+  struct FTP *ftp;
+
+  char *slash_pos;  /* position of the first '/' char in curpos */
+  char *cur_pos=conn->path; /* current position in ppath. point at the begin
+                               of next path component */
+
+  /* the ftp struct is already inited in ftp_connect() */
+  ftp = conn->proto.ftp;
+  ftp->ctl_valid = FALSE;
+  conn->size = -1; /* make sure this is unknown at this point */
+
+  Curl_pgrsSetUploadCounter(data, 0);
+  Curl_pgrsSetDownloadCounter(data, 0);
+  Curl_pgrsSetUploadSize(data, 0);
+  Curl_pgrsSetDownloadSize(data, 0);
+
+  ftp->dirdepth = 0;
+  ftp->diralloc = 5; /* default dir depth to allocate */
+  ftp->dirs = (char **)malloc(ftp->diralloc * sizeof(ftp->dirs[0]));
+  if(!ftp->dirs)
+    return CURLE_OUT_OF_MEMORY;
+  ftp->dirs[0] = NULL; /* to start with */
+
+  /* parse the URL path into separate path components */
+  while((slash_pos=strchr(cur_pos, '/'))) {
+    /* 1 or 0 to indicate absolute directory */
+    bool absolute_dir = (cur_pos - conn->path > 0) && (ftp->dirdepth == 0);
+
+    /* seek out the next path component */
+    if (slash_pos-cur_pos) {
+      /* we skip empty path components, like "x//y" since the FTP command CWD
+         requires a parameter and a non-existant parameter a) doesn't work on
+         many servers and b) has no effect on the others. */
+      int len = (int)(slash_pos - cur_pos + absolute_dir);
+      ftp->dirs[ftp->dirdepth] = curl_unescape(cur_pos - absolute_dir, len);
+
+      if (!ftp->dirs[ftp->dirdepth]) { /* run out of memory ... */
+        failf(data, "no memory");
+        freedirs(ftp);
+        return CURLE_OUT_OF_MEMORY;
+      }
+    }
+    else {
+      cur_pos = slash_pos + 1; /* jump to the rest of the string */
+      continue;
+    }
+
+    if(!retcode) {
+      cur_pos = slash_pos + 1; /* jump to the rest of the string */
+      if(++ftp->dirdepth >= ftp->diralloc) {
+        /* enlarge array */
+        char **bigger;
+        ftp->diralloc *= 2; /* double the size each time */
+        bigger = realloc(ftp->dirs, ftp->diralloc * sizeof(ftp->dirs[0]));
+        if(!bigger) {
+          freedirs(ftp);
+          return CURLE_OUT_OF_MEMORY;
+        }
+        ftp->dirs = (char **)bigger;
+      }
+    }
+  }
+
+  ftp->file = cur_pos;  /* the rest is the file name */
+
+  if(*ftp->file) {
+    ftp->file = curl_unescape(ftp->file, 0);
+    if(NULL == ftp->file) {
+      freedirs(ftp);
+      failf(data, "no memory");
+      return CURLE_OUT_OF_MEMORY;
+    }
+  }
+  else
+    ftp->file=NULL; /* instead of point to a zero byte, we make it a NULL
+                       pointer */
+
+  retcode = ftp_perform(conn, &connected);
+
+  if(CURLE_OK == retcode) {
+    if(connected)
+      retcode = Curl_ftp_nextconnect(conn);
+
+    if(retcode && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) {
+      /* Failure detected, close the second socket if it was created already */
+      sclose(conn->sock[SECONDARYSOCKET]);
+      conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
+    }
+
+    if(ftp->no_transfer)
+      /* no data to transfer */
+      retcode=Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+    else if(!connected)
+      /* since we didn't connect now, we want do_more to get called */
+      conn->bits.do_more = TRUE;
+  }
+  else
+    freedirs(ftp);
+
+  ftp->ctl_valid = TRUE; /* seems good */
+
+  return retcode;
+}
+
+
+
+/***********************************************************************
+ *
+ * ftp_3rdparty()
+ *
+ * The input argument is already checked for validity.
+ * Performs a 3rd party transfer between two remote hosts.
+ */
+static CURLcode ftp_3rdparty(struct connectdata *conn)
+{
+  CURLcode retcode;
+
+  conn->proto.ftp->ctl_valid = conn->sec_conn->proto.ftp->ctl_valid = TRUE;
+  conn->size = conn->sec_conn->size = -1;
+
+  retcode = ftp_3rdparty_pretransfer(conn);
+  if (!retcode)
+    retcode = ftp_3rdparty_transfer(conn);
+
+  return retcode;
+}
+
+#endif /* CURL_DISABLE_FTP */
diff --git a/Utilities/cmcurl/ftp.h b/Utilities/cmcurl/ftp.h
new file mode 100644
index 0000000..dc7cf79
--- /dev/null
+++ b/Utilities/cmcurl/ftp.h
@@ -0,0 +1,37 @@
+#ifndef __FTP_H
+#define __FTP_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#ifndef CURL_DISABLE_FTP
+CURLcode Curl_ftp(struct connectdata *conn);
+CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode);
+CURLcode Curl_ftp_connect(struct connectdata *conn);
+CURLcode Curl_ftp_disconnect(struct connectdata *conn);
+CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...);
+CURLcode Curl_GetFTPResponse(ssize_t *nread, struct connectdata *conn,
+                             int *ftpcode);
+CURLcode Curl_ftp_nextconnect(struct connectdata *conn);
+#endif
+
+#endif
diff --git a/Utilities/cmcurl/getdate.c b/Utilities/cmcurl/getdate.c
new file mode 100644
index 0000000..6aca48e
--- /dev/null
+++ b/Utilities/cmcurl/getdate.c
@@ -0,0 +1,2471 @@
+/* A Bison parser, made by GNU Bison 1.875a.  */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+/* As a special exception, when this file is copied by Bison into a
+   Bison output file, you may use that output file without restriction.
+   This special exception was added by the Free Software Foundation
+   in version 1.24 of Bison.  */
+
+/* Written by Richard Stallman by simplifying the original so called
+   ``semantic'' parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON 1
+
+/* Skeleton name.  */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers.  */
+#define YYPURE 1
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     tAGO = 258,
+     tDAY = 259,
+     tDAY_UNIT = 260,
+     tDAYZONE = 261,
+     tDST = 262,
+     tHOUR_UNIT = 263,
+     tID = 264,
+     tMERIDIAN = 265,
+     tMINUTE_UNIT = 266,
+     tMONTH = 267,
+     tMONTH_UNIT = 268,
+     tSEC_UNIT = 269,
+     tSNUMBER = 270,
+     tUNUMBER = 271,
+     tYEAR_UNIT = 272,
+     tZONE = 273
+   };
+#endif
+#define tAGO 258
+#define tDAY 259
+#define tDAY_UNIT 260
+#define tDAYZONE 261
+#define tDST 262
+#define tHOUR_UNIT 263
+#define tID 264
+#define tMERIDIAN 265
+#define tMINUTE_UNIT 266
+#define tMONTH 267
+#define tMONTH_UNIT 268
+#define tSEC_UNIT 269
+#define tSNUMBER 270
+#define tUNUMBER 271
+#define tYEAR_UNIT 272
+#define tZONE 273
+
+
+
+
+/* Copy the first part of user declarations.  */
+#line 1 "getdate.y"
+
+/*
+**  Originally written by Steven M. Bellovin <smb@research.att.com> while
+**  at the University of North Carolina at Chapel Hill.  Later tweaked by
+**  a couple of people on Usenet.  Completely overhauled by Rich $alz
+**  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990.
+**
+**  This code has been modified since it was included in curl, to make it
+**  thread-safe and to make compilers complain less about it.
+**
+**  This code is in the public domain and has no copyright.
+*/
+
+#include "setup.h"
+
+# ifdef HAVE_ALLOCA_H
+#  include <alloca.h>
+# endif
+
+# ifdef HAVE_TIME_H
+#  include <time.h>
+# endif
+
+#ifndef YYDEBUG
+  /* to satisfy gcc -Wundef, we set this to 0 */
+#define YYDEBUG 0
+#endif
+
+#ifndef YYSTACK_USE_ALLOCA
+  /* to satisfy gcc -Wundef, we set this to 0 */
+#define YYSTACK_USE_ALLOCA 0
+#endif
+
+/* Since the code of getdate.y is not included in the Emacs executable
+   itself, there is no need to #define static in this file.  Even if
+   the code were included in the Emacs executable, it probably
+   wouldn't do any harm to #undef it here; this will only cause
+   problems if we try to write to a static variable, which I don't
+   think this code needs to do.  */
+#ifdef emacs
+# undef static
+#endif
+
+#ifdef __APPLE__
+#include <sys/types.h>
+#include <sys/malloc.h>
+#else
+
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#if HAVE_STDLIB_H
+# include <stdlib.h> /* for `free'; used by Bison 1.27 */
+#else
+
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+
+#endif
+
+#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
+# define IN_CTYPE_DOMAIN(c) 1
+#else
+# define IN_CTYPE_DOMAIN(c) isascii(c)
+#endif
+
+#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c))
+#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c))
+#define ISUPPER(c) (IN_CTYPE_DOMAIN (c) && isupper (c))
+#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
+
+/* ISDIGIT differs from ISDIGIT_LOCALE, as follows:
+   - Its arg may be any int or unsigned int; it need not be an unsigned char.
+   - It's guaranteed to evaluate its argument exactly once.
+   - It's typically faster.
+   Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
+   only '0' through '9' are digits.  Prefer ISDIGIT to ISDIGIT_LOCALE unless
+   it's important to use the locale's definition of `digit' even when the
+   host does not conform to Posix.  */
+#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
+
+#if defined (STDC_HEADERS) || defined (USG)
+# include <string.h>
+#endif
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 0
+#endif
+
+#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
+# define __attribute__(x)
+#endif
+
+#ifndef ATTRIBUTE_UNUSED
+# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+#endif
+
+/* Some old versions of bison generate parsers that use bcopy.
+   That loses on systems that don't provide the function, so we have
+   to redefine it here.  */
+#if !defined (HAVE_BCOPY) && defined (HAVE_MEMCPY) && !defined (bcopy)
+# define bcopy(from, to, len) memcpy ((to), (from), (len))
+#endif
+
+/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
+   as well as gratuitiously global symbol names, so we can have multiple
+   yacc generated parsers in the same program.  Note that these are only
+   the variables produced by yacc.  If other parser generators (bison,
+   byacc, etc) produce additional global names that conflict at link time,
+   then those parser generators need to be fixed instead of adding those
+   names to this list. */
+
+#define yymaxdepth Curl_gd_maxdepth
+#define yyparse Curl_gd_parse
+#define yylex   Curl_gd_lex
+#define yyerror Curl_gd_error
+#define yylval  Curl_gd_lval
+#define yychar  Curl_gd_char
+#define yydebug Curl_gd_debug
+#define yypact  Curl_gd_pact
+#define yyr1    Curl_gd_r1
+#define yyr2    Curl_gd_r2
+#define yydef   Curl_gd_def
+#define yychk   Curl_gd_chk
+#define yypgo   Curl_gd_pgo
+#define yyact   Curl_gd_act
+#define yyexca  Curl_gd_exca
+#define yyerrflag Curl_gd_errflag
+#define yynerrs Curl_gd_nerrs
+#define yyps    Curl_gd_ps
+#define yypv    Curl_gd_pv
+#define yys     Curl_gd_s
+#define yy_yys  Curl_gd_yys
+#define yystate Curl_gd_state
+#define yytmp   Curl_gd_tmp
+#define yyv     Curl_gd_v
+#define yy_yyv  Curl_gd_yyv
+#define yyval   Curl_gd_val
+#define yylloc  Curl_gd_lloc
+#define yyreds  Curl_gd_reds          /* With YYDEBUG defined */
+#define yytoks  Curl_gd_toks          /* With YYDEBUG defined */
+#define yylhs   Curl_gd_yylhs
+#define yylen   Curl_gd_yylen
+#define yydefred Curl_gd_yydefred
+#define yydgoto Curl_gd_yydgoto
+#define yysindex Curl_gd_yysindex
+#define yyrindex Curl_gd_yyrindex
+#define yygindex Curl_gd_yygindex
+#define yytable  Curl_gd_yytable
+#define yycheck  Curl_gd_yycheck
+
+#define EPOCH           1970
+#define HOUR(x)         ((x) * 60)
+
+#define MAX_BUFF_LEN    128   /* size of buffer to read the date into */
+
+/*
+**  An entry in the lexical lookup table.
+*/
+typedef struct _TABLE {
+    const char  *name;
+    int         type;
+    int         value;
+} TABLE;
+
+
+/*
+**  Meridian:  am, pm, or 24-hour style.
+*/
+typedef enum _MERIDIAN {
+    MERam, MERpm, MER24
+} MERIDIAN;
+
+/* parse results and input string */
+typedef struct _CURL_CONTEXT {
+    const char  *yyInput;
+    int         yyDayOrdinal;
+    int         yyDayNumber;
+    int         yyHaveDate;
+    int         yyHaveDay;
+    int         yyHaveRel;
+    int         yyHaveTime;
+    int         yyHaveZone;
+    int         yyTimezone;
+    int         yyDay;
+    int         yyHour;
+    int         yyMinutes;
+    int         yyMonth;
+    int         yySeconds;
+    int         yyYear;
+    MERIDIAN    yyMeridian;
+    int         yyRelDay;
+    int         yyRelHour;
+    int         yyRelMinutes;
+    int         yyRelMonth;
+    int         yyRelSeconds;
+    int         yyRelYear;
+} CURL_CONTEXT;
+
+/* enable use of extra argument to yyparse and yylex which can be used to pass
+**  in a user defined value (CURL_CONTEXT struct in our case)
+*/
+#define YYPARSE_PARAM cookie
+#define YYLEX_PARAM cookie
+#define context ((CURL_CONTEXT *) cookie)
+
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED)
+#line 223 "getdate.y"
+typedef union YYSTYPE {
+    int                 Number;
+    enum _MERIDIAN      Meridian;
+} YYSTYPE;
+/* Line 191 of yacc.c.  */
+#line 331 "y.tab.c"
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+# define YYSTYPE_IS_TRIVIAL 1
+#endif
+
+
+
+/* Copy the second part of user declarations.  */
+#line 228 "getdate.y"
+
+static int yylex (YYSTYPE *yylval, void *cookie);
+static int yyerror (const char *s);
+
+
+/* Line 214 of yacc.c.  */
+#line 347 "y.tab.c"
+
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols.  */
+
+# if YYSTACK_USE_ALLOCA
+#  define YYSTACK_ALLOC alloca
+# else
+#  ifndef YYSTACK_USE_ALLOCA
+#   if defined (alloca) || defined (_ALLOCA_H)
+#    define YYSTACK_ALLOC alloca
+#   else
+#    ifdef __GNUC__
+#     define YYSTACK_ALLOC __builtin_alloca
+#    endif
+#   endif
+#  endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+   /* Pacify GCC's `empty if-body' warning. */
+#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# else
+#  if defined (__STDC__) || defined (__cplusplus)
+#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+#   define YYSIZE_T size_t
+#  endif
+#  define YYSTACK_ALLOC malloc
+#  define YYSTACK_FREE free
+# endif
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
+
+
+#if (! defined (yyoverflow) \
+     && (! defined (__cplusplus) \
+         || (YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member.  */
+union yyalloc
+{
+  short yyss;
+  YYSTYPE yyvs;
+  };
+
+/* The size of the maximum gap between one aligned stack and the next.  */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+   N elements.  */
+# define YYSTACK_BYTES(N) \
+     ((N) * (sizeof (short) + sizeof (YYSTYPE))                         \
+      + YYSTACK_GAP_MAXIMUM)
+
+/* Copy COUNT objects from FROM to TO.  The source and destination do
+   not overlap.  */
+# ifndef YYCOPY
+#  if 1 < __GNUC__
+#   define YYCOPY(To, From, Count) \
+      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
+#  else
+#   define YYCOPY(To, From, Count)              \
+      do                                        \
+        {                                       \
+          register YYSIZE_T yyi;                \
+          for (yyi = 0; yyi < (Count); yyi++)   \
+            (To)[yyi] = (From)[yyi];            \
+        }                                       \
+      while (0)
+#  endif
+# endif
+
+/* Relocate STACK from its old location to the new one.  The
+   local variables YYSIZE and YYSTACKSIZE give the old and new number of
+   elements in the stack, and YYPTR gives the new location of the
+   stack.  Advance YYPTR to a properly aligned location for the next
+   stack.  */
+# define YYSTACK_RELOCATE(Stack)                                        \
+    do                                                                  \
+      {                                                                 \
+        YYSIZE_T yynewbytes;                                            \
+        YYCOPY (&yyptr->Stack, Stack, yysize);                          \
+        Stack = &yyptr->Stack;                                          \
+        yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+        yyptr += yynewbytes / sizeof (*yyptr);                          \
+        (void)yyptr;                                                    \
+      }                                                                 \
+    while (0)
+
+#endif
+
+#if defined (__STDC__) || defined (__cplusplus)
+   typedef signed char yysigned_char;
+#else
+   typedef short yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL  2
+/* YYLAST -- Last index in YYTABLE.  */
+#define YYLAST   50
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS  22
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS  11
+/* YYNRULES -- Number of rules. */
+#define YYNRULES  51
+/* YYNRULES -- Number of states. */
+#define YYNSTATES  61
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   273
+
+#define YYTRANSLATE(YYX)                                                \
+  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const unsigned char yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,    20,     2,     2,    21,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,    19,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16,    17,    18
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const unsigned char yyprhs[] =
+{
+       0,     0,     3,     4,     7,     9,    11,    13,    15,    17,
+      19,    22,    27,    32,    39,    46,    48,    50,    53,    55,
+      58,    61,    65,    71,    75,    79,    82,    87,    90,    94,
+      97,    99,   102,   105,   107,   110,   113,   115,   118,   121,
+     123,   126,   129,   131,   134,   137,   139,   142,   145,   147,
+     149,   150
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+      23,     0,    -1,    -1,    23,    24,    -1,    25,    -1,    26,
+      -1,    28,    -1,    27,    -1,    29,    -1,    31,    -1,    16,
+      10,    -1,    16,    19,    16,    32,    -1,    16,    19,    16,
+      15,    -1,    16,    19,    16,    19,    16,    32,    -1,    16,
+      19,    16,    19,    16,    15,    -1,    18,    -1,     6,    -1,
+      18,     7,    -1,     4,    -1,     4,    20,    -1,    16,     4,
+      -1,    16,    21,    16,    -1,    16,    21,    16,    21,    16,
+      -1,    16,    15,    15,    -1,    16,    12,    15,    -1,    12,
+      16,    -1,    12,    16,    20,    16,    -1,    16,    12,    -1,
+      16,    12,    16,    -1,    30,     3,    -1,    30,    -1,    16,
+      17,    -1,    15,    17,    -1,    17,    -1,    16,    13,    -1,
+      15,    13,    -1,    13,    -1,    16,     5,    -1,    15,     5,
+      -1,     5,    -1,    16,     8,    -1,    15,     8,    -1,     8,
+      -1,    16,    11,    -1,    15,    11,    -1,    11,    -1,    16,
+      14,    -1,    15,    14,    -1,    14,    -1,    16,    -1,    -1,
+      10,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const unsigned short yyrline[] =
+{
+       0,   244,   244,   245,   248,   251,   254,   257,   260,   263,
+     266,   272,   278,   287,   293,   305,   308,   312,   317,   321,
+     325,   331,   335,   353,   359,   365,   369,   374,   378,   385,
+     393,   396,   399,   402,   405,   408,   411,   414,   417,   420,
+     423,   426,   429,   432,   435,   438,   441,   444,   447,   452,
+     487,   490
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "tAGO", "tDAY", "tDAY_UNIT", "tDAYZONE", 
+  "tDST", "tHOUR_UNIT", "tID", "tMERIDIAN", "tMINUTE_UNIT", "tMONTH", 
+  "tMONTH_UNIT", "tSEC_UNIT", "tSNUMBER", "tUNUMBER", "tYEAR_UNIT", 
+  "tZONE", "':'", "','", "'/'", "$accept", "spec", "item", "time", "zone", 
+  "day", "date", "rel", "relunit", "number", "o_merid", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const unsigned short yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,    58,
+      44,    47
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const unsigned char yyr1[] =
+{
+       0,    22,    23,    23,    24,    24,    24,    24,    24,    24,
+      25,    25,    25,    25,    25,    26,    26,    26,    27,    27,
+      27,    28,    28,    28,    28,    28,    28,    28,    28,    29,
+      29,    30,    30,    30,    30,    30,    30,    30,    30,    30,
+      30,    30,    30,    30,    30,    30,    30,    30,    30,    31,
+      32,    32
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const unsigned char yyr2[] =
+{
+       0,     2,     0,     2,     1,     1,     1,     1,     1,     1,
+       2,     4,     4,     6,     6,     1,     1,     2,     1,     2,
+       2,     3,     5,     3,     3,     2,     4,     2,     3,     2,
+       1,     2,     2,     1,     2,     2,     1,     2,     2,     1,
+       2,     2,     1,     2,     2,     1,     2,     2,     1,     1,
+       0,     1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const unsigned char yydefact[] =
+{
+       2,     0,     1,    18,    39,    16,    42,    45,     0,    36,
+      48,     0,    49,    33,    15,     3,     4,     5,     7,     6,
+       8,    30,     9,    19,    25,    38,    41,    44,    35,    47,
+      32,    20,    37,    40,    10,    43,    27,    34,    46,     0,
+      31,     0,     0,    17,    29,     0,    24,    28,    23,    50,
+      21,    26,    51,    12,     0,    11,     0,    50,    22,    14,
+      13
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yysigned_char yydefgoto[] =
+{
+      -1,     1,    15,    16,    17,    18,    19,    20,    21,    22,
+      55
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -20
+static const yysigned_char yypact[] =
+{
+     -20,     0,   -20,   -19,   -20,   -20,   -20,   -20,   -13,   -20,
+     -20,    30,    15,   -20,    14,   -20,   -20,   -20,   -20,   -20,
+     -20,    19,   -20,   -20,     4,   -20,   -20,   -20,   -20,   -20,
+     -20,   -20,   -20,   -20,   -20,   -20,    -6,   -20,   -20,    16,
+     -20,    17,    23,   -20,   -20,    24,   -20,   -20,   -20,    27,
+      28,   -20,   -20,   -20,    29,   -20,    32,    -8,   -20,   -20,
+     -20
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yysigned_char yypgoto[] =
+{
+     -20,   -20,   -20,   -20,   -20,   -20,   -20,   -20,   -20,   -20,
+      -7
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, syntax error.  */
+#define YYTABLE_NINF -1
+static const unsigned char yytable[] =
+{
+       2,    23,    52,    24,     3,     4,     5,    59,     6,    46,
+      47,     7,     8,     9,    10,    11,    12,    13,    14,    31,
+      32,    43,    44,    33,    45,    34,    35,    36,    37,    38,
+      39,    48,    40,    49,    41,    25,    42,    52,    26,    50,
+      51,    27,    53,    28,    29,    57,    54,    30,    58,    56,
+      60
+};
+
+static const unsigned char yycheck[] =
+{
+       0,    20,    10,    16,     4,     5,     6,    15,     8,    15,
+      16,    11,    12,    13,    14,    15,    16,    17,    18,     4,
+       5,     7,     3,     8,    20,    10,    11,    12,    13,    14,
+      15,    15,    17,    16,    19,     5,    21,    10,     8,    16,
+      16,    11,    15,    13,    14,    16,    19,    17,    16,    21,
+      57
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const unsigned char yystos[] =
+{
+       0,    23,     0,     4,     5,     6,     8,    11,    12,    13,
+      14,    15,    16,    17,    18,    24,    25,    26,    27,    28,
+      29,    30,    31,    20,    16,     5,     8,    11,    13,    14,
+      17,     4,     5,     8,    10,    11,    12,    13,    14,    15,
+      17,    19,    21,     7,     3,    20,    15,    16,    15,    16,
+      16,    16,    10,    15,    19,    32,    21,    16,    16,    15,
+      32
+};
+
+#if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
+# define YYSIZE_T __SIZE_TYPE__
+#endif
+#if ! defined (YYSIZE_T) && defined (size_t)
+# define YYSIZE_T size_t
+#endif
+#if ! defined (YYSIZE_T)
+# if defined (__STDC__) || defined (__cplusplus)
+#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYSIZE_T size_t
+# endif
+#endif
+#if ! defined (YYSIZE_T)
+# define YYSIZE_T unsigned int
+#endif
+
+#define yyerrok         (yyerrstatus = 0)
+#define yyclearin       (yychar = YYEMPTY)
+#define YYEMPTY         (-2)
+#define YYEOF           0
+
+#define YYACCEPT        goto yyacceptlab
+#define YYABORT         goto yyabortlab
+#define YYERROR         goto yyerrlab1
+
+
+/* Like YYERROR except do call yyerror.  This remains here temporarily
+   to ease the transition to the new meaning of YYERROR, for GCC.
+   Once GCC version 2 has supplanted version 1, this can go.  */
+
+#define YYFAIL          goto yyerrlab
+
+#define YYRECOVERING()  (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value)                                  \
+do                                                              \
+  if (yychar == YYEMPTY && yylen == 1)                          \
+    {                                                           \
+      yychar = (Token);                                         \
+      yylval = (Value);                                         \
+      yytoken = YYTRANSLATE (yychar);                           \
+      YYPOPSTACK;                                               \
+      goto yybackup;                                            \
+    }                                                           \
+  else                                                          \
+    {                                                           \
+      yyerror ("syntax error: cannot back up");\
+      YYERROR;                                                  \
+    }                                                           \
+while (0)
+
+#define YYTERROR        1
+#define YYERRCODE       256
+
+/* YYLLOC_DEFAULT -- Compute the default location (before the actions
+   are run).  */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N)         \
+  Current.first_line   = Rhs[1].first_line;      \
+  Current.first_column = Rhs[1].first_column;    \
+  Current.last_line    = Rhs[N].last_line;       \
+  Current.last_column  = Rhs[N].last_column;
+#endif
+
+/* YYLEX -- calling `yylex' with the right arguments.  */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (&yylval, YYLEX_PARAM)
+#else
+# define YYLEX yylex (&yylval)
+#endif
+
+/* Enable debugging if requested.  */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+#  define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args)                        \
+do {                                            \
+  if (yydebug)                                  \
+    YYFPRINTF Args;                             \
+} while (0)
+
+# define YYDSYMPRINT(Args)                      \
+do {                                            \
+  if (yydebug)                                  \
+    yysymprint Args;                            \
+} while (0)
+
+# define YYDSYMPRINTF(Title, Token, Value, Location)            \
+do {                                                            \
+  if (yydebug)                                                  \
+    {                                                           \
+      YYFPRINTF (stderr, "%s ", Title);                         \
+      yysymprint (stderr,                                       \
+                  Token, Value);        \
+      YYFPRINTF (stderr, "\n");                                 \
+    }                                                           \
+} while (0)
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (cinluded).                                                   |
+`------------------------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_stack_print (short *bottom, short *top)
+#else
+static void
+yy_stack_print (bottom, top)
+    short *bottom;
+    short *top;
+#endif
+{
+  YYFPRINTF (stderr, "Stack now");
+  for (/* Nothing. */; bottom <= top; ++bottom)
+    YYFPRINTF (stderr, " %d", *bottom);
+  YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top)                            \
+do {                                                            \
+  if (yydebug)                                                  \
+    yy_stack_print ((Bottom), (Top));                           \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced.  |
+`------------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yy_reduce_print (int yyrule)
+#else
+static void
+yy_reduce_print (yyrule)
+    int yyrule;
+#endif
+{
+  int yyi;
+  unsigned int yylineno = yyrline[yyrule];
+  YYFPRINTF (stderr, "Reducing stack by rule %d (line %u), ",
+             yyrule - 1, yylineno);
+  /* Print the symbols being reduced, and their result.  */
+  for (yyi = yyprhs[yyrule]; 0 <= yyrhs[yyi]; yyi++)
+    YYFPRINTF (stderr, "%s ", yytname [yyrhs[yyi]]);
+  YYFPRINTF (stderr, "-> %s\n", yytname [yyr1[yyrule]]);
+}
+
+# define YY_REDUCE_PRINT(Rule)          \
+do {                                    \
+  if (yydebug)                          \
+    yy_reduce_print (Rule);             \
+} while (0)
+
+/* Nonzero means print parse trace.  It is left uninitialized so that
+   multiple parsers can coexist.  */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YYDSYMPRINT(Args)
+# define YYDSYMPRINTF(Title, Token, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks.  */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+   if the built-in stack extension method is used).
+
+   Do not make this value too large; the results are undefined if
+   SIZE_MAX < YYSTACK_BYTES (YYMAXDEPTH)
+   evaluated with infinite-precision integer arithmetic.  */
+
+#if YYMAXDEPTH == 0
+# undef YYMAXDEPTH
+#endif
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+#  if defined (__GLIBC__) && defined (_STRING_H)
+#   define yystrlen strlen
+#  else
+/* Return the length of YYSTR.  */
+static YYSIZE_T
+#   if defined (__STDC__) || defined (__cplusplus)
+yystrlen (const char *yystr)
+#   else
+yystrlen (yystr)
+     const char *yystr;
+#   endif
+{
+  register const char *yys = yystr;
+
+  while (*yys++ != '\0')
+    continue;
+
+  return yys - yystr - 1;
+}
+#  endif
+# endif
+
+# ifndef yystpcpy
+#  if defined (__GLIBC__) && defined (_STRING_H) && defined (_GNU_SOURCE)
+#   define yystpcpy stpcpy
+#  else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+   YYDEST.  */
+static char *
+#   if defined (__STDC__) || defined (__cplusplus)
+yystpcpy (char *yydest, const char *yysrc)
+#   else
+yystpcpy (yydest, yysrc)
+     char *yydest;
+     const char *yysrc;
+#   endif
+{
+  register char *yyd = yydest;
+  register const char *yys = yysrc;
+
+  while ((*yyd++ = *yys++) != '\0')
+    continue;
+
+  return yyd - 1;
+}
+#  endif
+# endif
+
+#endif /* !YYERROR_VERBOSE */
+
+
+
+#if YYDEBUG
+/*--------------------------------.
+| Print this symbol on YYOUTPUT.  |
+`--------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yysymprint (FILE *yyoutput, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yysymprint (yyoutput, yytype, yyvaluep)
+    FILE *yyoutput;
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  /* Pacify ``unused variable'' warnings.  */
+  (void) yyvaluep;
+
+  if (yytype < YYNTOKENS)
+    {
+      YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+# ifdef YYPRINT
+      YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+    }
+  else
+    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+  switch (yytype)
+    {
+      default:
+        break;
+    }
+  YYFPRINTF (yyoutput, ")");
+}
+
+#endif /* ! YYDEBUG */
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+#if defined (__STDC__) || defined (__cplusplus)
+static void
+yydestruct (int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yytype, yyvaluep)
+    int yytype;
+    YYSTYPE *yyvaluep;
+#endif
+{
+  /* Pacify ``unused variable'' warnings.  */
+  (void) yyvaluep;
+
+  switch (yytype)
+    {
+
+      default:
+        break;
+    }
+}
+
+
+/* Prevent warnings from -Wmissing-prototypes.  */
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM);
+# else
+int yyparse ();
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+
+
+
+
+
+/*----------.
+| yyparse.  |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+# if defined (__STDC__) || defined (__cplusplus)
+int yyparse (void *YYPARSE_PARAM)
+# else
+int yyparse (YYPARSE_PARAM)
+  void *YYPARSE_PARAM;
+# endif
+#else /* ! YYPARSE_PARAM */
+#if defined (__STDC__) || defined (__cplusplus)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+  /* The lookahead symbol.  */
+int yychar;
+
+/* The semantic value of the lookahead symbol.  */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far.  */
+int yynerrs;
+
+  register int yystate;
+  register int yyn;
+  int yyresult;
+  /* Number of tokens to shift before error messages enabled.  */
+  int yyerrstatus;
+  /* Lookahead token as an internal (translated) token number.  */
+  int yytoken = 0;
+
+  /* Three stacks and their tools:
+     `yyss': related to states,
+     `yyvs': related to semantic values,
+     `yyls': related to locations.
+
+     Refer to the stacks thru separate pointers, to allow yyoverflow
+     to reallocate them elsewhere.  */
+
+  /* The state stack.  */
+  short yyssa[YYINITDEPTH];
+  short *yyss = yyssa;
+  register short *yyssp;
+
+  /* The semantic value stack.  */
+  YYSTYPE yyvsa[YYINITDEPTH];
+  YYSTYPE *yyvs = yyvsa;
+  register YYSTYPE *yyvsp;
+
+
+
+#define YYPOPSTACK   (yyvsp--, yyssp--)
+
+  YYSIZE_T yystacksize = YYINITDEPTH;
+
+  /* The variables used to return semantic value and location from the
+     action routines.  */
+  YYSTYPE yyval;
+
+
+  /* When reducing, the number of symbols on the RHS of the reduced
+     rule.  */
+  int yylen;
+
+  YYDPRINTF ((stderr, "Starting parse\n"));
+
+  yystate = 0;
+  yyerrstatus = 0;
+  yynerrs = 0;
+  yychar = YYEMPTY;             /* Cause a token to be read.  */
+
+  /* Initialize stack pointers.
+     Waste one element of value and location stack
+     so that they stay on the same level as the state stack.
+     The wasted elements are never initialized.  */
+
+  yyssp = yyss;
+  yyvsp = yyvs;
+
+  goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate.  |
+`------------------------------------------------------------*/
+ yynewstate:
+  /* In all cases, when you get here, the value and location stacks
+     have just been pushed. so pushing a state here evens the stacks.
+     */
+  yyssp++;
+
+ yysetstate:
+  *yyssp = yystate;
+
+  if (yyss + yystacksize - 1 <= yyssp)
+    {
+      /* Get the current used size of the three stacks, in elements.  */
+      YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+      {
+        /* Give user a chance to reallocate the stack. Use copies of
+           these so that the &'s don't force the real ones into
+           memory.  */
+        YYSTYPE *yyvs1 = yyvs;
+        short *yyss1 = yyss;
+
+
+        /* Each stack pointer address is followed by the size of the
+           data in use in that stack, in bytes.  This used to be a
+           conditional around just the two extra args, but that might
+           be undefined if yyoverflow is a macro.  */
+        yyoverflow ("parser stack overflow",
+                    &yyss1, yysize * sizeof (*yyssp),
+                    &yyvs1, yysize * sizeof (*yyvsp),
+
+                    &yystacksize);
+
+        yyss = yyss1;
+        yyvs = yyvs1;
+      }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+      goto yyoverflowlab;
+# else
+      /* Extend the stack our own way.  */
+      if (YYMAXDEPTH <= yystacksize)
+        goto yyoverflowlab;
+      yystacksize *= 2;
+      if (YYMAXDEPTH < yystacksize)
+        yystacksize = YYMAXDEPTH;
+
+      {
+        short *yyss1 = yyss;
+        union yyalloc *yyptr =
+          (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+        if (! yyptr)
+          goto yyoverflowlab;
+        YYSTACK_RELOCATE (yyss);
+        YYSTACK_RELOCATE (yyvs);
+
+#  undef YYSTACK_RELOCATE
+        if (yyss1 != yyssa)
+          YYSTACK_FREE (yyss1);
+      }
+# endif
+#endif /* no yyoverflow */
+
+      yyssp = yyss + yysize - 1;
+      yyvsp = yyvs + yysize - 1;
+
+
+      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+                  (unsigned long int) yystacksize));
+
+      if (yyss + yystacksize - 1 <= yyssp)
+        YYABORT;
+    }
+
+  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+  goto yybackup;
+
+/*-----------.
+| yybackup.  |
+`-----------*/
+yybackup:
+
+/* Do appropriate processing given the current state.  */
+/* Read a lookahead token if we need one and don't already have one.  */
+/* yyresume: */
+
+  /* First try to decide what to do without reference to lookahead token.  */
+
+  yyn = yypact[yystate];
+  if (yyn == YYPACT_NINF)
+    goto yydefault;
+
+  /* Not known => get a lookahead token if don't already have one.  */
+
+  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
+  if (yychar == YYEMPTY)
+    {
+      YYDPRINTF ((stderr, "Reading a token: "));
+      yychar = YYLEX;
+    }
+
+  if (yychar <= YYEOF)
+    {
+      yychar = yytoken = YYEOF;
+      YYDPRINTF ((stderr, "Now at end of input.\n"));
+    }
+  else
+    {
+      yytoken = YYTRANSLATE (yychar);
+      YYDSYMPRINTF ("Next token is", yytoken, &yylval, &yylloc);
+    }
+
+  /* If the proper action on seeing token YYTOKEN is to reduce or to
+     detect an error, take that action.  */
+  yyn += yytoken;
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+    goto yydefault;
+  yyn = yytable[yyn];
+  if (yyn <= 0)
+    {
+      if (yyn == 0 || yyn == YYTABLE_NINF)
+        goto yyerrlab;
+      yyn = -yyn;
+      goto yyreduce;
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  /* Shift the lookahead token.  */
+  YYDPRINTF ((stderr, "Shifting token %s, ", yytname[yytoken]));
+
+  /* Discard the token being shifted unless it is eof.  */
+  if (yychar != YYEOF)
+    yychar = YYEMPTY;
+
+  *++yyvsp = yylval;
+
+
+  /* Count tokens shifted since error; after three, turn off error
+     status.  */
+  if (yyerrstatus)
+    yyerrstatus--;
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state.  |
+`-----------------------------------------------------------*/
+yydefault:
+  yyn = yydefact[yystate];
+  if (yyn == 0)
+    goto yyerrlab;
+  goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction.  |
+`-----------------------------*/
+yyreduce:
+  /* yyn is the number of a rule to reduce with.  */
+  yylen = yyr2[yyn];
+
+  /* If YYLEN is nonzero, implement the default value of the action:
+     `$$ = $1'.
+
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
+     users should not rely upon it.  Assigning to YYVAL
+     unconditionally makes the parser a bit smaller, and it avoids a
+     GCC warning that YYVAL may be used uninitialized.  */
+  yyval = yyvsp[1-yylen];
+
+
+  YY_REDUCE_PRINT (yyn);
+  switch (yyn)
+    {
+        case 4:
+#line 248 "getdate.y"
+    {
+            context->yyHaveTime++;
+        }
+    break;
+
+  case 5:
+#line 251 "getdate.y"
+    {
+            context->yyHaveZone++;
+        }
+    break;
+
+  case 6:
+#line 254 "getdate.y"
+    {
+            context->yyHaveDate++;
+        }
+    break;
+
+  case 7:
+#line 257 "getdate.y"
+    {
+            context->yyHaveDay++;
+        }
+    break;
+
+  case 8:
+#line 260 "getdate.y"
+    {
+            context->yyHaveRel++;
+        }
+    break;
+
+  case 10:
+#line 266 "getdate.y"
+    {
+            context->yyHour = yyvsp[-1].Number;
+            context->yyMinutes = 0;
+            context->yySeconds = 0;
+            context->yyMeridian = yyvsp[0].Meridian;
+        }
+    break;
+
+  case 11:
+#line 272 "getdate.y"
+    {
+            context->yyHour = yyvsp[-3].Number;
+            context->yyMinutes = yyvsp[-1].Number;
+            context->yySeconds = 0;
+            context->yyMeridian = yyvsp[0].Meridian;
+        }
+    break;
+
+  case 12:
+#line 278 "getdate.y"
+    {
+            context->yyHour = yyvsp[-3].Number;
+            context->yyMinutes = yyvsp[-1].Number;
+            context->yyMeridian = MER24;
+            context->yyHaveZone++;
+            context->yyTimezone = (yyvsp[0].Number < 0
+                                   ? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60
+                                   : - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60));
+        }
+    break;
+
+  case 13:
+#line 287 "getdate.y"
+    {
+            context->yyHour = yyvsp[-5].Number;
+            context->yyMinutes = yyvsp[-3].Number;
+            context->yySeconds = yyvsp[-1].Number;
+            context->yyMeridian = yyvsp[0].Meridian;
+        }
+    break;
+
+  case 14:
+#line 293 "getdate.y"
+    {
+            context->yyHour = yyvsp[-5].Number;
+            context->yyMinutes = yyvsp[-3].Number;
+            context->yySeconds = yyvsp[-1].Number;
+            context->yyMeridian = MER24;
+            context->yyHaveZone++;
+            context->yyTimezone = (yyvsp[0].Number < 0
+                                   ? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60
+                                   : - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60));
+        }
+    break;
+
+  case 15:
+#line 305 "getdate.y"
+    {
+            context->yyTimezone = yyvsp[0].Number;
+        }
+    break;
+
+  case 16:
+#line 308 "getdate.y"
+    {
+            context->yyTimezone = yyvsp[0].Number - 60;
+        }
+    break;
+
+  case 17:
+#line 312 "getdate.y"
+    {
+            context->yyTimezone = yyvsp[-1].Number - 60;
+        }
+    break;
+
+  case 18:
+#line 317 "getdate.y"
+    {
+            context->yyDayOrdinal = 1;
+            context->yyDayNumber = yyvsp[0].Number;
+        }
+    break;
+
+  case 19:
+#line 321 "getdate.y"
+    {
+            context->yyDayOrdinal = 1;
+            context->yyDayNumber = yyvsp[-1].Number;
+        }
+    break;
+
+  case 20:
+#line 325 "getdate.y"
+    {
+            context->yyDayOrdinal = yyvsp[-1].Number;
+            context->yyDayNumber = yyvsp[0].Number;
+        }
+    break;
+
+  case 21:
+#line 331 "getdate.y"
+    {
+            context->yyMonth = yyvsp[-2].Number;
+            context->yyDay = yyvsp[0].Number;
+        }
+    break;
+
+  case 22:
+#line 335 "getdate.y"
+    {
+          /* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY.
+             The goal in recognizing YYYY/MM/DD is solely to support legacy
+             machine-generated dates like those in an RCS log listing.  If
+             you want portability, use the ISO 8601 format.  */
+          if (yyvsp[-4].Number >= 1000)
+            {
+              context->yyYear = yyvsp[-4].Number;
+              context->yyMonth = yyvsp[-2].Number;
+              context->yyDay = yyvsp[0].Number;
+            }
+          else
+            {
+              context->yyMonth = yyvsp[-4].Number;
+              context->yyDay = yyvsp[-2].Number;
+              context->yyYear = yyvsp[0].Number;
+            }
+        }
+    break;
+
+  case 23:
+#line 353 "getdate.y"
+    {
+            /* ISO 8601 format.  yyyy-mm-dd.  */
+            context->yyYear = yyvsp[-2].Number;
+            context->yyMonth = -yyvsp[-1].Number;
+            context->yyDay = -yyvsp[0].Number;
+        }
+    break;
+
+  case 24:
+#line 359 "getdate.y"
+    {
+            /* e.g. 17-JUN-1992.  */
+            context->yyDay = yyvsp[-2].Number;
+            context->yyMonth = yyvsp[-1].Number;
+            context->yyYear = -yyvsp[0].Number;
+        }
+    break;
+
+  case 25:
+#line 365 "getdate.y"
+    {
+            context->yyMonth = yyvsp[-1].Number;
+            context->yyDay = yyvsp[0].Number;
+        }
+    break;
+
+  case 26:
+#line 369 "getdate.y"
+    {
+            context->yyMonth = yyvsp[-3].Number;
+            context->yyDay = yyvsp[-2].Number;
+            context->yyYear = yyvsp[0].Number;
+        }
+    break;
+
+  case 27:
+#line 374 "getdate.y"
+    {
+            context->yyMonth = yyvsp[0].Number;
+            context->yyDay = yyvsp[-1].Number;
+        }
+    break;
+
+  case 28:
+#line 378 "getdate.y"
+    {
+            context->yyMonth = yyvsp[-1].Number;
+            context->yyDay = yyvsp[-2].Number;
+            context->yyYear = yyvsp[0].Number;
+        }
+    break;
+
+  case 29:
+#line 385 "getdate.y"
+    {
+            context->yyRelSeconds = -context->yyRelSeconds;
+            context->yyRelMinutes = -context->yyRelMinutes;
+            context->yyRelHour = -context->yyRelHour;
+            context->yyRelDay = -context->yyRelDay;
+            context->yyRelMonth = -context->yyRelMonth;
+            context->yyRelYear = -context->yyRelYear;
+        }
+    break;
+
+  case 31:
+#line 396 "getdate.y"
+    {
+            context->yyRelYear += yyvsp[-1].Number * yyvsp[0].Number;
+        }
+    break;
+
+  case 32:
+#line 399 "getdate.y"
+    {
+            context->yyRelYear += yyvsp[-1].Number * yyvsp[0].Number;
+        }
+    break;
+
+  case 33:
+#line 402 "getdate.y"
+    {
+            context->yyRelYear += yyvsp[0].Number;
+        }
+    break;
+
+  case 34:
+#line 405 "getdate.y"
+    {
+            context->yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
+        }
+    break;
+
+  case 35:
+#line 408 "getdate.y"
+    {
+            context->yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
+        }
+    break;
+
+  case 36:
+#line 411 "getdate.y"
+    {
+            context->yyRelMonth += yyvsp[0].Number;
+        }
+    break;
+
+  case 37:
+#line 414 "getdate.y"
+    {
+            context->yyRelDay += yyvsp[-1].Number * yyvsp[0].Number;
+        }
+    break;
+
+  case 38:
+#line 417 "getdate.y"
+    {
+            context->yyRelDay += yyvsp[-1].Number * yyvsp[0].Number;
+        }
+    break;
+
+  case 39:
+#line 420 "getdate.y"
+    {
+            context->yyRelDay += yyvsp[0].Number;
+        }
+    break;
+
+  case 40:
+#line 423 "getdate.y"
+    {
+            context->yyRelHour += yyvsp[-1].Number * yyvsp[0].Number;
+        }
+    break;
+
+  case 41:
+#line 426 "getdate.y"
+    {
+            context->yyRelHour += yyvsp[-1].Number * yyvsp[0].Number;
+        }
+    break;
+
+  case 42:
+#line 429 "getdate.y"
+    {
+            context->yyRelHour += yyvsp[0].Number;
+        }
+    break;
+
+  case 43:
+#line 432 "getdate.y"
+    {
+            context->yyRelMinutes += yyvsp[-1].Number * yyvsp[0].Number;
+        }
+    break;
+
+  case 44:
+#line 435 "getdate.y"
+    {
+            context->yyRelMinutes += yyvsp[-1].Number * yyvsp[0].Number;
+        }
+    break;
+
+  case 45:
+#line 438 "getdate.y"
+    {
+            context->yyRelMinutes += yyvsp[0].Number;
+        }
+    break;
+
+  case 46:
+#line 441 "getdate.y"
+    {
+            context->yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
+        }
+    break;
+
+  case 47:
+#line 444 "getdate.y"
+    {
+            context->yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
+        }
+    break;
+
+  case 48:
+#line 447 "getdate.y"
+    {
+            context->yyRelSeconds += yyvsp[0].Number;
+        }
+    break;
+
+  case 49:
+#line 453 "getdate.y"
+    {
+            if (context->yyHaveTime && context->yyHaveDate &&
+                !context->yyHaveRel)
+              context->yyYear = yyvsp[0].Number;
+            else
+              {
+                if (yyvsp[0].Number>10000)
+                  {
+                    context->yyHaveDate++;
+                    context->yyDay= (yyvsp[0].Number)%100;
+                    context->yyMonth= (yyvsp[0].Number/100)%100;
+                    context->yyYear = yyvsp[0].Number/10000;
+                  }
+                else
+                  {
+                    context->yyHaveTime++;
+                    if (yyvsp[0].Number < 100)
+                      {
+                        context->yyHour = yyvsp[0].Number;
+                        context->yyMinutes = 0;
+                      }
+                    else
+                      {
+                        context->yyHour = yyvsp[0].Number / 100;
+                        context->yyMinutes = yyvsp[0].Number % 100;
+                      }
+                    context->yySeconds = 0;
+                    context->yyMeridian = MER24;
+                  }
+              }
+          }
+    break;
+
+  case 50:
+#line 487 "getdate.y"
+    {
+            yyval.Meridian = MER24;
+          }
+    break;
+
+  case 51:
+#line 491 "getdate.y"
+    {
+            yyval.Meridian = yyvsp[0].Meridian;
+          }
+    break;
+
+
+    }
+
+/* Line 999 of yacc.c.  */
+#line 1688 "y.tab.c"
+
+  yyvsp -= yylen;
+  yyssp -= yylen;
+
+
+  YY_STACK_PRINT (yyss, yyssp);
+
+  *++yyvsp = yyval;
+
+
+  /* Now `shift' the result of the reduction.  Determine what state
+     that goes to, based on the state we popped back to and the rule
+     number reduced by.  */
+
+  yyn = yyr1[yyn];
+
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+    yystate = yytable[yystate];
+  else
+    yystate = yydefgoto[yyn - YYNTOKENS];
+
+  goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+  /* If not already recovering from an error, report this error.  */
+  if (!yyerrstatus)
+    {
+      ++yynerrs;
+#if YYERROR_VERBOSE
+      yyn = yypact[yystate];
+
+      if (YYPACT_NINF < yyn && yyn < YYLAST)
+        {
+          YYSIZE_T yysize = 0;
+          int yytype = YYTRANSLATE (yychar);
+          char *yymsg;
+          int yyx, yycount;
+
+          yycount = 0;
+          /* Start YYX at -YYN if negative to avoid negative indexes in
+             YYCHECK.  */
+          for (yyx = yyn < 0 ? -yyn : 0;
+               yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
+            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+              yysize += yystrlen (yytname[yyx]) + 15, yycount++;
+          yysize += yystrlen ("syntax error, unexpected ") + 1;
+          yysize += yystrlen (yytname[yytype]);
+          yymsg = (char *) YYSTACK_ALLOC (yysize);
+          if (yymsg != 0)
+            {
+              char *yyp = yystpcpy (yymsg, "syntax error, unexpected ");
+              yyp = yystpcpy (yyp, yytname[yytype]);
+
+              if (yycount < 5)
+                {
+                  yycount = 0;
+                  for (yyx = yyn < 0 ? -yyn : 0;
+                       yyx < (int) (sizeof (yytname) / sizeof (char *));
+                       yyx++)
+                    if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
+                      {
+                        const char *yyq = ! yycount ? ", expecting " : " or ";
+                        yyp = yystpcpy (yyp, yyq);
+                        yyp = yystpcpy (yyp, yytname[yyx]);
+                        yycount++;
+                      }
+                }
+              yyerror (yymsg);
+              YYSTACK_FREE (yymsg);
+            }
+          else
+            yyerror ("syntax error; also virtual memory exhausted");
+        }
+      else
+#endif /* YYERROR_VERBOSE */
+        yyerror ("syntax error");
+    }
+  (void)yynerrs;
+
+
+
+  if (yyerrstatus == 3)
+    {
+      /* If just tried and failed to reuse lookahead token after an
+         error, discard it.  */
+
+      /* Return failure if at end of input.  */
+      if (yychar == YYEOF)
+        {
+          /* Pop the error token.  */
+          YYPOPSTACK;
+          /* Pop the rest of the stack.  */
+          while (yyss < yyssp)
+            {
+              YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+              yydestruct (yystos[*yyssp], yyvsp);
+              YYPOPSTACK;
+            }
+          YYABORT;
+        }
+
+      YYDSYMPRINTF ("Error: discarding", yytoken, &yylval, &yylloc);
+      yydestruct (yytoken, &yylval);
+      yychar = YYEMPTY;
+
+    }
+
+  /* Else will try to reuse lookahead token after shifting the error
+     token.  */
+  goto yyerrlab1;
+
+
+/*----------------------------------------------------.
+| yyerrlab1 -- error raised explicitly by an action.  |
+`----------------------------------------------------*/
+yyerrlab1:
+  yyerrstatus = 3;      /* Each real token shifted decrements this.  */
+
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+        {
+          yyn += YYTERROR;
+          if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+            {
+              yyn = yytable[yyn];
+              if (0 < yyn)
+                break;
+            }
+        }
+
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+        YYABORT;
+
+      YYDSYMPRINTF ("Error: popping", yystos[*yyssp], yyvsp, yylsp);
+      yydestruct (yystos[yystate], yyvsp);
+      yyvsp--;
+      yystate = *--yyssp;
+
+      YY_STACK_PRINT (yyss, yyssp);
+    }
+
+  if (yyn == YYFINAL)
+    YYACCEPT;
+
+  YYDPRINTF ((stderr, "Shifting error token, "));
+
+  *++yyvsp = yylval;
+
+
+  yystate = yyn;
+  goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here.  |
+`-------------------------------------*/
+yyacceptlab:
+  yyresult = 0;
+  goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here.  |
+`-----------------------------------*/
+yyabortlab:
+  yyresult = 1;
+  goto yyreturn;
+
+#ifndef yyoverflow
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here.  |
+`----------------------------------------------*/
+yyoverflowlab:
+  yyerror ("parser stack overflow");
+  yyresult = 2;
+  /* Fall through.  */
+#endif
+
+yyreturn:
+#ifndef yyoverflow
+  if (yyss != yyssa)
+    YYSTACK_FREE (yyss);
+#endif
+  return yyresult;
+}
+
+
+#line 496 "getdate.y"
+
+
+/* Include this file down here because bison inserts code above which
+   may define-away `const'.  We want the prototype for get_date to have
+   the same signature as the function definition does. */
+#include "getdate.h"
+
+#ifndef WIN32 /* the windows dudes don't need these, does anyone really? */
+extern struct tm        *gmtime (const time_t *);
+extern struct tm        *localtime (const time_t *);
+extern time_t           mktime (struct tm *);
+#endif
+
+/* Month and day table. */
+static TABLE const MonthDayTable[] = {
+    { "january",        tMONTH,  1 },
+    { "february",       tMONTH,  2 },
+    { "march",          tMONTH,  3 },
+    { "april",          tMONTH,  4 },
+    { "may",            tMONTH,  5 },
+    { "june",           tMONTH,  6 },
+    { "july",           tMONTH,  7 },
+    { "august",         tMONTH,  8 },
+    { "september",      tMONTH,  9 },
+    { "sept",           tMONTH,  9 },
+    { "october",        tMONTH, 10 },
+    { "november",       tMONTH, 11 },
+    { "december",       tMONTH, 12 },
+    { "sunday",         tDAY, 0 },
+    { "monday",         tDAY, 1 },
+    { "tuesday",        tDAY, 2 },
+    { "tues",           tDAY, 2 },
+    { "wednesday",      tDAY, 3 },
+    { "wednes",         tDAY, 3 },
+    { "thursday",       tDAY, 4 },
+    { "thur",           tDAY, 4 },
+    { "thurs",          tDAY, 4 },
+    { "friday",         tDAY, 5 },
+    { "saturday",       tDAY, 6 },
+    { NULL, 0, 0 }
+};
+
+/* Time units table. */
+static TABLE const UnitsTable[] = {
+    { "year",           tYEAR_UNIT,     1 },
+    { "month",          tMONTH_UNIT,    1 },
+    { "fortnight",      tDAY_UNIT,      14 },
+    { "week",           tDAY_UNIT,      7 },
+    { "day",            tDAY_UNIT,      1 },
+    { "hour",           tHOUR_UNIT,     1 },
+    { "minute",         tMINUTE_UNIT,   1 },
+    { "min",            tMINUTE_UNIT,   1 },
+    { "second",         tSEC_UNIT,      1 },
+    { "sec",            tSEC_UNIT,      1 },
+    { NULL, 0, 0 }
+};
+
+/* Assorted relative-time words. */
+static TABLE const OtherTable[] = {
+    { "tomorrow",       tMINUTE_UNIT,   1 * 24 * 60 },
+    { "yesterday",      tMINUTE_UNIT,   -1 * 24 * 60 },
+    { "today",          tMINUTE_UNIT,   0 },
+    { "now",            tMINUTE_UNIT,   0 },
+    { "last",           tUNUMBER,       -1 },
+    { "this",           tMINUTE_UNIT,   0 },
+    { "next",           tUNUMBER,       1 },
+    { "first",          tUNUMBER,       1 },
+/*  { "second",         tUNUMBER,       2 }, */
+    { "third",          tUNUMBER,       3 },
+    { "fourth",         tUNUMBER,       4 },
+    { "fifth",          tUNUMBER,       5 },
+    { "sixth",          tUNUMBER,       6 },
+    { "seventh",        tUNUMBER,       7 },
+    { "eighth",         tUNUMBER,       8 },
+    { "ninth",          tUNUMBER,       9 },
+    { "tenth",          tUNUMBER,       10 },
+    { "eleventh",       tUNUMBER,       11 },
+    { "twelfth",        tUNUMBER,       12 },
+    { "ago",            tAGO,   1 },
+    { NULL, 0, 0 }
+};
+
+/* The timezone table. */
+static TABLE const TimezoneTable[] = {
+    { "gmt",    tZONE,     HOUR ( 0) }, /* Greenwich Mean */
+    { "ut",     tZONE,     HOUR ( 0) }, /* Universal (Coordinated) */
+    { "utc",    tZONE,     HOUR ( 0) },
+    { "wet",    tZONE,     HOUR ( 0) }, /* Western European */
+    { "bst",    tDAYZONE,  HOUR ( 0) }, /* British Summer */
+    { "wat",    tZONE,     HOUR ( 1) }, /* West Africa */
+    { "at",     tZONE,     HOUR ( 2) }, /* Azores */
+#if     0
+    /* For completeness.  BST is also British Summer, and GST is
+     * also Guam Standard. */
+    { "bst",    tZONE,     HOUR ( 3) }, /* Brazil Standard */
+    { "gst",    tZONE,     HOUR ( 3) }, /* Greenland Standard */
+#endif
+#if 0
+    { "nft",    tZONE,     HOUR (3.5) },        /* Newfoundland */
+    { "nst",    tZONE,     HOUR (3.5) },        /* Newfoundland Standard */
+    { "ndt",    tDAYZONE,  HOUR (3.5) },        /* Newfoundland Daylight */
+#endif
+    { "ast",    tZONE,     HOUR ( 4) }, /* Atlantic Standard */
+    { "adt",    tDAYZONE,  HOUR ( 4) }, /* Atlantic Daylight */
+    { "est",    tZONE,     HOUR ( 5) }, /* Eastern Standard */
+    { "edt",    tDAYZONE,  HOUR ( 5) }, /* Eastern Daylight */
+    { "cst",    tZONE,     HOUR ( 6) }, /* Central Standard */
+    { "cdt",    tDAYZONE,  HOUR ( 6) }, /* Central Daylight */
+    { "mst",    tZONE,     HOUR ( 7) }, /* Mountain Standard */
+    { "mdt",    tDAYZONE,  HOUR ( 7) }, /* Mountain Daylight */
+    { "pst",    tZONE,     HOUR ( 8) }, /* Pacific Standard */
+    { "pdt",    tDAYZONE,  HOUR ( 8) }, /* Pacific Daylight */
+    { "yst",    tZONE,     HOUR ( 9) }, /* Yukon Standard */
+    { "ydt",    tDAYZONE,  HOUR ( 9) }, /* Yukon Daylight */
+    { "hst",    tZONE,     HOUR (10) }, /* Hawaii Standard */
+    { "hdt",    tDAYZONE,  HOUR (10) }, /* Hawaii Daylight */
+    { "cat",    tZONE,     HOUR (10) }, /* Central Alaska */
+    { "ahst",   tZONE,     HOUR (10) }, /* Alaska-Hawaii Standard */
+    { "nt",     tZONE,     HOUR (11) }, /* Nome */
+    { "idlw",   tZONE,     HOUR (12) }, /* International Date Line West */
+    { "cet",    tZONE,     -HOUR (1) }, /* Central European */
+    { "met",    tZONE,     -HOUR (1) }, /* Middle European */
+    { "mewt",   tZONE,     -HOUR (1) }, /* Middle European Winter */
+    { "mest",   tDAYZONE,  -HOUR (1) }, /* Middle European Summer */
+    { "mesz",   tDAYZONE,  -HOUR (1) }, /* Middle European Summer */
+    { "swt",    tZONE,     -HOUR (1) }, /* Swedish Winter */
+    { "sst",    tDAYZONE,  -HOUR (1) }, /* Swedish Summer */
+    { "fwt",    tZONE,     -HOUR (1) }, /* French Winter */
+    { "fst",    tDAYZONE,  -HOUR (1) }, /* French Summer */
+    { "eet",    tZONE,     -HOUR (2) }, /* Eastern Europe, USSR Zone 1 */
+    { "bt",     tZONE,     -HOUR (3) }, /* Baghdad, USSR Zone 2 */
+#if 0
+    { "it",     tZONE,     -HOUR (3.5) },/* Iran */
+#endif
+    { "zp4",    tZONE,     -HOUR (4) }, /* USSR Zone 3 */
+    { "zp5",    tZONE,     -HOUR (5) }, /* USSR Zone 4 */
+#if 0
+    { "ist",    tZONE,     -HOUR (5.5) },/* Indian Standard */
+#endif
+    { "zp6",    tZONE,     -HOUR (6) }, /* USSR Zone 5 */
+#if     0
+    /* For completeness.  NST is also Newfoundland Standard, and SST is
+     * also Swedish Summer. */
+    { "nst",    tZONE,     -HOUR (6.5) },/* North Sumatra */
+    { "sst",    tZONE,     -HOUR (7) }, /* South Sumatra, USSR Zone 6 */
+#endif  /* 0 */
+    { "wast",   tZONE,     -HOUR (7) }, /* West Australian Standard */
+    { "wadt",   tDAYZONE,  -HOUR (7) }, /* West Australian Daylight */
+#if 0
+    { "jt",     tZONE,     -HOUR (7.5) },/* Java (3pm in Cronusland!) */
+#endif
+    { "cct",    tZONE,     -HOUR (8) }, /* China Coast, USSR Zone 7 */
+    { "jst",    tZONE,     -HOUR (9) }, /* Japan Standard, USSR Zone 8 */
+#if 0
+    { "cast",   tZONE,     -HOUR (9.5) },/* Central Australian Standard */
+    { "cadt",   tDAYZONE,  -HOUR (9.5) },/* Central Australian Daylight */
+#endif
+    { "east",   tZONE,     -HOUR (10) },        /* Eastern Australian Standard */
+    { "eadt",   tDAYZONE,  -HOUR (10) },        /* Eastern Australian Daylight */
+    { "gst",    tZONE,     -HOUR (10) },        /* Guam Standard, USSR Zone 9 */
+    { "nzt",    tZONE,     -HOUR (12) },        /* New Zealand */
+    { "nzst",   tZONE,     -HOUR (12) },        /* New Zealand Standard */
+    { "nzdt",   tDAYZONE,  -HOUR (12) },        /* New Zealand Daylight */
+    { "idle",   tZONE,     -HOUR (12) },        /* International Date Line East */
+    {  NULL, 0, 0  }
+};
+
+/* Military timezone table. */
+static TABLE const MilitaryTable[] = {
+    { "a",      tZONE,  HOUR (  1) },
+    { "b",      tZONE,  HOUR (  2) },
+    { "c",      tZONE,  HOUR (  3) },
+    { "d",      tZONE,  HOUR (  4) },
+    { "e",      tZONE,  HOUR (  5) },
+    { "f",      tZONE,  HOUR (  6) },
+    { "g",      tZONE,  HOUR (  7) },
+    { "h",      tZONE,  HOUR (  8) },
+    { "i",      tZONE,  HOUR (  9) },
+    { "k",      tZONE,  HOUR ( 10) },
+    { "l",      tZONE,  HOUR ( 11) },
+    { "m",      tZONE,  HOUR ( 12) },
+    { "n",      tZONE,  HOUR (- 1) },
+    { "o",      tZONE,  HOUR (- 2) },
+    { "p",      tZONE,  HOUR (- 3) },
+    { "q",      tZONE,  HOUR (- 4) },
+    { "r",      tZONE,  HOUR (- 5) },
+    { "s",      tZONE,  HOUR (- 6) },
+    { "t",      tZONE,  HOUR (- 7) },
+    { "u",      tZONE,  HOUR (- 8) },
+    { "v",      tZONE,  HOUR (- 9) },
+    { "w",      tZONE,  HOUR (-10) },
+    { "x",      tZONE,  HOUR (-11) },
+    { "y",      tZONE,  HOUR (-12) },
+    { "z",      tZONE,  HOUR (  0) },
+    { NULL, 0, 0 }
+};
+
+
+
+
+/* ARGSUSED */
+static int
+yyerror (const char *s ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+static int
+ToHour (int Hours, MERIDIAN Meridian)
+{
+  switch (Meridian)
+    {
+    case MER24:
+      if (Hours < 0 || Hours > 23)
+        return -1;
+      return Hours;
+    case MERam:
+      if (Hours < 1 || Hours > 12)
+        return -1;
+      if (Hours == 12)
+        Hours = 0;
+      return Hours;
+    case MERpm:
+      if (Hours < 1 || Hours > 12)
+        return -1;
+      if (Hours == 12)
+        Hours = 0;
+      return Hours + 12;
+    default:
+      break; /* used to do abort() here */
+    }
+  /* NOTREACHED - but make gcc happy! */
+  return -1;
+}
+
+static int
+ToYear (int Year)
+{
+  if (Year < 0)
+    Year = -Year;
+
+  /* XPG4 suggests that years 00-68 map to 2000-2068, and
+     years 69-99 map to 1969-1999.  */
+  if (Year < 69)
+    Year += 2000;
+  else if (Year < 100)
+    Year += 1900;
+
+  return Year;
+}
+
+static int
+LookupWord (YYSTYPE *yylval, char *buff)
+{
+  char *p;
+  char *q;
+  const TABLE *tp;
+  size_t i;
+  int abbrev;
+
+  /* Make it lowercase. */
+  for (p = buff; *p; p++)
+    if (ISUPPER ((unsigned char) *p))
+      *p = tolower ((int)*p);
+
+  if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0)
+    {
+      yylval->Meridian = MERam;
+      return tMERIDIAN;
+    }
+  if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0)
+    {
+      yylval->Meridian = MERpm;
+      return tMERIDIAN;
+    }
+
+  /* See if we have an abbreviation for a month. */
+  if (strlen (buff) == 3)
+    abbrev = 1;
+  else if (strlen (buff) == 4 && buff[3] == '.')
+    {
+      abbrev = 1;
+      buff[3] = '\0';
+    }
+  else
+    abbrev = 0;
+
+  for (tp = MonthDayTable; tp->name; tp++)
+    {
+      if (abbrev)
+        {
+          if (strncmp (buff, tp->name, 3) == 0)
+            {
+              yylval->Number = tp->value;
+              return tp->type;
+            }
+        }
+      else if (strcmp (buff, tp->name) == 0)
+        {
+          yylval->Number = tp->value;
+          return tp->type;
+        }
+    }
+
+  for (tp = TimezoneTable; tp->name; tp++)
+    if (strcmp (buff, tp->name) == 0)
+      {
+        yylval->Number = tp->value;
+        return tp->type;
+      }
+
+  if (strcmp (buff, "dst") == 0)
+    return tDST;
+
+  for (tp = UnitsTable; tp->name; tp++)
+    if (strcmp (buff, tp->name) == 0)
+      {
+        yylval->Number = tp->value;
+        return tp->type;
+      }
+
+  /* Strip off any plural and try the units table again. */
+  i = strlen (buff) - 1;
+  if (buff[i] == 's')
+    {
+      buff[i] = '\0';
+      for (tp = UnitsTable; tp->name; tp++)
+        if (strcmp (buff, tp->name) == 0)
+          {
+            yylval->Number = tp->value;
+            return tp->type;
+          }
+      buff[i] = 's';            /* Put back for "this" in OtherTable. */
+    }
+
+  for (tp = OtherTable; tp->name; tp++)
+    if (strcmp (buff, tp->name) == 0)
+      {
+        yylval->Number = tp->value;
+        return tp->type;
+      }
+
+  /* Military timezones. */
+  if (buff[1] == '\0' && ISALPHA ((unsigned char) *buff))
+    {
+      for (tp = MilitaryTable; tp->name; tp++)
+        if (strcmp (buff, tp->name) == 0)
+          {
+            yylval->Number = tp->value;
+            return tp->type;
+          }
+    }
+
+  /* Drop out any periods and try the timezone table again. */
+  for (i = 0, p = q = buff; *q; q++)
+    if (*q != '.')
+      *p++ = *q;
+    else
+      i++;
+  *p = '\0';
+  if (i)
+    for (tp = TimezoneTable; tp->name; tp++)
+      if (strcmp (buff, tp->name) == 0)
+        {
+          yylval->Number = tp->value;
+          return tp->type;
+        }
+
+  return tID;
+}
+
+static int
+yylex (YYSTYPE *yylval, void *cookie)
+{
+  register unsigned char c;
+  register char *p;
+  char buff[20];
+  int Count;
+  int sign;
+
+  for (;;)
+    {
+      while (ISSPACE ((unsigned char) *context->yyInput))
+        context->yyInput++;
+
+      if (ISDIGIT (c = *context->yyInput) || c == '-' || c == '+')
+        {
+          if (c == '-' || c == '+')
+            {
+              sign = c == '-' ? -1 : 1;
+              if (!ISDIGIT (*++context->yyInput))
+                /* skip the '-' sign */
+                continue;
+            }
+          else
+            sign = 0;
+          for (yylval->Number = 0; ISDIGIT (c = *context->yyInput++);)
+            yylval->Number = 10 * yylval->Number + c - '0';
+          context->yyInput--;
+          if (sign < 0)
+            yylval->Number = -yylval->Number;
+          return sign ? tSNUMBER : tUNUMBER;
+        }
+      if (ISALPHA (c))
+        {
+          for (p = buff; (c = *context->yyInput++, ISALPHA (c)) || c == '.';)
+            if (p < &buff[sizeof buff - 1])
+              *p++ = c;
+          *p = '\0';
+          context->yyInput--;
+          return LookupWord (yylval, buff);
+        }
+      if (c != '(')
+        return *context->yyInput++;
+      Count = 0;
+      do
+        {
+          c = *context->yyInput++;
+          if (c == '\0')
+            return c;
+          if (c == '(')
+            Count++;
+          else if (c == ')')
+            Count--;
+        }
+      while (Count > 0);
+    }
+}
+
+#define TM_YEAR_ORIGIN 1900
+
+/* Yield A - B, measured in seconds.  */
+static long
+difftm (struct tm *a, struct tm *b)
+{
+  int ay = a->tm_year + (TM_YEAR_ORIGIN - 1);
+  int by = b->tm_year + (TM_YEAR_ORIGIN - 1);
+  long days = (
+  /* difference in day of year */
+                a->tm_yday - b->tm_yday
+  /* + intervening leap days */
+                + ((ay >> 2) - (by >> 2))
+                - (ay / 100 - by / 100)
+                + ((ay / 100 >> 2) - (by / 100 >> 2))
+  /* + difference in years * 365 */
+                + (long) (ay - by) * 365
+  );
+  return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour))
+                + (a->tm_min - b->tm_min))
+          + (a->tm_sec - b->tm_sec));
+}
+
+time_t
+curl_getdate (const char *p, const time_t *now)
+{
+  struct tm tm, tm0, *tmp;
+  time_t Start;
+  CURL_CONTEXT cookie;
+#ifdef HAVE_LOCALTIME_R
+  struct tm keeptime;
+#endif
+  cookie.yyInput = p;
+  Start = now ? *now : time ((time_t *) NULL);
+#ifdef HAVE_LOCALTIME_R
+  tmp = (struct tm *)localtime_r(&Start, &keeptime);
+#else
+  tmp = localtime (&Start);
+#endif
+  if (!tmp)
+    return -1;
+  cookie.yyYear = tmp->tm_year + TM_YEAR_ORIGIN;
+  cookie.yyMonth = tmp->tm_mon + 1;
+  cookie.yyDay = tmp->tm_mday;
+  cookie.yyHour = tmp->tm_hour;
+  cookie.yyMinutes = tmp->tm_min;
+  cookie.yySeconds = tmp->tm_sec;
+  tm.tm_isdst = tmp->tm_isdst;
+  cookie.yyMeridian = MER24;
+  cookie.yyRelSeconds = 0;
+  cookie.yyRelMinutes = 0;
+  cookie.yyRelHour = 0;
+  cookie.yyRelDay = 0;
+  cookie.yyRelMonth = 0;
+  cookie.yyRelYear = 0;
+  cookie.yyHaveDate = 0;
+  cookie.yyHaveDay = 0;
+  cookie.yyHaveRel = 0;
+  cookie.yyHaveTime = 0;
+  cookie.yyHaveZone = 0;
+
+  if (yyparse ((void*)&cookie)
+      || cookie.yyHaveTime > 1 || cookie.yyHaveZone > 1 ||
+      cookie.yyHaveDate > 1 || cookie.yyHaveDay > 1)
+    return -1;
+
+  tm.tm_year = ToYear (cookie.yyYear) - TM_YEAR_ORIGIN + cookie.yyRelYear;
+  tm.tm_mon = cookie.yyMonth - 1 + cookie.yyRelMonth;
+  tm.tm_mday = cookie.yyDay + cookie.yyRelDay;
+  if (cookie.yyHaveTime ||
+      (cookie.yyHaveRel && !cookie.yyHaveDate && !cookie.yyHaveDay))
+    {
+      tm.tm_hour = ToHour (cookie.yyHour, cookie.yyMeridian);
+      if (tm.tm_hour < 0)
+        return -1;
+      tm.tm_min = cookie.yyMinutes;
+      tm.tm_sec = cookie.yySeconds;
+    }
+  else
+    {
+      tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+    }
+  tm.tm_hour += cookie.yyRelHour;
+  tm.tm_min += cookie.yyRelMinutes;
+  tm.tm_sec += cookie.yyRelSeconds;
+
+  /* Let mktime deduce tm_isdst if we have an absolute timestamp,
+     or if the relative timestamp mentions days, months, or years.  */
+  if (cookie.yyHaveDate | cookie.yyHaveDay | cookie.yyHaveTime |
+      cookie.yyRelDay | cookie.yyRelMonth | cookie.yyRelYear)
+    tm.tm_isdst = -1;
+
+  tm0 = tm;
+
+  Start = mktime (&tm);
+
+  if (Start == (time_t) -1)
+    {
+
+      /* Guard against falsely reporting errors near the time_t boundaries
+         when parsing times in other time zones.  For example, if the min
+         time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead
+         of UTC, then the min localtime value is 1970-01-01 08:00:00; if
+         we apply mktime to 1970-01-01 00:00:00 we will get an error, so
+         we apply mktime to 1970-01-02 08:00:00 instead and adjust the time
+         zone by 24 hours to compensate.  This algorithm assumes that
+         there is no DST transition within a day of the time_t boundaries.  */
+      if (cookie.yyHaveZone)
+        {
+          tm = tm0;
+          if (tm.tm_year <= EPOCH - TM_YEAR_ORIGIN)
+            {
+              tm.tm_mday++;
+              cookie.yyTimezone -= 24 * 60;
+            }
+          else
+            {
+              tm.tm_mday--;
+              cookie.yyTimezone += 24 * 60;
+            }
+          Start = mktime (&tm);
+        }
+
+      if (Start == (time_t) -1)
+        return Start;
+    }
+
+  if (cookie.yyHaveDay && !cookie.yyHaveDate)
+    {
+      tm.tm_mday += ((cookie.yyDayNumber - tm.tm_wday + 7) % 7
+                     + 7 * (cookie.yyDayOrdinal - (0 < cookie.yyDayOrdinal)));
+      Start = mktime (&tm);
+      if (Start == (time_t) -1)
+        return Start;
+    }
+
+  if (cookie.yyHaveZone)
+    {
+      long delta;
+      struct tm *gmt;
+#ifdef HAVE_GMTIME_R
+      /* thread-safe version */
+      struct tm keeptime2;
+      gmt = (struct tm *)gmtime_r(&Start, &keeptime2);
+#else
+      gmt = gmtime(&Start);
+#endif
+      if (!gmt)
+        return -1;
+      delta = cookie.yyTimezone * 60L + difftm (&tm, gmt);
+      if ((Start + delta < Start) != (delta < 0))
+        return -1;              /* time_t overflow */
+      Start += delta;
+    }
+
+  return Start;
+}
+
+
diff --git a/Utilities/cmcurl/getdate.h b/Utilities/cmcurl/getdate.h
new file mode 100644
index 0000000..85650e3
--- /dev/null
+++ b/Utilities/cmcurl/getdate.h
@@ -0,0 +1,37 @@
+/*
+**  Originally written by Steven M. Bellovin <smb@research.att.com> while
+**  at the University of North Carolina at Chapel Hill.  Later tweaked by
+**  a couple of people on Usenet.  Completely overhauled by Rich $alz
+**  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990.
+**
+**  This code is in the public domain and has no copyright.
+*/
+
+# include "setup.h"
+
+#ifndef PARAMS
+# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
+#  define PARAMS(Args) Args
+# else
+#  define PARAMS(Args) ()
+# endif
+#endif
+
+#ifdef vms
+# include <types.h>
+# include <time.h>
+#else
+# include <sys/types.h>
+# if TIME_WITH_SYS_TIME
+#  include <sys/time.h>
+#  include <time.h>
+# else
+#  if HAVE_SYS_TIME_H
+#   include <sys/time.h>
+#  else
+#   include <time.h>
+#  endif
+# endif
+#endif /* defined (vms) */
+
+time_t curl_getdate PARAMS ((const char *p, const time_t *now));
diff --git a/Utilities/cmcurl/getenv.c b/Utilities/cmcurl/getenv.c
new file mode 100644
index 0000000..302db2e
--- /dev/null
+++ b/Utilities/cmcurl/getenv.c
@@ -0,0 +1,70 @@
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef WIN32
+#include <windows.h>
+#endif
+
+#ifdef VMS
+#include <unixlib.h>
+#endif
+
+#include <curl/curl.h>
+#include "curl_memory.h"
+
+#include "memdebug.h"
+
+static
+char *GetEnv(const char *variable)
+{
+#ifdef WIN32
+  /* This shit requires windows.h (HUGE) to be included */
+  char env[MAX_PATH]; /* MAX_PATH is from windef.h */
+  char *temp = getenv(variable);
+  env[0] = '\0';
+  if (temp != NULL)
+    ExpandEnvironmentStrings(temp, env, sizeof(env));
+#else
+#ifdef  VMS
+  char *env = getenv(variable);
+  if (env && strcmp("HOME",variable) == 0) {
+        env = decc$translate_vms(env);
+  }
+#else
+  /* no length control */
+  char *env = getenv(variable);
+#endif
+#endif
+  return (env && env[0])?strdup(env):NULL;
+}
+
+char *curl_getenv(const char *v)
+{
+  return GetEnv(v);
+}
diff --git a/Utilities/cmcurl/getinfo.c b/Utilities/cmcurl/getinfo.c
new file mode 100644
index 0000000..7316d3a
--- /dev/null
+++ b/Utilities/cmcurl/getinfo.c
@@ -0,0 +1,174 @@
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "getinfo.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include "curl_memory.h"
+
+/* Make this the last #include */
+#include "memdebug.h"
+
+/*
+ * This is supposed to be called in the beginning of a permform() session
+ * and should reset all session-info variables
+ */
+CURLcode Curl_initinfo(struct SessionHandle *data)
+{
+  struct Progress *pro = &data->progress;
+  struct PureInfo *info =&data->info;
+
+  pro->t_nslookup = 0;
+  pro->t_connect = 0;
+  pro->t_pretransfer = 0;
+  pro->t_starttransfer = 0;
+  pro->timespent = 0;
+  pro->t_redirect = 0;
+
+  info->httpcode = 0;
+  info->httpversion=0;
+  info->filetime=-1; /* -1 is an illegal time and thus means unknown */
+  
+  if (info->contenttype)
+    free(info->contenttype);
+  info->contenttype = NULL;
+
+  info->header_size = 0;
+  info->request_size = 0;
+  return CURLE_OK;
+}
+
+CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
+{
+  va_list arg;
+  long *param_longp=NULL;
+  double *param_doublep=NULL;
+  char **param_charp=NULL;
+  va_start(arg, info);
+
+  switch(info&CURLINFO_TYPEMASK) {
+  default:
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  case CURLINFO_STRING:
+    param_charp = va_arg(arg, char **);  
+    if(NULL == param_charp)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    break;
+  case CURLINFO_LONG:
+    param_longp = va_arg(arg, long *);
+    if(NULL == param_longp)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    break;
+  case CURLINFO_DOUBLE:
+    param_doublep = va_arg(arg, double *);
+    if(NULL == param_doublep)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    break;
+  }
+  
+  switch(info) {
+  case CURLINFO_EFFECTIVE_URL:
+    *param_charp = data->change.url?data->change.url:(char *)"";
+    break;
+  case CURLINFO_RESPONSE_CODE:
+    *param_longp = data->info.httpcode;
+    break;
+  case CURLINFO_HTTP_CONNECTCODE:
+    *param_longp = data->info.httpproxycode;
+    break;
+  case CURLINFO_FILETIME:
+    *param_longp = data->info.filetime;
+    break;
+  case CURLINFO_HEADER_SIZE:
+    *param_longp = data->info.header_size;
+    break;
+  case CURLINFO_REQUEST_SIZE:
+    *param_longp = data->info.request_size;
+    break;
+  case CURLINFO_TOTAL_TIME:
+    *param_doublep = data->progress.timespent;
+    break;
+  case CURLINFO_NAMELOOKUP_TIME:
+    *param_doublep = data->progress.t_nslookup;
+    break;
+  case CURLINFO_CONNECT_TIME:
+    *param_doublep = data->progress.t_connect;
+    break;
+  case CURLINFO_PRETRANSFER_TIME:
+    *param_doublep =  data->progress.t_pretransfer;
+    break;
+  case CURLINFO_STARTTRANSFER_TIME:
+    *param_doublep = data->progress.t_starttransfer;
+    break;
+  case CURLINFO_SIZE_UPLOAD:
+    *param_doublep =  (double)data->progress.uploaded;
+    break;
+  case CURLINFO_SIZE_DOWNLOAD:
+    *param_doublep = (double)data->progress.downloaded;
+    break;
+  case CURLINFO_SPEED_DOWNLOAD:
+    *param_doublep =  (double)data->progress.dlspeed;
+    break;
+  case CURLINFO_SPEED_UPLOAD:
+    *param_doublep = (double)data->progress.ulspeed;
+    break;
+  case CURLINFO_SSL_VERIFYRESULT:
+    *param_longp = data->set.ssl.certverifyresult;
+    break;
+  case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
+    *param_doublep = (double)data->progress.size_dl;
+    break;
+  case CURLINFO_CONTENT_LENGTH_UPLOAD:
+    *param_doublep = (double)data->progress.size_ul;
+    break;
+  case CURLINFO_REDIRECT_TIME:
+    *param_doublep =  data->progress.t_redirect;
+    break;
+  case CURLINFO_REDIRECT_COUNT:
+    *param_longp = data->set.followlocation;
+    break;
+  case CURLINFO_CONTENT_TYPE:
+    *param_charp = data->info.contenttype;
+    break;
+  case CURLINFO_PRIVATE:
+    *param_charp = data->set.private;
+    break;
+  case CURLINFO_HTTPAUTH_AVAIL:
+    *param_longp = data->info.httpauthavail;
+    break;
+  case CURLINFO_PROXYAUTH_AVAIL:
+    *param_longp = data->info.proxyauthavail;
+    break;
+  default:
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+  return CURLE_OK;
+}
diff --git a/Utilities/cmcurl/getinfo.h b/Utilities/cmcurl/getinfo.h
new file mode 100644
index 0000000..2fe1b5c
--- /dev/null
+++ b/Utilities/cmcurl/getinfo.h
@@ -0,0 +1,28 @@
+#ifndef __GETINFO_H
+#define __GETINFO_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...);
+CURLcode Curl_initinfo(struct SessionHandle *data);
+
+#endif
diff --git a/Utilities/cmcurl/hash.c b/Utilities/cmcurl/hash.c
new file mode 100644
index 0000000..614d692
--- /dev/null
+++ b/Utilities/cmcurl/hash.c
@@ -0,0 +1,267 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "hash.h"
+#include "llist.h"
+#include "curl_memory.h"
+
+/* this must be the last include file */
+#include "memdebug.h"
+
+static unsigned long
+hash_str(const char *key, size_t key_length)
+{
+  char *end = (char *) key + key_length;
+  unsigned long h = 5381;
+
+  while (key < end) {
+    h += h << 5;
+    h ^= (unsigned long) *key++;
+  }
+
+  return h;
+}
+
+static void
+hash_element_dtor(void *user, void *element)
+{
+  curl_hash         *h = (curl_hash *) user;
+  curl_hash_element *e = (curl_hash_element *) element;
+
+  if (e->key) {
+    free(e->key);
+  }
+
+  h->dtor(e->ptr);
+
+  free(e);
+}
+
+/* return 1 on error, 0 is fine */
+int
+Curl_hash_init(curl_hash *h, int slots, curl_hash_dtor dtor)
+{
+  int i;
+
+  h->dtor = dtor;
+  h->size = 0;
+  h->slots = slots;
+
+  h->table = (curl_llist **) malloc(slots * sizeof(curl_llist *));
+  if(h->table) {
+    for (i = 0; i < slots; ++i) {
+      h->table[i] = Curl_llist_alloc((curl_llist_dtor) hash_element_dtor);
+      if(!h->table[i]) {
+        while(i--)
+          Curl_llist_destroy(h->table[i], NULL);
+        free(h->table);
+        return 1; /* failure */
+      }
+    }
+    return 0; /* fine */
+  }
+  else
+    return 1; /* failure */
+}
+
+curl_hash *
+Curl_hash_alloc(int slots, curl_hash_dtor dtor)
+{
+  curl_hash *h;
+
+  h = (curl_hash *) malloc(sizeof(curl_hash));
+  if (h) {
+    if(Curl_hash_init(h, slots, dtor)) {
+      /* failure */
+      free(h);
+      h = NULL;
+    }
+  }
+
+  return h;
+}
+
+static int
+hash_key_compare(char *key1, size_t key1_len, char *key2, size_t key2_len)
+{
+  if (key1_len == key2_len &&
+      *key1 == *key2 &&
+      memcmp(key1, key2, key1_len) == 0) {
+    return 1;
+  }
+
+  return 0;
+}
+
+static curl_hash_element *
+mk_hash_element(char *key, size_t key_len, const void *p)
+{
+  curl_hash_element *he =
+    (curl_hash_element *) malloc(sizeof(curl_hash_element));
+
+  if(he) {
+    char *dup = strdup(key);
+    if(dup) {
+      he->key = dup;
+      he->key_len = key_len;
+      he->ptr = (void *) p;
+    }
+    else {
+      /* failed to duplicate the key, free memory and fail */
+      free(he);
+      he = NULL;
+    }
+  }
+  return he;
+}
+
+#define find_slot(__h, __k, __k_len) (hash_str(__k, __k_len) % (__h)->slots)
+
+#define FETCH_LIST(x,y,z) x->table[find_slot(x, y, z)]
+
+/* Return the data in the hash. If there already was a match in the hash,
+   that data is returned. */
+void *
+Curl_hash_add(curl_hash *h, char *key, size_t key_len, void *p)
+{
+  curl_hash_element  *he;
+  curl_llist_element *le;
+  curl_llist *l = FETCH_LIST(h, key, key_len);
+
+  for (le = l->head; le; le = le->next) {
+    he = (curl_hash_element *) le->ptr;
+    if (hash_key_compare(he->key, he->key_len, key, key_len)) {
+      h->dtor(p);     /* remove the NEW entry */
+      return he->ptr; /* return the EXISTING entry */
+    }
+  }
+
+  he = mk_hash_element(key, key_len, p);
+  if (he) {
+    if(Curl_llist_insert_next(l, l->tail, he)) {
+      ++h->size;
+      return p; /* return the new entry */
+    }
+    /*
+     * Couldn't insert it, destroy the 'he' element and the key again. We
+     * don't call hash_element_dtor() since that would also call the
+     * "destructor" for the actual data 'p'. When we fail, we shall not touch
+     * that data.
+     */
+    free(he->key);
+    free(he);
+  }
+
+  return NULL; /* failure */
+}
+
+void *
+Curl_hash_pick(curl_hash *h, char *key, size_t key_len)
+{
+  curl_llist_element *le;
+  curl_hash_element  *he;
+  curl_llist *l = FETCH_LIST(h, key, key_len);
+
+  for (le = l->head;
+       le;
+       le = le->next) {
+    he = le->ptr;
+    if (hash_key_compare(he->key, he->key_len, key, key_len)) {
+      return he->ptr;
+    }
+  }
+
+  return NULL;
+}
+
+#if defined(CURLDEBUG) && defined(AGGRESIVE_TEST)
+void
+Curl_hash_apply(curl_hash *h, void *user,
+                void (*cb)(void *user, void *ptr))
+{
+  curl_llist_element  *le;
+  int                  i;
+
+  for (i = 0; i < h->slots; ++i) {
+    for (le = (h->table[i])->head;
+         le;
+         le = le->next) {
+      curl_hash_element *el = le->ptr;
+      cb(user, el->ptr);
+    }
+  }
+}
+#endif
+
+void
+Curl_hash_clean(curl_hash *h)
+{
+  int i;
+
+  for (i = 0; i < h->slots; ++i) {
+    Curl_llist_destroy(h->table[i], (void *) h);
+  }
+
+  free(h->table);
+}
+
+void
+Curl_hash_clean_with_criterium(curl_hash *h, void *user,
+                               int (*comp)(void *, void *))
+{
+  curl_llist_element *le;
+  curl_llist_element *lnext;
+  curl_llist *list;
+  int i;
+
+  for (i = 0; i < h->slots; ++i) {
+    list = h->table[i];
+    le = list->head; /* get first list entry */
+    while(le) {
+      curl_hash_element *he = le->ptr;
+      lnext = le->next;
+      /* ask the callback function if we shall remove this entry or not */
+      if (comp(user, he->ptr)) {
+        Curl_llist_remove(list, le, (void *) h);
+        --h->size; /* one less entry in the hash now */
+      }
+      le = lnext;
+    }
+  }
+}
+
+void
+Curl_hash_destroy(curl_hash *h)
+{
+  if (!h)
+    return;
+
+  Curl_hash_clean(h);
+  free(h);
+}
+
diff --git a/Utilities/cmcurl/hash.h b/Utilities/cmcurl/hash.h
new file mode 100644
index 0000000..7814674
--- /dev/null
+++ b/Utilities/cmcurl/hash.h
@@ -0,0 +1,60 @@
+#ifndef __HASH_H
+#define __HASH_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <stddef.h>
+
+#include "llist.h"
+
+typedef void (*curl_hash_dtor)(void *);
+
+typedef struct _curl_hash {
+  curl_llist     **table;
+  curl_hash_dtor   dtor;
+  int              slots;
+  size_t           size;
+} curl_hash;
+
+typedef struct _curl_hash_element {
+  void   *ptr;
+  char   *key;
+  size_t key_len;
+} curl_hash_element;
+
+
+int Curl_hash_init(curl_hash *, int, curl_hash_dtor);
+curl_hash *Curl_hash_alloc(int, curl_hash_dtor);
+void *Curl_hash_add(curl_hash *, char *, size_t, void *);
+int Curl_hash_delete(curl_hash *h, char *key, size_t key_len);
+void *Curl_hash_pick(curl_hash *, char *, size_t);
+void Curl_hash_apply(curl_hash *h, void *user,
+                     void (*cb)(void *user, void *ptr));
+int Curl_hash_count(curl_hash *h);
+void Curl_hash_clean(curl_hash *h);
+void Curl_hash_clean_with_criterium(curl_hash *h, void *user, int (*comp)(void *, void *));
+void Curl_hash_destroy(curl_hash *h);
+
+#endif
diff --git a/Utilities/cmcurl/hostares.c b/Utilities/cmcurl/hostares.c
new file mode 100644
index 0000000..197f540
--- /dev/null
+++ b/Utilities/cmcurl/hostares.c
@@ -0,0 +1,301 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <string.h>
+#include <errno.h>
+
+#define _REENTRANT
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#include <malloc.h>
+#else
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>     /* required for free() prototypes */
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>     /* for the close() proto */
+#endif
+#ifdef  VMS
+#include <in.h>
+#include <inet.h>
+#include <stdlib.h>
+#endif
+#endif
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#ifdef WIN32
+#include <process.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
+#include "inet_ntoa_r.h"
+#endif
+
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for ares-enabled builds
+ **********************************************************************/
+
+#ifdef CURLRES_ARES
+
+/*
+ * Curl_fdset() is called when someone from the outside world (using
+ * curl_multi_fdset()) wants to get our fd_set setup and we're talking with
+ * ares. The caller must make sure that this function is only called when we
+ * have a working ares channel.
+ *
+ * Returns: CURLE_OK always!
+ */
+
+CURLcode Curl_fdset(struct connectdata *conn,
+                    fd_set *read_fd_set,
+                    fd_set *write_fd_set,
+                    int *max_fdp)
+
+{
+  int max = ares_fds(conn->data->state.areschannel,
+                     read_fd_set, write_fd_set);
+  *max_fdp = max;
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_is_resolved() is called repeatedly to check if a previous name resolve
+ * request has completed. It should also make sure to time-out if the
+ * operation seems to take too long.
+ *
+ * Returns normal CURLcode errors.
+ */
+CURLcode Curl_is_resolved(struct connectdata *conn,
+                          struct Curl_dns_entry **dns)
+{
+  fd_set read_fds, write_fds;
+  struct timeval tv={0,0};
+  struct SessionHandle *data = conn->data;
+  int nfds;
+
+  FD_ZERO(&read_fds);
+  FD_ZERO(&write_fds);
+
+  nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds);
+
+  (void)select(nfds, &read_fds, &write_fds, NULL,
+               (struct timeval *)&tv);
+
+  /* Call ares_process() unconditonally here, even if we simply timed out
+     above, as otherwise the ares name resolve won't timeout! */
+  ares_process(data->state.areschannel, &read_fds, &write_fds);
+
+  *dns = NULL;
+
+  if(conn->async.done) {
+    /* we're done, kill the ares handle */
+    if(!conn->async.dns) {
+      failf(data, "Could not resolve host: %s (%s)", conn->host.dispname,
+            ares_strerror(conn->async.status));
+      return CURLE_COULDNT_RESOLVE_HOST;
+    }
+    *dns = conn->async.dns;
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_wait_for_resolv() waits for a resolve to finish. This function should
+ * be avoided since using this risk getting the multi interface to "hang".
+ *
+ * If 'entry' is non-NULL, make it point to the resolved dns entry
+ *
+ * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and
+ * CURLE_OPERATION_TIMEDOUT if a time-out occurred.
+ */
+CURLcode Curl_wait_for_resolv(struct connectdata *conn,
+                              struct Curl_dns_entry **entry)
+{
+  CURLcode rc=CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  long timeout = CURL_TIMEOUT_RESOLVE; /* default name resolve timeout */
+
+  /* now, see if there's a connect timeout or a regular timeout to
+     use instead of the default one */
+  if(conn->data->set.connecttimeout)
+    timeout = conn->data->set.connecttimeout;
+  else if(conn->data->set.timeout)
+    timeout = conn->data->set.timeout;
+
+  /* We convert the number of seconds into number of milliseconds here: */
+  if(timeout < 2147483)
+    /* maximum amount of seconds that can be multiplied with 1000 and
+       still fit within 31 bits */
+    timeout *= 1000;
+  else
+    timeout = 0x7fffffff; /* ridiculous amount of time anyway */
+
+  /* Wait for the name resolve query to complete. */
+  while (1) {
+    int nfds=0;
+    fd_set read_fds, write_fds;
+    struct timeval *tvp, tv, store;
+    int count;
+    struct timeval now = Curl_tvnow();
+    long timediff;
+
+    store.tv_sec = (int)timeout/1000;
+    store.tv_usec = (timeout%1000)*1000;
+
+    FD_ZERO(&read_fds);
+    FD_ZERO(&write_fds);
+    nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds);
+    if (nfds == 0)
+      /* no file descriptors means we're done waiting */
+      break;
+    tvp = ares_timeout(data->state.areschannel, &store, &tv);
+    count = select(nfds, &read_fds, &write_fds, NULL, tvp);
+    if (count < 0 && errno != EINVAL)
+      break;
+
+    ares_process(data->state.areschannel, &read_fds, &write_fds);
+
+    timediff = Curl_tvdiff(Curl_tvnow(), now); /* spent time */
+    timeout -= timediff?timediff:1; /* always deduct at least 1 */
+    if (timeout < 0) {
+      /* our timeout, so we cancel the ares operation */
+      ares_cancel(data->state.areschannel);
+      break;
+    }
+  }
+
+  /* Operation complete, if the lookup was successful we now have the entry
+     in the cache. */
+
+  if(entry)
+    *entry = conn->async.dns;
+
+  if(!conn->async.dns) {
+    /* a name was not resolved */
+    if((timeout < 0) || (conn->async.status == ARES_ETIMEOUT)) {
+      failf(data, "Resolving host timed out: %s", conn->host.dispname);
+      rc = CURLE_OPERATION_TIMEDOUT;
+    }
+    else if(conn->async.done) {
+      failf(data, "Could not resolve host: %s (%s)", conn->host.dispname,
+            ares_strerror(conn->async.status));
+      rc = CURLE_COULDNT_RESOLVE_HOST;
+    }
+    else
+      rc = CURLE_OPERATION_TIMEDOUT;
+
+    /* close the connection, since we can't return failure here without
+       cleaning up this connection properly */
+    Curl_disconnect(conn);
+  }
+
+  return rc;
+}
+
+/*
+ * Curl_getaddrinfo() - when using ares
+ *
+ * Returns name information about the given hostname and port number. If
+ * successful, the 'hostent' is returned and the forth argument will point to
+ * memory we need to free after use. That memory *MUST* be freed with
+ * Curl_freeaddrinfo(), nothing else.
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+                                char *hostname,
+                                int port,
+                                int *waitp)
+{
+  char *bufp;
+  struct SessionHandle *data = conn->data;
+  in_addr_t in = inet_addr(hostname);
+
+  *waitp = FALSE;
+
+  if (in != CURL_INADDR_NONE) {
+    /* This is a dotted IP address 123.123.123.123-style */
+    return Curl_ip2addr(in, hostname, port);
+  }
+
+  bufp = strdup(hostname);
+
+  if(bufp) {
+    Curl_safefree(conn->async.hostname);
+    conn->async.hostname = bufp;
+    conn->async.port = port;
+    conn->async.done = FALSE; /* not done */
+    conn->async.status = 0;   /* clear */
+    conn->async.dns = NULL;   /* clear */
+
+    /* areschannel is already setup in the Curl_open() function */
+    ares_gethostbyname(data->state.areschannel, hostname, PF_INET,
+                       Curl_addrinfo4_callback, conn);
+
+    *waitp = TRUE; /* please wait for the response */
+  }
+  return NULL; /* no struct yet */
+}
+
+#endif /* CURLRES_ARES */
diff --git a/Utilities/cmcurl/hostasyn.c b/Utilities/cmcurl/hostasyn.c
new file mode 100644
index 0000000..b3c9dfa
--- /dev/null
+++ b/Utilities/cmcurl/hostasyn.c
@@ -0,0 +1,170 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <string.h>
+#include <errno.h>
+
+#define _REENTRANT
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#include <malloc.h>
+#else
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>     /* required for free() prototypes */
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>     /* for the close() proto */
+#endif
+#ifdef  VMS
+#include <in.h>
+#include <inet.h>
+#include <stdlib.h>
+#endif
+#endif
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#ifdef WIN32
+#include <process.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
+#include "inet_ntoa_r.h"
+#endif
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for builds using asynchronous name resolves
+ **********************************************************************/
+#ifdef CURLRES_ASYNCH
+/*
+ * addrinfo_callback() gets called by ares, gethostbyname_thread() or
+ * getaddrinfo_thread() when we got the name resolved (or not!).
+ *
+ * If the status argument is CURL_ASYNC_SUCCESS, we might need to copy the
+ * address field since it might be freed when this function returns. This
+ * operation stores the resolved data in the DNS cache.
+ *
+ * NOTE: for IPv6 operations, Curl_addrinfo_copy() returns the same
+ * pointer it is given as argument!
+ *
+ * The storage operation locks and unlocks the DNS cache.
+ */
+static void addrinfo_callback(void *arg, /* "struct connectdata *" */
+                              int status,
+                              void *addr)
+{
+  struct connectdata *conn = (struct connectdata *)arg;
+  struct Curl_dns_entry *dns = NULL;
+
+  conn->async.done = TRUE;
+  conn->async.status = status;
+
+  if(CURL_ASYNC_SUCCESS == status) {
+
+    /*
+     * IPv4: Curl_addrinfo_copy() copies the address and returns an allocated
+     * version.
+     *
+     * IPv6: Curl_addrinfo_copy() returns the input pointer!
+     */
+    Curl_addrinfo *ai = Curl_addrinfo_copy(addr, conn->async.port);
+    if(ai) {
+      struct SessionHandle *data = conn->data;
+
+      if(data->share)
+        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+      dns = Curl_cache_addr(data, ai,
+                            conn->async.hostname,
+                            conn->async.port);
+      if(!dns)
+        /* failed to store, cleanup and return error */
+        Curl_freeaddrinfo(ai);
+
+      if(data->share)
+        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+    }
+  }
+
+  conn->async.dns = dns;
+
+  /* ipv4: The input hostent struct will be freed by ares when we return from
+     this function */
+}
+
+void Curl_addrinfo4_callback(void *arg, /* "struct connectdata *" */
+                             int status,
+                             struct hostent *hostent)
+{
+  addrinfo_callback(arg, status, hostent);
+}
+
+#ifdef CURLRES_IPV6
+void Curl_addrinfo6_callback(void *arg, /* "struct connectdata *" */
+                             int status,
+                             struct addrinfo *ai)
+{
+  addrinfo_callback(arg, status, ai);
+}
+#endif
+
+#endif /* CURLRES_ASYNC */
diff --git a/Utilities/cmcurl/hostip.c b/Utilities/cmcurl/hostip.c
new file mode 100644
index 0000000..43ade26
--- /dev/null
+++ b/Utilities/cmcurl/hostip.c
@@ -0,0 +1,540 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <string.h>
+#include <errno.h>
+
+#define _REENTRANT
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#include <malloc.h>
+#else
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>     /* required for free() prototypes */
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>     /* for the close() proto */
+#endif
+#ifdef  VMS
+#include <in.h>
+#include <inet.h>
+#include <stdlib.h>
+#endif
+#endif
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#ifdef WIN32
+#include <process.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+#include "inet_ntop.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
+#include "inet_ntoa_r.h"
+#endif
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * hostip.c explained
+ * ==================
+ *
+ * The main COMPILE-TIME DEFINES to keep in mind when reading the host*.c
+ * source file are these:
+ *
+ * CURLRES_IPV6 - this host has getaddrinfo() and family, and thus we use
+ * that. The host may not be able to resolve IPv6, but we don't really have to
+ * take that into account. Hosts that aren't IPv6-enabled have CURLRES_IPV4
+ * defined.
+ *
+ * CURLRES_ARES - is defined if libcurl is built to use c-ares for
+ * asynchronous name resolves. It cannot have ENABLE_IPV6 defined at the same
+ * time, as c-ares has no ipv6 support. This can be Windows or *nix.
+ *
+ * CURLRES_THREADED - is defined if libcurl is built to run under (native)
+ * Windows, and then the name resolve will be done in a new thread, and the
+ * supported API will be the same as for ares-builds.
+ *
+ * If any of the two previous are defined, CURLRES_ASYNCH is defined too. If
+ * libcurl is not built to use an asynchronous resolver, CURLRES_SYNCH is
+ * defined.
+ *
+ * The host*.c sources files are split up like this:
+ *
+ * hostip.c   - method-independent resolver functions and utility functions
+ * hostasyn.c - functions for asynchronous name resolves
+ * hostsyn.c  - functions for synchronous name resolves
+ * hostares.c - functions for ares-using name resolves
+ * hostthre.c - functions for threaded name resolves
+ * hostip4.c  - ipv4-specific functions
+ * hostip6.c  - ipv6-specific functions
+ *
+ * The hostip.h is the united header file for all this. It defines the
+ * CURLRES_* defines based on the config*.h and setup.h defines.
+ */
+
+/* These two symbols are for the global DNS cache */
+static curl_hash hostname_cache;
+static int host_cache_initialized;
+
+static void freednsentry(void *freethis);
+
+/*
+ * Curl_global_host_cache_init() initializes and sets up a global DNS cache.
+ * Global DNS cache is general badness. Do not use. This will be removed in
+ * a future version. Use the share interface instead!
+ */
+void Curl_global_host_cache_init(void)
+{
+  if (!host_cache_initialized) {
+    Curl_hash_init(&hostname_cache, 7, freednsentry);
+    host_cache_initialized = 1;
+  }
+}
+
+/*
+ * Return a pointer to the global cache
+ */
+curl_hash *Curl_global_host_cache_get(void)
+{
+  return &hostname_cache;
+}
+
+/*
+ * Destroy and cleanup the global DNS cache
+ */
+void Curl_global_host_cache_dtor(void)
+{
+  if (host_cache_initialized) {
+    Curl_hash_clean(&hostname_cache);
+    host_cache_initialized = 0;
+  }
+}
+
+/*
+ * Return # of adresses in a Curl_addrinfo struct
+ */
+int Curl_num_addresses(const Curl_addrinfo *addr)
+{
+  int i;
+  for (i = 0; addr; addr = addr->ai_next, i++);
+  return i;
+}
+
+#define GET_SIN_ADDR_FROM_CURL_ADDRINFO(ai_addr, si, sin, sinaddr, ip) \
+  { \
+  union { \
+    struct si* vsi; \
+    struct sin* vsin;\
+  } vi; \
+  vi.vsi = ai_addr; \
+  ip = &(vi.vsin->sinaddr); \
+  }
+
+/*
+ * Curl_printable_address() returns a printable version of the 1st address
+ * given in the 'ip' argument. The result will be stored in the buf that is
+ * bufsize bytes big.
+ *
+ * If the conversion fails, it returns NULL.
+ */
+const char *Curl_printable_address(const Curl_addrinfo *ip,
+                                   char *buf, size_t bufsize)
+{
+  int af = ip->ai_family;
+  const void *ip4;
+#ifdef CURLRES_IPV6
+  const void *ip6;
+  GET_SIN_ADDR_FROM_CURL_ADDRINFO(ip->ai_addr, sockaddr, sockaddr_in6,
+    sin6_addr, ip6);
+#else
+  const void *ip6 = NULL;
+#endif
+  GET_SIN_ADDR_FROM_CURL_ADDRINFO(ip->ai_addr, sockaddr, sockaddr_in,
+    sin_addr, ip4);
+
+  return Curl_inet_ntop(af, af == AF_INET ? ip4 : ip6, buf, bufsize);
+}
+
+/*
+ * Return a hostcache id string for the providing host + port, to be used by
+ * the DNS caching.
+ */
+static char *
+create_hostcache_id(char *server, int port)
+{
+  /* create and return the new allocated entry */
+  return aprintf("%s:%d", server, port);
+}
+
+struct hostcache_prune_data {
+  int cache_timeout;
+  time_t now;
+};
+
+/*
+ * This function is set as a callback to be called for every entry in the DNS
+ * cache when we want to prune old unused entries.
+ *
+ * Returning non-zero means remove the entry, return 0 to keep it in the
+ * cache.
+ */
+static int
+hostcache_timestamp_remove(void *datap, void *hc)
+{
+  struct hostcache_prune_data *data =
+    (struct hostcache_prune_data *) datap;
+  struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
+
+  if ((data->now - c->timestamp < data->cache_timeout) ||
+      c->inuse) {
+    /* please don't remove */
+    return 0;
+  }
+
+  /* fine, remove */
+  return 1;
+}
+
+/*
+ * Prune the DNS cache. This assumes that a lock has already been taken.
+ */
+static void
+hostcache_prune(curl_hash *hostcache, int cache_timeout, time_t now)
+{
+  struct hostcache_prune_data user;
+
+  user.cache_timeout = cache_timeout;
+  user.now = now;
+
+  Curl_hash_clean_with_criterium(hostcache,
+                                 (void *) &user,
+                                 hostcache_timestamp_remove);
+}
+
+/*
+ * Library-wide function for pruning the DNS cache. This function takes and
+ * returns the appropriate locks.
+ */
+void Curl_hostcache_prune(struct SessionHandle *data)
+{
+  time_t now;
+
+  if(data->set.dns_cache_timeout == -1)
+    /* cache forever means never prune! */
+    return;
+
+  if(data->share)
+    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+  time(&now);
+
+  /* Remove outdated and unused entries from the hostcache */
+  hostcache_prune(data->hostcache,
+                  data->set.dns_cache_timeout,
+                  now);
+
+  if(data->share)
+    Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+}
+
+#ifdef HAVE_SIGSETJMP
+/* Beware this is a global and unique instance. This is used to store the
+   return address that we can jump back to from inside a signal handler. This
+   is not thread-safe stuff. */
+sigjmp_buf curl_jmpenv;
+#endif
+
+
+/*
+ * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
+ *
+ * When calling Curl_resolv() has resulted in a response with a returned
+ * address, we call this function to store the information in the dns
+ * cache etc
+ *
+ * Returns the Curl_dns_entry entry pointer or NULL if the storage failed.
+ */
+struct Curl_dns_entry *
+Curl_cache_addr(struct SessionHandle *data,
+                Curl_addrinfo *addr,
+                char *hostname,
+                int port)
+{
+  char *entry_id;
+  size_t entry_len;
+  struct Curl_dns_entry *dns;
+  struct Curl_dns_entry *dns2;
+  time_t now;
+
+  /* Create an entry id, based upon the hostname and port */
+  entry_id = create_hostcache_id(hostname, port);
+  /* If we can't create the entry id, fail */
+  if (!entry_id)
+    return NULL;
+  entry_len = strlen(entry_id);
+
+  /* Create a new cache entry */
+  dns = (struct Curl_dns_entry *) malloc(sizeof(struct Curl_dns_entry));
+  if (!dns) {
+    free(entry_id);
+    return NULL;
+  }
+
+  dns->inuse = 0;   /* init to not used */
+  dns->addr = addr; /* this is the address(es) */
+
+  /* Store the resolved data in our DNS cache. This function may return a
+     pointer to an existing struct already present in the hash, and it may
+     return the same argument we pass in. Make no assumptions. */
+  dns2 = Curl_hash_add(data->hostcache, entry_id, entry_len+1, (void *)dns);
+  if(!dns2) {
+    /* Major badness, run away. */
+    free(dns);
+    free(entry_id);
+    return NULL;
+  }
+  time(&now);
+  dns = dns2;
+
+  dns->timestamp = now; /* used now */
+  dns->inuse++;         /* mark entry as in-use */
+
+  /* free the allocated entry_id again */
+  free(entry_id);
+
+  return dns;
+}
+
+/*
+ * Curl_resolv() is the main name resolve function within libcurl. It resolves
+ * a name and returns a pointer to the entry in the 'entry' argument (if one
+ * is provided). This function might return immediately if we're using asynch
+ * resolves. See the return codes.
+ *
+ * The cache entry we return will get its 'inuse' counter increased when this
+ * function is used. You MUST call Curl_resolv_unlock() later (when you're
+ * done using this struct) to decrease the counter again.
+ *
+ * Return codes:
+ *
+ * CURLRESOLV_ERROR   (-1) = error, no pointer
+ * CURLRESOLV_RESOLVED (0) = OK, pointer provided
+ * CURLRESOLV_PENDING  (1) = waiting for response, no pointer
+ */
+
+int Curl_resolv(struct connectdata *conn,
+                char *hostname,
+                int port,
+                struct Curl_dns_entry **entry)
+{
+  char *entry_id;
+  struct Curl_dns_entry *dns = NULL;
+  size_t entry_len;
+  int wait;
+  struct SessionHandle *data = conn->data;
+  CURLcode result;
+
+  /* default to failure */
+  int rc;
+  *entry = NULL;
+
+#ifdef HAVE_SIGSETJMP
+  /* this allows us to time-out from the name resolver, as the timeout
+     will generate a signal and we will siglongjmp() from that here */
+  if(!data->set.no_signal && sigsetjmp(curl_jmpenv, 1)) {
+    /* this is coming from a siglongjmp() */
+    failf(data, "name lookup timed out");
+    return CURLRESOLV_ERROR;
+  }
+#endif
+  rc = CURLRESOLV_ERROR;
+
+  /* Create an entry id, based upon the hostname and port */
+  entry_id = create_hostcache_id(hostname, port);
+  /* If we can't create the entry id, fail */
+  if (!entry_id)
+    return CURLRESOLV_ERROR;
+
+  entry_len = strlen(entry_id);
+
+  if(data->share)
+    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+  /* See if its already in our dns cache */
+  dns = Curl_hash_pick(data->hostcache, entry_id, entry_len+1);
+
+  if(data->share)
+    Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+
+  /* free the allocated entry_id again */
+  free(entry_id);
+
+  if (!dns) {
+    /* The entry was not in the cache. Resolve it to IP address */
+
+    Curl_addrinfo *addr;
+
+    /* Check what IP specifics the app has requested and if we can provide it.
+     * If not, bail out. */
+    if(!Curl_ipvalid(data))
+      return CURLRESOLV_ERROR;
+
+    /* If Curl_getaddrinfo() returns NULL, 'wait' might be set to a non-zero
+       value indicating that we need to wait for the response to the resolve
+       call */
+    addr = Curl_getaddrinfo(conn, hostname, port, &wait);
+
+    if (!addr) {
+      if(wait) {
+        /* the response to our resolve call will come asynchronously at
+           a later time, good or bad */
+        /* First, check that we haven't received the info by now */
+        result = Curl_is_resolved(conn, &dns);
+        if(result) /* error detected */
+          return CURLRESOLV_ERROR;
+        if(dns)
+          rc = CURLRESOLV_RESOLVED; /* pointer provided */
+        else
+          rc = CURLRESOLV_PENDING; /* no info yet */
+      }
+    }
+    else {
+      if(data->share)
+        Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+      /* we got a response, store it in the cache */
+      dns = Curl_cache_addr(data, addr, hostname, port);
+
+      if(data->share)
+        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+
+      if(!dns)
+        /* returned failure, bail out nicely */
+        Curl_freeaddrinfo(addr);
+      else
+        rc = CURLRESOLV_RESOLVED;
+    }
+  }
+  else {
+    dns->inuse++; /* we use it! */
+    rc = CURLRESOLV_RESOLVED;
+  }
+
+  *entry = dns;
+
+  return rc;
+}
+
+/*
+ * Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been
+ * made, the struct may be destroyed due to pruning. It is important that only
+ * one unlock is made for each Curl_resolv() call.
+ */
+void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns)
+{
+  curlassert(dns && (dns->inuse>0));
+
+  if(data->share)
+    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+  dns->inuse--;
+
+  if(data->share)
+    Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+}
+
+/*
+ * File-internal: free a cache dns entry.
+ */
+static void freednsentry(void *freethis)
+{
+  struct Curl_dns_entry *p = (struct Curl_dns_entry *) freethis;
+
+  Curl_freeaddrinfo(p->addr);
+
+  free(p);
+}
+
+/*
+ * Curl_mk_dnscache() creates a new DNS cache and returns the handle for it.
+ */
+curl_hash *Curl_mk_dnscache(void)
+{
+  return Curl_hash_alloc(7, freednsentry);
+}
+
+#ifdef CURLRES_ADDRINFO_COPY
+
+/* align on even 64bit boundaries */
+#define MEMALIGN(x) ((x)+(8-(((unsigned long)(x))&0x7)))
+
+/*
+ * Curl_addrinfo_copy() performs a "deep" copy of a hostent into a buffer and
+ * returns a pointer to the malloc()ed copy. You need to call free() on the
+ * returned buffer when you're done with it.
+ */
+Curl_addrinfo *Curl_addrinfo_copy(void *org, int port)
+{
+  struct hostent *orig = org;
+
+  return Curl_he2ai(orig, port);
+}
+#endif /* CURLRES_ADDRINFO_COPY */
diff --git a/Utilities/cmcurl/hostip.h b/Utilities/cmcurl/hostip.h
new file mode 100644
index 0000000..545fec0
--- /dev/null
+++ b/Utilities/cmcurl/hostip.h
@@ -0,0 +1,255 @@
+#ifndef __HOSTIP_H
+#define __HOSTIP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+#include "hash.h"
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+/*
+ * Setup comfortable CURLRES_* defines to use in the host*.c sources.
+ */
+
+#ifdef USE_ARES
+#define CURLRES_ASYNCH
+#define CURLRES_ARES
+#endif
+
+#ifdef USE_THREADING_GETHOSTBYNAME
+#define CURLRES_ASYNCH
+#define CURLRES_THREADED
+#endif
+
+#ifdef USE_THREADING_GETADDRINFO
+#define CURLRES_ASYNCH
+#define CURLRES_THREADED
+#endif
+
+#ifdef ENABLE_IPV6
+#define CURLRES_IPV6
+#else
+#define CURLRES_IPV4
+#endif
+
+#ifdef CURLRES_IPV4
+#if !defined(HAVE_GETHOSTBYNAME_R) || defined(CURLRES_ASYNCH)
+/* If built for ipv4 and missing gethostbyname_r(), or if using async name
+   resolve, we need the Curl_addrinfo_copy() function (which itself needs the
+   Curl_hostent_relocate() function)) */
+#define CURLRES_ADDRINFO_COPY
+#endif
+#endif /* IPv4-only */
+
+#ifndef CURLRES_ASYNCH
+#define CURLRES_SYNCH
+#endif
+
+#ifndef USE_LIBIDN
+#define CURLRES_IDN
+#endif
+
+/* Allocate enough memory to hold the full name information structs and
+ * everything. OSF1 is known to require at least 8872 bytes. The buffer
+ * required for storing all possible aliases and IP numbers is according to
+ * Stevens' Unix Network Programming 2nd edition, p. 304: 8192 bytes!
+ */
+#define CURL_HOSTENT_SIZE 9000
+
+#define CURL_TIMEOUT_RESOLVE 300 /* when using asynch methods, we allow this
+                                    many seconds for a name resolve */
+
+#ifdef CURLRES_ARES
+#define CURL_ASYNC_SUCCESS ARES_SUCCESS
+#else
+#define CURL_ASYNC_SUCCESS CURLE_OK
+#endif
+
+/*
+ * Curl_addrinfo MUST be used for all name resolved info.
+ */
+#ifdef CURLRES_IPV6
+typedef struct addrinfo Curl_addrinfo;
+#else
+/* OK, so some ipv4-only include tree probably have the addrinfo struct, but
+   to work even on those that don't, we provide our own look-alike! */
+struct Curl_addrinfo {
+  int     ai_flags;
+  int     ai_family;
+  int     ai_socktype;
+  int     ai_protocol;
+  size_t  ai_addrlen;
+  struct sockaddr *ai_addr;
+  char   *ai_canonname;
+  struct Curl_addrinfo *ai_next;
+};
+typedef struct Curl_addrinfo Curl_addrinfo;
+#endif
+
+struct addrinfo;
+struct SessionHandle;
+struct connectdata;
+
+void Curl_global_host_cache_init(void);
+void Curl_global_host_cache_dtor(void);
+curl_hash *Curl_global_host_cache_get(void);
+
+#define Curl_global_host_cache_use(__p) ((__p)->set.global_dns_cache)
+
+struct Curl_dns_entry {
+  Curl_addrinfo *addr;
+  time_t timestamp;
+  long inuse;      /* use-counter, make very sure you decrease this
+                      when you're done using the address you received */
+};
+
+/*
+ * Curl_resolv() returns an entry with the info for the specified host
+ * and port.
+ *
+ * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
+ * use, or we'll leak memory!
+ */
+/* return codes */
+#define CURLRESOLV_ERROR    -1
+#define CURLRESOLV_RESOLVED  0
+#define CURLRESOLV_PENDING   1
+int Curl_resolv(struct connectdata *conn, char *hostname,
+                int port, struct Curl_dns_entry **dnsentry);
+
+/*
+ * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
+ * been set and returns TRUE if they are OK.
+ */
+bool Curl_ipvalid(struct SessionHandle *data);
+
+/*
+ * Curl_getaddrinfo() is the generic low-level name resolve API within this
+ * source file. There are several versions of this function - for different
+ * name resolve layers (selected at build-time). They all take this same set
+ * of arguments
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+                                char *hostname,
+                                int port,
+                                int *waitp);
+
+CURLcode Curl_is_resolved(struct connectdata *conn,
+                          struct Curl_dns_entry **dns);
+CURLcode Curl_wait_for_resolv(struct connectdata *conn,
+                              struct Curl_dns_entry **dnsentry);
+
+/* Curl_fdset() is a generic function that exists in multiple versions
+   depending on what name resolve technology we've built to use. The function
+   is called from the curl_multi_fdset() function */
+CURLcode Curl_fdset(struct connectdata *conn,
+                    fd_set *read_fd_set,
+                    fd_set *write_fd_set,
+                    int *max_fdp);
+/* unlock a previously resolved dns entry */
+void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns);
+
+/* for debugging purposes only: */
+void Curl_scan_cache_used(void *user, void *ptr);
+
+/* free name info */
+void Curl_freeaddrinfo(Curl_addrinfo *freeaddr);
+
+/* make a new dns cache and return the handle */
+curl_hash *Curl_mk_dnscache(void);
+
+/* prune old entries from the DNS cache */
+void Curl_hostcache_prune(struct SessionHandle *data);
+
+/* Return # of adresses in a Curl_addrinfo struct */
+int Curl_num_addresses (const Curl_addrinfo *addr);
+
+#ifdef CURLDEBUG
+void curl_dofreeaddrinfo(struct addrinfo *freethis,
+                         int line, const char *source);
+int curl_dogetaddrinfo(char *hostname, char *service,
+                       struct addrinfo *hints,
+                       struct addrinfo **result,
+                       int line, const char *source);
+int curl_dogetnameinfo(const struct sockaddr *sa, socklen_t salen,
+                       char *host, size_t hostlen,
+                       char *serv, size_t servlen, int flags,
+                       int line, const char *source);
+#endif
+
+/* This is the callback function that is used when we build with asynch
+   resolve, ipv4 */
+void Curl_addrinfo4_callback(void *arg,
+                            int status,
+                            struct hostent *hostent);
+/* This is the callback function that is used when we build with asynch
+   resolve, ipv6 */
+void Curl_addrinfo6_callback(void *arg,
+                            int status,
+                            struct addrinfo *ai);
+
+
+/* [ipv4 only] Creates a Curl_addrinfo struct from a numerical-only IP
+   address */
+Curl_addrinfo *Curl_ip2addr(in_addr_t num, char *hostname, int port);
+
+/* [ipv4 only] Curl_he2ai() converts a struct hostent to a Curl_addrinfo chain
+   and returns it */
+Curl_addrinfo *Curl_he2ai(struct hostent *, int port);
+
+/* relocate a hostent struct */
+void Curl_hostent_relocate(struct hostent *h, long offset);
+
+/* Clone a Curl_addrinfo struct, works protocol independently */
+Curl_addrinfo *Curl_addrinfo_copy(void *orig, int port);
+
+/*
+ * Curl_printable_address() returns a printable version of the 1st address
+ * given in the 'ip' argument. The result will be stored in the buf that is
+ * bufsize bytes big.
+ */
+const char *Curl_printable_address(const Curl_addrinfo *ip,
+                                   char *buf, size_t bufsize);
+
+/*
+ * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
+ *
+ * Returns the Curl_dns_entry entry pointer or NULL if the storage failed.
+ */
+struct Curl_dns_entry *
+Curl_cache_addr(struct SessionHandle *data, Curl_addrinfo *addr,
+                char *hostname, int port);
+
+#ifndef INADDR_NONE
+#define CURL_INADDR_NONE (in_addr_t) ~0
+#else
+#define CURL_INADDR_NONE INADDR_NONE
+#endif
+
+
+
+
+#endif
diff --git a/Utilities/cmcurl/hostip4.c b/Utilities/cmcurl/hostip4.c
new file mode 100644
index 0000000..1b4c3c1
--- /dev/null
+++ b/Utilities/cmcurl/hostip4.c
@@ -0,0 +1,456 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <string.h>
+#include <errno.h>
+
+#define _REENTRANT
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#include <malloc.h>
+#else
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>     /* required for free() prototypes */
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>     /* for the close() proto */
+#endif
+#ifdef  VMS
+#include <in.h>
+#include <inet.h>
+#include <stdlib.h>
+#endif
+#endif
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#ifdef WIN32
+#include <process.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
+#include "inet_ntoa_r.h"
+#endif
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for plain-ipv4 builds
+ **********************************************************************/
+#ifdef CURLRES_IPV4 /* plain ipv4 code coming up */
+
+/*
+ * This is a function for freeing name information in a protocol independent
+ * way.
+ */
+void Curl_freeaddrinfo(Curl_addrinfo *ai)
+{
+  Curl_addrinfo *next;
+
+  /* walk over the list and free all entries */
+  while(ai) {
+    next = ai->ai_next;
+    free(ai);
+    ai = next;
+  }
+}
+
+/*
+ * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
+ * been set and returns TRUE if they are OK.
+ */
+bool Curl_ipvalid(struct SessionHandle *data)
+{
+  if(data->set.ip_version == CURL_IPRESOLVE_V6)
+    /* an ipv6 address was requested and we can't get/use one */
+    return FALSE;
+
+  return TRUE; /* OK, proceed */
+}
+
+struct namebuf {
+  struct hostent hostentry;
+  char *h_addr_list[2];
+  struct in_addr addrentry;
+  char h_name[16]; /* 123.123.123.123 = 15 letters is maximum */
+};
+
+/*
+ * Curl_ip2addr() takes a 32bit ipv4 internet address as input parameter
+ * together with a pointer to the string version of the address, and it
+ * returns a Curl_addrinfo chain filled in correctly with information for this
+ * address/host.
+ *
+ * The input parameters ARE NOT checked for validity but they are expected
+ * to have been checked already when this is called.
+ */
+Curl_addrinfo *Curl_ip2addr(in_addr_t num, char *hostname, int port)
+{
+  Curl_addrinfo *ai;
+  struct hostent *h;
+  struct in_addr *addrentry;
+  struct namebuf buffer;
+  struct namebuf *buf = &buffer;
+
+  h = &buf->hostentry;
+  h->h_addr_list = &buf->h_addr_list[0];
+  addrentry = &buf->addrentry;
+  addrentry->s_addr = num;
+  h->h_addr_list[0] = (char*)addrentry;
+  h->h_addr_list[1] = NULL;
+  h->h_addrtype = AF_INET;
+  h->h_length = sizeof(*addrentry);
+  h->h_name = &buf->h_name[0];
+  h->h_aliases = NULL;
+
+  /* Now store the dotted version of the address */
+  snprintf((char*)(h->h_name), 16, "%s", hostname);
+
+  ai = Curl_he2ai(h, port);
+
+  return ai;
+}
+
+#ifdef CURLRES_SYNCH /* the functions below are for synchronous resolves */
+
+/*
+ * Curl_getaddrinfo() - the ipv4 synchronous version.
+ *
+ * The original code to this function was once stolen from the Dancer source
+ * code, written by Bjorn Reese, it has since been patched and modified
+ * considerably.
+ *
+ * gethostbyname_r() is the thread-safe version of the gethostbyname()
+ * function. When we build for plain IPv4, we attempt to use this
+ * function. There are _three_ different gethostbyname_r() versions, and we
+ * detect which one this platform supports in the configure script and set up
+ * the HAVE_GETHOSTBYNAME_R_3, HAVE_GETHOSTBYNAME_R_5 or
+ * HAVE_GETHOSTBYNAME_R_6 defines accordingly. Note that HAVE_GETADDRBYNAME
+ * has the corresponding rules. This is primarily on *nix. Note that some unix
+ * flavours have thread-safe versions of the plain gethostbyname() etc.
+ *
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+                                char *hostname,
+                                int port,
+                                int *waitp)
+{
+  Curl_addrinfo *ai = NULL;
+  struct hostent *h = NULL;
+  in_addr_t in;
+  struct SessionHandle *data = conn->data;
+  struct hostent *buf = NULL;
+
+  (void)port; /* unused in IPv4 code */
+
+  *waitp = 0; /* don't wait, we act synchronously */
+
+  in=inet_addr(hostname);
+  if (in != CURL_INADDR_NONE) {
+    /* This is a dotted IP address 123.123.123.123-style */
+    return Curl_ip2addr(in, hostname, port);
+  }
+
+#if defined(HAVE_GETHOSTBYNAME_R)
+  /*
+   * gethostbyname_r() is the preferred resolve function for many platforms.
+   * Since there are three different versions of it, the following code is
+   * somewhat #ifdef-ridden.
+   */
+  else {
+    int h_errnop;
+    int res=ERANGE;
+
+    buf = (struct hostent *)calloc(CURL_HOSTENT_SIZE, 1);
+    if(!buf)
+      return NULL; /* major failure */
+    /*
+     * The clearing of the buffer is a workaround for a gethostbyname_r bug in
+     * qnx nto and it is also _required_ for some of these functions on some
+     * platforms.
+     */
+
+#ifdef HAVE_GETHOSTBYNAME_R_5
+    /* Solaris, IRIX and more */
+    (void)res; /* prevent compiler warning */
+    h = gethostbyname_r(hostname,
+                        (struct hostent *)buf,
+                        (char *)buf + sizeof(struct hostent),
+                        CURL_HOSTENT_SIZE - sizeof(struct hostent),
+                        &h_errnop);
+
+    /* If the buffer is too small, it returns NULL and sets errno to
+     * ERANGE. The errno is thread safe if this is compiled with
+     * -D_REENTRANT as then the 'errno' variable is a macro defined to get
+     * used properly for threads.
+     */
+
+    if(h) {
+      ;
+    }
+    else
+#endif /* HAVE_GETHOSTBYNAME_R_5 */
+#ifdef HAVE_GETHOSTBYNAME_R_6
+    /* Linux */
+
+    res=gethostbyname_r(hostname,
+                        (struct hostent *)buf,
+                        (char *)buf + sizeof(struct hostent),
+                        CURL_HOSTENT_SIZE - sizeof(struct hostent),
+                        &h, /* DIFFERENCE */
+                        &h_errnop);
+    /* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a
+     * sudden this function returns EAGAIN if the given buffer size is too
+     * small. Previous versions are known to return ERANGE for the same
+     * problem.
+     *
+     * This wouldn't be such a big problem if older versions wouldn't
+     * sometimes return EAGAIN on a common failure case. Alas, we can't
+     * assume that EAGAIN *or* ERANGE means ERANGE for any given version of
+     * glibc.
+     *
+     * For now, we do that and thus we may call the function repeatedly and
+     * fail for older glibc versions that return EAGAIN, until we run out of
+     * buffer size (step_size grows beyond CURL_HOSTENT_SIZE).
+     *
+     * If anyone has a better fix, please tell us!
+     *
+     * -------------------------------------------------------------------
+     *
+     * On October 23rd 2003, Dan C dug up more details on the mysteries of
+     * gethostbyname_r() in glibc:
+     *
+     * In glibc 2.2.5 the interface is different (this has also been
+     * discovered in glibc 2.1.1-6 as shipped by Redhat 6). What I can't
+     * explain, is that tests performed on glibc 2.2.4-34 and 2.2.4-32
+     * (shipped/upgraded by Redhat 7.2) don't show this behavior!
+     *
+     * In this "buggy" version, the return code is -1 on error and 'errno'
+     * is set to the ERANGE or EAGAIN code. Note that 'errno' is not a
+     * thread-safe variable.
+     */
+
+    if(!h) /* failure */
+#endif/* HAVE_GETHOSTBYNAME_R_6 */
+#ifdef HAVE_GETHOSTBYNAME_R_3
+    /* AIX, Digital Unix/Tru64, HPUX 10, more? */
+
+    /* For AIX 4.3 or later, we don't use gethostbyname_r() at all, because of
+     * the plain fact that it does not return unique full buffers on each
+     * call, but instead several of the pointers in the hostent structs will
+     * point to the same actual data! This have the unfortunate down-side that
+     * our caching system breaks down horribly. Luckily for us though, AIX 4.3
+     * and more recent versions have a "completely thread-safe"[*] libc where
+     * all the data is stored in thread-specific memory areas making calls to
+     * the plain old gethostbyname() work fine even for multi-threaded
+     * programs.
+     *
+     * This AIX 4.3 or later detection is all made in the configure script.
+     *
+     * Troels Walsted Hansen helped us work this out on March 3rd, 2003.
+     *
+     * [*] = much later we've found out that it isn't at all "completely
+     * thread-safe", but at least the gethostbyname() function is.
+     */
+
+    if(CURL_HOSTENT_SIZE >=
+       (sizeof(struct hostent)+sizeof(struct hostent_data))) {
+
+      /* August 22nd, 2000: Albert Chin-A-Young brought an updated version
+       * that should work! September 20: Richard Prescott worked on the buffer
+       * size dilemma.
+       */
+
+      res = gethostbyname_r(hostname,
+                            (struct hostent *)buf,
+                            (struct hostent_data *)((char *)buf +
+                                                    sizeof(struct hostent)));
+      h_errnop= errno; /* we don't deal with this, but set it anyway */
+    }
+    else
+      res = -1; /* failure, too smallish buffer size */
+
+    if(!res) { /* success */
+
+      h = buf; /* result expected in h */
+
+      /* This is the worst kind of the different gethostbyname_r() interfaces.
+       * Since we don't know how big buffer this particular lookup required,
+       * we can't realloc down the huge alloc without doing closer analysis of
+       * the returned data. Thus, we always use CURL_HOSTENT_SIZE for every
+       * name lookup. Fixing this would require an extra malloc() and then
+       * calling Curl_addrinfo_copy() that subsequent realloc()s down the new
+       * memory area to the actually used amount.
+       */
+    }
+    else
+#endif /* HAVE_GETHOSTBYNAME_R_3 */
+      {
+      infof(data, "gethostbyname_r(2) failed for %s\n", hostname);
+      h = NULL; /* set return code to NULL */
+      free(buf);
+    }
+#else /* HAVE_GETHOSTBYNAME_R */
+    /*
+     * Here is code for platforms that don't have gethostbyname_r() or for
+     * which the gethostbyname() is the preferred() function.
+     */
+  else {
+    h = gethostbyname(hostname);
+    if (!h)
+      infof(data, "gethostbyname(2) failed for %s\n", hostname);
+#endif /*HAVE_GETHOSTBYNAME_R */
+  }
+
+  if(h) {
+    ai = Curl_he2ai(h, port);
+
+    if (buf) /* used a *_r() function */
+      free(buf);
+  }
+
+  return ai;
+}
+
+#endif /* CURLRES_SYNCH */
+
+/*
+ * Curl_he2ai() translates from a hostent struct to a Curl_addrinfo struct.
+ * The Curl_addrinfo is meant to work like the addrinfo struct does for IPv6
+ * stacks, but for all hosts and environments.
+
+struct Curl_addrinfo {
+  int     ai_flags;
+  int     ai_family;
+  int     ai_socktype;
+  int     ai_protocol;
+  size_t  ai_addrlen;
+  struct sockaddr *ai_addr;
+  char   *ai_canonname;
+  struct addrinfo *ai_next;
+};
+
+struct hostent {
+  char    *h_name;        * official name of host *
+  char    **h_aliases;    * alias list *
+  int     h_addrtype;     * host address type *
+  int     h_length;       * length of address *
+  char    **h_addr_list;  * list of addresses *
+}
+#define h_addr  h_addr_list[0]  * for backward compatibility *
+
+*/
+
+Curl_addrinfo *Curl_he2ai(struct hostent *he, int port)
+{
+  Curl_addrinfo *ai;
+  Curl_addrinfo *prevai = NULL;
+  Curl_addrinfo *firstai = NULL;
+  int i;
+
+  union {
+    struct in_addr *addr;
+    char* list;
+  } curr;
+  union {
+    struct sockaddr_in* addr_in;
+    struct sockaddr* addr;
+  } address;
+
+  if(!he)
+    /* no input == no output! */
+    return NULL;
+
+  for(i=0; (curr.list = he->h_addr_list[i]); i++) {
+
+    ai = calloc(1, sizeof(Curl_addrinfo) + sizeof(struct sockaddr_in));
+
+    if(!ai)
+      break;
+
+    if(!firstai)
+      /* store the pointer we want to return from this function */
+      firstai = ai;
+
+    if(prevai)
+      /* make the previous entry point to this */
+      prevai->ai_next = ai;
+
+    ai->ai_family = AF_INET;              /* we only support this */
+    ai->ai_socktype = SOCK_STREAM;        /* we only support this */
+    ai->ai_addrlen = sizeof(struct sockaddr_in);
+    /* make the ai_addr point to the address immediately following this struct
+       and use that area to store the address */
+    ai->ai_addr = (struct sockaddr *) (ai + 1);
+
+    /* leave the rest of the struct filled with zero */
+
+    address.addr = ai->ai_addr; /* storage area for this info */
+
+    memcpy((char *)&(address.addr_in->sin_addr), curr.addr, sizeof(struct in_addr));
+    address.addr_in->sin_family = he->h_addrtype;
+    address.addr_in->sin_port = htons((unsigned short)port);
+
+    prevai = ai;
+  }
+  return firstai;
+}
+
+#endif /* CURLRES_IPV4 */
diff --git a/Utilities/cmcurl/hostip6.c b/Utilities/cmcurl/hostip6.c
new file mode 100644
index 0000000..6717c00
--- /dev/null
+++ b/Utilities/cmcurl/hostip6.c
@@ -0,0 +1,263 @@
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <string.h>
+#include <errno.h>
+
+#define _REENTRANT
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#include <malloc.h>
+#else
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>     /* required for free() prototypes */
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>     /* for the close() proto */
+#endif
+#ifdef  VMS
+#include <in.h>
+#include <inet.h>
+#include <stdlib.h>
+#endif
+#endif
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#ifdef WIN32
+#include <process.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
+#include "inet_ntoa_r.h"
+#endif
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for ipv6-enabled builds
+ **********************************************************************/
+#ifdef CURLRES_IPV6
+/*
+ * This is a wrapper function for freeing name information in a protocol
+ * independent way. This takes care of using the appropriate underlaying
+ * function.
+ */
+void Curl_freeaddrinfo(Curl_addrinfo *p)
+{
+  freeaddrinfo(p);
+}
+
+#ifdef CURLRES_ASYNCH
+/*
+ * Curl_addrinfo_copy() is used by the asynch callback to copy a given
+ * address. But this is an ipv6 build and then we don't copy the address, we
+ * just return the same pointer!
+ */
+Curl_addrinfo *Curl_addrinfo_copy(void *source, int port)
+{
+  (void) port;
+  return source;
+}
+#endif
+
+#ifdef CURLDEBUG
+/* These are strictly for memory tracing and are using the same style as the
+ * family otherwise present in memdebug.c. I put these ones here since they
+ * require a bunch of structs I didn't wanna include in memdebug.c
+ */
+int curl_dogetaddrinfo(char *hostname, char *service,
+                       struct addrinfo *hints,
+                       struct addrinfo **result,
+                       int line, const char *source)
+{
+  int res=(getaddrinfo)(hostname, service, hints, result);
+  if(0 == res) {
+    /* success */
+    if(logfile)
+      fprintf(logfile, "ADDR %s:%d getaddrinfo() = %p\n",
+              source, line, (void *)*result);
+  }
+  else {
+    if(logfile)
+      fprintf(logfile, "ADDR %s:%d getaddrinfo() failed\n",
+              source, line);
+  }
+  return res;
+}
+
+int curl_dogetnameinfo(const struct sockaddr *sa, socklen_t salen,
+                       char *host, size_t hostlen,
+                       char *serv, size_t servlen, int flags,
+                       int line, const char *source)
+{
+  int res=(getnameinfo)(sa, salen, host, hostlen, serv, servlen, flags);
+  if(0 == res) {
+    /* success */
+    if(logfile)
+      fprintf(logfile, "GETNAME %s:%d getnameinfo()\n",
+              source, line);
+  }
+  else {
+    if(logfile)
+      fprintf(logfile, "GETNAME %s:%d getnameinfo() failed = %d\n",
+              source, line, res);
+  }
+  return res;
+}
+
+void curl_dofreeaddrinfo(struct addrinfo *freethis,
+                         int line, const char *source)
+{
+  (freeaddrinfo)(freethis);
+  if(logfile)
+    fprintf(logfile, "ADDR %s:%d freeaddrinfo(%p)\n",
+            source, line, (void *)freethis);
+}
+
+#endif
+
+/*
+ * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
+ * been set and returns TRUE if they are OK.
+ */
+bool Curl_ipvalid(struct SessionHandle *data)
+{
+  if(data->set.ip_version == CURL_IPRESOLVE_V6) {
+    /* see if we have an IPv6 stack */
+    curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
+    if (s == CURL_SOCKET_BAD)
+      /* an ipv6 address was requested and we can't get/use one */
+      return FALSE;
+    sclose(s);
+  }
+  return TRUE;
+}
+
+#ifndef USE_THREADING_GETADDRINFO
+/*
+ * Curl_getaddrinfo() when built ipv6-enabled (non-threading version).
+ *
+ * Returns name information about the given hostname and port number. If
+ * successful, the 'addrinfo' is returned and the forth argument will point to
+ * memory we need to free after use. That memory *MUST* be freed with
+ * Curl_freeaddrinfo(), nothing else.
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+                                char *hostname,
+                                int port,
+                                int *waitp)
+{
+  struct addrinfo hints, *res;
+  int error;
+  char sbuf[NI_MAXSERV];
+  curl_socket_t s;
+  int pf;
+  struct SessionHandle *data = conn->data;
+
+  *waitp=0; /* don't wait, we have the response now */
+
+  /* see if we have an IPv6 stack */
+  s = socket(PF_INET6, SOCK_DGRAM, 0);
+  if (s < 0) {
+    /* Some non-IPv6 stacks have been found to make very slow name resolves
+     * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if
+     * the stack seems to be a non-ipv6 one. */
+
+    pf = PF_INET;
+  }
+  else {
+    /* This seems to be an IPv6-capable stack, use PF_UNSPEC for the widest
+     * possible checks. And close the socket again.
+     */
+    sclose(s);
+
+    /*
+     * Check if a more limited name resolve has been requested.
+     */
+    switch(data->set.ip_version) {
+    case CURL_IPRESOLVE_V4:
+      pf = PF_INET;
+      break;
+    case CURL_IPRESOLVE_V6:
+      pf = PF_INET6;
+      break;
+    default:
+      pf = PF_UNSPEC;
+      break;
+    }
+  }
+ 
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = pf;
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_flags = AI_CANONNAME;
+  snprintf(sbuf, sizeof(sbuf), "%d", port);
+  error = getaddrinfo(hostname, sbuf, &hints, &res);
+  if (error) {
+    infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port);    
+    return NULL;
+  }
+
+  return res;
+}
+#endif /* USE_THREADING_GETADDRINFO */
+#endif /* ipv6 */
+
diff --git a/Utilities/cmcurl/hostsyn.c b/Utilities/cmcurl/hostsyn.c
new file mode 100644
index 0000000..786f9d9
--- /dev/null
+++ b/Utilities/cmcurl/hostsyn.c
@@ -0,0 +1,149 @@
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <string.h>
+#include <errno.h>
+
+#define _REENTRANT
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#include <malloc.h>
+#else
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>     /* required for free() prototypes */
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>     /* for the close() proto */
+#endif
+#ifdef  VMS
+#include <in.h>
+#include <inet.h>
+#include <stdlib.h>
+#endif
+#endif
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#ifdef WIN32
+#include <process.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
+#include "inet_ntoa_r.h"
+#endif
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for builds using synchronous name resolves
+ **********************************************************************/
+#ifdef CURLRES_SYNCH
+
+/*
+ * Curl_wait_for_resolv() for synch-builds.  Curl_resolv() can never return
+ * wait==TRUE, so this function will never be called. If it still gets called,
+ * we return failure at once.
+ *
+ * We provide this function only to allow multi.c to remain unaware if we are
+ * doing asynch resolves or not.
+ */
+CURLcode Curl_wait_for_resolv(struct connectdata *conn,
+                              struct Curl_dns_entry **entry)
+{
+  (void)conn;
+  *entry=NULL;
+  return CURLE_COULDNT_RESOLVE_HOST;
+}
+
+/*
+ * This function will never be called when synch-built. If it still gets
+ * called, we return failure at once.
+ *
+ * We provide this function only to allow multi.c to remain unaware if we are
+ * doing asynch resolves or not.
+ */
+CURLcode Curl_is_resolved(struct connectdata *conn,
+                          struct Curl_dns_entry **dns)
+{
+  (void)conn;
+  *dns = NULL;
+
+  return CURLE_COULDNT_RESOLVE_HOST;
+}
+
+/*
+ * We just return OK, this function is never actually used for synch builds.
+ * It is present here to keep #ifdefs out from multi.c
+ */
+
+CURLcode Curl_fdset(struct connectdata *conn,
+                    fd_set *read_fd_set,
+                    fd_set *write_fd_set,
+                    int *max_fdp)
+{
+  (void)conn;
+  (void)read_fd_set;
+  (void)write_fd_set;
+  (void)max_fdp;
+
+  return CURLE_OK;
+}
+
+#endif /* truly sync */
diff --git a/Utilities/cmcurl/hostthre.c b/Utilities/cmcurl/hostthre.c
new file mode 100644
index 0000000..4f56ccb
--- /dev/null
+++ b/Utilities/cmcurl/hostthre.c
@@ -0,0 +1,551 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <string.h>
+#include <errno.h>
+
+#define _REENTRANT
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#include <malloc.h>
+#else
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>     /* required for free() prototypes */
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>     /* for the close() proto */
+#endif
+#ifdef  VMS
+#include <in.h>
+#include <inet.h>
+#include <stdlib.h>
+#endif
+#endif
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#ifdef WIN32
+#include <process.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "inet_ntop.h"
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for Windows threaded name resolves builds
+ **********************************************************************/
+#ifdef CURLRES_THREADED
+
+/* This function is used to init a threaded resolve */
+static bool init_resolve_thread(struct connectdata *conn,
+                                const char *hostname, int port,
+                                const Curl_addrinfo *hints);
+
+#ifdef CURLRES_IPV4
+  #define THREAD_FUNC  gethostbyname_thread
+  #define THREAD_NAME "gethostbyname_thread"
+#else
+  #define THREAD_FUNC  getaddrinfo_thread
+  #define THREAD_NAME "getaddrinfo_thread"
+#endif
+
+#if defined(DEBUG_THREADING_GETHOSTBYNAME) || \
+    defined(DEBUG_THREADING_GETADDRINFO)
+/* If this is defined, provide tracing */
+#define TRACE(args)  \
+ do { trace_it("%u: ", __LINE__); trace_it args; } while (0)
+
+static void trace_it (const char *fmt, ...)
+{
+  static int do_trace = -1;
+  va_list args;
+
+  if (do_trace == -1) {
+    const char *env = getenv("CURL_TRACE");
+    do_trace = (env && atoi(env) > 0);
+  }
+  if (!do_trace)
+    return;
+  va_start (args, fmt);
+  vfprintf (stderr, fmt, args);
+  fflush (stderr);
+  va_end (args);
+}
+#else
+#define TRACE(x)
+#endif
+
+#ifdef DEBUG_THREADING_GETADDRINFO
+static void dump_addrinfo (struct connectdata *conn, const struct addrinfo *ai)
+{
+  TRACE(("dump_addrinfo:\n"));
+  for ( ; ai; ai = ai->ai_next) {
+    char  buf [INET6_ADDRSTRLEN];
+
+    trace_it("    fam %2d, CNAME %s, ",
+             ai->ai_family, ai->ai_canonname ? ai->ai_canonname : "<none>");
+    if (Curl_printable_address(ai, buf, sizeof(buf)))
+      trace_it("%s\n", buf);
+    else
+      trace_it("failed; %s\n", Curl_strerror(conn,WSAGetLastError()));
+  }
+}
+#endif
+
+struct thread_data {
+  HANDLE thread_hnd;
+  unsigned thread_id;
+  DWORD  thread_status;
+  curl_socket_t dummy_sock;   /* dummy for Curl_fdset() */
+  FILE *stderr_file;
+#ifdef CURLRES_IPV6
+  struct addrinfo hints;
+#endif
+};
+
+#if defined(CURLRES_IPV4)
+/*
+ * gethostbyname_thread() resolves a name, calls the Curl_addrinfo4_callback
+ * and then exits.
+ *
+ * For builds without ARES/ENABLE_IPV6, create a resolver thread and wait on
+ * it.
+ */
+static unsigned __stdcall gethostbyname_thread (void *arg)
+{
+  struct connectdata *conn = (struct connectdata*) arg;
+  struct thread_data *td = (struct thread_data*) conn->async.os_specific;
+  struct hostent *he;
+  int    rc;
+
+  /* Sharing the same _iob[] element with our parent thread should
+   * hopefully make printouts synchronised. I'm not sure it works
+   * with a static runtime lib (MSVC's libc.lib).
+   */
+  *stderr = *td->stderr_file;
+
+  WSASetLastError (conn->async.status = NO_DATA); /* pending status */
+  he = gethostbyname (conn->async.hostname);
+  if (he) {
+    Curl_addrinfo4_callback(conn, CURL_ASYNC_SUCCESS, he);
+    rc = 1;
+  }
+  else {
+    Curl_addrinfo4_callback(conn, (int)WSAGetLastError(), NULL);
+    rc = 0;
+  }
+  TRACE(("Winsock-error %d, addr %s\n", conn->async.status,
+         he ? inet_ntoa(*(struct in_addr*)he->h_addr) : "unknown"));
+  return (rc);
+  /* An implicit _endthreadex() here */
+}
+
+#elif defined(CURLRES_IPV6)
+
+/*
+ * getaddrinfo_thread() resolves a name, calls Curl_addrinfo6_callback and then
+ * exits.
+ *
+ * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
+ * and wait on it.
+ */
+static unsigned __stdcall getaddrinfo_thread (void *arg)
+{
+  struct connectdata *conn = (struct connectdata*) arg;
+  struct thread_data *td   = (struct thread_data*) conn->async.os_specific;
+  struct addrinfo    *res;
+  char   service [NI_MAXSERV];
+  int    rc;
+
+  *stderr = *td->stderr_file;
+
+  itoa(conn->async.port, service, 10);
+
+  WSASetLastError(conn->async.status = NO_DATA); /* pending status */
+
+  rc = getaddrinfo(conn->async.hostname, service, &td->hints, &res);
+
+  if (rc == 0) {
+#ifdef DEBUG_THREADING_GETADDRINFO
+    dump_addrinfo (conn, res);
+#endif
+    Curl_addrinfo6_callback(conn, CURL_ASYNC_SUCCESS, res);
+  }
+  else {
+    Curl_addrinfo6_callback(conn, (int)WSAGetLastError(), NULL);
+    TRACE(("Winsock-error %d, no address\n", conn->async.status));
+  }
+  return (rc);
+  /* An implicit _endthreadex() here */
+}
+#endif
+
+/*
+ * destroy_thread_data() cleans up async resolver data.
+ * Complementary of ares_destroy.
+ */
+static void destroy_thread_data (struct Curl_async *async)
+{
+  if (async->hostname)
+    free(async->hostname);
+
+  if (async->os_specific) {
+    curl_socket_t sock = ((const struct thread_data*)async->os_specific)->dummy_sock;
+
+    if (sock != CURL_SOCKET_BAD)
+      sclose(sock);
+    free(async->os_specific);
+  }
+  async->hostname = NULL;
+  async->os_specific = NULL;
+}
+
+/*
+ * init_resolve_thread() starts a new thread that performs the actual
+ * resolve. This function returns before the resolve is done.
+ *
+ * Returns FALSE in case of failure, otherwise TRUE.
+ */
+static bool init_resolve_thread (struct connectdata *conn,
+                                 const char *hostname, int port,
+                                 const Curl_addrinfo *hints)
+{
+  struct thread_data *td = calloc(sizeof(*td), 1);
+
+  if (!td) {
+    SetLastError(ENOMEM);
+    return FALSE;
+  }
+
+  Curl_safefree(conn->async.hostname);
+  conn->async.hostname = strdup(hostname);
+  if (!conn->async.hostname) {
+    free(td);
+    SetLastError(ENOMEM);
+    return FALSE;
+  }
+
+  conn->async.port = port;
+  conn->async.done = FALSE;
+  conn->async.status = 0;
+  conn->async.dns = NULL;
+  conn->async.os_specific = (void*) td;
+
+  td->dummy_sock = CURL_SOCKET_BAD;
+  td->stderr_file = stderr;
+  td->thread_hnd = (HANDLE) _beginthreadex(NULL, 0, THREAD_FUNC,
+                                           conn, 0, &td->thread_id);
+#ifdef CURLRES_IPV6
+  curlassert(hints);
+  td->hints = *hints;
+#else
+  (void) hints;
+#endif
+
+  if (!td->thread_hnd) {
+     SetLastError(errno);
+     TRACE(("_beginthreadex() failed; %s\n", Curl_strerror(conn,errno)));
+     destroy_thread_data(&conn->async);
+     return FALSE;
+  }
+  /* This socket is only to keep Curl_fdset() and select() happy; should never
+   * become signalled for read/write since it's unbound but Windows needs
+   * atleast 1 socket in select().
+   */
+  td->dummy_sock = socket(AF_INET, SOCK_DGRAM, 0);
+  return TRUE;
+}
+
+
+/*
+ * Curl_wait_for_resolv() waits for a resolve to finish. This function should
+ * be avoided since using this risk getting the multi interface to "hang".
+ *
+ * If 'entry' is non-NULL, make it point to the resolved dns entry
+ *
+ * This is the version for resolves-in-a-thread.
+ */
+CURLcode Curl_wait_for_resolv(struct connectdata *conn,
+                              struct Curl_dns_entry **entry)
+{
+  struct thread_data   *td = (struct thread_data*) conn->async.os_specific;
+  struct SessionHandle *data = conn->data;
+  long   timeout;
+  DWORD  status, ticks;
+  CURLcode rc;
+
+  curlassert (conn && td);
+
+  /* now, see if there's a connect timeout or a regular timeout to
+     use instead of the default one */
+  timeout =
+    conn->data->set.connecttimeout ? conn->data->set.connecttimeout :
+    conn->data->set.timeout ? conn->data->set.timeout :
+    CURL_TIMEOUT_RESOLVE; /* default name resolve timeout */
+  ticks = GetTickCount();
+  (void)ticks;
+
+  status = WaitForSingleObject(td->thread_hnd, 1000UL*timeout);
+  if (status == WAIT_OBJECT_0 || status == WAIT_ABANDONED) {
+     /* Thread finished before timeout; propagate Winsock error to this thread.
+      * 'conn->async.done = TRUE' is set in Curl_addrinfo4/6_callback().
+      */
+     WSASetLastError(conn->async.status);
+     GetExitCodeThread(td->thread_hnd, &td->thread_status);
+     TRACE(("%s() status %lu, thread retval %lu, ",
+            THREAD_NAME, status, td->thread_status));
+  }
+  else {
+     conn->async.done = TRUE;
+     td->thread_status = (DWORD)-1;
+     TRACE(("%s() timeout, ", THREAD_NAME));
+  }
+
+  TRACE(("elapsed %lu ms\n", GetTickCount()-ticks));
+
+  CloseHandle(td->thread_hnd);
+
+  if(entry)
+    *entry = conn->async.dns;
+
+  rc = CURLE_OK;
+
+  if (!conn->async.dns) {
+    /* a name was not resolved */
+    if (td->thread_status == (DWORD)-1 || conn->async.status == NO_DATA) {
+      failf(data, "Resolving host timed out: %s", conn->host.name);
+      rc = CURLE_OPERATION_TIMEDOUT;
+    }
+    else if(conn->async.done) {
+      failf(data, "Could not resolve host: %s; %s",
+            conn->host.name, Curl_strerror(conn,conn->async.status));
+      rc = CURLE_COULDNT_RESOLVE_HOST;
+    }
+    else
+      rc = CURLE_OPERATION_TIMEDOUT;
+  }
+
+  destroy_thread_data(&conn->async);
+
+  if(CURLE_OK != rc)
+    /* close the connection, since we must not return failure from here
+       without cleaning up this connection properly */
+    Curl_disconnect(conn);
+
+  return (rc);
+}
+
+/*
+ * Curl_is_resolved() is called repeatedly to check if a previous name resolve
+ * request has completed. It should also make sure to time-out if the
+ * operation seems to take too long.
+ */
+CURLcode Curl_is_resolved(struct connectdata *conn,
+                          struct Curl_dns_entry **entry)
+{
+  *entry = NULL;
+
+  if (conn->async.done) {
+    /* we're done */
+    destroy_thread_data(&conn->async);
+    if (!conn->async.dns) {
+      TRACE(("Curl_is_resolved(): CURLE_COULDNT_RESOLVE_HOST\n"));
+      return CURLE_COULDNT_RESOLVE_HOST;
+    }
+    *entry = conn->async.dns;
+    TRACE(("resolved okay, dns %p\n", *entry));
+  }
+  else
+    TRACE(("not yet\n"));
+  return CURLE_OK;
+}
+
+CURLcode Curl_fdset(struct connectdata *conn,
+                    fd_set *read_fd_set,
+                    fd_set *write_fd_set,
+                    int *max_fdp)
+{
+  const struct thread_data *td =
+    (const struct thread_data *) conn->async.os_specific;
+
+  if (td && td->dummy_sock != CURL_SOCKET_BAD) {
+    FD_SET(td->dummy_sock,write_fd_set);
+    *max_fdp = td->dummy_sock;
+  }
+  (void) read_fd_set;
+  return CURLE_OK;
+}
+
+#ifdef CURLRES_IPV4
+/*
+ * Curl_getaddrinfo() - for Windows threading without ENABLE_IPV6.
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+                                char *hostname,
+                                int port,
+                                int *waitp)
+{
+  struct hostent *h;
+  struct SessionHandle *data = conn->data;
+  in_addr_t in;
+
+  *waitp = 0; /* don't wait, we act synchronously */
+
+  in = inet_addr(hostname);
+  if (in != CURL_INADDR_NONE)
+    /* This is a dotted IP address 123.123.123.123-style */
+    return Curl_ip2addr(in, hostname, port);
+
+  /* fire up a new resolver thread! */
+  if (init_resolve_thread(conn, hostname, port, NULL)) {
+    *waitp = TRUE;  /* please wait for the response */
+    return NULL;
+  }
+
+  /* fall-back to blocking version */
+  infof(data, "init_resolve_thread() failed for %s; code %lu\n",
+        hostname, GetLastError());
+
+  h = gethostbyname(hostname);
+  if (!h) {
+    infof(data, "gethostbyname(2) failed for %s:%d; %s\n",
+          hostname, port, Curl_strerror(conn,WSAGetLastError()));
+    return NULL;
+  }
+  return Curl_he2ai(h, port);
+}
+#endif /* CURLRES_IPV4 */
+
+#ifdef CURLRES_IPV6
+/*
+ * Curl_getaddrinfo() - for Windows threading IPv6 enabled
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+                                char *hostname,
+                                int port,
+                                int *waitp)
+{
+  struct addrinfo hints, *res;
+  int error;
+  char sbuf[NI_MAXSERV];
+  curl_socket_t s;
+  int pf;
+  struct SessionHandle *data = conn->data;
+
+  *waitp = FALSE; /* default to synch response */
+
+  /* see if we have an IPv6 stack */
+  s = socket(PF_INET6, SOCK_DGRAM, 0);
+  if (s == CURL_SOCKET_BAD) {
+    /* Some non-IPv6 stacks have been found to make very slow name resolves
+     * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if
+     * the stack seems to be a non-ipv6 one. */
+
+    pf = PF_INET;
+  }
+  else {
+    /* This seems to be an IPv6-capable stack, use PF_UNSPEC for the widest
+     * possible checks. And close the socket again.
+     */
+    sclose(s);
+
+    /*
+     * Check if a more limited name resolve has been requested.
+     */
+    switch(data->set.ip_version) {
+    case CURL_IPRESOLVE_V4:
+      pf = PF_INET;
+      break;
+    case CURL_IPRESOLVE_V6:
+      pf = PF_INET6;
+      break;
+    default:
+      pf = PF_UNSPEC;
+      break;
+    }
+  }
+
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = pf;
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_flags = AI_CANONNAME;
+  itoa(port, sbuf, 10);
+
+  /* fire up a new resolver thread! */
+  if (init_resolve_thread(conn, hostname, port, &hints)) {
+    *waitp = TRUE;  /* please wait for the response */
+    return NULL;
+  }
+
+  /* fall-back to blocking version */
+  infof(data, "init_resolve_thread() failed for %s; code %lu\n",
+        hostname, GetLastError());
+
+  error = getaddrinfo(hostname, sbuf, &hints, &res);
+  if (error) {
+    infof(data, "getaddrinfo() failed for %s:%d; %s\n",
+          hostname, port, Curl_strerror(conn,WSAGetLastError()));
+    return NULL;
+  }
+  return res;
+}
+#endif /* CURLRES_IPV6 */
+#endif /* CURLRES_THREADED */
diff --git a/Utilities/cmcurl/http.c b/Utilities/cmcurl/http.c
new file mode 100644
index 0000000..7cf543b
--- /dev/null
+++ b/Utilities/cmcurl/http.c
@@ -0,0 +1,1996 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#ifndef CURL_DISABLE_HTTP
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#include <time.h>
+#include <io.h>
+#else
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#include <sys/time.h>
+
+#ifdef HAVE_TIME_H
+#ifdef TIME_WITH_SYS_TIME
+#include <time.h>
+#endif
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <netdb.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#include <sys/ioctl.h>
+#include <signal.h>
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "formdata.h"
+#include "progress.h"
+#include "base64.h"
+#include "cookie.h"
+#include "strequal.h"
+#include "ssluse.h"
+#include "http_digest.h"
+#include "http_ntlm.h"
+#include "http_negotiate.h"
+#include "url.h"
+#include "share.h"
+#include "hostip.h"
+#include "http.h"
+#include "curl_memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * checkheaders() checks the linked list of custom HTTP headers for a
+ * particular header (prefix).
+ *
+ * Returns a pointer to the first matching header or NULL if none matched.
+ */
+static char *checkheaders(struct SessionHandle *data, const char *thisheader)
+{
+  struct curl_slist *head;
+  size_t thislen = strlen(thisheader);
+
+  for(head = data->set.headers; head; head=head->next) {
+    if(strnequal(head->data, thisheader, thislen))
+      return head->data;
+  }
+  return NULL;
+}
+
+/*
+ * Curl_output_basic() sets up an Authorization: header (or the proxy version)
+ * for HTTP Basic authentication.
+ *
+ * Returns CURLcode.
+ */
+static CURLcode Curl_output_basic(struct connectdata *conn, bool proxy)
+{
+  char *authorization;
+  struct SessionHandle *data=conn->data;
+  char **userp;
+  char *user;
+  char *pwd;
+
+  if(proxy) {
+    userp = &conn->allocptr.proxyuserpwd;
+    user = conn->proxyuser;
+    pwd = conn->proxypasswd;
+  }
+  else {
+    userp = &conn->allocptr.userpwd;
+    user = conn->user;
+    pwd = conn->passwd;
+  }
+
+  snprintf(data->state.buffer, sizeof(data->state.buffer), "%s:%s", user, pwd);
+  if(Curl_base64_encode(data->state.buffer,
+                        strlen(data->state.buffer),
+                        &authorization) > 0) {
+    if(*userp)
+      free(*userp);
+    *userp = aprintf( "%sAuthorization: Basic %s\015\012",
+                      proxy?"Proxy-":"",
+                      authorization);
+    free(authorization);
+  }
+  else
+    return CURLE_OUT_OF_MEMORY;
+  return CURLE_OK;
+}
+
+/* pickoneauth() selects the most favourable authentication method from the
+ * ones available and the ones we want.
+ *
+ * return TRUE if one was picked
+ */
+static bool pickoneauth(struct auth *pick)
+{
+  bool picked;
+  /* only deal with authentication we want */
+  long avail = pick->avail & pick->want;
+  picked = TRUE;
+
+  /* The order of these checks is highly relevant, as this will be the order
+     of preference in case of the existance of multiple accepted types. */
+  if(avail & CURLAUTH_GSSNEGOTIATE)
+    pick->picked = CURLAUTH_GSSNEGOTIATE;
+  else if(avail & CURLAUTH_DIGEST)
+    pick->picked = CURLAUTH_DIGEST;
+  else if(avail & CURLAUTH_NTLM)
+    pick->picked = CURLAUTH_NTLM;
+  else if(avail & CURLAUTH_BASIC)
+    pick->picked = CURLAUTH_BASIC;
+  else {
+    pick->picked = CURLAUTH_PICKNONE; /* we select to use nothing */
+    picked = FALSE;
+  }
+  pick->avail = CURLAUTH_NONE; /* clear it here */
+
+  return picked;
+}
+
+/*
+ * Curl_http_auth_act() gets called when a all HTTP headers have been received
+ * and it checks what authentication methods that are available and decides
+ * which one (if any) to use. It will set 'newurl' if an auth metod was
+ * picked.
+ */
+
+CURLcode Curl_http_auth_act(struct connectdata *conn)
+{
+  struct SessionHandle *data = conn->data;
+  bool pickhost = FALSE;
+  bool pickproxy = FALSE;
+  CURLcode code = CURLE_OK;
+
+  if(data->state.authproblem)
+    return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK;
+
+  if(conn->bits.user_passwd &&
+     ((conn->keep.httpcode == 401) ||
+      (conn->bits.authprobe && conn->keep.httpcode < 300))) {
+    pickhost = pickoneauth(&data->state.authhost);
+    if(!pickhost)
+      data->state.authproblem = TRUE;
+  }
+  if(conn->bits.proxy_user_passwd &&
+     ((conn->keep.httpcode == 407) ||
+      (conn->bits.authprobe && conn->keep.httpcode < 300))) {
+    pickproxy = pickoneauth(&data->state.authproxy);
+    if(!pickproxy)
+      data->state.authproblem = TRUE;
+  }
+
+  if(pickhost || pickproxy)
+    conn->newurl = strdup(data->change.url); /* clone URL */
+
+  else if((conn->keep.httpcode < 300) &&
+          (!data->state.authhost.done) &&
+          conn->bits.authprobe) {
+    /* no (known) authentication available,
+       authentication is not "done" yet and
+       no authentication seems to be required and
+       we didn't try HEAD or GET */
+    if((data->set.httpreq != HTTPREQ_GET) &&
+       (data->set.httpreq != HTTPREQ_HEAD)) {
+      conn->newurl = strdup(data->change.url); /* clone URL */
+      data->state.authhost.done = TRUE;
+    }
+  }
+  if (Curl_http_should_fail(conn)) {
+    failf (data, "The requested URL returned error: %d",
+           conn->keep.httpcode);
+    code = CURLE_HTTP_RETURNED_ERROR;
+  }
+
+  return code;
+}
+
+/**
+ * Curl_http_output_auth() setups the authentication headers for the
+ * host/proxy and the correct authentication
+ * method. conn->data->state.authdone is set to TRUE when authentication is
+ * done.
+ *
+ * @param conn all information about the current connection
+ * @param request pointer to the request keyword
+ * @param path pointer to the requested path
+ * @param proxytunnel boolean if this is the request setting up a "proxy
+ * tunnel"
+ *
+ * @returns CURLcode
+ */
+static CURLcode
+Curl_http_output_auth(struct connectdata *conn,
+                      char *request,
+                      char *path,
+                      bool proxytunnel) /* TRUE if this is the request setting
+                                           up the proxy tunnel */
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  char *auth=NULL;
+
+  curlassert(data);
+
+  if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
+     conn->bits.user_passwd)
+    /* continue please */ ;
+  else {
+    data->state.authhost.done = TRUE;
+    data->state.authproxy.done = TRUE;
+    return CURLE_OK; /* no authentication with no user or password */
+  }
+
+  if(data->state.authhost.want && !data->state.authhost.picked)
+    /* The app has selected one or more methods, but none has been picked
+       so far by a server round-trip. Then we set the picked one to the
+       want one, and if this is one single bit it'll be used instantly. */
+    data->state.authhost.picked = data->state.authhost.want;
+
+  if(data->state.authproxy.want && !data->state.authproxy.picked)
+    /* The app has selected one or more methods, but none has been picked so
+       far by a proxy round-trip. Then we set the picked one to the want one,
+       and if this is one single bit it'll be used instantly. */
+    data->state.authproxy.picked = data->state.authproxy.want;
+
+  /* To prevent the user+password to get sent to other than the original
+     host due to a location-follow, we do some weirdo checks here */
+  if(!data->state.this_is_a_follow ||
+     !data->state.auth_host ||
+     curl_strequal(data->state.auth_host, conn->host.name) ||
+     data->set.http_disable_hostname_check_before_authentication) {
+
+    /* Send proxy authentication header if needed */
+    if (conn->bits.httpproxy &&
+        (conn->bits.tunnel_proxy == proxytunnel)) {
+#ifdef USE_SSLEAY
+      if(data->state.authproxy.want == CURLAUTH_NTLM) {
+        auth=(char *)"NTLM";
+        result = Curl_output_ntlm(conn, TRUE);
+        if(result)
+          return result;
+      }
+      else
+#endif
+      if(data->state.authproxy.want == CURLAUTH_BASIC) {
+        /* Basic */
+        if(conn->bits.proxy_user_passwd &&
+           !checkheaders(data, "Proxy-authorization:")) {
+          auth=(char *)"Basic";
+          result = Curl_output_basic(conn, TRUE);
+          if(result)
+            return result;
+        }
+        data->state.authproxy.done = TRUE;
+      }
+      else if(data->state.authproxy.want == CURLAUTH_DIGEST) {
+        auth=(char *)"Digest";
+        result = Curl_output_digest(conn,
+                                    TRUE, /* proxy */
+                                    (unsigned char *)request,
+                                    (unsigned char *)path);
+        if(result)
+          return result;
+      }
+
+      infof(data, "Proxy auth using %s with user '%s'\n",
+            auth, conn->proxyuser?conn->proxyuser:"");
+    }
+    else
+      /* we have no proxy so let's pretend we're done authenticating
+         with it */
+      data->state.authproxy.done = TRUE;
+
+    /* Send web authentication header if needed */
+    {
+      auth = NULL;
+#ifdef HAVE_GSSAPI
+      if((data->state.authhost.want == CURLAUTH_GSSNEGOTIATE) &&
+         data->state.negotiate.context &&
+         !GSS_ERROR(data->state.negotiate.status)) {
+        auth=(char *)"GSS-Negotiate";
+        result = Curl_output_negotiate(conn);
+        if (result)
+          return result;
+        data->state.authhost.done = TRUE;
+      }
+      else
+#endif
+#ifdef USE_SSLEAY
+      if(data->state.authhost.picked == CURLAUTH_NTLM) {
+        auth=(char *)"NTLM";
+        result = Curl_output_ntlm(conn, FALSE);
+        if(result)
+          return result;
+      }
+      else
+#endif
+      {
+        if(data->state.authhost.picked == CURLAUTH_DIGEST) {
+          auth=(char *)"Digest";
+          result = Curl_output_digest(conn,
+                                      FALSE, /* not a proxy */
+                                      (unsigned char *)request,
+                                      (unsigned char *)path);
+          if(result)
+            return result;
+        }
+        else if(data->state.authhost.picked == CURLAUTH_BASIC) {
+          if(conn->bits.user_passwd &&
+             !checkheaders(data, "Authorization:")) {
+            auth=(char *)"Basic";
+            result = Curl_output_basic(conn, FALSE);
+            if(result)
+              return result;
+          }
+          /* basic is always ready */
+          data->state.authhost.done = TRUE;
+        }
+      }
+      if(auth)
+        infof(data, "Server auth using %s with user '%s'\n",
+              auth, conn->user);
+    }
+  }
+  else
+    data->state.authhost.done = TRUE;
+
+  return result;
+}
+
+
+/*
+ * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
+ * headers. They are dealt with both in the transfer.c main loop and in the
+ * proxy CONNECT loop.
+ */
+
+CURLcode Curl_http_input_auth(struct connectdata *conn,
+                              int httpcode,
+                              char *header) /* the first non-space */
+{
+  /*
+   * This resource requires authentication
+   */
+  struct SessionHandle *data = conn->data;
+
+  long *availp;
+  char *start;
+  struct auth *authp;
+
+  if (httpcode == 407) {
+    start = header+strlen("Proxy-authenticate:");
+    availp = &data->info.proxyauthavail;
+    authp = &data->state.authproxy;
+  }
+  else {
+    start = header+strlen("WWW-Authenticate:");
+    availp = &data->info.httpauthavail;
+    authp = &data->state.authhost;
+  }
+
+  /* pass all white spaces */
+  while(*start && isspace((int)*start))
+    start++;
+
+  /*
+   * Here we check if we want the specific single authentiction (using ==) and
+   * if we do, we initiate usage of it.
+   *
+   * If the provided authentication is wanted as one out of several accepted
+   * types (using &), we OR this authenticaion type to the authavail
+   * variable.
+   */
+
+#ifdef HAVE_GSSAPI
+  if (checkprefix("GSS-Negotiate", start) ||
+      checkprefix("Negotiate", start)) {
+    *availp |= CURLAUTH_GSSNEGOTIATE;
+    authp->avail |= CURLAUTH_GSSNEGOTIATE;
+    if(authp->picked == CURLAUTH_GSSNEGOTIATE) {
+      /* if exactly this is wanted, go */
+      int neg = Curl_input_negotiate(conn, start);
+      if (neg == 0) {
+        conn->newurl = strdup(data->change.url);
+        data->state.authproblem = (conn->newurl == NULL);
+      }
+      else {
+        infof(data, "Authentication problem. Ignoring this.\n");
+        data->state.authproblem = TRUE;
+      }
+    }
+  }
+  else
+#endif
+#ifdef USE_SSLEAY
+    /* NTLM support requires the SSL crypto libs */
+    if(checkprefix("NTLM", start)) {
+      *availp |= CURLAUTH_NTLM;
+      authp->avail |= CURLAUTH_NTLM;
+      if(authp->picked == CURLAUTH_NTLM) {
+        /* NTLM authentication is picked and activated */
+        CURLntlm ntlm =
+          Curl_input_ntlm(conn, (bool)(httpcode == 407), start);
+
+        if(CURLNTLM_BAD != ntlm)
+          data->state.authproblem = FALSE;
+        else {
+          infof(data, "Authentication problem. Ignoring this.\n");
+          data->state.authproblem = TRUE;
+        }
+      }
+    }
+    else
+#endif
+      if(checkprefix("Digest", start)) {
+        CURLdigest dig;
+        *availp |= CURLAUTH_DIGEST;
+        authp->avail |= CURLAUTH_DIGEST;
+
+        /* We call this function on input Digest headers even if Digest
+         * authentication isn't activated yet, as we need to store the
+         * incoming data from this header in case we are gonna use Digest. */
+        dig = Curl_input_digest(conn, (bool)(httpcode == 407), start);
+
+        if(CURLDIGEST_FINE != dig) {
+          infof(data, "Authentication problem. Ignoring this.\n");
+          data->state.authproblem = TRUE;
+        }
+      }
+      else if(checkprefix("Basic", start)) {
+        *availp |= CURLAUTH_BASIC;
+        authp->avail |= CURLAUTH_BASIC;
+        if(authp->picked == CURLAUTH_BASIC) {
+          /* We asked for Basic authentication but got a 40X back
+             anyway, which basicly means our name+password isn't
+             valid. */
+          authp->avail = CURLAUTH_NONE;
+          infof(data, "Authentication problem. Ignoring this.\n");
+          data->state.authproblem = TRUE;
+        }
+      }
+
+  return CURLE_OK;
+}
+
+/**
+ * Curl_http_should_fail() determines whether an HTTP response has gotten us
+ * into an error state or not.
+ *
+ * @param conn all information about the current connection
+ *
+ * @retval 0 communications should continue
+ *
+ * @retval 1 communications should not continue
+ */
+int Curl_http_should_fail(struct connectdata *conn)
+{
+  struct SessionHandle *data;
+  struct Curl_transfer_keeper *k;
+
+  curlassert(conn);
+  data = conn->data;
+  curlassert(data);
+
+  /*
+  ** For readability
+  */
+  k = &conn->keep;
+
+  /*
+  ** If we haven't been asked to fail on error,
+  ** don't fail.
+  */
+  if (!data->set.http_fail_on_error)
+    return 0;
+
+  /*
+  ** Any code < 400 is never terminal.
+  */
+  if (k->httpcode < 400)
+    return 0;
+
+  /*
+  ** Any code >= 400 that's not 401 or 407 is always
+  ** a terminal error
+  */
+  if ((k->httpcode != 401) &&
+      (k->httpcode != 407))
+    return 1;
+
+  /*
+  ** All we have left to deal with is 401 and 407
+  */
+  curlassert((k->httpcode == 401) || (k->httpcode == 407));
+
+  /*
+  ** Examine the current authentication state to see if this
+  ** is an error.  The idea is for this function to get
+  ** called after processing all the headers in a response
+  ** message.  So, if we've been to asked to authenticate a
+  ** particular stage, and we've done it, we're OK.  But, if
+  ** we're already completely authenticated, it's not OK to
+  ** get another 401 or 407.
+  **
+  ** It is possible for authentication to go stale such that
+  ** the client needs to reauthenticate.  Once that info is
+  ** available, use it here.
+  */
+#if 0 /* set to 1 when debugging this functionality */
+  infof(data,"%s: authstage = %d\n",__FUNCTION__,data->state.authstage);
+  infof(data,"%s: authwant = 0x%08x\n",__FUNCTION__,data->state.authwant);
+  infof(data,"%s: authavail = 0x%08x\n",__FUNCTION__,data->state.authavail);
+  infof(data,"%s: httpcode = %d\n",__FUNCTION__,k->httpcode);
+  infof(data,"%s: authdone = %d\n",__FUNCTION__,data->state.authdone);
+  infof(data,"%s: newurl = %s\n",__FUNCTION__,conn->newurl ? conn->newurl : "(null)");
+  infof(data,"%s: authproblem = %d\n",__FUNCTION__,data->state.authproblem);
+#endif
+
+  /*
+  ** Either we're not authenticating, or we're supposed to
+  ** be authenticating something else.  This is an error.
+  */
+  if((k->httpcode == 401) && !conn->bits.user_passwd)
+    return TRUE;
+  if((k->httpcode == 407) && !conn->bits.proxy_user_passwd)
+    return TRUE;
+
+  return data->state.authproblem;
+}
+
+/*
+ * readmoredata() is a "fread() emulation" to provide POST and/or request
+ * data. It is used when a huge POST is to be made and the entire chunk wasn't
+ * sent in the first send(). This function will then be called from the
+ * transfer.c loop when more data is to be sent to the peer.
+ *
+ * Returns the amount of bytes it filled the buffer with.
+ */
+static size_t readmoredata(char *buffer,
+                           size_t size,
+                           size_t nitems,
+                           void *userp)
+{
+  struct connectdata *conn = (struct connectdata *)userp;
+  struct HTTP *http = conn->proto.http;
+  size_t fullsize = size * nitems;
+
+  if(0 == http->postsize)
+    /* nothing to return */
+    return 0;
+
+  /* make sure that a HTTP request is never sent away chunked! */
+  conn->bits.forbidchunk= (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE;
+
+  if(http->postsize <= (curl_off_t)fullsize) {
+    memcpy(buffer, http->postdata, (size_t)http->postsize);
+    fullsize = (size_t)http->postsize;
+
+    if(http->backup.postsize) {
+      /* move backup data into focus and continue on that */
+      http->postdata = http->backup.postdata;
+      http->postsize = http->backup.postsize;
+      conn->fread =    http->backup.fread;
+      conn->fread_in = http->backup.fread_in;
+
+      http->sending++; /* move one step up */
+
+      http->backup.postsize=0;
+    }
+    else
+      http->postsize = 0;
+
+    return fullsize;
+  }
+
+  memcpy(buffer, http->postdata, fullsize);
+  http->postdata += fullsize;
+  http->postsize -= fullsize;
+
+  return fullsize;
+}
+
+/* ------------------------------------------------------------------------- */
+/*
+ * The add_buffer series of functions are used to build one large memory chunk
+ * from repeated function invokes. Used so that the entire HTTP request can
+ * be sent in one go.
+ */
+
+struct send_buffer {
+  char *buffer;
+  size_t size_max;
+  size_t size_used;
+};
+typedef struct send_buffer send_buffer;
+
+static CURLcode
+ add_buffer(send_buffer *in, const void *inptr, size_t size);
+
+/*
+ * add_buffer_init() sets up and returns a fine buffer struct
+ */
+static
+send_buffer *add_buffer_init(void)
+{
+  send_buffer *blonk;
+  blonk=(send_buffer *)malloc(sizeof(send_buffer));
+  if(blonk) {
+    memset(blonk, 0, sizeof(send_buffer));
+    return blonk;
+  }
+  return NULL; /* failed, go home */
+}
+
+/*
+ * add_buffer_send() sends a buffer and frees all associated memory.
+ *
+ * Returns CURLcode
+ */
+static
+CURLcode add_buffer_send(send_buffer *in,
+                         struct connectdata *conn,
+                         long *bytes_written) /* add the number of sent
+                                                 bytes to this counter */
+{
+  ssize_t amount;
+  CURLcode res;
+  char *ptr;
+  size_t size;
+  struct HTTP *http = conn->proto.http;
+  size_t sendsize;
+  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+
+  /* The looping below is required since we use non-blocking sockets, but due
+     to the circumstances we will just loop and try again and again etc */
+
+  ptr = in->buffer;
+  size = in->size_used;
+
+  if(conn->protocol & PROT_HTTPS) {
+    /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk
+       when we speak HTTPS, as if only a fraction of it is sent now, this data
+       needs to fit into the normal read-callback buffer later on and that
+       buffer is using this size.
+    */
+
+    sendsize= (size > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:size;
+
+    /* OpenSSL is very picky and we must send the SAME buffer pointer to the
+       library when we attempt to re-send this buffer. Sending the same data
+       is not enough, we must use the exact same address. For this reason, we
+       must copy the data to the uploadbuffer first, since that is the buffer
+       we will be using if this send is retried later.
+    */
+    memcpy(conn->data->state.uploadbuffer, ptr, sendsize);
+    ptr = conn->data->state.uploadbuffer;
+  }
+  else
+    sendsize = size;
+
+  res = Curl_write(conn, sockfd, ptr, sendsize, &amount);
+
+  if(CURLE_OK == res) {
+
+    if(conn->data->set.verbose)
+      /* this data _may_ contain binary stuff */
+      Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, amount,
+                 conn->host.dispname);
+
+    *bytes_written += amount;
+
+    if((size_t)amount != size) {
+      /* The whole request could not be sent in one system call. We must queue
+         it up and send it later when we get the chance. We must not loop here
+         and wait until it might work again. */
+
+      size -= amount;
+
+      ptr = in->buffer + amount;
+
+      /* backup the currently set pointers */
+      http->backup.fread = conn->fread;
+      http->backup.fread_in = conn->fread_in;
+      http->backup.postdata = http->postdata;
+      http->backup.postsize = http->postsize;
+
+      /* set the new pointers for the request-sending */
+      conn->fread = (curl_read_callback)readmoredata;
+      conn->fread_in = (void *)conn;
+      http->postdata = ptr;
+      http->postsize = (curl_off_t)size;
+
+      http->send_buffer = in;
+      http->sending = HTTPSEND_REQUEST;
+
+      return CURLE_OK;
+    }
+    http->sending = HTTPSEND_BODY;
+    /* the full buffer was sent, clean up and return */
+  }
+  if(in->buffer)
+    free(in->buffer);
+  free(in);
+
+  return res;
+}
+
+
+/*
+ * add_bufferf() add the formatted input to the buffer.
+ */
+static
+CURLcode add_bufferf(send_buffer *in, const char *fmt, ...)
+{
+  char *s;
+  va_list ap;
+  va_start(ap, fmt);
+  s = vaprintf(fmt, ap); /* this allocs a new string to append */
+  va_end(ap);
+
+  if(s) {
+    CURLcode result = add_buffer(in, s, strlen(s));
+    free(s);
+    if(CURLE_OK == result)
+      return CURLE_OK;
+  }
+  /* If we failed, we cleanup the whole buffer and return error */
+  if(in->buffer)
+    free(in->buffer);
+  free(in);
+  return CURLE_OUT_OF_MEMORY;
+}
+
+/*
+ * add_buffer() appends a memory chunk to the existing buffer
+ */
+static
+CURLcode add_buffer(send_buffer *in, const void *inptr, size_t size)
+{
+  char *new_rb;
+  size_t new_size;
+
+  if(!in->buffer ||
+     ((in->size_used + size) > (in->size_max - 1))) {
+    new_size = (in->size_used+size)*2;
+    if(in->buffer)
+      /* we have a buffer, enlarge the existing one */
+      new_rb = (char *)realloc(in->buffer, new_size);
+    else
+      /* create a new buffer */
+      new_rb = (char *)malloc(new_size);
+
+    if(!new_rb)
+      return CURLE_OUT_OF_MEMORY;
+
+    in->buffer = new_rb;
+    in->size_max = new_size;
+  }
+  memcpy(&in->buffer[in->size_used], inptr, size);
+
+  in->size_used += size;
+
+  return CURLE_OK;
+}
+
+/* end of the add_buffer functions */
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Curl_compareheader()
+ *
+ * Returns TRUE if 'headerline' contains the 'header' with given 'content'.
+ * Pass headers WITH the colon.
+ */
+bool
+Curl_compareheader(char *headerline,    /* line to check */
+                   const char *header,  /* header keyword _with_ colon */
+                   const char *content) /* content string to find */
+{
+  /* RFC2616, section 4.2 says: "Each header field consists of a name followed
+   * by a colon (":") and the field value. Field names are case-insensitive.
+   * The field value MAY be preceded by any amount of LWS, though a single SP
+   * is preferred." */
+
+  size_t hlen = strlen(header);
+  size_t clen;
+  size_t len;
+  char *start;
+  char *end;
+
+  if(!strnequal(headerline, header, hlen))
+    return FALSE; /* doesn't start with header */
+
+  /* pass the header */
+  start = &headerline[hlen];
+
+  /* pass all white spaces */
+  while(*start && isspace((int)*start))
+    start++;
+
+  /* find the end of the header line */
+  end = strchr(start, '\r'); /* lines end with CRLF */
+  if(!end) {
+    /* in case there's a non-standard compliant line here */
+    end = strchr(start, '\n');
+
+    if(!end)
+      /* hm, there's no line ending here, use the zero byte! */
+      end = strchr(start, '\0');
+  }
+
+  len = end-start; /* length of the content part of the input line */
+  clen = strlen(content); /* length of the word to find */
+
+  /* find the content string in the rest of the line */
+  for(;len>=clen;len--, start++) {
+    if(strnequal(start, content, clen))
+      return TRUE; /* match! */
+  }
+
+  return FALSE; /* no match */
+}
+
+/*
+ * ConnectHTTPProxyTunnel() requires that we're connected to a HTTP proxy. This
+ * function will issue the necessary commands to get a seamless tunnel through
+ * this proxy. After that, the socket can be used just as a normal socket.
+ */
+
+CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
+                                     int sockindex,
+                                     char *hostname,
+                                     int remote_port)
+{
+  int subversion=0;
+  struct SessionHandle *data=conn->data;
+  struct Curl_transfer_keeper *k = &conn->keep;
+  CURLcode result;
+  int res;
+
+  size_t nread;   /* total size read */
+  int perline; /* count bytes per line */
+  bool keepon=TRUE;
+  ssize_t gotbytes;
+  char *ptr;
+  long timeout; /* default timeout in seconds */
+  struct timeval interval;
+  fd_set rkeepfd;
+  fd_set readfd;
+  char *line_start;
+  char *host_port;
+  curl_socket_t tunnelsocket = conn->sock[sockindex];
+
+#define SELECT_OK      0
+#define SELECT_ERROR   1
+#define SELECT_TIMEOUT 2
+  int error = SELECT_OK;
+
+  infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port);
+
+  do {
+    if(conn->newurl) {
+      /* This only happens if we've looped here due to authentication reasons,
+         and we don't really use the newly cloned URL here then. Just free()
+         it. */
+      free(conn->newurl);
+      conn->newurl = NULL;
+    }
+
+    host_port = aprintf("%s:%d", hostname, remote_port);
+    if(!host_port)
+      return CURLE_OUT_OF_MEMORY;
+
+    /* Setup the proxy-authorization header, if any */
+    result = Curl_http_output_auth(conn, (char *)"CONNECT", host_port, TRUE);
+    if(CURLE_OK == result) {
+
+      /* OK, now send the connect request to the proxy */
+      result =
+        Curl_sendf(tunnelsocket, conn,
+                   "CONNECT %s:%d HTTP/1.0\015\012"
+                   "%s"
+                   "%s"
+                   "\r\n",
+                   hostname, remote_port,
+                   conn->bits.proxy_user_passwd?
+                   conn->allocptr.proxyuserpwd:"",
+                   data->set.useragent?conn->allocptr.uagent:""
+                   );
+      if(result)
+        failf(data, "Failed sending CONNECT to proxy");
+    }
+    free(host_port);
+    if(result)
+      return result;
+
+    FD_ZERO (&readfd);          /* clear it */
+    FD_SET (tunnelsocket, &readfd);     /* read socket */
+
+    /* get this in a backup variable to be able to restore it on each lap in
+       the select() loop */
+    rkeepfd = readfd;
+
+    ptr=data->state.buffer;
+    line_start = ptr;
+
+    nread=0;
+    perline=0;
+
+    while((nread<BUFSIZE) && (keepon && !error)) {
+      readfd = rkeepfd;     /* set every lap */
+      interval.tv_sec = 1;  /* timeout each second and check the timeout */
+      interval.tv_usec = 0;
+
+      if(data->set.timeout) {
+        /* if timeout is requested, find out how much remaining time we have */
+        timeout = data->set.timeout - /* timeout time */
+          Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
+        if(timeout <=0 ) {
+          failf(data, "Proxy connection aborted due to timeout");
+          error = SELECT_TIMEOUT; /* already too little time */
+          break;
+        }
+      }
+
+      switch (select (tunnelsocket+1, &readfd, NULL, NULL, &interval)) {
+      case -1: /* select() error, stop reading */
+        error = SELECT_ERROR;
+        failf(data, "Proxy CONNECT aborted due to select() error");
+        break;
+      case 0: /* timeout */
+        break;
+      default:
+        /*
+         * This code previously didn't use the kerberos sec_read() code
+         * to read, but when we use Curl_read() it may do so. Do confirm
+         * that this is still ok and then remove this comment!
+         */
+        res= Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread, &gotbytes);
+        if(res< 0)
+          /* EWOULDBLOCK */
+          continue; /* go loop yourself */
+        else if(res)
+          keepon = FALSE;
+        else if(gotbytes <= 0) {
+          keepon = FALSE;
+          error = SELECT_ERROR;
+          failf(data, "Proxy CONNECT aborted");
+        }
+        else {
+          /*
+           * We got a whole chunk of data, which can be anything from one byte
+           * to a set of lines and possibly just a piece of the last line.
+           *
+           * TODO: To make this code work less error-prone, we need to make
+           * sure that we read and create full lines before we compare them,
+           * as there is really nothing that stops the proxy from delivering
+           * the response lines in multiple parts, each part consisting of
+           * only a little piece of the line(s).  */
+          int i;
+
+          nread += gotbytes;
+          for(i = 0; i < gotbytes; ptr++, i++) {
+            perline++; /* amount of bytes in this line so far */
+            if(*ptr=='\n') {
+              char letter;
+              int writetype;
+
+              /* output debug output if that is requested */
+              if(data->set.verbose)
+                Curl_debug(data, CURLINFO_HEADER_IN, line_start, perline,
+                           conn->host.dispname);
+
+              /* send the header to the callback */
+              writetype = CLIENTWRITE_HEADER;
+              if(data->set.include_header)
+                writetype |= CLIENTWRITE_BODY;
+
+              result = Curl_client_write(data, writetype, line_start, perline);
+              if(result)
+                return result;
+
+              /* Newlines are CRLF, so the CR is ignored as the line isn't
+                 really terminated until the LF comes. Treat a following CR
+                 as end-of-headers as well.*/
+
+              if(('\r' == line_start[0]) ||
+                 ('\n' == line_start[0])) {
+                /* end of response-headers from the proxy */
+                keepon=FALSE;
+                break; /* breaks out of for-loop, not switch() */
+              }
+
+              /* keep a backup of the position we are about to blank */
+              letter = line_start[perline];
+              line_start[perline]=0; /* zero terminate the buffer */
+              if((checkprefix("WWW-Authenticate:", line_start) &&
+                  (401 == k->httpcode)) ||
+                 (checkprefix("Proxy-authenticate:", line_start) &&
+                  (407 == k->httpcode))) {
+                result = Curl_http_input_auth(conn, k->httpcode, line_start);
+                if(result)
+                  return result;
+              }
+              else if(2 == sscanf(line_start, "HTTP/1.%d %d",
+                                  &subversion,
+                                  &k->httpcode)) {
+                /* store the HTTP code from the proxy */
+                data->info.httpproxycode = k->httpcode;
+              }
+              /* put back the letter we blanked out before */
+              line_start[perline]= letter;
+
+              perline=0; /* line starts over here */
+              line_start = ptr+1; /* this skips the zero byte we wrote */
+            }
+          }
+        }
+        break;
+      } /* switch */
+    } /* while there's buffer left and loop is requested */
+
+    if(error)
+      return CURLE_RECV_ERROR;
+
+    if(data->info.httpproxycode != 200)
+      /* Deal with the possibly already received authenticate
+         headers. 'newurl' is set to a new URL if we must loop. */
+      Curl_http_auth_act(conn);
+
+  } while(conn->newurl);
+
+  if(200 != k->httpcode) {
+    failf(data, "Received HTTP code %d from proxy after CONNECT",
+          k->httpcode);
+    return CURLE_RECV_ERROR;
+  }
+
+  /* If a proxy-authorization header was used for the proxy, then we should
+     make sure that it isn't accidentally used for the document request
+     after we've connected. So let's free and clear it here. */
+  Curl_safefree(conn->allocptr.proxyuserpwd);
+  conn->allocptr.proxyuserpwd = NULL;
+
+  data->state.authproxy.done = TRUE;
+
+  infof (data, "Proxy replied OK to CONNECT request\n");
+  return CURLE_OK;
+}
+
+/*
+ * Curl_http_connect() performs HTTP stuff to do at connect-time, called from
+ * the generic Curl_connect().
+ */
+CURLcode Curl_http_connect(struct connectdata *conn)
+{
+  struct SessionHandle *data;
+  CURLcode result;
+
+  data=conn->data;
+
+  /* If we are not using a proxy and we want a secure connection, perform SSL
+   * initialization & connection now.  If using a proxy with https, then we
+   * must tell the proxy to CONNECT to the host we want to talk to.  Only
+   * after the connect has occured, can we start talking SSL
+   */
+
+  if(conn->bits.tunnel_proxy) {
+
+    /* either SSL over proxy, or explicitly asked for */
+    result = Curl_ConnectHTTPProxyTunnel(conn, FIRSTSOCKET,
+                                         conn->host.name,
+                                         conn->remote_port);
+    if(CURLE_OK != result)
+      return result;
+  }
+
+  if(conn->protocol & PROT_HTTPS) {
+    /* now, perform the SSL initialization for this socket */
+    result = Curl_SSLConnect(conn, FIRSTSOCKET);
+    if(result)
+      return result;
+  }
+
+  if(conn->bits.user_passwd && !data->state.this_is_a_follow) {
+    /* Authorization: is requested, this is not a followed location, get the
+       original host name */
+    if (data->state.auth_host)
+      /* Free to avoid leaking memory on multiple requests*/
+      free(data->state.auth_host);
+
+    data->state.auth_host = strdup(conn->host.name);
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_http_done() gets called from Curl_done() after a single HTTP request
+ * has been performed.
+ */
+
+CURLcode Curl_http_done(struct connectdata *conn,
+                        CURLcode status)
+{
+  struct SessionHandle *data;
+  struct HTTP *http;
+  (void)status; /* no use for us */
+
+  data=conn->data;
+  http=conn->proto.http;
+
+  /* set the proper values (possibly modified on POST) */
+  conn->fread = data->set.fread; /* restore */
+  conn->fread_in = data->set.in; /* restore */
+
+  if (http == NULL)
+    return CURLE_OK;
+
+  if(http->send_buffer) {
+    send_buffer *buff = http->send_buffer;
+
+    free(buff->buffer);
+    free(buff);
+    http->send_buffer = NULL; /* cleaer the pointer */
+  }
+
+  if(HTTPREQ_POST_FORM == data->set.httpreq) {
+    conn->bytecount = http->readbytecount + http->writebytecount;
+
+    Curl_formclean(http->sendit); /* Now free that whole lot */
+  }
+  else if(HTTPREQ_PUT == data->set.httpreq)
+    conn->bytecount = http->readbytecount + http->writebytecount;
+
+  if(!conn->bits.retry &&
+     ((http->readbytecount +
+       conn->headerbytecount -
+       conn->deductheadercount)) <= 0) {
+    /* If this connection isn't simply closed to be retried, AND nothing was
+       read from the HTTP server (that counts), this can't be right so we
+       return an error here */
+    failf(data, "Empty reply from server");
+    return CURLE_GOT_NOTHING;
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_http() gets called from the generic Curl_do() function when a HTTP
+ * request is to be performed. This creates and sends a properly constructed
+ * HTTP request.
+ */
+CURLcode Curl_http(struct connectdata *conn)
+{
+  struct SessionHandle *data=conn->data;
+  char *buf = data->state.buffer; /* this is a short cut to the buffer */
+  CURLcode result;
+  struct HTTP *http;
+  char *ppath = conn->path;
+  char *host = conn->host.name;
+  const char *te = ""; /* tranfer-encoding */
+  char *ptr;
+  char *request;
+  Curl_HttpReq httpreq = data->set.httpreq;
+  char *addcookies = NULL;
+
+  if(!conn->proto.http) {
+    /* Only allocate this struct if we don't already have it! */
+
+    http = (struct HTTP *)malloc(sizeof(struct HTTP));
+    if(!http)
+      return CURLE_OUT_OF_MEMORY;
+    memset(http, 0, sizeof(struct HTTP));
+    conn->proto.http = http;
+  }
+  else
+    http = conn->proto.http;
+
+  /* We default to persistant connections */
+  conn->bits.close = FALSE;
+
+  if ( (conn->protocol&(PROT_HTTP|PROT_FTP)) &&
+       data->set.upload) {
+    httpreq = HTTPREQ_PUT;
+  }
+
+  /* Now set the 'request' pointer to the proper request string */
+  if(data->set.customrequest)
+    request = data->set.customrequest;
+  else {
+    if(conn->bits.no_body)
+      request = (char *)"HEAD";
+    else {
+      curlassert((httpreq > HTTPREQ_NONE) && (httpreq < HTTPREQ_LAST));
+      switch(httpreq) {
+      case HTTPREQ_POST:
+      case HTTPREQ_POST_FORM:
+        request = (char *)"POST";
+        break;
+      case HTTPREQ_PUT:
+        request = (char *)"PUT";
+        break;
+      default: /* this should never happen */
+      case HTTPREQ_GET:
+        request = (char *)"GET";
+        break;
+      case HTTPREQ_HEAD:
+        request = (char *)"HEAD";
+        break;
+      }
+    }
+  }
+
+  /* The User-Agent string might have been allocated in url.c already, because
+     it might have been used in the proxy connect, but if we have got a header
+     with the user-agent string specified, we erase the previously made string
+     here. */
+  if(checkheaders(data, "User-Agent:") && conn->allocptr.uagent) {
+    free(conn->allocptr.uagent);
+    conn->allocptr.uagent=NULL;
+  }
+
+  /* setup the authentication headers */
+  result = Curl_http_output_auth(conn, request, ppath, FALSE);
+  if(result)
+    return result;
+
+  if((!data->state.authhost.done || !data->state.authproxy.done ) &&
+     (httpreq != HTTPREQ_GET)) {
+    /* Until we are authenticated, we switch over to HEAD. Unless its a GET
+       we want to do. The explanation for this is rather long and boring, but
+       the point is that it can't be done otherwise without risking having to
+       send the POST or PUT data multiple times. */
+    httpreq = HTTPREQ_HEAD;
+    request = (char *)"HEAD";
+    conn->bits.no_body = TRUE;
+    conn->bits.authprobe = TRUE; /* this is a request done to probe for
+                                    authentication methods */
+  }
+  else
+    conn->bits.authprobe = FALSE;
+
+  Curl_safefree(conn->allocptr.ref);
+  if(data->change.referer && !checkheaders(data, "Referer:"))
+    conn->allocptr.ref = aprintf("Referer: %s\015\012", data->change.referer);
+  else
+    conn->allocptr.ref = NULL;
+
+  if(data->set.cookie && !checkheaders(data, "Cookie:"))
+    addcookies = data->set.cookie;
+
+  if(!conn->bits.upload_chunky && (httpreq != HTTPREQ_GET)) {
+    /* not a chunky transfer yet, but data is to be sent */
+    ptr = checkheaders(data, "Transfer-Encoding:");
+    if(ptr) {
+      /* Some kind of TE is requested, check if 'chunked' is chosen */
+      conn->bits.upload_chunky =
+        Curl_compareheader(ptr, "Transfer-Encoding:", "chunked");
+      te = "";
+    }
+  }
+  else if(conn->bits.upload_chunky) {
+    /* RFC2616 section 4.4:
+       Messages MUST NOT include both a Content-Length header field and a
+       non-identity transfer-coding. If the message does include a non-
+       identity transfer-coding, the Content-Length MUST be ignored. */
+
+    if(!checkheaders(data, "Transfer-Encoding:")) {
+      te = "Transfer-Encoding: chunked\r\n";
+    }
+    else {
+      te = "";
+      conn->bits.upload_chunky = FALSE; /* transfer-encoding was disabled,
+                                           so don't chunkify this! */
+    }
+  }
+
+  Curl_safefree(conn->allocptr.host);
+
+  ptr = checkheaders(data, "Host:");
+  if(ptr && !data->state.this_is_a_follow) {
+    /* If we have a given custom Host: header, we extract the host name in
+       order to possibly use it for cookie reasons later on. We only allow the
+       custom Host: header if this is NOT a redirect, as setting Host: in the
+       redirected request is being out on thin ice. */
+    char *start = ptr+strlen("Host:");
+    while(*start && isspace((int)*start ))
+      start++;
+    ptr = start; /* start host-scanning here */
+
+    /* scan through the string to find the end (space or colon) */
+    while(*ptr && !isspace((int)*ptr) && !(':'==*ptr))
+      ptr++;
+
+    if(ptr != start) {
+      size_t len=ptr-start;
+      conn->allocptr.cookiehost = malloc(len+1);
+      if(!conn->allocptr.cookiehost)
+        return CURLE_OUT_OF_MEMORY;
+      memcpy(conn->allocptr.cookiehost, start, len);
+      conn->allocptr.cookiehost[len]=0;
+    }
+
+    conn->allocptr.host = NULL;
+  }
+  else {
+    /* When building Host: headers, we must put the host name within
+       [brackets] if the host name is a plain IPv6-address. RFC2732-style. */
+
+    if(((conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTPS)) ||
+       (!(conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTP)) )
+      /* If (HTTPS on port 443) OR (non-HTTPS on port 80) then don't include
+         the port number in the host string */
+      conn->allocptr.host = aprintf("Host: %s%s%s\r\n",
+                                    conn->bits.ipv6_ip?"[":"",
+                                    host,
+                                    conn->bits.ipv6_ip?"]":"");
+    else
+      conn->allocptr.host = aprintf("Host: %s%s%s:%d\r\n",
+                                    conn->bits.ipv6_ip?"[":"",
+                                    host,
+                                    conn->bits.ipv6_ip?"]":"",
+                                    conn->remote_port);
+
+    if(!conn->allocptr.host)
+      /* without Host: we can't make a nice request */
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  if (conn->bits.httpproxy && !conn->bits.tunnel_proxy)  {
+    /* Using a proxy but does not tunnel through it */
+
+    /* The path sent to the proxy is in fact the entire URL. But if the remote
+       host is a IDN-name, we must make sure that the request we produce only
+       uses the encoded host name! */
+    if(conn->host.dispname != conn->host.name) {
+      char *url = data->change.url;
+      char *iPtr = strstr(url, conn->host.dispname);
+      if(iPtr) {
+        /* This is where the display name starts in the URL, now replace this
+           part with the encoded name. TODO: This method of replacing the host
+           name is rather crude as I believe there's a slight risk that the
+           user has entered a user name or password that contain the host name
+           string. */
+        size_t currlen = strlen(conn->host.dispname);
+        size_t newlen = strlen(conn->host.name);
+        size_t urllen = strlen(url);
+
+        char *newurl;
+
+        newurl = malloc(urllen + newlen - currlen + 1);
+        if(newurl) {
+          /* copy the part before the host name */
+          memcpy(newurl, url, iPtr - url);
+          /* append the new host name instead of the old */
+          memcpy(newurl + (iPtr - url), conn->host.name, newlen);
+          /* append the piece after the host name */
+          memcpy(newurl + newlen + (iPtr - url),
+                 iPtr + currlen, /* copy the trailing zero byte too */
+                 urllen - (iPtr-url) - currlen + 1);
+          if(data->change.url_alloc)
+            free(data->change.url);
+          data->change.url = newurl;
+          data->change.url_alloc = TRUE;
+        }
+        else
+          return CURLE_OUT_OF_MEMORY;
+      }
+    }
+    ppath = data->change.url;
+  }
+  if(HTTPREQ_POST_FORM == httpreq) {
+    /* we must build the whole darned post sequence first, so that we have
+       a size of the whole shebang before we start to send it */
+     result = Curl_getFormData(&http->sendit, data->set.httppost,
+                               &http->postsize);
+     if(CURLE_OK != result) {
+       /* Curl_getFormData() doesn't use failf() */
+       failf(data, "failed creating formpost data");
+       return result;
+     }
+  }
+
+
+  if(!checkheaders(data, "Pragma:"))
+    http->p_pragma = "Pragma: no-cache\r\n";
+
+  if(!checkheaders(data, "Accept:"))
+    http->p_accept = "Accept: */*\r\n";
+
+  if(( (HTTPREQ_POST == httpreq) ||
+       (HTTPREQ_POST_FORM == httpreq) ||
+       (HTTPREQ_PUT == httpreq) ) &&
+     conn->resume_from) {
+    /**********************************************************************
+     * Resuming upload in HTTP means that we PUT or POST and that we have
+     * got a resume_from value set. The resume value has already created
+     * a Range: header that will be passed along. We need to "fast forward"
+     * the file the given number of bytes and decrease the assume upload
+     * file size before we continue this venture in the dark lands of HTTP.
+     *********************************************************************/
+
+    if(conn->resume_from < 0 ) {
+      /*
+       * This is meant to get the size of the present remote-file by itself.
+       * We don't support this now. Bail out!
+       */
+       conn->resume_from = 0;
+    }
+
+    if(conn->resume_from) {
+      /* do we still game? */
+      curl_off_t passed=0;
+
+      /* Now, let's read off the proper amount of bytes from the
+         input. If we knew it was a proper file we could've just
+         fseek()ed but we only have a stream here */
+      do {
+        size_t readthisamountnow = (size_t)(conn->resume_from - passed);
+        size_t actuallyread;
+
+        if(readthisamountnow > BUFSIZE)
+          readthisamountnow = BUFSIZE;
+
+        actuallyread =
+          data->set.fread(data->state.buffer, 1, (size_t)readthisamountnow,
+                          data->set.in);
+
+        passed += actuallyread;
+        if(actuallyread != readthisamountnow) {
+          failf(data, "Could only read %" FORMAT_OFF_T
+                " bytes from the input",
+                passed);
+          return CURLE_READ_ERROR;
+        }
+      } while(passed != conn->resume_from); /* loop until done */
+
+      /* now, decrease the size of the read */
+      if(data->set.infilesize>0) {
+        data->set.infilesize -= conn->resume_from;
+
+        if(data->set.infilesize <= 0) {
+          failf(data, "File already completely uploaded");
+          return CURLE_PARTIAL_FILE;
+        }
+      }
+      /* we've passed, proceed as normal */
+    }
+  }
+  if(conn->bits.use_range) {
+    /*
+     * A range is selected. We use different headers whether we're downloading
+     * or uploading and we always let customized headers override our internal
+     * ones if any such are specified.
+     */
+    if((httpreq == HTTPREQ_GET) &&
+       !checkheaders(data, "Range:")) {
+      /* if a line like this was already allocated, free the previous one */
+      if(conn->allocptr.rangeline)
+        free(conn->allocptr.rangeline);
+      conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", conn->range);
+    }
+    else if((httpreq != HTTPREQ_GET) &&
+            !checkheaders(data, "Content-Range:")) {
+
+      if(conn->resume_from) {
+        /* This is because "resume" was selected */
+        curl_off_t total_expected_size=
+          conn->resume_from + data->set.infilesize;
+        conn->allocptr.rangeline =
+            aprintf("Content-Range: bytes %s%" FORMAT_OFF_T
+                    "/%" FORMAT_OFF_T "\r\n",
+                    conn->range, total_expected_size-1,
+                    total_expected_size);
+      }
+      else {
+        /* Range was selected and then we just pass the incoming range and
+           append total size */
+        conn->allocptr.rangeline =
+            aprintf("Content-Range: bytes %s/%" FORMAT_OFF_T "\r\n",
+                    conn->range, data->set.infilesize);
+      }
+    }
+  }
+
+  {
+    /* Use 1.1 unless the use specificly asked for 1.0 */
+    const char *httpstring=
+      data->set.httpversion==CURL_HTTP_VERSION_1_0?"1.0":"1.1";
+
+    send_buffer *req_buffer;
+    struct curl_slist *headers=data->set.headers;
+    curl_off_t postsize; /* off_t type to be able to hold a large file size */
+
+    /* initialize a dynamic send-buffer */
+    req_buffer = add_buffer_init();
+
+    if(!req_buffer)
+      return CURLE_OUT_OF_MEMORY;
+
+    /* add the main request stuff */
+    result =
+      add_bufferf(req_buffer,
+                  "%s " /* GET/HEAD/POST/PUT */
+                  "%s HTTP/%s\r\n" /* path + HTTP version */
+                  "%s" /* proxyuserpwd */
+                  "%s" /* userpwd */
+                  "%s" /* range */
+                  "%s" /* user agent */
+                  "%s" /* host */
+                  "%s" /* pragma */
+                  "%s" /* accept */
+                  "%s" /* accept-encoding */
+                  "%s" /* referer */
+                  "%s",/* transfer-encoding */
+
+                request,
+                ppath,
+                httpstring,
+                conn->allocptr.proxyuserpwd?
+                conn->allocptr.proxyuserpwd:"",
+                conn->allocptr.userpwd?conn->allocptr.userpwd:"",
+                (conn->bits.use_range && conn->allocptr.rangeline)?
+                conn->allocptr.rangeline:"",
+                (data->set.useragent && *data->set.useragent && conn->allocptr.uagent)?
+                conn->allocptr.uagent:"",
+                (conn->allocptr.host?conn->allocptr.host:""), /* Host: host */
+                http->p_pragma?http->p_pragma:"",
+                http->p_accept?http->p_accept:"",
+                (data->set.encoding && *data->set.encoding && conn->allocptr.accept_encoding)?
+                conn->allocptr.accept_encoding:"",
+                (data->change.referer && conn->allocptr.ref)?conn->allocptr.ref:"" /* Referer: <data> */,
+                te
+                );
+
+    if(result)
+      return result;
+
+    if(data->cookies || addcookies) {
+      struct Cookie *co=NULL; /* no cookies from start */
+      int count=0;
+
+      if(data->cookies) {
+        Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+        co = Curl_cookie_getlist(data->cookies,
+                                 conn->allocptr.cookiehost?
+                                 conn->allocptr.cookiehost:host, ppath,
+                                 (bool)(conn->protocol&PROT_HTTPS?TRUE:FALSE));
+        Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+      }
+      if(co) {
+        struct Cookie *store=co;
+        /* now loop through all cookies that matched */
+        while(co) {
+          if(co->value) {
+            if(0 == count) {
+              result = add_bufferf(req_buffer, "Cookie: ");
+              if(result)
+                break;
+            }
+            result = add_bufferf(req_buffer,
+                                 "%s%s=%s", count?"; ":"",
+                                 co->name, co->value);
+            if(result)
+              break;
+            count++;
+          }
+          co = co->next; /* next cookie please */
+        }
+        Curl_cookie_freelist(store); /* free the cookie list */
+      }
+      if(addcookies && (CURLE_OK == result)) {
+        if(!count)
+          result = add_bufferf(req_buffer, "Cookie: ");
+        if(CURLE_OK == result) {
+          result = add_bufferf(req_buffer, "%s%s",
+                               count?"; ":"",
+                               addcookies);
+          count++;
+        }
+      }
+      if(count && (CURLE_OK == result))
+        result = add_buffer(req_buffer, "\r\n", 2);
+
+      if(result)
+        return result;
+    }
+
+    if(data->set.timecondition) {
+      struct tm *thistime;
+
+      /* Phil Karn (Fri, 13 Apr 2001) pointed out that the If-Modified-Since
+       * header family should have their times set in GMT as RFC2616 defines:
+       * "All HTTP date/time stamps MUST be represented in Greenwich Mean Time
+       * (GMT), without exception. For the purposes of HTTP, GMT is exactly
+       * equal to UTC (Coordinated Universal Time)." (see page 20 of RFC2616).
+       */
+
+#ifdef HAVE_GMTIME_R
+      /* thread-safe version */
+      struct tm keeptime;
+      thistime = (struct tm *)gmtime_r(&data->set.timevalue, &keeptime);
+#else
+      thistime = gmtime(&data->set.timevalue);
+#endif
+
+#ifdef HAVE_STRFTIME
+      /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
+      strftime(buf, BUFSIZE-1, "%a, %d %b %Y %H:%M:%S GMT", thistime);
+#else
+      /* TODO: Right, we *could* write a replacement here */
+      strcpy(buf, "no strftime() support");
+#endif
+      switch(data->set.timecondition) {
+      case CURL_TIMECOND_IFMODSINCE:
+      default:
+        result = add_bufferf(req_buffer,
+                             "If-Modified-Since: %s\r\n", buf);
+        break;
+      case CURL_TIMECOND_IFUNMODSINCE:
+        result = add_bufferf(req_buffer,
+                             "If-Unmodified-Since: %s\r\n", buf);
+        break;
+      case CURL_TIMECOND_LASTMOD:
+        result = add_bufferf(req_buffer,
+                             "Last-Modified: %s\r\n", buf);
+        break;
+      }
+      if(result)
+        return result;
+    }
+
+    while(headers) {
+      ptr = strchr(headers->data, ':');
+      if(ptr) {
+        /* we require a colon for this to be a true header */
+
+        ptr++; /* pass the colon */
+        while(*ptr && isspace((int)*ptr))
+          ptr++;
+
+        if(*ptr) {
+          /* only send this if the contents was non-blank */
+
+          result = add_bufferf(req_buffer, "%s\r\n", headers->data);
+          if(result)
+            return result;
+        }
+      }
+      headers = headers->next;
+    }
+
+    http->postdata = NULL;  /* nothing to post at this point */
+    Curl_pgrsSetUploadSize(data, 0); /* upload size is 0 atm */
+
+    /* If 'authdone' is FALSE, we must not set the write socket index to the
+       Curl_transfer() call below, as we're not ready to actually upload any
+       data yet. */
+
+    switch(httpreq) {
+
+    case HTTPREQ_POST_FORM:
+      if(Curl_FormInit(&http->form, http->sendit)) {
+        failf(data, "Internal HTTP POST error!");
+        return CURLE_HTTP_POST_ERROR;
+      }
+
+      /* set the read function to read from the generated form data */
+      conn->fread = (curl_read_callback)Curl_FormReader;
+      conn->fread_in = &http->form;
+
+      http->sending = HTTPSEND_BODY;
+
+      if(!conn->bits.upload_chunky) {
+        /* only add Content-Length if not uploading chunked */
+        result = add_bufferf(req_buffer,
+                             "Content-Length: %" FORMAT_OFF_T "\r\n",
+                             http->postsize);
+        if(result)
+          return result;
+      }
+
+      if(!checkheaders(data, "Expect:")) {
+        /* if not disabled explicitly we add a Expect: 100-continue
+           to the headers which actually speeds up post operations (as
+           there is one packet coming back from the web server) */
+        result = add_bufferf(req_buffer,
+                             "Expect: 100-continue\r\n");
+        if(result)
+          return result;
+        data->set.expect100header = TRUE;
+      }
+
+      if(!checkheaders(data, "Content-Type:")) {
+        /* Get Content-Type: line from Curl_formpostheader.
+
+           The Content-Type header line also contains the MIME boundary
+           string etc why disabling this header is likely to not make things
+           work, but we support disabling it anyway.
+        */
+        char *contentType;
+        size_t linelength=0;
+        contentType = Curl_formpostheader((void *)&http->form,
+                                          &linelength);
+        if(!contentType) {
+          failf(data, "Could not get Content-Type header line!");
+          return CURLE_HTTP_POST_ERROR;
+        }
+        result = add_buffer(req_buffer, contentType, linelength);
+        if(result)
+          return result;
+      }
+
+      /* make the request end in a true CRLF */
+      result = add_buffer(req_buffer, "\r\n", 2);
+      if(result)
+        return result;
+
+      /* set upload size to the progress meter */
+      Curl_pgrsSetUploadSize(data, http->postsize);
+
+      /* fire away the whole request to the server */
+      result = add_buffer_send(req_buffer, conn,
+                               &data->info.request_size);
+      if(result)
+        failf(data, "Failed sending POST request");
+      else
+        /* setup variables for the upcoming transfer */
+        result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
+                               &http->readbytecount,
+                               FIRSTSOCKET,
+                               &http->writebytecount);
+      if(result) {
+        Curl_formclean(http->sendit); /* free that whole lot */
+        return result;
+      }
+      break;
+
+    case HTTPREQ_PUT: /* Let's PUT the data to the server! */
+
+      if((data->set.infilesize>0) && !conn->bits.upload_chunky) {
+        /* only add Content-Length if not uploading chunked */
+        result = add_bufferf(req_buffer,
+                             "Content-Length: %" FORMAT_OFF_T "\r\n", /* size */
+                             data->set.infilesize );
+        if(result)
+          return result;
+      }
+
+      if(!checkheaders(data, "Expect:")) {
+        /* if not disabled explicitly we add a Expect: 100-continue
+           to the headers which actually speeds up post operations (as
+           there is one packet coming back from the web server) */
+        result = add_bufferf(req_buffer,
+                             "Expect: 100-continue\r\n");
+        if(result)
+          return result;
+        data->set.expect100header = TRUE;
+      }
+
+      result = add_buffer(req_buffer, "\r\n", 2); /* end of headers */
+      if(result)
+        return result;
+
+      /* set the upload size to the progress meter */
+      Curl_pgrsSetUploadSize(data, data->set.infilesize);
+
+      /* this sends the buffer and frees all the buffer resources */
+      result = add_buffer_send(req_buffer, conn,
+                               &data->info.request_size);
+      if(result)
+        failf(data, "Failed sending POST request");
+      else
+        /* prepare for transfer */
+        result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
+                               &http->readbytecount,
+                               FIRSTSOCKET,
+                               &http->writebytecount);
+      if(result)
+        return result;
+      break;
+
+    case HTTPREQ_POST:
+      /* this is the simple POST, using x-www-form-urlencoded style */
+
+      /* store the size of the postfields */
+      postsize = data->set.postfieldsize?
+        data->set.postfieldsize:
+        (data->set.postfields?(curl_off_t)strlen(data->set.postfields):0);
+
+      if(!conn->bits.upload_chunky) {
+        /* We only set Content-Length and allow a custom Content-Length if
+           we don't upload data chunked, as RFC2616 forbids us to set both
+           kinds of headers (Transfer-Encoding: chunked and Content-Length) */
+
+        if(!checkheaders(data, "Content-Length:")) {
+          /* we allow replacing this header, although it isn't very wise to
+             actually set your own */
+          result = add_bufferf(req_buffer,
+                               "Content-Length: %" FORMAT_OFF_T"\r\n",
+                               postsize);
+          if(result)
+            return result;
+        }
+      }
+
+      if(!checkheaders(data, "Content-Type:")) {
+        result = add_bufferf(req_buffer,
+                             "Content-Type: application/x-www-form-urlencoded\r\n");
+        if(result)
+          return result;
+      }
+
+      if(data->set.postfields) {
+
+        if((data->state.authhost.done || data->state.authproxy.done )
+           && (postsize < (100*1024))) {
+          /* If we're not done with the authentication phase, we don't expect
+             to actually send off any data yet. Hence, we delay the sending of
+             the body until we receive that friendly 100-continue response */
+
+          /* The post data is less than 100K, then append it to the header.
+             This limit is no magic limit but only set to prevent really huge
+             POSTs to get the data duplicated with malloc() and family. */
+
+          result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
+          if(result)
+            return result;
+
+          if(!conn->bits.upload_chunky) {
+            /* We're not sending it 'chunked', append it to the request
+               already now to reduce the number if send() calls */
+            result = add_buffer(req_buffer, data->set.postfields,
+                                (size_t)postsize);
+          }
+          else {
+            /* Append the POST data chunky-style */
+            result = add_bufferf(req_buffer, "%x\r\n", (int)postsize);
+            if(CURLE_OK == result)
+              result = add_buffer(req_buffer, data->set.postfields,
+                                  (size_t)postsize);
+            if(CURLE_OK == result)
+              result = add_buffer(req_buffer,
+                                  "\r\n0\r\n\r\n", 7); /* end of a chunked
+                                                          transfer stream */
+          }
+          if(result)
+            return result;
+        }
+        else {
+          /* A huge POST coming up, do data separate from the request */
+          http->postsize = postsize;
+          http->postdata = data->set.postfields;
+
+          http->sending = HTTPSEND_BODY;
+
+          conn->fread = (curl_read_callback)readmoredata;
+          conn->fread_in = (void *)conn;
+
+          /* set the upload size to the progress meter */
+          Curl_pgrsSetUploadSize(data, http->postsize);
+
+          if(!checkheaders(data, "Expect:")) {
+            /* if not disabled explicitly we add a Expect: 100-continue to the
+               headers which actually speeds up post operations (as there is
+               one packet coming back from the web server) */
+            add_bufferf(req_buffer,
+                        "Expect: 100-continue\r\n");
+            data->set.expect100header = TRUE;
+          }
+
+          add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
+        }
+      }
+      else {
+        add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
+
+        /* set the upload size to the progress meter */
+        Curl_pgrsSetUploadSize(data, data->set.infilesize);
+
+        /* set the pointer to mark that we will send the post body using
+           the read callback */
+        http->postdata = (char *)&http->postdata;
+      }
+      /* issue the request */
+      result = add_buffer_send(req_buffer, conn,
+                               &data->info.request_size);
+
+      if(result)
+        failf(data, "Failed sending HTTP POST request");
+      else
+        result =
+          Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
+                        &http->readbytecount,
+                        http->postdata?FIRSTSOCKET:-1,
+                        http->postdata?&http->writebytecount:NULL);
+      break;
+
+    default:
+      add_buffer(req_buffer, "\r\n", 2);
+
+      /* issue the request */
+      result = add_buffer_send(req_buffer, conn,
+                               &data->info.request_size);
+
+      if(result)
+        failf(data, "Failed sending HTTP request");
+      else
+        /* HTTP GET/HEAD download: */
+        result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
+                               &http->readbytecount,
+                               http->postdata?FIRSTSOCKET:-1,
+                               http->postdata?&http->writebytecount:NULL);
+    }
+    if(result)
+      return result;
+  }
+
+  return CURLE_OK;
+}
+#endif
diff --git a/Utilities/cmcurl/http.h b/Utilities/cmcurl/http.h
new file mode 100644
index 0000000..80c1807
--- /dev/null
+++ b/Utilities/cmcurl/http.h
@@ -0,0 +1,61 @@
+#ifndef __HTTP_H
+#define __HTTP_H
+
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+#ifndef CURL_DISABLE_HTTP
+bool Curl_compareheader(char *headerline,     /* line to check */
+                        const char *header,   /* header keyword _with_ colon */
+                        const char *content); /* content string to find */
+
+/* ftp can use this as well */
+CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
+                                     int tunnelsocket,
+                                     char *hostname, int remote_port);
+
+/* protocol-specific functions set up to be called by the main engine */
+CURLcode Curl_http(struct connectdata *conn);
+CURLcode Curl_http_done(struct connectdata *, CURLcode);
+CURLcode Curl_http_connect(struct connectdata *conn);
+
+/* The following functions are defined in http_chunks.c */
+void Curl_httpchunk_init(struct connectdata *conn);
+CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap,
+                              ssize_t length, ssize_t *wrote);
+
+/* These functions are in http.c */
+void Curl_http_auth_stage(struct SessionHandle *data, int stage);
+CURLcode Curl_http_input_auth(struct connectdata *conn,
+                              int httpcode, char *header);
+CURLcode Curl_http_auth_act(struct connectdata *conn);
+
+int Curl_http_should_fail(struct connectdata *conn);
+
+/* If only the PICKNONE bit is set, there has been a round-trip and we
+   selected to use no auth at all. Ie, we actively select no auth, as opposed
+   to not having one selected. The other CURLAUTH_* defines are present in the
+   public curl/curl.h header. */
+#define CURLAUTH_PICKNONE (1<<30) /* don't use auth */
+
+#endif
+#endif
diff --git a/Utilities/cmcurl/http_chunks.c b/Utilities/cmcurl/http_chunks.c
new file mode 100644
index 0000000..02fdfc5
--- /dev/null
+++ b/Utilities/cmcurl/http_chunks.c
@@ -0,0 +1,264 @@
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+#include "setup.h"
+
+#ifndef CURL_DISABLE_HTTP
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "urldata.h" /* it includes http_chunks.h */
+#include "sendf.h"   /* for the client write stuff */
+
+#include "content_encoding.h"
+#include "http.h"
+#include "curl_memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* 
+ * Chunk format (simplified):
+ *
+ * <HEX SIZE>[ chunk extension ] CRLF
+ * <DATA> CRLF
+ *
+ * Highlights from RFC2616 section 3.6 say:
+
+   The chunked encoding modifies the body of a message in order to
+   transfer it as a series of chunks, each with its own size indicator,
+   followed by an OPTIONAL trailer containing entity-header fields. This
+   allows dynamically produced content to be transferred along with the
+   information necessary for the recipient to verify that it has
+   received the full message.
+
+       Chunked-Body   = *chunk
+                        last-chunk
+                        trailer
+                        CRLF
+
+       chunk          = chunk-size [ chunk-extension ] CRLF
+                        chunk-data CRLF
+       chunk-size     = 1*HEX
+       last-chunk     = 1*("0") [ chunk-extension ] CRLF
+
+       chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
+       chunk-ext-name = token
+       chunk-ext-val  = token | quoted-string
+       chunk-data     = chunk-size(OCTET)
+       trailer        = *(entity-header CRLF)
+
+   The chunk-size field is a string of hex digits indicating the size of
+   the chunk. The chunked encoding is ended by any chunk whose size is
+   zero, followed by the trailer, which is terminated by an empty line.
+
+ */
+
+
+void Curl_httpchunk_init(struct connectdata *conn)
+{
+  struct Curl_chunker *chunk = &conn->proto.http->chunk;
+  chunk->hexindex=0; /* start at 0 */
+  chunk->dataleft=0; /* no data left yet! */
+  chunk->state = CHUNK_HEX; /* we get hex first! */
+}
+
+/*
+ * chunk_read() returns a OK for normal operations, or a positive return code
+ * for errors. STOP means this sequence of chunks is complete.  The 'wrote'
+ * argument is set to tell the caller how many bytes we actually passed to the
+ * client (for byte-counting and whatever).
+ *
+ * The states and the state-machine is further explained in the header file.
+ */
+CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
+                              char *datap,
+                              ssize_t datalen,
+                              ssize_t *wrotep)
+{
+  CURLcode result=CURLE_OK;
+  struct Curl_chunker *ch = &conn->proto.http->chunk;
+  struct Curl_transfer_keeper *k = &conn->keep;
+  size_t piece;
+  size_t length = (size_t)datalen;
+  size_t *wrote = (size_t *)wrotep;
+
+  *wrote = 0; /* nothing's written yet */
+
+  while(length) {
+    switch(ch->state) {
+    case CHUNK_HEX:
+      if(isxdigit((int)*datap)) {
+        if(ch->hexindex < MAXNUM_SIZE) {
+          ch->hexbuffer[ch->hexindex] = *datap;
+          datap++;
+          length--;
+          ch->hexindex++;
+        }
+        else {
+          return CHUNKE_TOO_LONG_HEX; /* longer hex than we support */
+        }
+      }
+      else {
+        if(0 == ch->hexindex) {
+          /* This is illegal data, we received junk where we expected
+             a hexadecimal digit. */
+          return CHUNKE_ILLEGAL_HEX;
+        }
+        /* length and datap are unmodified */
+        ch->hexbuffer[ch->hexindex]=0;
+        ch->datasize=strtoul(ch->hexbuffer, NULL, 16);
+        ch->state = CHUNK_POSTHEX;
+      }
+      break;
+
+    case CHUNK_POSTHEX:
+      /* In this state, we're waiting for CRLF to arrive. We support
+         this to allow so called chunk-extensions to show up here
+         before the CRLF comes. */
+      if(*datap == '\r')
+        ch->state = CHUNK_CR;
+      length--;
+      datap++;
+      break;
+
+    case CHUNK_CR:
+      /* waiting for the LF */
+      if(*datap == '\n') {
+        /* we're now expecting data to come, unless size was zero! */
+        if(0 == ch->datasize) {
+          ch->state = CHUNK_STOP; /* stop reading! */
+          if(1 == length) {
+            /* This was the final byte, return right now */
+            return CHUNKE_STOP;
+          }
+        }
+        else
+          ch->state = CHUNK_DATA;
+      }
+      else
+        /* previously we got a fake CR, go back to CR waiting! */
+        ch->state = CHUNK_CR;
+      datap++;
+      length--;
+      break;
+
+    case CHUNK_DATA:
+      /* we get pure and fine data
+
+         We expect another 'datasize' of data. We have 'length' right now,
+         it can be more or less than 'datasize'. Get the smallest piece.
+      */
+      piece = (ch->datasize >= length)?length:ch->datasize;
+
+      /* Write the data portion available */
+#ifdef HAVE_LIBZ
+      switch (conn->keep.content_encoding) {
+        case IDENTITY:
+#endif
+          if(!k->ignorebody)
+            result = Curl_client_write(conn->data, CLIENTWRITE_BODY, datap,
+                                       piece);
+#ifdef HAVE_LIBZ
+          break;
+
+        case DEFLATE: 
+          /* update conn->keep.str to point to the chunk data. */
+          conn->keep.str = datap;
+          result = Curl_unencode_deflate_write(conn->data, &conn->keep,
+                                               (ssize_t)piece);
+          break;
+
+        case GZIP:
+          /* update conn->keep.str to point to the chunk data. */
+          conn->keep.str = datap;
+          result = Curl_unencode_gzip_write(conn->data, &conn->keep,
+                                            (ssize_t)piece);
+          break;
+
+        case COMPRESS:
+        default:
+          failf (conn->data,
+                 "Unrecognized content encoding type. "
+                 "libcurl understands `identity', `deflate' and `gzip' "
+                 "content encodings.");
+          return CHUNKE_BAD_ENCODING;
+      }
+#endif
+
+      if(result)
+        return CHUNKE_WRITE_ERROR;
+
+      *wrote += piece;
+
+      ch->datasize -= piece; /* decrease amount left to expect */
+      datap += piece;    /* move read pointer forward */
+      length -= piece;   /* decrease space left in this round */
+
+      if(0 == ch->datasize)
+        /* end of data this round, we now expect a trailing CRLF */
+        ch->state = CHUNK_POSTCR;
+      break;
+
+    case CHUNK_POSTCR:
+      if(*datap == '\r') {
+        ch->state = CHUNK_POSTLF;
+        datap++;
+        length--;
+      }
+      else
+        return CHUNKE_BAD_CHUNK;
+      break;
+
+    case CHUNK_POSTLF:
+      if(*datap == '\n') {
+        /*
+         * The last one before we go back to hex state and start all
+         * over.
+         */
+        Curl_httpchunk_init(conn);
+        datap++;
+        length--;
+      }
+      else
+        return CHUNKE_BAD_CHUNK;
+      break;
+
+    case CHUNK_STOP:
+      /* If we arrive here, there is data left in the end of the buffer
+         even if there's no more chunks to read */
+      ch->dataleft = length;
+      return CHUNKE_STOP; /* return stop */
+    default:
+      return CHUNKE_STATE_ERROR;
+    }
+  }
+  return CHUNKE_OK;
+}
+#endif /* CURL_DISABLE_HTTP */
diff --git a/Utilities/cmcurl/http_chunks.h b/Utilities/cmcurl/http_chunks.h
new file mode 100644
index 0000000..26b79de
--- /dev/null
+++ b/Utilities/cmcurl/http_chunks.h
@@ -0,0 +1,88 @@
+#ifndef __HTTP_CHUNKS_H
+#define __HTTP_CHUNKS_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+/*
+ * The longest possible hexadecimal number we support in a chunked transfer.
+ * Weird enough, RFC2616 doesn't set a maximum size! Since we use strtoul()
+ * to convert it, we "only" support 2^32 bytes chunk data.
+ */
+#define MAXNUM_SIZE 16
+
+typedef enum {
+  CHUNK_FIRST, /* never use */
+
+  /* In this we await and buffer all hexadecimal digits until we get one
+     that isn't a hexadecimal digit. When done, we go POSTHEX */
+  CHUNK_HEX,
+
+  /* We have received the hexadecimal digit and we eat all characters until
+     we get a CRLF pair. When we see a CR we go to the CR state. */
+  CHUNK_POSTHEX,
+
+  /* A single CR has been found and we should get a LF right away in this
+     state or we go back to POSTHEX. When LF is received, we go to DATA.
+     If the size given was zero, we set state to STOP and return. */
+  CHUNK_CR,
+
+  /* We eat the amount of data specified. When done, we move on to the
+     POST_CR state. */
+  CHUNK_DATA,
+
+  /* POSTCR should get a CR and nothing else, then move to POSTLF */
+  CHUNK_POSTCR,
+
+  /* POSTLF should get a LF and nothing else, then move back to HEX as
+     the CRLF combination marks the end of a chunk */
+  CHUNK_POSTLF,
+
+  /* This is mainly used to really mark that we're out of the game.
+     NOTE: that there's a 'dataleft' field in the struct that will tell how
+     many bytes that were not passed to the client in the end of the last
+     buffer! */
+  CHUNK_STOP,
+
+  CHUNK_LAST /* never use */
+} ChunkyState;
+
+typedef enum {
+  CHUNKE_STOP = -1,
+  CHUNKE_OK = 0,
+  CHUNKE_TOO_LONG_HEX = 1,
+  CHUNKE_ILLEGAL_HEX,
+  CHUNKE_BAD_CHUNK,
+  CHUNKE_WRITE_ERROR,
+  CHUNKE_STATE_ERROR,
+  CHUNKE_BAD_ENCODING,
+  CHUNKE_LAST
+} CHUNKcode;
+
+struct Curl_chunker {
+  char hexbuffer[ MAXNUM_SIZE + 1];
+  int hexindex;
+  ChunkyState state;
+  size_t datasize;
+  size_t dataleft; /* untouched data amount at the end of the last buffer */
+};
+
+#endif
diff --git a/Utilities/cmcurl/http_digest.c b/Utilities/cmcurl/http_digest.c
new file mode 100644
index 0000000..b997ccb
--- /dev/null
+++ b/Utilities/cmcurl/http_digest.c
@@ -0,0 +1,482 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+#include "setup.h"
+
+#ifndef CURL_DISABLE_HTTP
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "urldata.h"
+#include "sendf.h"
+#include "strequal.h"
+#include "base64.h"
+#include "md5.h"
+#include "http_digest.h"
+#include "strtok.h"
+#include "url.h" /* for Curl_safefree() */
+#include "curl_memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* Test example headers:
+
+WWW-Authenticate: Digest realm="testrealm", nonce="1053604598"
+Proxy-Authenticate: Digest realm="testrealm", nonce="1053604598"
+
+*/
+
+CURLdigest Curl_input_digest(struct connectdata *conn,
+                             bool proxy,
+                             char *header) /* rest of the *-authenticate:
+                                              header */
+{
+  bool more = TRUE;
+  char *token;
+  char *tmp;
+  bool foundAuth = FALSE;
+  bool foundAuthInt = FALSE;
+  struct SessionHandle *data=conn->data;
+  bool before = FALSE; /* got a nonce before */
+  struct digestdata *d;
+
+  if(proxy) {
+    d = &data->state.proxydigest;
+  }
+  else {
+    d = &data->state.digest;
+  }
+
+  /* skip initial whitespaces */
+  while(*header && isspace((int)*header))
+    header++;
+
+  if(checkprefix("Digest", header)) {
+    header += strlen("Digest");
+
+    /* If we already have received a nonce, keep that in mind */
+    if(d->nonce)
+      before = TRUE;
+
+    /* clear off any former leftovers and init to defaults */
+    Curl_digest_cleanup_one(d);
+
+    while(more) {
+      char value[32];
+      char content[128];
+      size_t totlen;
+
+      while(*header && isspace((int)*header))
+        header++;
+
+      /* how big can these strings be? */
+      if((2 == sscanf(header, "%31[^=]=\"%127[^\"]\"",
+                      value, content)) ||
+         /* try the same scan but without quotes around the content but don't
+            include the possibly trailing comma */
+         (2 ==  sscanf(header, "%31[^=]=%127[^,]",
+                       value, content)) ) {
+        if(strequal(value, "nonce")) {
+          d->nonce = strdup(content);
+          if(!d->nonce)
+            return CURLDIGEST_NOMEM;
+        }
+        else if(strequal(value, "stale")) {
+          if(strequal(content, "true")) {
+            d->stale = TRUE;
+            d->nc = 1; /* we make a new nonce now */
+          }
+        }
+        else if(strequal(value, "realm")) {
+          d->realm = strdup(content);
+          if(!d->realm)
+            return CURLDIGEST_NOMEM;
+        }
+        else if(strequal(value, "opaque")) {
+          d->opaque = strdup(content);
+          if(!d->opaque)
+            return CURLDIGEST_NOMEM;
+        }
+        else if(strequal(value, "qop")) {
+          char *tok_buf;
+          /* tokenize the list and choose auth if possible, use a temporary
+             clone of the buffer since strtok_r() ruins it */
+          tmp = strdup(content);
+          if(!tmp)
+            return CURLDIGEST_NOMEM;
+          token = strtok_r(tmp, ",", &tok_buf);
+          while (token != NULL) {
+            if (strequal(token, "auth")) {
+              foundAuth = TRUE;
+            }
+            else if (strequal(token, "auth-int")) {
+              foundAuthInt = TRUE;
+            }
+            token = strtok_r(NULL, ",", &tok_buf);
+          }
+          free(tmp);
+          /*select only auth o auth-int. Otherwise, ignore*/
+          if (foundAuth) {
+            d->qop = strdup("auth");
+            if(!d->qop)
+              return CURLDIGEST_NOMEM;
+          }
+          else if (foundAuthInt) {
+            d->qop = strdup("auth-int");
+            if(!d->qop)
+              return CURLDIGEST_NOMEM;
+          }
+        }
+        else if(strequal(value, "algorithm")) {
+          d->algorithm = strdup(content);
+          if(!d->algorithm)
+            return CURLDIGEST_NOMEM;
+          if(strequal(content, "MD5-sess"))
+            d->algo = CURLDIGESTALGO_MD5SESS;
+          else if(strequal(content, "MD5"))
+            d->algo = CURLDIGESTALGO_MD5;
+          else
+            return CURLDIGEST_BADALGO;
+        }
+        else {
+          /* unknown specifier, ignore it! */
+        }
+        totlen = strlen(value)+strlen(content)+1;
+
+        if(header[strlen(value)+1] == '\"')
+          /* the contents were within quotes, then add 2 for them to the
+             length */
+          totlen += 2;
+      }
+      else
+        break; /* we're done here */
+
+      header += totlen;
+      if(',' == *header)
+        /* allow the list to be comma-separated */
+        header++;
+    }
+    /* We had a nonce since before, and we got another one now without
+       'stale=true'. This means we provided bad credentials in the previous
+       request */
+    if(before && !d->stale)
+      return CURLDIGEST_BAD;
+
+    /* We got this header without a nonce, that's a bad Digest line! */
+    if(!d->nonce)
+      return CURLDIGEST_BAD;
+  }
+  else
+    /* else not a digest, get out */
+    return CURLDIGEST_NONE;
+
+  return CURLDIGEST_FINE;
+}
+
+/* convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/
+static void md5_to_ascii(unsigned char *source, /* 16 bytes */
+                         unsigned char *dest) /* 33 bytes */
+{
+  int i;
+  for(i=0; i<16; i++)
+    snprintf((char *)&dest[i*2], 3, "%02x", source[i]);
+}
+
+CURLcode Curl_output_digest(struct connectdata *conn,
+                            bool proxy,
+                            unsigned char *request,
+                            unsigned char *uripath)
+{
+  /* We have a Digest setup for this, use it!  Now, to get all the details for
+     this sorted out, I must urge you dear friend to read up on the RFC2617
+     section 3.2.2, */
+  unsigned char md5buf[16]; /* 16 bytes/128 bits */
+  unsigned char request_digest[33];
+  unsigned char *md5this;
+  unsigned char *ha1;
+  unsigned char ha2[33];/* 32 digits and 1 zero byte */
+  char cnoncebuf[7];
+  char *cnonce;
+  char *tmp;
+  struct timeval now;
+
+  char **allocuserpwd;
+  char *userp;
+  char *passwdp;
+  struct auth *authp;
+
+  struct SessionHandle *data = conn->data;
+  struct digestdata *d;
+
+  if(proxy) {
+    d = &data->state.proxydigest;
+    allocuserpwd = &conn->allocptr.proxyuserpwd;
+    userp = conn->proxyuser;
+    passwdp = conn->proxypasswd;
+    authp = &data->state.authproxy;
+  }
+  else {
+    d = &data->state.digest;
+    allocuserpwd = &conn->allocptr.userpwd;
+    userp = conn->user;
+    passwdp = conn->passwd;
+    authp = &data->state.authhost;
+  }
+
+  /* not set means empty */
+  if(!userp)
+    userp=(char *)"";
+
+  if(!passwdp)
+    passwdp=(char *)"";
+
+  if(!d->nonce) {
+    authp->done = FALSE;
+    return CURLE_OK;
+  }
+  authp->done = TRUE;
+
+  if(!d->nc)
+    d->nc = 1;
+
+  if(!d->cnonce) {
+    /* Generate a cnonce */
+    now = Curl_tvnow();
+    snprintf(cnoncebuf, sizeof(cnoncebuf), "%06ld", now.tv_sec);
+    if(Curl_base64_encode(cnoncebuf, strlen(cnoncebuf), &cnonce))
+      d->cnonce = cnonce;
+    else
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  /*
+    if the algorithm is "MD5" or unspecified (which then defaults to MD5):
+
+    A1 = unq(username-value) ":" unq(realm-value) ":" passwd
+
+    if the algorithm is "MD5-sess" then:
+
+    A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd )
+         ":" unq(nonce-value) ":" unq(cnonce-value)
+  */
+
+  md5this = (unsigned char *)
+    aprintf("%s:%s:%s", userp, d->realm, passwdp);
+  if(!md5this)
+    return CURLE_OUT_OF_MEMORY;
+  Curl_md5it(md5buf, md5this);
+  free(md5this); /* free this again */
+
+  ha1 = (unsigned char *)malloc(33); /* 32 digits and 1 zero byte */
+  if(!ha1)
+    return CURLE_OUT_OF_MEMORY;
+
+  md5_to_ascii(md5buf, ha1);
+
+  if(d->algo == CURLDIGESTALGO_MD5SESS) {
+    /* nonce and cnonce are OUTSIDE the hash */
+    tmp = aprintf("%s:%s:%s", ha1, d->nonce, d->cnonce);
+    free(ha1);
+    if(!tmp)
+      return CURLE_OUT_OF_MEMORY;
+    ha1 = (unsigned char *)tmp;
+  }
+
+  /*
+    If the "qop" directive's value is "auth" or is unspecified, then A2 is:
+
+      A2       = Method ":" digest-uri-value
+
+          If the "qop" value is "auth-int", then A2 is:
+
+      A2       = Method ":" digest-uri-value ":" H(entity-body)
+
+    (The "Method" value is the HTTP request method as specified in section
+    5.1.1 of RFC 2616)
+  */
+
+  md5this = (unsigned char *)aprintf("%s:%s", request, uripath);
+  if(!md5this) {
+    free(ha1);
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  if (d->qop && strequal(d->qop, "auth-int")) {
+    /* We don't support auth-int at the moment. I can't see a easy way to get
+       entity-body here */
+    /* TODO: Append H(entity-body)*/
+  }
+  Curl_md5it(md5buf, md5this);
+  free(md5this); /* free this again */
+  md5_to_ascii(md5buf, ha2);
+
+  if (d->qop) {
+    md5this = (unsigned char *)aprintf("%s:%s:%08x:%s:%s:%s",
+                                       ha1,
+                                       d->nonce,
+                                       d->nc,
+                                       d->cnonce,
+                                       d->qop,
+                                       ha2);
+  }
+  else {
+    md5this = (unsigned char *)aprintf("%s:%s:%s",
+                                       ha1,
+                                       d->nonce,
+                                       ha2);
+  }
+  free(ha1);
+  if(!md5this)
+    return CURLE_OUT_OF_MEMORY;
+
+  Curl_md5it(md5buf, md5this);
+  free(md5this); /* free this again */
+  md5_to_ascii(md5buf, request_digest);
+
+  /* for test case 64 (snooped from a Mozilla 1.3a request)
+
+    Authorization: Digest username="testuser", realm="testrealm", \
+    nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca"
+  */
+
+  Curl_safefree(*allocuserpwd);
+
+  if (d->qop) {
+    *allocuserpwd =
+      aprintf( "%sAuthorization: Digest "
+               "username=\"%s\", "
+               "realm=\"%s\", "
+               "nonce=\"%s\", "
+               "uri=\"%s\", "
+               "cnonce=\"%s\", "
+               "nc=%08x, "
+               "qop=\"%s\", "
+               "response=\"%s\"",
+               proxy?"Proxy-":"",
+               userp,
+               d->realm,
+               d->nonce,
+               uripath, /* this is the PATH part of the URL */
+               d->cnonce,
+               d->nc,
+               d->qop,
+               request_digest);
+
+    if(strequal(d->qop, "auth"))
+      d->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0 padded
+                  which tells to the server how many times you are using the
+                  same nonce in the qop=auth mode. */
+  }
+  else {
+    *allocuserpwd =
+      aprintf( "%sAuthorization: Digest "
+               "username=\"%s\", "
+               "realm=\"%s\", "
+               "nonce=\"%s\", "
+               "uri=\"%s\", "
+               "response=\"%s\"",
+               proxy?"Proxy-":"",
+               userp,
+               d->realm,
+               d->nonce,
+               uripath, /* this is the PATH part of the URL */
+               request_digest);
+  }
+  if(!*allocuserpwd)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Add optional fields */
+  if(d->opaque) {
+    /* append opaque */
+    tmp = aprintf("%s, opaque=\"%s\"", *allocuserpwd, d->opaque);
+    if(!tmp)
+      return CURLE_OUT_OF_MEMORY;
+    free(*allocuserpwd);
+    *allocuserpwd = tmp;
+  }
+
+  if(d->algorithm) {
+    /* append algorithm */
+    tmp = aprintf("%s, algorithm=\"%s\"", *allocuserpwd, d->algorithm);
+    if(!tmp)
+      return CURLE_OUT_OF_MEMORY;
+    free(*allocuserpwd);
+    *allocuserpwd = tmp;
+  }
+
+  /* append CRLF to the userpwd header */
+  tmp = (char*) realloc(*allocuserpwd, strlen(*allocuserpwd) + 3 + 1);
+  if(!tmp)
+    return CURLE_OUT_OF_MEMORY;
+  strcat(tmp, "\r\n");
+  *allocuserpwd = tmp;
+
+  return CURLE_OK;
+}
+
+void Curl_digest_cleanup_one(struct digestdata *d)
+{
+  if(d->nonce)
+    free(d->nonce);
+  d->nonce = NULL;
+
+  if(d->cnonce)
+    free(d->cnonce);
+  d->cnonce = NULL;
+
+  if(d->realm)
+    free(d->realm);
+  d->realm = NULL;
+
+  if(d->opaque)
+    free(d->opaque);
+  d->opaque = NULL;
+
+  if(d->qop)
+    free(d->qop);
+  d->qop = NULL;
+
+  if(d->algorithm)
+    free(d->algorithm);
+  d->algorithm = NULL;
+
+  d->nc = 0;
+  d->algo = CURLDIGESTALGO_MD5; /* default algorithm */
+  d->stale = FALSE; /* default means normal, not stale */
+}
+
+
+void Curl_digest_cleanup(struct SessionHandle *data)
+{
+  Curl_digest_cleanup_one(&data->state.digest);
+  Curl_digest_cleanup_one(&data->state.proxydigest);
+}
+
+#endif
diff --git a/Utilities/cmcurl/http_digest.h b/Utilities/cmcurl/http_digest.h
new file mode 100644
index 0000000..b4fca06
--- /dev/null
+++ b/Utilities/cmcurl/http_digest.h
@@ -0,0 +1,53 @@
+#ifndef __HTTP_DIGEST_H
+#define __HTTP_DIGEST_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+typedef enum {
+  CURLDIGEST_NONE, /* not a digest */
+  CURLDIGEST_BAD,  /* a digest, but one we don't like */
+  CURLDIGEST_BADALGO, /* unsupported algorithm requested */
+  CURLDIGEST_NOMEM,
+  CURLDIGEST_FINE, /* a digest we act on */
+
+  CURLDIGEST_LAST  /* last entry in this enum, don't use */
+} CURLdigest;
+
+enum {
+  CURLDIGESTALGO_MD5,
+  CURLDIGESTALGO_MD5SESS
+};
+
+/* this is for digest header input */
+CURLdigest Curl_input_digest(struct connectdata *conn,
+                             bool proxy, char *header);
+
+/* this is for creating digest header output */
+CURLcode Curl_output_digest(struct connectdata *conn,
+                            bool proxy,
+                            unsigned char *request,
+                            unsigned char *uripath);
+void Curl_digest_cleanup(struct SessionHandle *data);
+void Curl_digest_cleanup_one(struct digestdata *dig);
+
+#endif
diff --git a/Utilities/cmcurl/http_negotiate.c b/Utilities/cmcurl/http_negotiate.c
new file mode 100644
index 0000000..62a23f1
--- /dev/null
+++ b/Utilities/cmcurl/http_negotiate.c
@@ -0,0 +1,332 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+#include "setup.h"
+
+#ifdef HAVE_GSSAPI
+#ifdef HAVE_GSSMIT
+#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
+#endif
+
+#ifndef CURL_DISABLE_HTTP
+ /* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "urldata.h"
+#include "sendf.h"
+#include "strequal.h"
+#include "base64.h"
+#include "http_negotiate.h"
+#include "curl_memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+static int
+get_gss_name(struct connectdata *conn, gss_name_t *server)
+{
+  struct negotiatedata *neg_ctx = &conn->data->state.negotiate;
+  OM_uint32 major_status, minor_status;
+  gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
+  char name[2048];
+  const char* service;
+
+  /* GSSAPI implementation by Globus (known as GSI) requires the name to be
+     of form "<service>/<fqdn>" instead of <service>@<fqdn> (ie. slash instead
+     of at-sign). Also GSI servers are often identified as 'host' not 'khttp'.
+     Change following lines if you want to use GSI */
+
+  /* IIS uses the <service>@<fqdn> form but uses 'http' as the service name */
+
+  if (neg_ctx->gss)
+    service = "KHTTP";
+  else
+    service = "HTTP";
+
+  token.length = strlen(service) + 1 + strlen(conn->host.name) + 1;
+  if (token.length + 1 > sizeof(name))
+    return EMSGSIZE;
+
+  snprintf(name, sizeof(name), "%s@%s", service, conn->host.name);
+
+  token.value = (void *) name;
+  major_status = gss_import_name(&minor_status,
+                                 &token,
+                                 GSS_C_NT_HOSTBASED_SERVICE,
+                                 server);
+
+  return GSS_ERROR(major_status) ? -1 : 0;
+}
+
+static void
+log_gss_error(struct connectdata *conn, OM_uint32 error_status, char *prefix)
+{
+  OM_uint32 maj_stat, min_stat;
+  OM_uint32 msg_ctx = 0;
+  gss_buffer_desc status_string;
+  char buf[1024];
+  size_t len;
+
+  snprintf(buf, sizeof(buf), "%s", prefix);
+  len = strlen(buf);
+  do {
+    maj_stat = gss_display_status (&min_stat,
+                                   error_status,
+                                   GSS_C_MECH_CODE,
+                                   GSS_C_NO_OID,
+                                   &msg_ctx,
+                                   &status_string);
+      if (sizeof(buf) > len + status_string.length + 1) {
+        snprintf(buf + len, sizeof(buf) - len,
+                 ": %s", (char*) status_string.value);
+      len += status_string.length;
+    }
+    gss_release_buffer(&min_stat, &status_string);
+  } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
+
+  infof(conn->data, buf);
+}
+
+int Curl_input_negotiate(struct connectdata *conn, char *header)
+{
+  struct negotiatedata *neg_ctx = &conn->data->state.negotiate;
+  OM_uint32 major_status, minor_status, minor_status2;
+  gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
+  gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+  int ret;
+  size_t len;
+  bool gss;
+  const char* protocol;
+
+  while(*header && isspace((int)*header))
+    header++;
+  if(checkprefix("GSS-Negotiate", header)) {
+    protocol = "GSS-Negotiate";
+    gss = TRUE;
+  }
+  else if (checkprefix("Negotiate", header)) {
+    protocol = "Negotiate";
+    gss = FALSE;
+  }
+  else
+    return -1;
+
+  if (neg_ctx->context) {
+    if (neg_ctx->gss != gss) {
+      return -1;
+    }
+  }
+  else {
+    neg_ctx->protocol = protocol;
+    neg_ctx->gss = gss;
+  }
+
+  if (neg_ctx->context && neg_ctx->status == GSS_S_COMPLETE) {
+    /* We finished succesfully our part of authentication, but server
+     * rejected it (since we're again here). Exit with an error since we
+     * can't invent anything better */
+    Curl_cleanup_negotiate(conn->data);
+    return -1;
+  }
+
+  if (neg_ctx->server_name == NULL &&
+      (ret = get_gss_name(conn, &neg_ctx->server_name)))
+    return ret;
+
+  header += strlen(neg_ctx->protocol);
+  while(*header && isspace((int)*header))
+    header++;
+
+  len = strlen(header);
+  if (len > 0) {
+    int rawlen;
+    input_token.length = (len+3)/4 * 3;
+    input_token.value = malloc(input_token.length);
+    if (input_token.value == NULL)
+      return ENOMEM;
+    rawlen = Curl_base64_decode(header, input_token.value);
+    if (rawlen < 0)
+      return -1;
+    input_token.length = rawlen;
+
+#ifdef HAVE_SPNEGO /* Handle SPNEGO */
+    if (checkprefix("Negotiate", header)) {
+        ASN1_OBJECT *   object            = NULL;
+        int             rc                = 1;
+        unsigned char * spnegoToken       = NULL;
+        size_t          spnegoTokenLength = 0;
+        unsigned char * mechToken         = NULL;
+        size_t          mechTokenLength   = 0;
+
+        spnegoToken = malloc(input_token.length);
+        if (input_token.value == NULL)
+          return ENOMEM;
+        spnegoTokenLength = input_token.length;
+
+        object = OBJ_txt2obj ("1.2.840.113554.1.2.2", 1);
+        if (!parseSpnegoTargetToken(spnegoToken,
+                                    spnegoTokenLength,
+                                    NULL,
+                                    NULL,
+                                    &mechToken,
+                                    &mechTokenLength,
+                                    NULL,
+                                    NULL)) {
+          free(spnegoToken);
+          spnegoToken = NULL;
+          infof(conn->data, "Parse SPNEGO Target Token failed\n");
+        }
+        else {
+          free(input_token.value);
+          input_token.value = NULL;
+          input_token.value = malloc(mechTokenLength);
+          memcpy(input_token.value, mechToken,mechTokenLength);
+          input_token.length = mechTokenLength;
+          free(mechToken);
+          mechToken = NULL;
+          infof(conn->data, "Parse SPNEGO Target Token succeded\n");
+        }
+    }
+#endif
+  }
+
+  major_status = gss_init_sec_context(&minor_status,
+                                      GSS_C_NO_CREDENTIAL,
+                                      &neg_ctx->context,
+                                      neg_ctx->server_name,
+                                      GSS_C_NO_OID,
+                                      GSS_C_DELEG_FLAG,
+                                      0,
+                                      GSS_C_NO_CHANNEL_BINDINGS,
+                                      &input_token,
+                                      NULL,
+                                      &output_token,
+                                      NULL,
+                                      NULL);
+  if (input_token.length > 0)
+    gss_release_buffer(&minor_status2, &input_token);
+  neg_ctx->status = major_status;
+  if (GSS_ERROR(major_status)) {
+    /* Curl_cleanup_negotiate(conn->data) ??? */
+    log_gss_error(conn, minor_status,
+                  (char *)"gss_init_sec_context() failed: ");
+    return -1;
+  }
+
+  if (output_token.length == 0) {
+    return -1;
+  }
+
+  neg_ctx->output_token = output_token;
+  /* conn->bits.close = FALSE; */
+
+  return 0;
+}
+
+
+CURLcode Curl_output_negotiate(struct connectdata *conn)
+{
+  struct negotiatedata *neg_ctx = &conn->data->state.negotiate;
+  OM_uint32 minor_status;
+  char *encoded = NULL;
+  int len;
+
+#ifdef HAVE_SPNEGO /* Handle SPNEGO */
+  if (checkprefix("Negotiate",neg_ctx->protocol)) {
+    ASN1_OBJECT *   object            = NULL;
+    int             rc                = 1;
+    unsigned char * spnegoToken       = NULL;
+    size_t          spnegoTokenLength = 0;
+    unsigned char * responseToken       = NULL;
+    size_t          responseTokenLength = 0;
+
+    responseToken = malloc(neg_ctx->output_token.length);
+    if ( responseToken == NULL)
+      return CURLE_OUT_OF_MEMORY;
+    memcpy(responseToken, neg_ctx->output_token.value,
+           neg_ctx->output_token.length);
+    responseTokenLength = neg_ctx->output_token.length;
+
+    object=OBJ_txt2obj ("1.2.840.113554.1.2.2", 1);
+    if (!makeSpnegoInitialToken (object,
+                                 responseToken,
+                                 responseTokenLength,
+                                 &spnegoToken,
+                                 &spnegoTokenLength)) {
+      free(responseToken);
+      responseToken = NULL;
+      infof(conn->data, "Make SPNEGO Initial Token failed\n");
+    }
+    else {
+      free(neg_ctx->output_token.value);
+      responseToken = NULL;
+      neg_ctx->output_token.value = malloc(spnegoTokenLength);
+      memcpy(neg_ctx->output_token.value, spnegoToken,spnegoTokenLength);
+      neg_ctx->output_token.length = spnegoTokenLength;
+      free(spnegoToken);
+      spnegoToken = NULL;
+      infof(conn->data, "Make SPNEGO Initial Token succeded\n");
+    }
+  }
+#endif
+  len = Curl_base64_encode(neg_ctx->output_token.value,
+                           neg_ctx->output_token.length,
+                           &encoded);
+
+  if (len < 0)
+    return CURLE_OUT_OF_MEMORY;
+
+  conn->allocptr.userpwd =
+    aprintf("Authorization: %s %s\r\n", neg_ctx->protocol, encoded);
+  free(encoded);
+  gss_release_buffer(&minor_status, &neg_ctx->output_token);
+  return (conn->allocptr.userpwd == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK;
+}
+
+void Curl_cleanup_negotiate(struct SessionHandle *data)
+{
+  OM_uint32 minor_status;
+  struct negotiatedata *neg_ctx = &data->state.negotiate;
+
+  if (neg_ctx->context != GSS_C_NO_CONTEXT)
+    gss_delete_sec_context(&minor_status, &neg_ctx->context, GSS_C_NO_BUFFER);
+
+  if (neg_ctx->output_token.length != 0)
+    gss_release_buffer(&minor_status, &neg_ctx->output_token);
+
+  if (neg_ctx->server_name != GSS_C_NO_NAME)
+    gss_release_name(&minor_status, &neg_ctx->server_name);
+
+  memset(neg_ctx, 0, sizeof(*neg_ctx));
+}
+
+
+#endif
+#endif
diff --git a/Utilities/cmcurl/http_negotiate.h b/Utilities/cmcurl/http_negotiate.h
new file mode 100644
index 0000000..ce0d083
--- /dev/null
+++ b/Utilities/cmcurl/http_negotiate.h
@@ -0,0 +1,39 @@
+#ifndef __HTTP_NEGOTIATE_H
+#define __HTTP_NEGOTIATE_H
+
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#ifdef HAVE_GSSAPI
+
+/* this is for Negotiate header input */
+int Curl_input_negotiate(struct connectdata *conn, char *header);
+
+/* this is for creating Negotiate header output */
+CURLcode Curl_output_negotiate(struct connectdata *conn);
+
+void Curl_cleanup_negotiate(struct SessionHandle *data);
+
+#endif
+
+#endif
diff --git a/Utilities/cmcurl/http_ntlm.c b/Utilities/cmcurl/http_ntlm.c
new file mode 100644
index 0000000..fe0b653
--- /dev/null
+++ b/Utilities/cmcurl/http_ntlm.c
@@ -0,0 +1,585 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+#include "setup.h"
+
+/* NTLM details:
+
+   http://davenport.sourceforge.net/ntlm.html
+   http://www.innovation.ch/java/ntlm.html
+
+*/
+
+#ifndef CURL_DISABLE_HTTP
+#ifdef USE_SSLEAY
+/* We need OpenSSL for the crypto lib to provide us with MD4 and DES */
+
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "urldata.h"
+#include "sendf.h"
+#include "strequal.h"
+#include "base64.h"
+#include "http_ntlm.h"
+#include "url.h"
+#include "curl_memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include <openssl/des.h>
+#include <openssl/md4.h>
+#include <openssl/ssl.h>
+
+#if OPENSSL_VERSION_NUMBER < 0x00907001L
+#define DES_key_schedule des_key_schedule
+#define DES_cblock des_cblock
+#define DES_set_odd_parity des_set_odd_parity
+#define DES_set_key des_set_key
+#define DES_ecb_encrypt des_ecb_encrypt
+
+/* This is how things were done in the old days */
+#define DESKEY(x) x
+#define DESKEYARG(x) x
+#else
+/* Modern version */
+#define DESKEYARG(x) *x
+#define DESKEY(x) &x
+#endif
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* Define this to make the type-3 message include the NT response message */
+#define USE_NTRESPONSES 1
+
+/*
+  (*) = A "security buffer" is a triplet consisting of two shorts and one
+  long:
+
+  1. a 'short' containing the length of the buffer in bytes
+  2. a 'short' containing the allocated space for the buffer in bytes
+  3. a 'long' containing the offset to the start of the buffer from the
+     beginning of the NTLM message, in bytes.
+*/
+
+
+CURLntlm Curl_input_ntlm(struct connectdata *conn,
+                         bool proxy,   /* if proxy or not */
+                         char *header) /* rest of the www-authenticate:
+                                          header */
+{
+  /* point to the correct struct with this */
+  struct ntlmdata *ntlm;
+
+  ntlm = proxy?&conn->proxyntlm:&conn->ntlm;
+
+  /* skip initial whitespaces */
+  while(*header && isspace((int)*header))
+    header++;
+
+  if(checkprefix("NTLM", header)) {
+    unsigned char buffer[256];
+    header += strlen("NTLM");
+
+    while(*header && isspace((int)*header))
+      header++;
+
+    if(*header) {
+      /* We got a type-2 message here:
+
+         Index   Description         Content
+         0       NTLMSSP Signature   Null-terminated ASCII "NTLMSSP"
+                                     (0x4e544c4d53535000)
+         8       NTLM Message Type   long (0x02000000)
+         12      Target Name         security buffer(*)
+         20      Flags               long
+         24      Challenge           8 bytes
+         (32)    Context (optional)  8 bytes (two consecutive longs)
+         (40)    Target Information  (optional) security buffer(*)
+         32 (48) start of data block
+      */
+
+      size_t size = Curl_base64_decode(header, (char *)buffer);
+
+      ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */
+
+      if(size >= 48)
+        /* the nonce of interest is index [24 .. 31], 8 bytes */
+        memcpy(ntlm->nonce, &buffer[24], 8);
+
+      /* at index decimal 20, there's a 32bit NTLM flag field */
+
+    }
+    else {
+      if(ntlm->state >= NTLMSTATE_TYPE1)
+        return CURLNTLM_BAD;
+
+      ntlm->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */
+    }
+  }
+  return CURLNTLM_FINE;
+}
+
+/*
+ * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.  The
+ * key schedule ks is also set.
+ */
+static void setup_des_key(unsigned char *key_56,
+                          DES_key_schedule DESKEYARG(ks))
+{
+  DES_cblock key;
+
+  key[0] = key_56[0];
+  key[1] = ((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1);
+  key[2] = ((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2);
+  key[3] = ((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3);
+  key[4] = ((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4);
+  key[5] = ((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5);
+  key[6] = ((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6);
+  key[7] =  (key_56[6] << 1) & 0xFF;
+
+  DES_set_odd_parity(&key);
+  DES_set_key(&key, ks);
+}
+
+ /*
+  * takes a 21 byte array and treats it as 3 56-bit DES keys. The
+  * 8 byte plaintext is encrypted with each key and the resulting 24
+  * bytes are stored in the results array.
+  */
+static void calc_resp(unsigned char *keys,
+                      unsigned char *plaintext,
+                      unsigned char *results)
+{
+  DES_key_schedule ks;
+
+  setup_des_key(keys, DESKEY(ks));
+  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
+                  DESKEY(ks), DES_ENCRYPT);
+
+  setup_des_key(keys+7, DESKEY(ks));
+  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8),
+                  DESKEY(ks), DES_ENCRYPT);
+
+  setup_des_key(keys+14, DESKEY(ks));
+  DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16),
+                  DESKEY(ks), DES_ENCRYPT);
+}
+
+/*
+ * Set up lanmanager and nt hashed passwords
+ */
+static void mkhash(char *password,
+                   unsigned char *nonce,  /* 8 bytes */
+                   unsigned char *lmresp  /* must fit 0x18 bytes */
+#ifdef USE_NTRESPONSES
+                   , unsigned char *ntresp  /* must fit 0x18 bytes */
+#endif
+  )
+{
+  unsigned char lmbuffer[21];
+#ifdef USE_NTRESPONSES
+  unsigned char ntbuffer[21];
+#endif
+  unsigned char *pw;
+  static const unsigned char magic[] = {
+    0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25
+  };
+  unsigned int i;
+  size_t len = strlen(password);
+
+  /* make it fit at least 14 bytes */
+  pw = malloc(len<7?14:len*2);
+  if(!pw)
+    return; /* this will lead to a badly generated package */
+
+  if (len > 14)
+    len = 14;
+
+  for (i=0; i<len; i++)
+    pw[i] = toupper(password[i]);
+
+  for (; i<14; i++)
+    pw[i] = 0;
+
+  {
+    /* create LanManager hashed password */
+    DES_key_schedule ks;
+
+    setup_des_key(pw, DESKEY(ks));
+    DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer,
+                    DESKEY(ks), DES_ENCRYPT);
+
+    setup_des_key(pw+7, DESKEY(ks));
+    DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8),
+                    DESKEY(ks), DES_ENCRYPT);
+
+    memset(lmbuffer+16, 0, 5);
+  }
+  /* create LM responses */
+  calc_resp(lmbuffer, nonce, lmresp);
+
+#ifdef USE_NTRESPONSES
+  {
+    /* create NT hashed password */
+    MD4_CTX MD4;
+
+    len = strlen(password);
+
+    for (i=0; i<len; i++) {
+      pw[2*i]   = password[i];
+      pw[2*i+1] = 0;
+    }
+
+    MD4_Init(&MD4);
+    MD4_Update(&MD4, pw, 2*len);
+    MD4_Final(ntbuffer, &MD4);
+
+    memset(ntbuffer+16, 0, 8);
+  }
+
+  calc_resp(ntbuffer, nonce, ntresp);
+#endif
+
+  free(pw);
+}
+
+#define SHORTPAIR(x) ((x) & 0xff), ((x) >> 8)
+#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
+  (((x) >>16)&0xff), ((x)>>24)
+
+/* this is for creating ntlm header output */
+CURLcode Curl_output_ntlm(struct connectdata *conn,
+                          bool proxy)
+{
+  const char *domain=""; /* empty */
+  const char *host=""; /* empty */
+  int domlen=(int)strlen(domain);
+  int hostlen = (int)strlen(host);
+  int hostoff; /* host name offset */
+  int domoff;  /* domain name offset */
+  size_t size;
+  char *base64=NULL;
+  unsigned char ntlmbuf[256]; /* enough, unless the host/domain is very long */
+
+  /* point to the address of the pointer that holds the string to sent to the
+     server, which is for a plain host or for a HTTP proxy */
+  char **allocuserpwd;
+
+  /* point to the name and password for this */
+  char *userp;
+  char *passwdp;
+  /* point to the correct struct with this */
+  struct ntlmdata *ntlm;
+  struct auth *authp;
+
+  curlassert(conn);
+  curlassert(conn->data);
+
+  if(proxy) {
+    allocuserpwd = &conn->allocptr.proxyuserpwd;
+    userp = conn->proxyuser;
+    passwdp = conn->proxypasswd;
+    ntlm = &conn->proxyntlm;
+    authp = &conn->data->state.authproxy;
+  }
+  else {
+    allocuserpwd = &conn->allocptr.userpwd;
+    userp = conn->user;
+    passwdp = conn->passwd;
+    ntlm = &conn->ntlm;
+    authp = &conn->data->state.authhost;
+  }
+  authp->done = FALSE;
+
+  /* not set means empty */
+  if(!userp)
+    userp=(char *)"";
+
+  if(!passwdp)
+    passwdp=(char *)"";
+
+  switch(ntlm->state) {
+  case NTLMSTATE_TYPE1:
+  default: /* for the weird cases we (re)start here */
+    hostoff = 32;
+    domoff = hostoff + hostlen;
+
+    /* Create and send a type-1 message:
+
+    Index Description          Content
+    0     NTLMSSP Signature    Null-terminated ASCII "NTLMSSP"
+                               (0x4e544c4d53535000)
+    8     NTLM Message Type    long (0x01000000)
+    12    Flags                long
+    16    Supplied Domain      security buffer(*)
+    24    Supplied Workstation security buffer(*)
+    32    start of data block
+
+    */
+
+    snprintf((char *)ntlmbuf, sizeof(ntlmbuf), "NTLMSSP%c"
+             "\x01%c%c%c" /* 32-bit type = 1 */
+             "%c%c%c%c"   /* 32-bit NTLM flag field */
+             "%c%c"  /* domain length */
+             "%c%c"  /* domain allocated space */
+             "%c%c"  /* domain name offset */
+             "%c%c"  /* 2 zeroes */
+             "%c%c"  /* host length */
+             "%c%c"  /* host allocated space */
+             "%c%c"  /* host name offset */
+             "%c%c"  /* 2 zeroes */
+             "%s"   /* host name */
+             "%s",  /* domain string */
+             0,     /* trailing zero */
+             0,0,0, /* part of type-1 long */
+
+             LONGQUARTET(
+               NTLMFLAG_NEGOTIATE_OEM|      /*   2 */
+               NTLMFLAG_NEGOTIATE_NTLM_KEY  /* 200 */
+               /* equals 0x0202 */
+               ),
+             SHORTPAIR(domlen),
+             SHORTPAIR(domlen),
+             SHORTPAIR(domoff),
+             0,0,
+             SHORTPAIR(hostlen),
+             SHORTPAIR(hostlen),
+             SHORTPAIR(hostoff),
+             0,0,
+             host, domain);
+
+    /* initial packet length */
+    size = 32 + hostlen + domlen;
+
+    /* now keeper of the base64 encoded package size */
+    size = Curl_base64_encode((char *)ntlmbuf, size, &base64);
+
+    if(size >0 ) {
+      Curl_safefree(*allocuserpwd);
+      *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+                              proxy?"Proxy-":"",
+                              base64);
+      free(base64);
+    }
+    else
+      return CURLE_OUT_OF_MEMORY; /* FIX TODO */
+
+    break;
+
+  case NTLMSTATE_TYPE2:
+    /* We received the type-2 already, create a type-3 message:
+
+    Index   Description            Content
+    0       NTLMSSP Signature      Null-terminated ASCII "NTLMSSP"
+                                   (0x4e544c4d53535000)
+    8       NTLM Message Type      long (0x03000000)
+    12      LM/LMv2 Response       security buffer(*)
+    20      NTLM/NTLMv2 Response   security buffer(*)
+    28      Domain Name            security buffer(*)
+    36      User Name              security buffer(*)
+    44      Workstation Name       security buffer(*)
+    (52)    Session Key (optional) security buffer(*)
+    (60)    Flags (optional)       long
+    52 (64) start of data block
+
+    */
+
+  {
+    int lmrespoff;
+    int ntrespoff;
+    int useroff;
+    unsigned char lmresp[0x18]; /* fixed-size */
+#ifdef USE_NTRESPONSES
+    unsigned char ntresp[0x18]; /* fixed-size */
+#endif
+    const char *user;
+    int userlen;
+
+    user = strchr(userp, '\\');
+    if(!user)
+      user = strchr(userp, '/');
+
+    if (user) {
+      domain = userp;
+      domlen = (int)(user - domain);
+      user++;
+    }
+    else
+      user = userp;
+    userlen = (int)strlen(user);
+
+    mkhash(passwdp, &ntlm->nonce[0], lmresp
+#ifdef USE_NTRESPONSES
+           , ntresp
+#endif
+      );
+
+    domoff = 64; /* always */
+    useroff = domoff + domlen;
+    hostoff = useroff + userlen;
+    lmrespoff = hostoff + hostlen;
+    ntrespoff = lmrespoff + 0x18;
+
+    /* Create the big type-3 message binary blob */
+    size = snprintf((char *)ntlmbuf, sizeof(ntlmbuf),
+                    "NTLMSSP%c"
+                    "\x03%c%c%c" /* type-3, 32 bits */
+
+                    "%c%c%c%c" /* LanManager length + allocated space */
+                    "%c%c" /* LanManager offset */
+                    "%c%c" /* 2 zeroes */
+
+                    "%c%c" /* NT-response length */
+                    "%c%c" /* NT-response allocated space */
+                    "%c%c" /* NT-response offset */
+                    "%c%c" /* 2 zeroes */
+
+                    "%c%c"  /* domain length */
+                    "%c%c"  /* domain allocated space */
+                    "%c%c"  /* domain name offset */
+                    "%c%c"  /* 2 zeroes */
+
+                    "%c%c"  /* user length */
+                    "%c%c"  /* user allocated space */
+                    "%c%c"  /* user offset */
+                    "%c%c"  /* 2 zeroes */
+
+                    "%c%c"  /* host length */
+                    "%c%c"  /* host allocated space */
+                    "%c%c"  /* host offset */
+                    "%c%c%c%c%c%c"  /* 6 zeroes */
+
+                    "\xff\xff"  /* message length */
+                    "%c%c"  /* 2 zeroes */
+
+                    "\x01\x82" /* flags */
+                    "%c%c"  /* 2 zeroes */
+
+                    /* domain string */
+                    /* user string */
+                    /* host string */
+                    /* LanManager response */
+                    /* NT response */
+                    ,
+                    0, /* zero termination */
+                    0,0,0, /* type-3 long, the 24 upper bits */
+
+                    SHORTPAIR(0x18),  /* LanManager response length, twice */
+                    SHORTPAIR(0x18),
+                    SHORTPAIR(lmrespoff),
+                    0x0, 0x0,
+
+#ifdef USE_NTRESPONSES
+                    SHORTPAIR(0x18),  /* NT-response length, twice */
+                    SHORTPAIR(0x18),
+#else
+                    0x0, 0x0,
+                    0x0, 0x0,
+#endif
+                    SHORTPAIR(ntrespoff),
+                    0x0, 0x0,
+
+                    SHORTPAIR(domlen),
+                    SHORTPAIR(domlen),
+                    SHORTPAIR(domoff),
+                    0x0, 0x0,
+
+                    SHORTPAIR(userlen),
+                    SHORTPAIR(userlen),
+                    SHORTPAIR(useroff),
+                    0x0, 0x0,
+
+                    SHORTPAIR(hostlen),
+                    SHORTPAIR(hostlen),
+                    SHORTPAIR(hostoff),
+                    0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+
+                    0x0, 0x0,
+
+                    0x0, 0x0);
+
+    /* size is now 64 */
+    size=64;
+    ntlmbuf[62]=ntlmbuf[63]=0;
+
+    memcpy(&ntlmbuf[size], domain, domlen);
+    size += domlen;
+
+    memcpy(&ntlmbuf[size], user, userlen);
+    size += userlen;
+
+    /* we append the binary hashes to the end of the blob */
+    if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
+      memcpy(&ntlmbuf[size], lmresp, 0x18);
+      size += 0x18;
+    }
+
+#ifdef USE_NTRESPONSES
+    if(size < ((int)sizeof(ntlmbuf) - 0x18)) {
+      memcpy(&ntlmbuf[size], ntresp, 0x18);
+      size += 0x18;
+    }
+#endif
+
+    ntlmbuf[56] = (unsigned char)(size & 0xff);
+    ntlmbuf[57] = (unsigned char)(size >> 8);
+
+    /* convert the binary blob into base64 */
+    size = Curl_base64_encode((char *)ntlmbuf, size, &base64);
+
+    if(size >0 ) {
+      Curl_safefree(*allocuserpwd);
+      *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+                              proxy?"Proxy-":"",
+                              base64);
+      free(base64);
+    }
+    else
+      return CURLE_OUT_OF_MEMORY; /* FIX TODO */
+
+    ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
+    authp->done = TRUE;
+  }
+  break;
+
+  case NTLMSTATE_TYPE3:
+    /* connection is already authenticated,
+     * don't send a header in future requests */
+    if(*allocuserpwd) {
+      free(*allocuserpwd);
+      *allocuserpwd=NULL;
+    }
+    authp->done = TRUE;
+    break;
+  }
+
+  return CURLE_OK;
+}
+#endif /* USE_SSLEAY */
+#endif /* !CURL_DISABLE_HTTP */
diff --git a/Utilities/cmcurl/http_ntlm.h b/Utilities/cmcurl/http_ntlm.h
new file mode 100644
index 0000000..4386a1c
--- /dev/null
+++ b/Utilities/cmcurl/http_ntlm.h
@@ -0,0 +1,143 @@
+#ifndef __HTTP_NTLM_H
+#define __HTTP_NTLM_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+typedef enum {
+  CURLNTLM_NONE, /* not a ntlm */
+  CURLNTLM_BAD,  /* an ntlm, but one we don't like */
+  CURLNTLM_FIRST, /* the first 401-reply we got with NTLM */
+  CURLNTLM_FINE, /* an ntlm we act on */
+
+  CURLNTLM_LAST  /* last entry in this enum, don't use */
+} CURLntlm;
+
+/* this is for ntlm header input */
+CURLntlm Curl_input_ntlm(struct connectdata *conn, bool proxy, char *header);
+
+/* this is for creating ntlm header output */
+CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy);
+
+void Curl_ntlm_cleanup(struct SessionHandle *data);
+
+
+/* Flag bits definitions based on http://davenport.sourceforge.net/ntlm.html */
+
+#define NTLMFLAG_NEGOTIATE_UNICODE               (1<<0)
+/* Indicates that Unicode strings are supported for use in security buffer
+   data. */
+
+#define NTLMFLAG_NEGOTIATE_OEM                   (1<<1)
+/* Indicates that OEM strings are supported for use in security buffer data. */
+
+#define NTLMFLAG_REQUEST_TARGET                  (1<<2)
+/* Requests that the server's authentication realm be included in the Type 2
+   message. */
+
+/* unknown (1<<3) */
+#define NTLMFLAG_NEGOTIATE_SIGN                  (1<<4)
+/* Specifies that authenticated communication between the client and server
+   should carry a digital signature (message integrity). */
+
+#define NTLMFLAG_NEGOTIATE_SEAL                  (1<<5)
+/* Specifies that authenticated communication between the client and server
+   should be encrypted (message confidentiality). */
+
+#define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE        (1<<6)
+/* unknown purpose */
+
+#define NTLMFLAG_NEGOTIATE_LM_KEY                (1<<7)
+/* Indicates that the LAN Manager session key should be used for signing and
+   sealing authenticated communications. */
+
+#define NTLMFLAG_NEGOTIATE_NETWARE               (1<<8)
+/* unknown purpose */
+
+#define NTLMFLAG_NEGOTIATE_NTLM_KEY              (1<<9)
+/* Indicates that NTLM authentication is being used. */
+
+/* unknown (1<<10) */
+/* unknown (1<<11) */
+
+#define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED       (1<<12)
+/* Sent by the client in the Type 1 message to indicate that a desired
+   authentication realm is included in the message. */
+
+#define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED  (1<<13)
+/* Sent by the client in the Type 1 message to indicate that the client
+   workstation's name is included in the message. */
+
+#define NTLMFLAG_NEGOTIATE_LOCAL_CALL            (1<<14)
+/* Sent by the server to indicate that the server and client are on the same
+   machine. Implies that the client may use a pre-established local security
+   context rather than responding to the challenge. */
+
+#define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN           (1<<15)
+/* Indicates that authenticated communication between the client and server
+   should be signed with a "dummy" signature. */
+
+#define NTLMFLAG_TARGET_TYPE_DOMAIN              (1<<16)
+/* Sent by the server in the Type 2 message to indicate that the target
+   authentication realm is a domain. */
+
+#define NTLMFLAG_TARGET_TYPE_SERVER              (1<<17)
+/* Sent by the server in the Type 2 message to indicate that the target
+   authentication realm is a server. */
+
+#define NTLMFLAG_TARGET_TYPE_SHARE               (1<<18)
+/* Sent by the server in the Type 2 message to indicate that the target
+   authentication realm is a share. Presumably, this is for share-level
+   authentication. Usage is unclear. */
+
+#define NTLMFLAG_NEGOTIATE_NTLM2_KEY             (1<<19)
+/* Indicates that the NTLM2 signing and sealing scheme should be used for
+   protecting authenticated communications. */
+
+#define NTLMFLAG_REQUEST_INIT_RESPONSE           (1<<20)
+/* unknown purpose */
+
+#define NTLMFLAG_REQUEST_ACCEPT_RESPONSE         (1<<21)
+/* unknown purpose */
+
+#define NTLMFLAG_REQUEST_NONNT_SESSION_KEY       (1<<22)
+/* unknown purpose */
+
+#define NTLMFLAG_NEGOTIATE_TARGET_INFO           (1<<23)
+/* Sent by the server in the Type 2 message to indicate that it is including a
+   Target Information block in the message. */
+
+/* unknown (1<24) */
+/* unknown (1<25) */
+/* unknown (1<26) */
+/* unknown (1<27) */
+/* unknown (1<28) */
+
+#define NTLMFLAG_NEGOTIATE_128                   (1<<29)
+/* Indicates that 128-bit encryption is supported. */
+
+#define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE          (1<<30)
+/* unknown purpose */
+
+#define NTLMFLAG_NEGOTIATE_56                    (1<<31)
+/* Indicates that 56-bit encryption is supported. */
+#endif
diff --git a/Utilities/cmcurl/if2ip.c b/Utilities/cmcurl/if2ip.c
new file mode 100644
index 0000000..8bccc94
--- /dev/null
+++ b/Utilities/cmcurl/if2ip.c
@@ -0,0 +1,142 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if !defined(WIN32) && !defined(__BEOS__) && !defined(__CYGWIN32__) && \
+    !defined(__riscos__) && !defined(__INTERIX) && !defined(NETWARE)
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+/* This must be before net/if.h for AIX 3.2 to enjoy life */
+#include <sys/time.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+/* -- if2ip() -- */
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+
+#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
+#include "inet_ntoa_r.h"
+#endif
+
+#ifdef  VMS
+#include <inet.h>
+#endif
+
+#include "if2ip.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#define SYS_ERROR -1
+
+char *Curl_if2ip(const char *interface, char *buf, int buf_size)
+{
+  int dummy;
+  char *ip=NULL;
+
+  if(!interface)
+    return NULL;
+
+  dummy = socket(AF_INET, SOCK_STREAM, 0);
+  if (SYS_ERROR == dummy) {
+    return NULL;
+  }
+  else {
+    struct ifreq req;
+    size_t len = strlen(interface);
+    memset(&req, 0, sizeof(req));
+    if(len >= sizeof(req.ifr_name))
+      return NULL; /* this can't be a fine interface name */
+    memcpy(req.ifr_name, interface, len+1);
+    req.ifr_addr.sa_family = AF_INET;
+#ifdef  IOCTL_3_ARGS
+    if (SYS_ERROR == ioctl(dummy, SIOCGIFADDR, &req)) {
+#else
+    if (SYS_ERROR == ioctl(dummy, SIOCGIFADDR, &req, sizeof(req))) {
+#endif
+      sclose(dummy);
+      return NULL;
+    }
+    else {
+      struct in_addr in;
+
+      union {
+        struct sockaddr_in *sin;
+        struct sockaddr *s;
+      } soadd;
+
+      soadd.s = &req.ifr_dstaddr;
+      memcpy(&in, &(soadd.sin->sin_addr.s_addr), sizeof(in));
+#if defined(HAVE_INET_NTOA_R)
+      ip = inet_ntoa_r(in,buf,buf_size);
+#else
+      ip = strncpy(buf,inet_ntoa(in),buf_size);
+      ip[buf_size - 1] = 0;
+#endif
+    }
+    sclose(dummy);
+  }
+  return ip;
+}
+
+/* -- end of if2ip() -- */
+#else
+char *Curl_if2ip(const char *interface, char *buf, int buf_size)
+{
+    (void) interface;
+    (void) buf;
+    (void) buf_size;
+    return NULL;
+}
+#endif
diff --git a/Utilities/cmcurl/if2ip.h b/Utilities/cmcurl/if2ip.h
new file mode 100644
index 0000000..45a1805
--- /dev/null
+++ b/Utilities/cmcurl/if2ip.h
@@ -0,0 +1,69 @@
+#ifndef __IF2IP_H
+#define __IF2IP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+#include "setup.h"
+
+#if !defined(WIN32) && !defined(__BEOS__) && !defined(__CYGWIN32__) && \
+    !defined(__riscos__) && !defined(__INTERIX)
+extern char *Curl_if2ip(const char *interface, char *buf, int buf_size);
+#else
+#define Curl_if2ip(a,b,c) NULL
+#endif
+#ifdef __INTERIX
+/* Nedelcho Stanev's work-around for SFU 3.0 */
+struct ifreq {
+#define IFNAMSIZ 16
+#define IFHWADDRLEN 6
+  union {
+    char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+  } ifr_ifrn;
+
+ union {
+   struct sockaddr ifru_addr;
+   struct sockaddr ifru_broadaddr;
+   struct sockaddr ifru_netmask;
+   struct sockaddr ifru_hwaddr;
+   short ifru_flags;
+   int ifru_metric;
+   int ifru_mtu;
+ } ifr_ifru;
+};
+
+/* This define was added by Daniel to avoid an extra #ifdef INTERIX in the
+   C code. */
+#define ifr_dstaddr ifr_addr
+
+#define ifr_name ifr_ifrn.ifrn_name /* interface name */
+#define ifr_addr ifr_ifru.ifru_addr /* address */
+#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
+#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */
+#define ifr_flags ifr_ifru.ifru_flags /* flags */
+#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
+#define ifr_metric ifr_ifru.ifru_metric /* metric */
+#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
+
+#define SIOCGIFADDR _IOW('s', 102, struct ifreq) /* Get if addr */
+#endif /* interix */
+
+#endif
diff --git a/Utilities/cmcurl/inet_ntoa_r.h b/Utilities/cmcurl/inet_ntoa_r.h
new file mode 100644
index 0000000..7959c49
--- /dev/null
+++ b/Utilities/cmcurl/inet_ntoa_r.h
@@ -0,0 +1,9 @@
+#ifndef __INET_NTOA_R_H
+#define __INET_NTOA_R_H
+/*
+ * My solaris 5.6 system running gcc 2.8.1 does *not* have this prototype
+ * in any system include file! Isn't that weird?
+ */
+char *inet_ntoa_r(const struct in_addr in, char *buffer, int buflen);
+
+#endif
diff --git a/Utilities/cmcurl/inet_ntop.c b/Utilities/cmcurl/inet_ntop.c
new file mode 100644
index 0000000..6809a92
--- /dev/null
+++ b/Utilities/cmcurl/inet_ntop.c
@@ -0,0 +1,204 @@
+/*
+ * Original code by Paul Vixie. "curlified" by Gisle Vanem.
+ */
+
+#include "setup.h"
+
+#ifndef HAVE_INET_NTOP
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "inet_ntop.h"
+
+#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
+/* this platform has a inet_ntoa_r() function, but no proto declared anywhere
+   so we include our own proto to make compilers happy */
+#include "inet_ntoa_r.h"
+#endif
+
+#define IN6ADDRSZ       16
+#define INADDRSZ         4
+#define INT16SZ          2
+
+#ifdef WIN32
+#define EAFNOSUPPORT    WSAEAFNOSUPPORT
+#define SET_ERRNO(e)    WSASetLastError(errno = (e))
+#else
+#define SET_ERRNO(e)    errno = e
+#endif
+
+/*
+ * Format an IPv4 address, more or less like inet_ntoa().
+ *
+ * Returns `dst' (as a const)
+ * Note:
+ *  - uses no statics
+ *  - takes a u_char* not an in_addr as input
+ */
+static const char *inet_ntop4 (const u_char *src, char *dst, size_t size)
+{
+#ifdef HAVE_INET_NTOA_R
+  return inet_ntoa_r(*(struct in_addr*)src, dst, size);
+#else
+  union {
+    const u_char* uch;
+    const struct in_addr* iad;
+  } srcaddr;
+  const char *addr;
+  srcaddr.uch = src;
+  addr = inet_ntoa(*srcaddr.iad);
+
+  if (strlen(addr) >= size)
+  {
+    SET_ERRNO(ENOSPC);
+    return (NULL);
+  }
+  return strcpy(dst, addr);
+#endif
+}
+
+#ifdef ENABLE_IPV6
+/*
+ * Convert IPv6 binary address into presentation (printable) format.
+ */
+static const char *inet_ntop6 (const u_char *src, char *dst, size_t size)
+{
+  /*
+   * Note that int32_t and int16_t need only be "at least" large enough
+   * to contain a value of the specified size.  On some systems, like
+   * Crays, there is no such thing as an integer variable with 16 bits.
+   * Keep this in mind if you think this function should have been coded
+   * to use pointer overlays.  All the world's not a VAX.
+   */
+  char  tmp [sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
+  char *tp;
+  struct {
+    long base;
+    long len;
+  } best, cur;
+  u_long words [IN6ADDRSZ / INT16SZ];
+  int    i;
+
+  /* Preprocess:
+   *  Copy the input (bytewise) array into a wordwise array.
+   *  Find the longest run of 0x00's in src[] for :: shorthanding.
+   */
+  memset(words, 0, sizeof(words));
+  for (i = 0; i < IN6ADDRSZ; i++)
+      words[i/2] |= (src[i] << ((1 - (i % 2)) << 3));
+
+  best.base = -1;
+  cur.base  = -1;
+  for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
+  {
+    if (words[i] == 0)
+    {
+      if (cur.base == -1)
+        cur.base = i, cur.len = 1;
+      else
+        cur.len++;
+    }
+    else if (cur.base != -1)
+    {
+      if (best.base == -1 || cur.len > best.len)
+         best = cur;
+      cur.base = -1;
+    }
+  }
+  if ((cur.base != -1) && (best.base == -1 || cur.len > best.len))
+     best = cur;
+  if (best.base != -1 && best.len < 2)
+     best.base = -1;
+
+  /* Format the result.
+   */
+  tp = tmp;
+  for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
+  {
+    /* Are we inside the best run of 0x00's?
+     */
+    if (best.base != -1 && i >= best.base && i < (best.base + best.len))
+    {
+      if (i == best.base)
+         *tp++ = ':';
+      continue;
+    }
+
+    /* Are we following an initial run of 0x00s or any real hex?
+     */
+    if (i != 0)
+       *tp++ = ':';
+
+    /* Is this address an encapsulated IPv4?
+     */
+    if (i == 6 && best.base == 0 &&
+        (best.len == 6 || (best.len == 5 && words[5] == 0xffff)))
+    {
+      if (!inet_ntop4(src+12, tp, sizeof(tmp) - (tp - tmp)))
+      {
+        SET_ERRNO(ENOSPC);
+        return (NULL);
+      }
+      tp += strlen(tp);
+      break;
+    }
+    tp += snprintf(tp, 5, "%lx", words[i]);
+  }
+
+  /* Was it a trailing run of 0x00's?
+   */
+  if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
+     *tp++ = ':';
+  *tp++ = '\0';
+
+  /* Check for overflow, copy, and we're done.
+   */
+  if ((size_t)(tp - tmp) > size)
+  {
+    SET_ERRNO(ENOSPC);
+    return (NULL);
+  }
+  return strcpy (dst, tmp);
+}
+#endif  /* ENABLE_IPV6 */
+
+/*
+ * Convert a network format address to presentation format.
+ *
+ * Returns pointer to presentation format address (`dst'),
+ * Returns NULL on error (see errno).
+ */
+const char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
+{
+  switch (af) {
+  case AF_INET:
+    return inet_ntop4((const u_char*)src, buf, size);
+#ifdef ENABLE_IPV6
+  case AF_INET6:
+    return inet_ntop6((const u_char*)src, buf, size);
+#endif
+  default:
+    SET_ERRNO(EAFNOSUPPORT);
+    return NULL;
+  }
+}
+#endif  /* HAVE_INET_NTOP */
diff --git a/Utilities/cmcurl/inet_ntop.h b/Utilities/cmcurl/inet_ntop.h
new file mode 100644
index 0000000..5948a12
--- /dev/null
+++ b/Utilities/cmcurl/inet_ntop.h
@@ -0,0 +1,37 @@
+#ifndef __INET_NTOP_H
+#define __INET_NTOP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#ifdef HAVE_INET_NTOP
+#define Curl_inet_ntop(af,addr,buf,size) inet_ntop(af,addr,buf,size)
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#else
+const char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size);
+#endif
+
+#endif /* __INET_NTOP_H */
diff --git a/Utilities/cmcurl/inet_pton.c b/Utilities/cmcurl/inet_pton.c
new file mode 100644
index 0000000..5e8e9b3
--- /dev/null
+++ b/Utilities/cmcurl/inet_pton.c
@@ -0,0 +1,240 @@
+/* This is from the BIND 4.9.4 release, modified to compile by itself */
+
+/* Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include "setup.h"
+
+#ifndef HAVE_INET_PTON
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+#include "inet_pton.h"
+
+#define IN6ADDRSZ       16
+#define INADDRSZ         4
+#define INT16SZ          2
+
+#ifdef WIN32
+#define EAFNOSUPPORT    WSAEAFNOSUPPORT
+#endif
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static int      inet_pton4(const char *src, unsigned char *dst);
+#ifdef ENABLE_IPV6
+static int      inet_pton6(const char *src, unsigned char *dst);
+#endif
+
+/* int
+ * inet_pton(af, src, dst)
+ *      convert from presentation format (which usually means ASCII printable)
+ *      to network format (which is usually some kind of binary format).
+ * return:
+ *      1 if the address was valid for the specified address family
+ *      0 if the address wasn't valid (`dst' is untouched in this case)
+ *      -1 if some other error occurred (`dst' is untouched in this case, too)
+ * author:
+ *      Paul Vixie, 1996.
+ */
+int
+Curl_inet_pton(int af, const char *src, void *dst)
+{
+        switch (af) {
+        case AF_INET:
+                return (inet_pton4(src, dst));
+#ifdef ENABLE_IPV6
+#ifndef AF_INET6
+#define AF_INET6        AF_MAX+1        /* just to let this compile */
+#endif
+        case AF_INET6:
+                return (inet_pton6(src, dst));
+#endif
+        default:
+                errno = EAFNOSUPPORT;
+                return (-1);
+        }
+        /* NOTREACHED */
+}
+
+/* int
+ * inet_pton4(src, dst)
+ *      like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ *      1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ *      does not touch `dst' unless it's returning 1.
+ * author:
+ *      Paul Vixie, 1996.
+ */
+static int
+inet_pton4(const char *src, unsigned char *dst)
+{
+        static const char digits[] = "0123456789";
+        int saw_digit, octets, ch;
+        unsigned char tmp[INADDRSZ], *tp;
+
+        saw_digit = 0;
+        octets = 0;
+        *(tp = tmp) = 0;
+        while ((ch = *src++) != '\0') {
+                const char *pch;
+
+                if ((pch = strchr(digits, ch)) != NULL) {
+                        u_int new = *tp * 10 + (pch - digits);
+
+                        if (new > 255)
+                                return (0);
+                        *tp = new;
+                        if (! saw_digit) {
+                                if (++octets > 4)
+                                        return (0);
+                                saw_digit = 1;
+                        }
+                } else if (ch == '.' && saw_digit) {
+                        if (octets == 4)
+                                return (0);
+                        *++tp = 0;
+                        saw_digit = 0;
+                } else
+                        return (0);
+        }
+        if (octets < 4)
+                return (0);
+        /* bcopy(tmp, dst, INADDRSZ); */
+        memcpy(dst, tmp, INADDRSZ);
+        return (1);
+}
+
+#ifdef ENABLE_IPV6
+/* int
+ * inet_pton6(src, dst)
+ *      convert presentation level address to network order binary form.
+ * return:
+ *      1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ *      (1) does not touch `dst' unless it's returning 1.
+ *      (2) :: in a full address is silently ignored.
+ * credit:
+ *      inspired by Mark Andrews.
+ * author:
+ *      Paul Vixie, 1996.
+ */
+static int
+inet_pton6(const char *src, unsigned char *dst)
+{
+        static const char xdigits_l[] = "0123456789abcdef",
+                          xdigits_u[] = "0123456789ABCDEF";
+        unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
+        const char *xdigits, *curtok;
+        int ch, saw_xdigit;
+        u_int val;
+
+        memset((tp = tmp), 0, IN6ADDRSZ);
+        endp = tp + IN6ADDRSZ;
+        colonp = NULL;
+        /* Leading :: requires some special handling. */
+        if (*src == ':')
+                if (*++src != ':')
+                        return (0);
+        curtok = src;
+        saw_xdigit = 0;
+        val = 0;
+        while ((ch = *src++) != '\0') {
+                const char *pch;
+
+                if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+                        pch = strchr((xdigits = xdigits_u), ch);
+                if (pch != NULL) {
+                        val <<= 4;
+                        val |= (pch - xdigits);
+                        if (val > 0xffff)
+                                return (0);
+                        saw_xdigit = 1;
+                        continue;
+                }
+                if (ch == ':') {
+                        curtok = src;
+                        if (!saw_xdigit) {
+                                if (colonp)
+                                        return (0);
+                                colonp = tp;
+                                continue;
+                        }
+                        if (tp + INT16SZ > endp)
+                                return (0);
+                        *tp++ = (unsigned char) (val >> 8) & 0xff;
+                        *tp++ = (unsigned char) val & 0xff;
+                        saw_xdigit = 0;
+                        val = 0;
+                        continue;
+                }
+                if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
+                    inet_pton4(curtok, tp) > 0) {
+                        tp += INADDRSZ;
+                        saw_xdigit = 0;
+                        break;  /* '\0' was seen by inet_pton4(). */
+                }
+                return (0);
+        }
+        if (saw_xdigit) {
+                if (tp + INT16SZ > endp)
+                        return (0);
+                *tp++ = (unsigned char) (val >> 8) & 0xff;
+                *tp++ = (unsigned char) val & 0xff;
+        }
+        if (colonp != NULL) {
+                /*
+                 * Since some memmove()'s erroneously fail to handle
+                 * overlapping regions, we'll do the shift by hand.
+                 */
+                const int n = tp - colonp;
+                int i;
+
+                for (i = 1; i <= n; i++) {
+                        endp[- i] = colonp[n - i];
+                        colonp[n - i] = 0;
+                }
+                tp = endp;
+        }
+        if (tp != endp)
+                return (0);
+        /* bcopy(tmp, dst, IN6ADDRSZ); */
+        memcpy(dst, tmp, IN6ADDRSZ);
+        return (1);
+}
+#endif /* ENABLE_IPV6 */
+
+#endif /* HAVE_INET_PTON */
diff --git a/Utilities/cmcurl/inet_pton.h b/Utilities/cmcurl/inet_pton.h
new file mode 100644
index 0000000..b0a70d4
--- /dev/null
+++ b/Utilities/cmcurl/inet_pton.h
@@ -0,0 +1,37 @@
+#ifndef __INET_PTON_H
+#define __INET_PTON_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#ifdef HAVE_INET_PTON
+#define Curl_inet_pton(x,y,z) inet_pton(x,y,z)
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#else
+int Curl_inet_pton(int, const char *, void *);
+#endif
+
+#endif /* __INET_PTON_H */
diff --git a/Utilities/cmcurl/krb4.c b/Utilities/cmcurl/krb4.c
new file mode 100644
index 0000000..50467e3
--- /dev/null
+++ b/Utilities/cmcurl/krb4.c
@@ -0,0 +1,408 @@
+/* This source code was modified by Martin Hedenfalk <mhe@stacken.kth.se> for
+ * use in Curl. His latest changes were done 2000-09-18.
+ *
+ * It has since been patched away like a madman by Daniel Stenberg
+ * <daniel@haxx.se> to make it better applied to curl conditions, and to make
+ * it not use globals, pollute name space and more. This source code awaits a
+ * rewrite to work around the paragraph 2 in the BSD licenses as explained
+ * below.
+ *
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska H�gskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.  */
+
+#include "setup.h"
+
+#ifndef CURL_DISABLE_FTP
+#ifdef HAVE_KRB4
+
+#include "security.h"
+#include "base64.h"
+#include <stdlib.h>
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#include <string.h>
+#include <krb.h>
+#include <des.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h> /* for getpid() */
+#endif
+
+#include "ftp.h"
+#include "sendf.h"
+#include "krb4.h"
+#include "curl_memory.h"
+
+#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
+#include "inet_ntoa_r.h"
+#endif
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#define LOCAL_ADDR (&conn->local_addr)
+#define REMOTE_ADDR conn->ip_addr->ai_addr
+#define myctladdr LOCAL_ADDR
+#define hisctladdr REMOTE_ADDR
+
+struct krb4_data {
+  des_cblock key;
+  des_key_schedule schedule;
+  char name[ANAME_SZ];
+  char instance[INST_SZ];
+  char realm[REALM_SZ];
+};
+
+#ifndef HAVE_STRLCPY
+/* if it ever goes non-static, make it Curl_ prefixed! */
+static size_t
+strlcpy (char *dst, const char *src, size_t dst_sz)
+{
+  size_t n;
+  char *p;
+
+  for (p = dst, n = 0;
+       n + 1 < dst_sz && *src != '\0';
+       ++p, ++src, ++n)
+    *p = *src;
+  *p = '\0';
+  if (*src == '\0')
+    return n;
+  else
+    return n + strlen (src);
+}
+#else
+size_t strlcpy (char *dst, const char *src, size_t dst_sz);
+#endif
+
+static int
+krb4_check_prot(void *app_data, int level)
+{
+  app_data = NULL; /* prevent compiler warning */
+  if(level == prot_confidential)
+    return -1;
+  return 0;
+}
+
+static int
+krb4_decode(void *app_data, void *buf, int len, int level,
+            struct connectdata *conn)
+{
+  MSG_DAT m;
+  int e;
+  struct krb4_data *d = app_data;
+
+  if(level == prot_safe)
+    e = krb_rd_safe(buf, len, &d->key,
+                    (struct sockaddr_in *)REMOTE_ADDR,
+                    (struct sockaddr_in *)LOCAL_ADDR, &m);
+  else
+    e = krb_rd_priv(buf, len, d->schedule, &d->key,
+                    (struct sockaddr_in *)REMOTE_ADDR,
+                    (struct sockaddr_in *)LOCAL_ADDR, &m);
+  if(e) {
+    struct SessionHandle *data = conn->data;
+    infof(data, "krb4_decode: %s\n", krb_get_err_text(e));
+    return -1;
+  }
+  memmove(buf, m.app_data, m.app_length);
+  return m.app_length;
+}
+
+static int
+krb4_overhead(void *app_data, int level, int len)
+{
+  /* no arguments are used, just init them to prevent compiler warnings */
+  app_data = NULL;
+  level = 0;
+  len = 0;
+  return 31;
+}
+
+static int
+krb4_encode(void *app_data, void *from, int length, int level, void **to,
+            struct connectdata *conn)
+{
+  struct krb4_data *d = app_data;
+  *to = malloc(length + 31);
+  if(level == prot_safe)
+    return krb_mk_safe(from, *to, length, &d->key,
+                       (struct sockaddr_in *)LOCAL_ADDR,
+                       (struct sockaddr_in *)REMOTE_ADDR);
+  else if(level == prot_private)
+    return krb_mk_priv(from, *to, length, d->schedule, &d->key,
+                       (struct sockaddr_in *)LOCAL_ADDR,
+                       (struct sockaddr_in *)REMOTE_ADDR);
+  else
+    return -1;
+}
+
+static int
+mk_auth(struct krb4_data *d, KTEXT adat,
+        const char *service, char *host, int checksum)
+{
+  int ret;
+  CREDENTIALS cred;
+  char sname[SNAME_SZ], inst[INST_SZ], realm[REALM_SZ];
+
+  strlcpy(sname, service, sizeof(sname));
+  strlcpy(inst, krb_get_phost(host), sizeof(inst));
+  strlcpy(realm, krb_realmofhost(host), sizeof(realm));
+  ret = krb_mk_req(adat, sname, inst, realm, checksum);
+  if(ret)
+    return ret;
+  strlcpy(sname, service, sizeof(sname));
+  strlcpy(inst, krb_get_phost(host), sizeof(inst));
+  strlcpy(realm, krb_realmofhost(host), sizeof(realm));
+  ret = krb_get_cred(sname, inst, realm, &cred);
+  memmove(&d->key, &cred.session, sizeof(des_cblock));
+  des_key_sched(&d->key, d->schedule);
+  memset(&cred, 0, sizeof(cred));
+  return ret;
+}
+
+#ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM
+int krb_get_our_ip_for_realm(char *, struct in_addr *);
+#endif
+
+static int
+krb4_auth(void *app_data, struct connectdata *conn)
+{
+  int ret;
+  char *p;
+  int len;
+  KTEXT_ST adat;
+  MSG_DAT msg_data;
+  int checksum;
+  u_int32_t cs;
+  struct krb4_data *d = app_data;
+  char *host = conn->host.name;
+  ssize_t nread;
+  int l = sizeof(conn->local_addr);
+  struct SessionHandle *data = conn->data;
+  CURLcode result;
+
+  if(getsockname(conn->sock[FIRSTSOCKET],
+                 (struct sockaddr *)LOCAL_ADDR, &l) < 0)
+    perror("getsockname()");
+
+  checksum = getpid();
+  ret = mk_auth(d, &adat, "ftp", host, checksum);
+  if(ret == KDC_PR_UNKNOWN)
+    ret = mk_auth(d, &adat, "rcmd", host, checksum);
+  if(ret) {
+    Curl_infof(data, "%s\n", krb_get_err_text(ret));
+    return AUTH_CONTINUE;
+  }
+
+#ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM
+  if (krb_get_config_bool("nat_in_use")) {
+    struct sockaddr_in *localaddr  = (struct sockaddr_in *)LOCAL_ADDR;
+    struct in_addr natAddr;
+
+    if (krb_get_our_ip_for_realm(krb_realmofhost(host),
+                                 &natAddr) != KSUCCESS
+        && krb_get_our_ip_for_realm(NULL, &natAddr) != KSUCCESS)
+      Curl_infof(data, "Can't get address for realm %s\n",
+                 krb_realmofhost(host));
+    else {
+      if (natAddr.s_addr != localaddr->sin_addr.s_addr) {
+#ifdef HAVE_INET_NTOA_R
+        char ntoa_buf[64];
+        char *ip = (char *)inet_ntoa_r(natAddr, ntoa_buf, sizeof(ntoa_buf));
+#else
+        char *ip = (char *)inet_ntoa(natAddr);
+#endif
+        Curl_infof(data, "Using NAT IP address (%s) for kerberos 4\n", ip);
+        localaddr->sin_addr = natAddr;
+      }
+    }
+  }
+#endif
+
+  if(Curl_base64_encode((char *)adat.dat, adat.length, &p) < 1) {
+    Curl_failf(data, "Out of memory base64-encoding");
+    return AUTH_CONTINUE;
+  }
+
+  result = Curl_ftpsendf(conn, "ADAT %s", p);
+
+  free(p);
+
+  if(result)
+    return -2;
+
+  if(Curl_GetFTPResponse(&nread, conn, NULL))
+    return -1;
+
+  if(data->state.buffer[0] != '2'){
+    Curl_failf(data, "Server didn't accept auth data");
+    return AUTH_ERROR;
+  }
+
+  p = strstr(data->state.buffer, "ADAT=");
+  if(!p) {
+    Curl_failf(data, "Remote host didn't send adat reply");
+    return AUTH_ERROR;
+  }
+  p += 5;
+  len = Curl_base64_decode(p, (char *)adat.dat);
+  if(len < 0) {
+    Curl_failf(data, "Failed to decode base64 from server");
+    return AUTH_ERROR;
+  }
+  adat.length = len;
+  ret = krb_rd_safe(adat.dat, adat.length, &d->key,
+                    (struct sockaddr_in *)hisctladdr,
+                    (struct sockaddr_in *)myctladdr, &msg_data);
+  if(ret) {
+    Curl_failf(data, "Error reading reply from server: %s",
+               krb_get_err_text(ret));
+    return AUTH_ERROR;
+  }
+  krb_get_int(msg_data.app_data, &cs, 4, 0);
+  if(cs - checksum != 1) {
+    Curl_failf(data, "Bad checksum returned from server");
+    return AUTH_ERROR;
+  }
+  return AUTH_OK;
+}
+
+struct Curl_sec_client_mech Curl_krb4_client_mech = {
+    "KERBEROS_V4",
+    sizeof(struct krb4_data),
+    NULL, /* init */
+    krb4_auth,
+    NULL, /* end */
+    krb4_check_prot,
+    krb4_overhead,
+    krb4_encode,
+    krb4_decode
+};
+
+CURLcode Curl_krb_kauth(struct connectdata *conn)
+{
+  des_cblock key;
+  des_key_schedule schedule;
+  KTEXT_ST tkt, tktcopy;
+  char *name;
+  char *p;
+  char passwd[100];
+  int tmp;
+  ssize_t nread;
+  int save;
+  CURLcode result;
+
+  save = Curl_set_command_prot(conn, prot_private);
+
+  result = Curl_ftpsendf(conn, "SITE KAUTH %s", conn->user);
+
+  if(result)
+    return result;
+
+  result = Curl_GetFTPResponse(&nread, conn, NULL);
+  if(result)
+    return result;
+
+  if(conn->data->state.buffer[0] != '3'){
+    Curl_set_command_prot(conn, save);
+    return CURLE_FTP_WEIRD_SERVER_REPLY;
+  }
+
+  p = strstr(conn->data->state.buffer, "T=");
+  if(!p) {
+    Curl_failf(conn->data, "Bad reply from server");
+    Curl_set_command_prot(conn, save);
+    return CURLE_FTP_WEIRD_SERVER_REPLY;
+  }
+
+  p += 2;
+  tmp = Curl_base64_decode(p, (char *)tkt.dat);
+  if(tmp < 0) {
+    Curl_failf(conn->data, "Failed to decode base64 in reply.\n");
+    Curl_set_command_prot(conn, save);
+    return CURLE_FTP_WEIRD_SERVER_REPLY;
+  }
+  tkt.length = tmp;
+  tktcopy.length = tkt.length;
+
+  p = strstr(conn->data->state.buffer, "P=");
+  if(!p) {
+    Curl_failf(conn->data, "Bad reply from server");
+    Curl_set_command_prot(conn, save);
+    return CURLE_FTP_WEIRD_SERVER_REPLY;
+  }
+  name = p + 2;
+  for(; *p && *p != ' ' && *p != '\r' && *p != '\n'; p++);
+  *p = 0;
+
+  des_string_to_key (conn->passwd, &key);
+  des_key_sched(&key, schedule);
+
+  des_pcbc_encrypt((void *)tkt.dat, (void *)tktcopy.dat,
+                   tkt.length,
+                   schedule, &key, DES_DECRYPT);
+  if (strcmp ((char*)tktcopy.dat + 8,
+              KRB_TICKET_GRANTING_TICKET) != 0) {
+    afs_string_to_key(passwd,
+                      krb_realmofhost(conn->host.name),
+                      &key);
+    des_key_sched(&key, schedule);
+    des_pcbc_encrypt((void *)tkt.dat, (void *)tktcopy.dat,
+                     tkt.length,
+                     schedule, &key, DES_DECRYPT);
+  }
+  memset(key, 0, sizeof(key));
+  memset(schedule, 0, sizeof(schedule));
+  memset(passwd, 0, sizeof(passwd));
+  if(Curl_base64_encode((char *)tktcopy.dat, tktcopy.length, &p) < 1) {
+    failf(conn->data, "Out of memory base64-encoding.");
+    Curl_set_command_prot(conn, save);
+    return CURLE_OUT_OF_MEMORY;
+  }
+  memset (tktcopy.dat, 0, tktcopy.length);
+
+  result = Curl_ftpsendf(conn, "SITE KAUTH %s %s", name, p);
+  free(p);
+  if(result)
+    return result;
+
+  result = Curl_GetFTPResponse(&nread, conn, NULL);
+  if(result)
+    return result;
+  Curl_set_command_prot(conn, save);
+
+  return CURLE_OK;
+}
+
+#endif /* HAVE_KRB4 */
+#endif /* CURL_DISABLE_FTP */
diff --git a/Utilities/cmcurl/krb4.h b/Utilities/cmcurl/krb4.h
new file mode 100644
index 0000000..cded35b
--- /dev/null
+++ b/Utilities/cmcurl/krb4.h
@@ -0,0 +1,27 @@
+#ifndef __KRB4_H
+#define __KRB4_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+CURLcode Curl_krb_kauth(struct connectdata *conn);
+
+#endif
diff --git a/Utilities/cmcurl/ldap.c b/Utilities/cmcurl/ldap.c
new file mode 100644
index 0000000..62e5b26
--- /dev/null
+++ b/Utilities/cmcurl/ldap.c
@@ -0,0 +1,625 @@
+/***************************************************************************
+ *                      _   _ ____  _
+ *  Project         ___| | | |  _ \| |
+ *                 / __| | | | |_) | |
+ *                | (__| |_| |  _ <| |___
+ *                \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#ifndef CURL_DISABLE_LDAP
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#if defined(WIN32)
+# include <windows.h>
+# include <malloc.h>
+# include <WinLdap.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_DLFCN_H
+# include <dlfcn.h>
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "sendf.h"
+#include "escape.h"
+#include "transfer.h"
+#include "strequal.h"
+#include "strtok.h"
+#include "ldap.h"
+#include "curl_memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "memdebug.h"
+
+/* WLdap32.dll functions are *not* stdcall. Must call these via __cdecl
+ * pointers in case libcurl was compiled as fastcall (-Gr).
+ */
+#if !defined(WIN32) && !defined(__cdecl)
+#define __cdecl
+#endif
+
+#ifndef LDAP_SIZELIMIT_EXCEEDED
+#define LDAP_SIZELIMIT_EXCEEDED 4
+#endif
+
+#define DLOPEN_MODE   RTLD_LAZY  /*! assume all dlopen() implementations have 
+                                   this */
+
+#if defined(RTLD_LAZY_GLOBAL)    /* It turns out some systems use this: */
+# undef  DLOPEN_MODE
+# define DLOPEN_MODE  RTLD_LAZY_GLOBAL
+#elif defined(RTLD_GLOBAL)
+# undef  DLOPEN_MODE
+# define DLOPEN_MODE  (RTLD_LAZY | RTLD_GLOBAL)
+#endif
+
+#define DYNA_GET_FUNCTION(type, fnc) do { \
+          (fnc) = (type)DynaGetFunction(#fnc); \
+          if ((fnc) == NULL) \
+             return CURLE_FUNCTION_NOT_FOUND; \
+        } while (0)
+
+/*! CygWin etc. configure could set these, but we don't want it.
+ * Must use WLdap32.dll code.
+ */
+#if defined(WIN32)
+#undef HAVE_DLOPEN
+#undef HAVE_LIBDL
+#endif
+
+typedef void * (*dynafunc)(void *input);
+
+/***********************************************************************
+ */
+static void *libldap = NULL;
+#ifndef WIN32
+static void *liblber = NULL;
+#endif
+
+static int DynaOpen(const char **mod_name)
+{
+#if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL)
+  if (libldap == NULL) {
+    /*
+     * libldap.so should be able to resolve its dependency on
+     * liblber.so automatically, but since it does not we will
+     * handle it here by opening liblber.so as global.
+     */
+    *mod_name = "liblber.so";
+    liblber = dlopen(*mod_name, DLOPEN_MODE);
+
+    /* Assume loading libldap.so will fail if loading of liblber.so failed
+     */
+    if (liblber)  {
+      *mod_name = "libldap.so";
+      libldap = dlopen(*mod_name, RTLD_LAZY);
+    }
+  }
+  return (libldap != NULL && liblber != NULL);
+
+#elif defined(WIN32)
+  *mod_name = "wldap32.dll";
+  if (!libldap)
+    libldap = (void*)LoadLibrary(*mod_name);
+  return (libldap != NULL);
+
+#else
+  return (0);
+#endif
+}
+
+static void DynaClose(void)
+{
+#if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL)
+  if (libldap) {
+    dlclose(libldap);
+    libldap=NULL;
+  }
+  if (liblber) {
+    dlclose(liblber);
+    liblber=NULL;
+  }
+#elif defined(WIN32)
+  if (libldap) {
+    FreeLibrary ((HMODULE)libldap);
+    libldap = NULL;
+  }
+#endif
+}
+
+static dynafunc DynaGetFunction(const char *name)
+{
+  dynafunc func = (dynafunc)NULL;
+
+#if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL)
+  if (libldap) {
+    /* This typecast magic below was brought by Joe Halpin. In ISO C, you
+     * cannot typecast a data pointer to a function pointer, but that's
+     * exactly what we need to do here to avoid compiler warnings on picky
+     * compilers! */
+    *(void**) (&func) = dlsym(libldap, name);
+  }
+#elif defined(WIN32)
+  if (libldap) {
+    func = (dynafunc)GetProcAddress((HINSTANCE)libldap, name);
+  }
+#endif
+  return func;
+}
+
+/***********************************************************************
+ */
+typedef struct ldap_url_desc {
+    struct ldap_url_desc *lud_next;
+    char   *lud_scheme;
+    char   *lud_host;
+    int     lud_port;
+    char   *lud_dn;
+    char  **lud_attrs;
+    int     lud_scope;
+    char   *lud_filter;
+    char  **lud_exts;
+    int     lud_crit_exts;
+} LDAPURLDesc;
+
+#ifdef WIN32
+static int  _ldap_url_parse (const struct connectdata *conn,
+                             LDAPURLDesc **ludp);
+static void _ldap_free_urldesc (LDAPURLDesc *ludp);
+
+static void (*ldap_free_urldesc)(LDAPURLDesc *) = _ldap_free_urldesc;
+#endif
+
+#ifdef DEBUG_LDAP
+  #define LDAP_TRACE(x)   do { \
+                            _ldap_trace ("%u: ", __LINE__); \
+                            _ldap_trace x; \
+                          } while (0)
+
+  static void _ldap_trace (const char *fmt, ...);
+#else
+  #define LDAP_TRACE(x)   ((void)0)
+#endif
+
+
+CURLcode Curl_ldap(struct connectdata *conn)
+{
+  CURLcode status = CURLE_OK;
+  int rc = 0;
+#ifndef WIN32
+  int    (*ldap_url_parse)(char *, LDAPURLDesc **);
+  void   (*ldap_free_urldesc)(void *);
+#endif
+  void  *(__cdecl *ldap_init)(char *, int);
+  int    (__cdecl *ldap_simple_bind_s)(void *, char *, char *);
+  int    (__cdecl *ldap_unbind_s)(void *);
+  int    (__cdecl *ldap_search_s)(void *, char *, int, char *, char **,
+                                  int, void **);
+  void  *(__cdecl *ldap_first_entry)(void *, void *);
+  void  *(__cdecl *ldap_next_entry)(void *, void *);
+  char  *(__cdecl *ldap_err2string)(int);
+  char  *(__cdecl *ldap_get_dn)(void *, void *);
+  char  *(__cdecl *ldap_first_attribute)(void *, void *, void **);
+  char  *(__cdecl *ldap_next_attribute)(void *, void *, void *);
+  char **(__cdecl *ldap_get_values)(void *, void *, const char *);
+  void   (__cdecl *ldap_value_free)(char **);
+  void   (__cdecl *ldap_memfree)(void *);
+  void   (__cdecl *ber_free)(void *, int);
+
+  void *server;
+  LDAPURLDesc *ludp = NULL;
+  const char *mod_name;
+  void *result;
+  void *entryIterator;     /*! type should be 'LDAPMessage *' */
+  int num = 0;
+  struct SessionHandle *data=conn->data;
+
+  infof(data, "LDAP local: %s\n", data->change.url);
+
+  if (!DynaOpen(&mod_name)) {
+    failf(data, "The %s LDAP library/libraries couldn't be opened", mod_name);
+    return CURLE_LIBRARY_NOT_FOUND;
+  }
+
+  /* The types are needed because ANSI C distinguishes between
+   * pointer-to-object (data) and pointer-to-function.
+   */
+  DYNA_GET_FUNCTION(void *(*)(char *, int), ldap_init);
+  DYNA_GET_FUNCTION(int (*)(void *, char *, char *), ldap_simple_bind_s);
+  DYNA_GET_FUNCTION(int (*)(void *), ldap_unbind_s);
+#ifndef WIN32
+  DYNA_GET_FUNCTION(int (*)(char *, LDAPURLDesc **), ldap_url_parse);
+  DYNA_GET_FUNCTION(void (*)(void *), ldap_free_urldesc);
+#endif
+  DYNA_GET_FUNCTION(int (*)(void *, char *, int, char *, char **, int,
+                            void **), ldap_search_s);
+  DYNA_GET_FUNCTION(void *(*)(void *, void *), ldap_first_entry);
+  DYNA_GET_FUNCTION(void *(*)(void *, void *), ldap_next_entry);
+  DYNA_GET_FUNCTION(char *(*)(int), ldap_err2string);
+  DYNA_GET_FUNCTION(char *(*)(void *, void *), ldap_get_dn);
+  DYNA_GET_FUNCTION(char *(*)(void *, void *, void **), ldap_first_attribute);
+  DYNA_GET_FUNCTION(char *(*)(void *, void *, void *), ldap_next_attribute);
+  DYNA_GET_FUNCTION(char **(*)(void *, void *, const char *), ldap_get_values);
+  DYNA_GET_FUNCTION(void (*)(char **), ldap_value_free);
+  DYNA_GET_FUNCTION(void (*)(void *), ldap_memfree);
+  DYNA_GET_FUNCTION(void (*)(void *, int), ber_free);
+
+  server = (*ldap_init)(conn->host.name, (int)conn->port);
+  if (server == NULL) {
+    failf(data, "LDAP local: Cannot connect to %s:%d",
+          conn->host.name, conn->port);
+    status = CURLE_COULDNT_CONNECT;
+    goto quit;
+  }
+
+  rc = (*ldap_simple_bind_s)(server,
+                             conn->bits.user_passwd ? conn->user : NULL,
+                             conn->bits.user_passwd ? conn->passwd : NULL);
+  if (rc != 0) {
+     failf(data, "LDAP local: %s", (*ldap_err2string)(rc));
+     status = CURLE_LDAP_CANNOT_BIND;
+     goto quit;
+  }
+
+#ifdef WIN32
+  rc = _ldap_url_parse(conn, &ludp);
+#else
+  rc = (*ldap_url_parse)(data->change.url, &ludp);
+#endif
+
+  if (rc != 0) {
+     failf(data, "LDAP local: %s", (*ldap_err2string)(rc));
+     status = CURLE_LDAP_INVALID_URL;
+     goto quit;
+  }
+
+  rc = (*ldap_search_s)(server, ludp->lud_dn, ludp->lud_scope,
+                        ludp->lud_filter, ludp->lud_attrs, 0, &result);
+
+  if (rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) {
+    failf(data, "LDAP remote: %s", (*ldap_err2string)(rc));
+    status = CURLE_LDAP_SEARCH_FAILED;
+    goto quit;
+  }
+
+  for(num = 0, entryIterator = (*ldap_first_entry)(server, result);
+      entryIterator;
+      entryIterator = (*ldap_next_entry)(server, entryIterator), num++)
+  {
+    void  *ber = NULL;      /*! is really 'BerElement **' */
+    void  *attribute;       /*! suspicious that this isn't 'const' */
+    char  *dn = (*ldap_get_dn)(server, entryIterator);
+    int i;
+
+    Curl_client_write(data, CLIENTWRITE_BODY, (char *)"DN: ", 4);
+    Curl_client_write(data, CLIENTWRITE_BODY, (char *)dn, 0);
+    Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
+
+    for (attribute = (*ldap_first_attribute)(server, entryIterator, &ber);
+         attribute;
+         attribute = (*ldap_next_attribute)(server, entryIterator, ber))
+    {
+      char **vals = (*ldap_get_values)(server, entryIterator, attribute);
+
+      if (vals != NULL)
+      {
+        for (i = 0; (vals[i] != NULL); i++)
+        {
+          Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1);
+          Curl_client_write(data, CLIENTWRITE_BODY, (char*) attribute, 0);
+          Curl_client_write(data, CLIENTWRITE_BODY, (char *)": ", 2);
+          Curl_client_write(data, CLIENTWRITE_BODY, vals[i], 0);
+          Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 0);
+        }
+
+        /* Free memory used to store values */
+        (*ldap_value_free)(vals);
+      }
+      Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
+
+      (*ldap_memfree)(attribute);
+      (*ldap_memfree)(dn);
+    }
+    if (ber)
+       (*ber_free)(ber, 0);
+  }
+
+quit:
+  LDAP_TRACE (("Received %d entries\n", num));
+  if (rc == LDAP_SIZELIMIT_EXCEEDED)
+     infof(data, "There are more than %d entries\n", num);
+  if (ludp)
+     (*ldap_free_urldesc)(ludp);
+  if (server)
+     (*ldap_unbind_s)(server);
+
+  DynaClose();
+
+  /* no data to transfer */
+  Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+
+  return status;
+}
+
+#ifdef DEBUG_LDAP
+static void _ldap_trace (const char *fmt, ...)
+{
+  static int do_trace = -1;
+  va_list args;
+
+  if (do_trace == -1) {
+    const char *env = getenv("CURL_TRACE");
+    do_trace = (env && atoi(env) > 0);
+  }
+  if (!do_trace)
+    return;
+
+  va_start (args, fmt);
+  vfprintf (stderr, fmt, args);
+  va_end (args);
+}
+#endif
+
+#ifdef WIN32
+/*
+ * Return scope-value for a scope-string.
+ */
+static int str2scope (const char *p)
+{
+  if (!stricmp(p, "one"))
+     return LDAP_SCOPE_ONELEVEL;
+  if (!stricmp(p, "onetree"))
+     return LDAP_SCOPE_ONELEVEL;
+  if (!stricmp(p, "base"))
+     return LDAP_SCOPE_BASE;
+  if (!stricmp(p, "sub"))
+     return LDAP_SCOPE_SUBTREE;
+  if (!stricmp( p, "subtree"))
+     return LDAP_SCOPE_SUBTREE;
+  return (-1);
+}
+
+/*
+ * Split 'str' into strings separated by commas.
+ * Note: res[] points into 'str'.
+ */
+static char **split_str (char *str)
+{
+  char **res, *lasts, *s;
+  int  i;
+
+  for (i = 2, s = strchr(str,','); s; i++)
+     s = strchr(++s,',');
+
+  res = calloc(i, sizeof(char*));
+  if (!res)
+    return NULL;
+
+  for (i = 0, s = strtok_r(str, ",", &lasts); s;
+       s = strtok_r(NULL, ",", &lasts), i++)
+    res[i] = s;
+  return res;
+}
+
+/*
+ * Unescape the LDAP-URL components
+ */
+static bool unescape_elements (LDAPURLDesc *ludp)
+{
+  int i;
+
+  if (ludp->lud_filter) {
+    ludp->lud_filter = curl_unescape(ludp->lud_filter, 0);
+    if (!ludp->lud_filter)
+       return (FALSE);
+  }
+
+  for (i = 0; ludp->lud_attrs && ludp->lud_attrs[i]; i++) {
+    ludp->lud_attrs[i] = curl_unescape(ludp->lud_attrs[i], 0);
+    if (!ludp->lud_attrs[i])
+       return (FALSE);
+  }
+
+  for (i = 0; ludp->lud_exts && ludp->lud_exts[i]; i++) {
+    ludp->lud_exts[i] = curl_unescape(ludp->lud_exts[i], 0);
+    if (!ludp->lud_exts[i])
+       return (FALSE);
+  }
+
+  if (ludp->lud_dn) {
+    char *dn = ludp->lud_dn;
+    char *new_dn = curl_unescape(dn, 0);
+
+    free(dn);
+    if (!new_dn)
+       return (FALSE);
+    ludp->lud_dn = new_dn;
+  }
+  return (TRUE);
+}
+
+/*
+ * Break apart the pieces of an LDAP URL.
+ * Syntax:
+ *   ldap://<hostname>:<port>/<base_dn>?<attributes>?<scope>?<filter>?<ext>
+ *
+ * <hostname> already known from 'conn->host.name'.
+ * <port>     already known from 'conn->remote_port'.
+ * extract the rest from 'conn->path+1'. All fields are optional. e.g.
+ *   ldap://<hostname>:<port>/?<attributes>?<scope>?<filter> yields ludp->lud_dn = "".
+ *
+ * Ref. http://developer.netscape.com/docs/manuals/dirsdk/csdk30/url.htm#2831915
+ */
+static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp)
+{
+  char *p, *q;
+  int i;
+
+  if (!conn->path || conn->path[0] != '/' ||
+      !checkprefix(conn->protostr, conn->data->change.url))
+     return LDAP_INVALID_SYNTAX;
+
+  ludp->lud_scope = LDAP_SCOPE_BASE;
+  ludp->lud_port  = conn->remote_port;
+  ludp->lud_host  = conn->host.name;
+
+  /* parse DN (Distinguished Name).
+   */
+  ludp->lud_dn = strdup(conn->path+1);
+  if (!ludp->lud_dn)
+     return LDAP_NO_MEMORY;
+
+  p = strchr(ludp->lud_dn, '?');
+  LDAP_TRACE (("DN '%.*s'\n", p ? (size_t)(p-ludp->lud_dn) : strlen(ludp->lud_dn),
+               ludp->lud_dn));
+
+  if (!p)
+     goto success;
+
+  *p++ = '\0';
+
+  /* parse attributes. skip "??".
+   */
+  q = strchr(p, '?');
+  if (q)
+     *q++ = '\0';
+
+  if (*p && *p != '?') {
+    ludp->lud_attrs = split_str(p);
+    if (!ludp->lud_attrs)
+       return LDAP_NO_MEMORY;
+
+    for (i = 0; ludp->lud_attrs[i]; i++)
+        LDAP_TRACE (("attr[%d] '%s'\n", i, ludp->lud_attrs[i]));
+  }
+
+  p = q;
+  if (!p)
+     goto success;
+
+  /* parse scope. skip "??"
+   */
+  q = strchr(p, '?');
+  if (q)
+     *q++ = '\0';
+
+  if (*p && *p != '?') {
+    ludp->lud_scope = str2scope(p);
+    if (ludp->lud_scope == -1)
+       return LDAP_INVALID_SYNTAX;
+    LDAP_TRACE (("scope %d\n", ludp->lud_scope));
+  }
+
+  p = q;
+  if (!p)
+     goto success;
+
+  /* parse filter
+   */
+  q = strchr(p, '?');
+  if (q)
+     *q++ = '\0';
+  if (!*p)
+     return LDAP_INVALID_SYNTAX;
+
+  ludp->lud_filter = p;
+  LDAP_TRACE (("filter '%s'\n", ludp->lud_filter));
+
+  p = q;
+  if (!p)
+     goto success;
+
+  /* parse extensions
+   */
+  ludp->lud_exts = split_str(p);
+  if (!ludp->lud_exts)
+     return LDAP_NO_MEMORY;
+
+  for (i = 0; ludp->lud_exts[i]; i++)
+      LDAP_TRACE (("exts[%d] '%s'\n", i, ludp->lud_exts[i]));
+
+success:
+  if (!unescape_elements(ludp))
+     return LDAP_NO_MEMORY;
+  return LDAP_SUCCESS;
+}
+
+static int _ldap_url_parse (const struct connectdata *conn,
+                            LDAPURLDesc **ludpp)
+{
+  LDAPURLDesc *ludp = calloc(sizeof(*ludp), 1);
+  int rc;
+
+  *ludpp = NULL;
+  if (!ludp)
+     return LDAP_NO_MEMORY;
+
+  rc = _ldap_url_parse2 (conn, ludp);
+  if (rc != LDAP_SUCCESS) {
+    _ldap_free_urldesc(ludp);
+    ludp = NULL;
+  }
+  *ludpp = ludp;
+  return (rc);
+}
+
+static void _ldap_free_urldesc (LDAPURLDesc *ludp)
+{
+  int i;
+
+  if (!ludp)
+     return;
+
+  if (ludp->lud_dn)
+     free(ludp->lud_dn);
+
+  if (ludp->lud_filter)
+     free(ludp->lud_filter);
+
+  if (ludp->lud_attrs) {
+    for (i = 0; ludp->lud_attrs[i]; i++)
+       free(ludp->lud_attrs[i]);
+    free(ludp->lud_attrs);
+  }
+
+  if (ludp->lud_exts) {
+    for (i = 0; ludp->lud_exts[i]; i++)
+       free(ludp->lud_exts[i]);
+    free(ludp->lud_exts);
+  }
+  free (ludp);
+}
+#endif  /* WIN32 */
+#endif  /* CURL_DISABLE_LDAP */
diff --git a/Utilities/cmcurl/ldap.h b/Utilities/cmcurl/ldap.h
new file mode 100644
index 0000000..b95cf74
--- /dev/null
+++ b/Utilities/cmcurl/ldap.h
@@ -0,0 +1,29 @@
+#ifndef __LDAP_H
+#define __LDAP_H
+
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+#ifndef CURL_DISABLE_LDAP
+CURLcode Curl_ldap(struct connectdata *conn);
+#endif
+#endif /* __LDAP_H */
diff --git a/Utilities/cmcurl/llist.c b/Utilities/cmcurl/llist.c
new file mode 100644
index 0000000..90ac1c8
--- /dev/null
+++ b/Utilities/cmcurl/llist.c
@@ -0,0 +1,130 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "llist.h"
+#include "curl_memory.h"
+
+/* this must be the last include file */
+#include "memdebug.h"
+
+void
+Curl_llist_init(curl_llist *l, curl_llist_dtor dtor)
+{
+  l->size = 0;
+  l->dtor = dtor;
+  l->head = NULL;
+  l->tail = NULL;
+}
+
+curl_llist *
+Curl_llist_alloc(curl_llist_dtor dtor)
+{
+  curl_llist *list;
+
+  list = (curl_llist *)malloc(sizeof(curl_llist));
+  if(NULL == list)
+    return NULL;
+
+  Curl_llist_init(list, dtor);
+
+  return list;
+}
+
+/*
+ * Curl_llist_insert_next() returns 1 on success and 0 on failure.
+ */
+int
+Curl_llist_insert_next(curl_llist *list, curl_llist_element *e, const void *p)
+{
+  curl_llist_element *ne =
+    (curl_llist_element *) malloc(sizeof(curl_llist_element));
+  if(!ne)
+    return 0;
+
+  ne->ptr = (void *) p;
+  if (list->size == 0) {
+    list->head = ne;
+    list->head->prev = NULL;
+    list->head->next = NULL;
+    list->tail = ne;
+  }
+  else {
+    ne->next = e->next;
+    ne->prev = e;
+    if (e->next) {
+      e->next->prev = ne;
+    }
+    else {
+      list->tail = ne;
+    }
+    e->next = ne;
+  }
+
+  ++list->size;
+
+  return 1;
+}
+
+int
+Curl_llist_remove(curl_llist *list, curl_llist_element *e, void *user)
+{
+  if (e == NULL || list->size == 0)
+    return 1;
+
+  if (e == list->head) {
+    list->head = e->next;
+
+    if (list->head == NULL)
+      list->tail = NULL;
+    else
+      e->next->prev = NULL;
+  } else {
+    e->prev->next = e->next;
+    if (!e->next)
+      list->tail = e->prev;
+    else
+      e->next->prev = e->prev;
+  }
+
+  list->dtor(user, e->ptr);
+  free(e);
+  --list->size;
+
+  return 1;
+}
+
+void
+Curl_llist_destroy(curl_llist *list, void *user)
+{
+  if(list) {
+    while (list->size > 0)
+      Curl_llist_remove(list, list->tail, user);
+
+    free(list);
+  }
+}
diff --git a/Utilities/cmcurl/llist.h b/Utilities/cmcurl/llist.h
new file mode 100644
index 0000000..4f76513
--- /dev/null
+++ b/Utilities/cmcurl/llist.h
@@ -0,0 +1,56 @@
+#ifndef __LLIST_H
+#define __LLIST_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+#include <stddef.h>
+
+typedef void (*curl_llist_dtor)(void *, void *);
+
+typedef struct _curl_llist_element {
+  void *ptr;
+
+  struct _curl_llist_element *prev;
+  struct _curl_llist_element *next;
+} curl_llist_element;
+
+typedef struct _curl_llist {
+  curl_llist_element *head;
+  curl_llist_element *tail;
+
+  curl_llist_dtor dtor;
+
+  size_t size;
+} curl_llist;
+
+void Curl_llist_init(curl_llist *, curl_llist_dtor);
+curl_llist *Curl_llist_alloc(curl_llist_dtor);
+int Curl_llist_insert_next(curl_llist *, curl_llist_element *, const void *);
+int Curl_llist_insert_prev(curl_llist *, curl_llist_element *, const void *);
+int Curl_llist_remove(curl_llist *, curl_llist_element *, void *);
+int Curl_llist_remove_next(curl_llist *, curl_llist_element *, void *);
+size_t Curl_llist_count(curl_llist *);
+void Curl_llist_destroy(curl_llist *, void *);
+
+#endif
diff --git a/Utilities/cmcurl/md5.c b/Utilities/cmcurl/md5.c
new file mode 100644
index 0000000..269726b
--- /dev/null
+++ b/Utilities/cmcurl/md5.c
@@ -0,0 +1,348 @@
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#ifndef USE_SSLEAY
+/* This code segment is only used if OpenSSL is not provided, as if it is
+   we use the MD5-function provided there instead. No good duplicating
+   code! */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+#include <string.h>
+
+/* UINT4 defines a four byte word */
+typedef unsigned int UINT4;
+
+/* MD5 context. */
+struct md5_ctx {
+  UINT4 state[4];                                   /* state (ABCD) */
+  UINT4 count[2];        /* number of bits, modulo 2^64 (lsb first) */
+  unsigned char buffer[64];                         /* input buffer */
+};
+
+typedef struct md5_ctx MD5_CTX;
+
+static void MD5_Init(struct md5_ctx *);
+static void MD5_Update(struct md5_ctx *, unsigned char *, unsigned int);
+static void MD5_Final(unsigned char [16], struct md5_ctx *);
+
+/* Constants for MD5Transform routine.
+ */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform(UINT4 [4], unsigned char [64]);
+static void Encode(unsigned char *, UINT4 *, unsigned int);
+static void Decode(UINT4 *, unsigned char *, unsigned int);
+
+static unsigned char PADDING[64] = {
+  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+static void MD5_Init(struct md5_ctx *context)
+{
+  context->count[0] = context->count[1] = 0;
+  /* Load magic initialization constants. */
+  context->state[0] = 0x67452301;
+  context->state[1] = 0xefcdab89;
+  context->state[2] = 0x98badcfe;
+  context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+  operation, processing another message block, and updating the
+  context.
+ */
+static void MD5_Update (struct md5_ctx *context, /* context */
+                        unsigned char *input, /* input block */
+                        unsigned int inputLen)/* length of input block */
+{
+  unsigned int i, bufindex, partLen;
+
+  /* Compute number of bytes mod 64 */
+  bufindex = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+  /* Update number of bits */
+  if ((context->count[0] += ((UINT4)inputLen << 3))
+      < ((UINT4)inputLen << 3))
+    context->count[1]++;
+  context->count[1] += ((UINT4)inputLen >> 29);
+  
+  partLen = 64 - bufindex;
+
+  /* Transform as many times as possible. */
+  if (inputLen >= partLen) {
+    memcpy((void *)&context->buffer[bufindex], (void *)input, partLen);
+    MD5Transform(context->state, context->buffer);
+    
+    for (i = partLen; i + 63 < inputLen; i += 64)
+      MD5Transform(context->state, &input[i]);
+    
+    bufindex = 0;
+  }
+  else
+    i = 0;
+
+  /* Buffer remaining input */
+  memcpy((void *)&context->buffer[bufindex], (void *)&input[i], inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+   the message digest and zeroizing the context.
+*/
+static void MD5_Final(unsigned char digest[16], /* message digest */
+                      struct md5_ctx *context) /* context */
+{
+  unsigned char bits[8];
+  unsigned int count, padLen;
+
+  /* Save number of bits */
+  Encode (bits, context->count, 8);
+
+  /* Pad out to 56 mod 64. */
+  count = (unsigned int)((context->count[0] >> 3) & 0x3f);
+  padLen = (count < 56) ? (56 - count) : (120 - count);
+  MD5_Update (context, PADDING, padLen);
+
+  /* Append length (before padding) */
+  MD5_Update (context, bits, 8);
+
+  /* Store state in digest */
+  Encode (digest, context->state, 16);
+
+  /* Zeroize sensitive information. */
+  memset ((void *)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block. */
+static void MD5Transform(UINT4 state[4],
+                         unsigned char block[64])
+{
+  UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+  Decode (x, block, 64);
+
+  /* Round 1 */
+  FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+  FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+  FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+  FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+  FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+  FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+  FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+  FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+  FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+  FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+  FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+  FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+  FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+  FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+  FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+  FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+  GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+  GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+  GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+  GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+  GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+  GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
+  GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+  GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+  GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+  GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+  GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+  GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+  GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+  GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+  GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+  GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+  /* Round 3 */
+  HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+  HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+  HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+  HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+  HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+  HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+  HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+  HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+  HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+  HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+  HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+  HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
+  HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+  HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+  HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+  HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+  /* Round 4 */
+  II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+  II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+  II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+  II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+  II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+  II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+  II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+  II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+  II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+  II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+  II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+  II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+  II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+  II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+  II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+  II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+  state[0] += a;
+  state[1] += b;
+  state[2] += c;
+  state[3] += d;
+
+  /* Zeroize sensitive information. */
+  memset((void *)x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+  a multiple of 4.
+ */
+static void Encode (unsigned char *output,
+                    UINT4 *input,
+                    unsigned int len)
+{
+  unsigned int i, j;
+
+  for (i = 0, j = 0; j < len; i++, j += 4) {
+    output[j] = (unsigned char)(input[i] & 0xff);
+    output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+    output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+    output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+  }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+   a multiple of 4.
+*/
+static void Decode (UINT4 *output,
+                    unsigned char *input,
+                    unsigned int len)
+{
+  unsigned int i, j;
+
+  for (i = 0, j = 0; j < len; i++, j += 4)
+    output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+      (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+#else
+/* If OpenSSL is present */
+#include <openssl/md5.h>
+#include <string.h>
+#endif
+
+#include "md5.h"
+
+void Curl_md5it(unsigned char *outbuffer, /* 16 bytes */
+                unsigned char *input)
+{
+  MD5_CTX ctx;
+  MD5_Init(&ctx);
+  MD5_Update(&ctx, input, strlen((char *)input));
+  MD5_Final(outbuffer, &ctx);
+}
diff --git a/Utilities/cmcurl/md5.h b/Utilities/cmcurl/md5.h
new file mode 100644
index 0000000..12b3a5e
--- /dev/null
+++ b/Utilities/cmcurl/md5.h
@@ -0,0 +1,29 @@
+#ifndef __MD5_H
+#define __MD5_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+void Curl_md5it(unsigned char *output,
+                unsigned char *input);
+
+#endif
diff --git a/Utilities/cmcurl/memdebug.c b/Utilities/cmcurl/memdebug.c
new file mode 100644
index 0000000..799fe7c
--- /dev/null
+++ b/Utilities/cmcurl/memdebug.c
@@ -0,0 +1,293 @@
+#ifdef CURLDEBUG
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <curl/curl.h>
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#define _MPRINTF_REPLACE
+#include <curl/mprintf.h>
+#include "urldata.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#define MEMDEBUG_NODEFINES /* don't redefine the standard functions */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+struct memdebug {
+  size_t size;
+  double mem[1];
+  /* I'm hoping this is the thing with the strictest alignment
+   * requirements.  That also means we waste some space :-( */
+};
+
+/*
+ * Note that these debug functions are very simple and they are meant to
+ * remain so. For advanced analysis, record a log file and write perl scripts
+ * to analyze them!
+ *
+ * Don't use these with multithreaded test programs!
+ */
+
+#define logfile curl_debuglogfile
+FILE *curl_debuglogfile;
+static bool memlimit; /* enable memory limit */
+static long memsize;  /* set number of mallocs allowed */
+
+/* this sets the log file name */
+void curl_memdebug(const char *logname)
+{
+  if(logname)
+    logfile = fopen(logname, "w");
+  else
+    logfile = stderr;
+}
+
+/* This function sets the number of malloc() calls that should return
+   successfully! */
+void curl_memlimit(long limit)
+{
+  memlimit = TRUE;
+  memsize = limit;
+}
+
+/* returns TRUE if this isn't allowed! */
+static bool countcheck(const char *func, int line, const char *source)
+{
+  /* if source is NULL, then the call is made internally and this check
+     should not be made */
+  if(memlimit && source) {
+    if(!memsize) {
+      if(logfile && source)
+        fprintf(logfile, "LIMIT %s:%d %s reached memlimit\n",
+                source, line, func);
+      if(source)
+        fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
+                source, line, func);
+      return TRUE; /* RETURN ERROR! */
+    }
+    else
+      memsize--; /* countdown */
+
+    /* log the countdown */
+    if(logfile && source)
+      fprintf(logfile, "LIMIT %s:%d %ld ALLOCS left\n",
+              source, line, memsize);
+
+  }
+
+  return FALSE; /* allow this */
+}
+
+void *curl_domalloc(size_t wantedsize, int line, const char *source)
+{
+  struct memdebug *mem;
+  size_t size;
+
+  if(countcheck("malloc", line, source))
+    return NULL;
+
+  /* alloc at least 64 bytes */
+  size = sizeof(struct memdebug)+wantedsize;
+
+  mem=(struct memdebug *)(Curl_cmalloc)(size);
+  if(mem) {
+    /* fill memory with junk */
+    memset(mem->mem, 0xA5, wantedsize);
+    mem->size = wantedsize;
+  }
+
+  if(logfile && source)
+    fprintf(logfile, "MEM %s:%d malloc(%zd) = %p\n",
+            source, line, wantedsize, mem ? mem->mem : 0);
+  return (mem ? mem->mem : NULL);
+}
+
+void *curl_docalloc(size_t wanted_elements, size_t wanted_size,
+                    int line, const char *source)
+{
+  struct memdebug *mem;
+  size_t size, user_size;
+
+  if(countcheck("calloc", line, source))
+    return NULL;
+
+  /* alloc at least 64 bytes */
+  user_size = wanted_size * wanted_elements;
+  size = sizeof(struct memdebug) + user_size;
+
+  mem = (struct memdebug *)(Curl_cmalloc)(size);
+  if(mem) {
+    /* fill memory with zeroes */
+    memset(mem->mem, 0, user_size);
+    mem->size = user_size;
+  }
+
+  if(logfile && source)
+    fprintf(logfile, "MEM %s:%d calloc(%u,%u) = %p\n",
+            source, line, wanted_elements, wanted_size, mem ? mem->mem : 0);
+  return (mem ? mem->mem : NULL);
+}
+
+char *curl_dostrdup(const char *str, int line, const char *source)
+{
+  char *mem;
+  size_t len;
+
+  curlassert(str != NULL);
+
+  if(countcheck("strdup", line, source))
+    return NULL;
+
+  len=strlen(str)+1;
+
+  mem=curl_domalloc(len, 0, NULL); /* NULL prevents logging */
+  if (mem)
+  memcpy(mem, str, len);
+
+  if(logfile)
+    fprintf(logfile, "MEM %s:%d strdup(%p) (%zd) = %p\n",
+            source, line, str, len, mem);
+
+  return mem;
+}
+
+/* We provide a realloc() that accepts a NULL as pointer, which then
+   performs a malloc(). In order to work with ares. */
+void *curl_dorealloc(void *ptr, size_t wantedsize,
+                     int line, const char *source)
+{
+  struct memdebug *mem=NULL;
+
+  size_t size = sizeof(struct memdebug)+wantedsize;
+
+  if(countcheck("realloc", line, source))
+    return NULL;
+
+  if(ptr)
+    mem = (struct memdebug *)((char *)ptr - offsetof(struct memdebug, mem));
+
+  mem=(struct memdebug *)(Curl_crealloc)(mem, size);
+  if(logfile)
+    fprintf(logfile, "MEM %s:%d realloc(0x%x, %zd) = %p\n",
+            source, line, ptr, wantedsize, mem?mem->mem:NULL);
+
+  if(mem) {
+    mem->size = wantedsize;
+    return mem->mem;
+  }
+
+  return NULL;
+}
+
+void curl_dofree(void *ptr, int line, const char *source)
+{
+  struct memdebug *mem;
+
+  curlassert(ptr != NULL);
+
+  mem = (struct memdebug *)((char *)ptr - offsetof(struct memdebug, mem));
+
+  /* destroy  */
+  memset(mem->mem, 0x13, mem->size);
+
+  /* free for real */
+  (Curl_cfree)(mem);
+
+  if(logfile)
+    fprintf(logfile, "MEM %s:%d free(%p)\n", source, line, ptr);
+}
+
+int curl_socket(int domain, int type, int protocol, int line,
+                const char *source)
+{
+  int sockfd=(socket)(domain, type, protocol);
+  if(logfile && (sockfd!=-1))
+    fprintf(logfile, "FD %s:%d socket() = %d\n",
+            source, line, sockfd);
+  return sockfd;
+}
+
+int curl_accept(int s, void *saddr, void *saddrlen,
+                int line, const char *source)
+{
+  struct sockaddr *addr = (struct sockaddr *)saddr;
+  socklen_t *addrlen = (socklen_t *)saddrlen;
+  int sockfd=(accept)(s, addr, addrlen);
+  if(logfile)
+    fprintf(logfile, "FD %s:%d accept() = %d\n",
+            source, line, sockfd);
+  return sockfd;
+}
+
+/* this is our own defined way to close sockets on *ALL* platforms */
+int curl_sclose(int sockfd, int line, const char *source)
+{
+  int res=sclose(sockfd);
+  if(logfile)
+    fprintf(logfile, "FD %s:%d sclose(%d)\n",
+            source, line, sockfd);
+  return res;
+}
+
+FILE *curl_fopen(const char *file, const char *mode,
+                 int line, const char *source)
+{
+  FILE *res=(fopen)(file, mode);
+  if(logfile)
+    fprintf(logfile, "FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
+            source, line, file, mode, res);
+  return res;
+}
+
+int curl_fclose(FILE *file, int line, const char *source)
+{
+  int res;
+
+  curlassert(file != NULL);
+
+  res=(fclose)(file);
+  if(logfile)
+    fprintf(logfile, "FILE %s:%d fclose(%p)\n",
+            source, line, file);
+  return res;
+}
+#else
+#ifdef VMS
+int VOID_VAR_MEMDEBUG;
+#else
+/* we provide a fake do-nothing function here to avoid compiler warnings */
+void curl_memdebug(void) {}
+#endif /* VMS */
+#endif /* CURLDEBUG */
diff --git a/Utilities/cmcurl/memdebug.h b/Utilities/cmcurl/memdebug.h
new file mode 100644
index 0000000..42574cf
--- /dev/null
+++ b/Utilities/cmcurl/memdebug.h
@@ -0,0 +1,108 @@
+#ifdef CURLDEBUG
+#ifndef _CURL_MEDEBUG_H
+#define _CURL_MEDEBUG_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/*
+ * CAUTION: this header is designed to work when included by the app-side
+ * as well as the library. Do not mix with library internals!
+ */
+
+#include "setup.h"
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+
+#define logfile curl_debuglogfile
+
+extern FILE *logfile;
+
+/* memory functions */
+void *curl_domalloc(size_t size, int line, const char *source);
+void *curl_docalloc(size_t elements, size_t size, int line, const char *source);
+void *curl_dorealloc(void *ptr, size_t size, int line, const char *source);
+void curl_dofree(void *ptr, int line, const char *source);
+char *curl_dostrdup(const char *str, int line, const char *source);
+void curl_memdebug(const char *logname);
+void curl_memlimit(long limit);
+
+/* file descriptor manipulators */
+int curl_socket(int domain, int type, int protocol, int line , const char *);
+int curl_sclose(int sockfd, int, const char *source);
+int curl_accept(int s, void *addr, void *addrlen,
+                int line, const char *source);
+
+/* FILE functions */
+FILE *curl_fopen(const char *file, const char *mode, int line,
+                 const char *source);
+int curl_fclose(FILE *file, int line, const char *source);
+
+#ifndef MEMDEBUG_NODEFINES
+
+/* Set this symbol on the command-line, recompile all lib-sources */
+#undef strdup
+#define strdup(ptr) curl_dostrdup(ptr, __LINE__, __FILE__)
+#define malloc(size) curl_domalloc(size, __LINE__, __FILE__)
+#define calloc(nbelem,size) curl_docalloc(nbelem, size, __LINE__, __FILE__)
+#define realloc(ptr,size) curl_dorealloc(ptr, size, __LINE__, __FILE__)
+#define free(ptr) curl_dofree(ptr, __LINE__, __FILE__)
+
+#define socket(domain,type,protocol)\
+ curl_socket(domain,type,protocol,__LINE__,__FILE__)
+#undef accept /* for those with accept as a macro */
+#define accept(sock,addr,len)\
+ curl_accept(sock,addr,len,__LINE__,__FILE__)
+
+#define getaddrinfo(host,serv,hint,res) \
+  curl_dogetaddrinfo(host,serv,hint,res,__LINE__,__FILE__)
+#define getnameinfo(sa,salen,host,hostlen,serv,servlen,flags) \
+  curl_dogetnameinfo(sa,salen,host,hostlen,serv,servlen,flags, __LINE__, \
+  __FILE__)
+#define freeaddrinfo(data) \
+  curl_dofreeaddrinfo(data,__LINE__,__FILE__)
+
+/* sclose is probably already defined, redefine it! */
+#undef sclose
+#define sclose(sockfd) curl_sclose(sockfd,__LINE__,__FILE__)
+/* ares-adjusted define: */
+#undef closesocket
+#define closesocket(sockfd) curl_sclose(sockfd,__LINE__,__FILE__)
+
+#undef fopen
+#define fopen(file,mode) curl_fopen(file,mode,__LINE__,__FILE__)
+#define fclose(file) curl_fclose(file,__LINE__,__FILE__)
+
+#endif /* MEMDEBUG_NODEFINES */
+
+#endif /* _CURL_MEDEBUG_H */
+#endif /* CURLDEBUG */
diff --git a/Utilities/cmcurl/mprintf.c b/Utilities/cmcurl/mprintf.c
new file mode 100644
index 0000000..d620fcd
--- /dev/null
+++ b/Utilities/cmcurl/mprintf.c
@@ -0,0 +1,1219 @@
+/****************************************************************************
+ *
+ * $Id$
+ *
+ *************************************************************************
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
+ * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
+ *
+ * Purpose:
+ *  A merge of Bjorn Reese's format() function and Daniel's dsprintf()
+ *  1.0. A full blooded printf() clone with full support for <num>$
+ *  everywhere (parameters, widths and precisions) including variabled
+ *  sized parameters (like doubles, long longs, long doubles and even
+ *  void * in 64-bit architectures).
+ *
+ * Current restrictions:
+ * - Max 128 parameters
+ * - No 'long double' support.
+ *
+ * If you ever want truly portable and good *printf() clones, the project that
+ * took on from here is named 'Trio' and you find more details on the trio web
+ * page at http://daniel.haxx.se/trio/
+ */
+
+
+#include "setup.h"
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <curl/mprintf.h>
+
+#ifndef SIZEOF_LONG_DOUBLE
+#define SIZEOF_LONG_DOUBLE 0
+#endif
+
+#ifndef SIZEOF_SIZE_T
+/* default to 4 bytes for size_t unless defined in the config.h */
+#define SIZEOF_SIZE_T 4
+#endif
+
+#ifdef DPRINTF_DEBUG
+#define HAVE_LONGLONG
+#define LONG_LONG long long
+#define ENABLE_64BIT
+#endif
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#define BUFFSIZE 256 /* buffer for long-to-str and float-to-str calcs */
+#define MAX_PARAMETERS 128 /* lame static limit */
+
+#undef TRUE
+#undef FALSE
+#undef BOOL
+#ifdef __cplusplus
+# define TRUE true
+# define FALSE false
+# define BOOL bool
+#else
+# define TRUE  ((char)(1 == 1))
+# define FALSE ((char)(0 == 1))
+# define BOOL char
+#endif
+
+
+/* Lower-case digits.  */
+static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+
+/* Upper-case digits.  */
+static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+#define OUTCHAR(x) \
+  do{ \
+    if(stream((unsigned char)(x), (FILE *)data) != -1) \
+      done++; \
+    else \
+     return done; /* return immediately on failure */ \
+  } while(0)
+
+/* Data type to read from the arglist */
+typedef enum  {
+  FORMAT_UNKNOWN = 0,
+  FORMAT_STRING,
+  FORMAT_PTR,
+  FORMAT_INT,
+  FORMAT_INTPTR,
+  FORMAT_LONG,
+  FORMAT_LONGLONG,
+  FORMAT_DOUBLE,
+  FORMAT_LONGDOUBLE,
+  FORMAT_WIDTH /* For internal use */
+} FormatType;
+
+/* convertion and display flags */
+enum {
+  FLAGS_NEW        = 0,
+  FLAGS_SPACE      = 1<<0,
+  FLAGS_SHOWSIGN   = 1<<1,
+  FLAGS_LEFT       = 1<<2,
+  FLAGS_ALT        = 1<<3,
+  FLAGS_SHORT      = 1<<4,
+  FLAGS_LONG       = 1<<5,
+  FLAGS_LONGLONG   = 1<<6,
+  FLAGS_LONGDOUBLE = 1<<7,
+  FLAGS_PAD_NIL    = 1<<8,
+  FLAGS_UNSIGNED   = 1<<9,
+  FLAGS_OCTAL      = 1<<10,
+  FLAGS_HEX        = 1<<11,
+  FLAGS_UPPER      = 1<<12,
+  FLAGS_WIDTH      = 1<<13, /* '*' or '*<num>$' used */
+  FLAGS_WIDTHPARAM = 1<<14, /* width PARAMETER was specified */
+  FLAGS_PREC       = 1<<15, /* precision was specified */
+  FLAGS_PRECPARAM  = 1<<16, /* precision PARAMETER was specified */
+  FLAGS_CHAR       = 1<<17, /* %c story */
+  FLAGS_FLOATE     = 1<<18, /* %e or %E */
+  FLAGS_FLOATG     = 1<<19  /* %g or %G */
+};
+
+typedef struct {
+  FormatType type;
+  int flags;
+  long width;     /* width OR width parameter number */
+  long precision; /* precision OR precision parameter number */
+  union {
+    char *str;
+    void *ptr;
+    long num;
+#ifdef ENABLE_64BIT
+    LONG_LONG lnum;
+#endif
+    double dnum;
+  } data;
+} va_stack_t;
+
+struct nsprintf {
+  char *buffer;
+  size_t length;
+  size_t max;
+};
+
+struct asprintf {
+  char *buffer; /* allocated buffer */
+  size_t len;   /* length of string */
+  size_t alloc; /* length of alloc */
+  bool fail;    /* TRUE if an alloc has failed and thus the output is not
+                   the complete data */
+};
+
+int curl_msprintf(char *buffer, const char *format, ...);
+
+static long dprintf_DollarString(char *input, char **end)
+{
+  int number=0;
+  while(isdigit((int)*input)) {
+    number *= 10;
+    number += *input-'0';
+    input++;
+  }
+  if(number && ('$'==*input++)) {
+    *end = input;
+    return number;
+  }
+  return 0;
+}
+
+static BOOL dprintf_IsQualifierNoDollar(char c)
+{
+  switch (c) {
+  case '-': case '+': case ' ': case '#': case '.':
+  case '0': case '1': case '2': case '3': case '4':
+  case '5': case '6': case '7': case '8': case '9':
+  case 'h': case 'l': case 'L': case 'z': case 'q':
+  case '*': case 'O':
+    return TRUE;
+  default:
+    return FALSE;
+  }
+}
+
+#ifdef DPRINTF_DEBUG2
+int dprintf_Pass1Report(va_stack_t *vto, int max)
+{
+  int i;
+  char buffer[128];
+  int bit;
+  int flags;
+
+  for(i=0; i<max; i++) {
+    char *type;
+    switch(vto[i].type) {
+    case FORMAT_UNKNOWN:
+      type = "unknown";
+      break;
+    case FORMAT_STRING:
+      type ="string";
+      break;
+    case FORMAT_PTR:
+      type ="pointer";
+      break;
+    case FORMAT_INT:
+      type = "int";
+      break;
+    case FORMAT_LONG:
+      type = "long";
+      break;
+    case FORMAT_LONGLONG:
+      type = "long long";
+      break;
+    case FORMAT_DOUBLE:
+      type = "double";
+      break;
+    case FORMAT_LONGDOUBLE:
+      type = "long double";
+      break;
+    }
+
+
+    buffer[0]=0;
+
+    for(bit=0; bit<31; bit++) {
+      flags = vto[i].flags & (1<<bit);
+
+      if(flags & FLAGS_SPACE)
+        strcat(buffer, "space ");
+      else if(flags & FLAGS_SHOWSIGN)
+        strcat(buffer, "plus ");
+      else if(flags & FLAGS_LEFT)
+        strcat(buffer, "left ");
+      else if(flags & FLAGS_ALT)
+        strcat(buffer, "alt ");
+      else if(flags & FLAGS_SHORT)
+        strcat(buffer, "short ");
+      else if(flags & FLAGS_LONG)
+        strcat(buffer, "long ");
+      else if(flags & FLAGS_LONGLONG)
+        strcat(buffer, "longlong ");
+      else if(flags & FLAGS_LONGDOUBLE)
+        strcat(buffer, "longdouble ");
+      else if(flags & FLAGS_PAD_NIL)
+        strcat(buffer, "padnil ");
+      else if(flags & FLAGS_UNSIGNED)
+        strcat(buffer, "unsigned ");
+      else if(flags & FLAGS_OCTAL)
+        strcat(buffer, "octal ");
+      else if(flags & FLAGS_HEX)
+        strcat(buffer, "hex ");
+      else if(flags & FLAGS_UPPER)
+        strcat(buffer, "upper ");
+      else if(flags & FLAGS_WIDTH)
+        strcat(buffer, "width ");
+      else if(flags & FLAGS_WIDTHPARAM)
+        strcat(buffer, "widthparam ");
+      else if(flags & FLAGS_PREC)
+        strcat(buffer, "precision ");
+      else if(flags & FLAGS_PRECPARAM)
+        strcat(buffer, "precparam ");
+      else if(flags & FLAGS_CHAR)
+        strcat(buffer, "char ");
+      else if(flags & FLAGS_FLOATE)
+        strcat(buffer, "floate ");
+      else if(flags & FLAGS_FLOATG)
+        strcat(buffer, "floatg ");
+    }
+    printf("REPORT: %d. %s [%s]\n", i, type, buffer);
+
+  }
+
+
+}
+#endif
+
+/******************************************************************
+ *
+ * Pass 1:
+ * Create an index with the type of each parameter entry and its
+ * value (may vary in size)
+ *
+ ******************************************************************/
+
+static long dprintf_Pass1(char *format, va_stack_t *vto, char **endpos,
+                          va_list arglist)
+{
+  char *fmt = format;
+  int param_num = 0;
+  long this_param;
+  long width;
+  long precision;
+  int flags;
+  long max_param=0;
+  long i;
+
+  while (*fmt) {
+    if (*fmt++ == '%') {
+      if (*fmt == '%') {
+        fmt++;
+        continue; /* while */
+      }
+
+      flags = FLAGS_NEW;
+
+      /* Handle the positional case (N$) */
+
+      param_num++;
+
+      this_param = dprintf_DollarString(fmt, &fmt);
+      if (0 == this_param)
+        /* we got no positional, get the next counter */
+        this_param = param_num;
+
+      if (this_param > max_param)
+        max_param = this_param;
+
+      /*
+       * The parameter with number 'i' should be used. Next, we need
+       * to get SIZE and TYPE of the parameter. Add the information
+       * to our array.
+       */
+
+      width = 0;
+      precision = 0;
+
+      /* Handle the flags */
+
+      while (dprintf_IsQualifierNoDollar(*fmt)) {
+        switch (*fmt++) {
+        case ' ':
+          flags |= FLAGS_SPACE;
+          break;
+        case '+':
+          flags |= FLAGS_SHOWSIGN;
+          break;
+        case '-':
+          flags |= FLAGS_LEFT;
+          flags &= ~FLAGS_PAD_NIL;
+          break;
+        case '#':
+          flags |= FLAGS_ALT;
+          break;
+        case '.':
+          flags |= FLAGS_PREC;
+          if ('*' == *fmt) {
+            /* The precision is picked from a specified parameter */
+
+            flags |= FLAGS_PRECPARAM;
+            fmt++;
+            param_num++;
+
+            i = dprintf_DollarString(fmt, &fmt);
+            if (i)
+              precision = i;
+            else
+              precision = param_num;
+
+            if (precision > max_param)
+              max_param = precision;
+          }
+          else {
+            flags |= FLAGS_PREC;
+            precision = strtol(fmt, &fmt, 10);
+          }
+          break;
+        case 'h':
+          flags |= FLAGS_SHORT;
+          break;
+        case 'l':
+          if (flags & FLAGS_LONG)
+            flags |= FLAGS_LONGLONG;
+          else
+            flags |= FLAGS_LONG;
+          break;
+        case 'L':
+          flags |= FLAGS_LONGDOUBLE;
+          break;
+        case 'q':
+          flags |= FLAGS_LONGLONG;
+          break;
+        case 'z':
+          /* the code below generates a warning if -Wunreachable-code is
+             used */
+#if SIZEOF_SIZE_T>4
+          flags |= FLAGS_LONGLONG;
+#else
+          flags |= FLAGS_LONG;
+#endif
+          break;
+        case 'O':
+#if SIZEOF_CURL_OFF_T > 4
+          flags |= FLAGS_LONGLONG;
+#else
+          flags |= FLAGS_LONG;
+#endif
+          break;
+        case '0':
+          if (!(flags & FLAGS_LEFT))
+            flags |= FLAGS_PAD_NIL;
+          /* FALLTHROUGH */
+        case '1': case '2': case '3': case '4':
+        case '5': case '6': case '7': case '8': case '9':
+          flags |= FLAGS_WIDTH;
+          width = strtol(fmt-1, &fmt, 10);
+          break;
+        case '*':  /* Special case */
+          flags |= FLAGS_WIDTHPARAM;
+          param_num++;
+
+          i = dprintf_DollarString(fmt, &fmt);
+          if(i)
+            width = i;
+          else
+            width = param_num;
+          if(width > max_param)
+            max_param=width;
+          break;
+        default:
+          break;
+        }
+      } /* switch */
+
+      /* Handle the specifier */
+
+      i = this_param - 1;
+
+      switch (*fmt) {
+      case 'S':
+        flags |= FLAGS_ALT;
+        /* FALLTHROUGH */
+      case 's':
+        vto[i].type = FORMAT_STRING;
+        break;
+      case 'n':
+        vto[i].type = FORMAT_INTPTR;
+        break;
+      case 'p':
+        vto[i].type = FORMAT_PTR;
+        break;
+      case 'd': case 'i':
+        vto[i].type = FORMAT_INT;
+        break;
+      case 'u':
+        vto[i].type = FORMAT_INT;
+        flags |= FLAGS_UNSIGNED;
+        break;
+      case 'o':
+        vto[i].type = FORMAT_INT;
+        flags |= FLAGS_OCTAL;
+        break;
+      case 'x':
+        vto[i].type = FORMAT_INT;
+        flags |= FLAGS_HEX;
+        break;
+      case 'X':
+        vto[i].type = FORMAT_INT;
+        flags |= FLAGS_HEX|FLAGS_UPPER;
+        break;
+      case 'c':
+        vto[i].type = FORMAT_INT;
+        flags |= FLAGS_CHAR;
+        break;
+      case 'f':
+        vto[i].type = FORMAT_DOUBLE;
+        break;
+      case 'e':
+        vto[i].type = FORMAT_DOUBLE;
+        flags |= FLAGS_FLOATE;
+        break;
+      case 'E':
+        vto[i].type = FORMAT_DOUBLE;
+        flags |= FLAGS_FLOATE|FLAGS_UPPER;
+        break;
+      case 'g':
+        vto[i].type = FORMAT_DOUBLE;
+        flags |= FLAGS_FLOATG;
+        break;
+      case 'G':
+        vto[i].type = FORMAT_DOUBLE;
+        flags |= FLAGS_FLOATG|FLAGS_UPPER;
+        break;
+      default:
+        vto[i].type = FORMAT_UNKNOWN;
+        break;
+      } /* switch */
+
+      vto[i].flags = flags;
+      vto[i].width = width;
+      vto[i].precision = precision;
+
+      if (flags & FLAGS_WIDTHPARAM) {
+        /* we have the width specified from a parameter, so we make that
+           parameter's info setup properly */
+        vto[i].width = width - 1;
+        i = width - 1;
+        vto[i].type = FORMAT_WIDTH;
+        vto[i].flags = FLAGS_NEW;
+        vto[i].precision = vto[i].width = 0; /* can't use width or precision
+                                                of width! */
+      }
+      if (flags & FLAGS_PRECPARAM) {
+        /* we have the precision specified from a parameter, so we make that
+           parameter's info setup properly */
+        vto[i].precision = precision - 1;
+        i = precision - 1;
+        vto[i].type = FORMAT_WIDTH;
+        vto[i].flags = FLAGS_NEW;
+        vto[i].precision = vto[i].width = 0; /* can't use width or precision
+                                                of width! */
+      }
+      *endpos++ = fmt + 1; /* end of this sequence */
+    }
+  }
+
+#ifdef DPRINTF_DEBUG2
+  dprintf_Pass1Report(vto, max_param);
+#endif
+
+  /* Read the arg list parameters into our data list */
+  for (i=0; i<max_param; i++) {
+    if ((i + 1 < max_param) && (vto[i + 1].type == FORMAT_WIDTH))
+      {
+        /* Width/precision arguments must be read before the main argument
+         * they are attached to
+         */
+        vto[i + 1].data.num = va_arg(arglist, int);
+      }
+
+    switch (vto[i].type)
+      {
+      case FORMAT_STRING:
+        vto[i].data.str = va_arg(arglist, char *);
+        break;
+
+      case FORMAT_INTPTR:
+      case FORMAT_UNKNOWN:
+      case FORMAT_PTR:
+        vto[i].data.ptr = va_arg(arglist, void *);
+        break;
+
+      case FORMAT_INT:
+#ifdef ENABLE_64BIT
+        if(vto[i].flags & FLAGS_LONGLONG)
+          vto[i].data.lnum = va_arg(arglist, LONG_LONG);
+        else
+#endif
+          if(vto[i].flags & FLAGS_LONG)
+            vto[i].data.num = va_arg(arglist, long);
+        else
+          vto[i].data.num = va_arg(arglist, int);
+        break;
+
+      case FORMAT_DOUBLE:
+        vto[i].data.dnum = va_arg(arglist, double);
+        break;
+
+      case FORMAT_WIDTH:
+        /* Argument has been read. Silently convert it into an integer
+         * for later use
+         */
+        vto[i].type = FORMAT_INT;
+        break;
+
+      default:
+        break;
+      }
+  }
+
+  return max_param;
+
+}
+
+static int dprintf_formatf(
+  void *data, /* untouched by format(), just sent to the stream() function in
+                 the second argument */
+  /* function pointer called for each output character */
+  int (*stream)(int, FILE *),
+  const char *format,    /* %-formatted string */
+  va_list ap_save) /* list of parameters */
+{
+  /* Base-36 digits for numbers.  */
+  const char *digits = lower_digits;
+
+  /* Pointer into the format string.  */
+  char *f;
+
+  /* Number of characters written.  */
+  int done = 0;
+
+  long param; /* current parameter to read */
+  long param_num=0; /* parameter counter */
+
+  va_stack_t vto[MAX_PARAMETERS];
+  char *endpos[MAX_PARAMETERS];
+  char **end;
+
+  char work[BUFFSIZE];
+
+  va_stack_t *p;
+
+  /* Do the actual %-code parsing */
+  dprintf_Pass1((char *)format, vto, endpos, ap_save);
+
+  end = &endpos[0]; /* the initial end-position from the list dprintf_Pass1()
+                       created for us */
+
+  f = (char *)format;
+  while (*f != '\0') {
+    /* Format spec modifiers.  */
+    char alt;
+
+    /* Width of a field.  */
+    long width;
+
+    /* Precision of a field.  */
+    long prec;
+
+    /* Decimal integer is negative.  */
+    char is_neg;
+
+    /* Base of a number to be written.  */
+    long base;
+
+    /* Integral values to be written.  */
+#ifdef ENABLE_64BIT
+    unsigned LONG_LONG num;
+#else
+    unsigned long num;
+#endif
+    long signed_num;
+
+    if (*f != '%') {
+      /* This isn't a format spec, so write everything out until the next one
+         OR end of string is reached.  */
+      do {
+        OUTCHAR(*f);
+      } while(*++f && ('%' != *f));
+      continue;
+    }
+
+    ++f;
+
+    /* Check for "%%".  Note that although the ANSI standard lists
+       '%' as a conversion specifier, it says "The complete format
+       specification shall be `%%'," so we can avoid all the width
+       and precision processing.  */
+    if (*f == '%') {
+      ++f;
+      OUTCHAR('%');
+      continue;
+    }
+
+    /* If this is a positional parameter, the position must follow imediately
+       after the %, thus create a %<num>$ sequence */
+    param=dprintf_DollarString(f, &f);
+
+    if(!param)
+      param = param_num;
+    else
+      --param;
+
+    param_num++; /* increase this always to allow "%2$s %1$s %s" and then the
+                    third %s will pick the 3rd argument */
+
+    p = &vto[param];
+
+    /* pick up the specified width */
+    if(p->flags & FLAGS_WIDTHPARAM)
+      width = vto[p->width].data.num;
+    else
+      width = p->width;
+
+    /* pick up the specified precision */
+    if(p->flags & FLAGS_PRECPARAM)
+      prec = vto[p->precision].data.num;
+    else if(p->flags & FLAGS_PREC)
+      prec = p->precision;
+    else
+      prec = -1;
+
+    alt = (p->flags & FLAGS_ALT)?TRUE:FALSE;
+
+    switch (p->type) {
+    case FORMAT_INT:
+      num = p->data.num;
+      if(p->flags & FLAGS_CHAR) {
+        /* Character.  */
+        if (!(p->flags & FLAGS_LEFT))
+          while (--width > 0)
+            OUTCHAR(' ');
+        OUTCHAR((char) num);
+        if (p->flags & FLAGS_LEFT)
+          while (--width > 0)
+            OUTCHAR(' ');
+        break;
+      }
+      if(p->flags & FLAGS_UNSIGNED) {
+        /* Decimal unsigned integer.  */
+        base = 10;
+        goto unsigned_number;
+      }
+      if(p->flags & FLAGS_OCTAL) {
+        /* Octal unsigned integer.  */
+        base = 8;
+        goto unsigned_number;
+      }
+      if(p->flags & FLAGS_HEX) {
+        /* Hexadecimal unsigned integer.  */
+
+        digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
+        base = 16;
+        goto unsigned_number;
+      }
+
+      /* Decimal integer.  */
+      base = 10;
+
+#ifdef ENABLE_64BIT
+      if(p->flags & FLAGS_LONGLONG) {
+        /* long long */
+        is_neg = p->data.lnum < 0;
+        num = is_neg ? (- p->data.lnum) : p->data.lnum;
+      }
+      else
+#endif
+      {
+        signed_num = (long) num;
+        is_neg = signed_num < 0;
+        num = is_neg ? (- signed_num) : signed_num;
+      }
+      goto number;
+
+      unsigned_number:
+      /* Unsigned number of base BASE.  */
+      is_neg = 0;
+
+      number:
+      /* Number of base BASE.  */
+      {
+        char *workend = &work[sizeof(work) - 1];
+        char *w;
+
+        /* Supply a default precision if none was given.  */
+        if (prec == -1)
+          prec = 1;
+
+        /* Put the number in WORK.  */
+        w = workend;
+        while (num > 0) {
+          *w-- = digits[num % base];
+          num /= base;
+        }
+        width -= workend - w;
+        prec -= workend - w;
+
+        if (alt && base == 8 && prec <= 0) {
+          *w-- = '0';
+          --width;
+        }
+
+        if (prec > 0) {
+          width -= prec;
+          while (prec-- > 0)
+            *w-- = '0';
+        }
+
+        if (alt && base == 16)
+          width -= 2;
+
+        if (is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE))
+          --width;
+
+        if (!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL))
+          while (width-- > 0)
+            OUTCHAR(' ');
+
+        if (is_neg)
+          OUTCHAR('-');
+        else if (p->flags & FLAGS_SHOWSIGN)
+          OUTCHAR('+');
+        else if (p->flags & FLAGS_SPACE)
+          OUTCHAR(' ');
+
+        if (alt && base == 16) {
+          OUTCHAR('0');
+          if(p->flags & FLAGS_UPPER)
+            OUTCHAR('X');
+          else
+            OUTCHAR('x');
+        }
+
+        if (!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL))
+          while (width-- > 0)
+            OUTCHAR('0');
+
+        /* Write the number.  */
+        while (++w <= workend) {
+          OUTCHAR(*w);
+        }
+
+        if (p->flags & FLAGS_LEFT)
+          while (width-- > 0)
+            OUTCHAR(' ');
+      }
+      break;
+
+    case FORMAT_STRING:
+            /* String.  */
+      {
+        static char null[] = "(nil)";
+        char *str;
+        size_t len;
+
+        str = (char *) p->data.str;
+        if ( str == NULL) {
+          /* Write null[] if there's space.  */
+          if (prec == -1 || prec >= (long) sizeof(null) - 1) {
+            str = null;
+            len = sizeof(null) - 1;
+            /* Disable quotes around (nil) */
+            p->flags &= (~FLAGS_ALT);
+          }
+          else {
+            str = (char *)"";
+            len = 0;
+          }
+        }
+        else
+          len = strlen(str);
+
+        if (prec != -1 && (size_t) prec < len)
+          len = prec;
+        width -= len;
+
+        if (p->flags & FLAGS_ALT)
+          OUTCHAR('"');
+
+        if (!(p->flags&FLAGS_LEFT))
+          while (width-- > 0)
+            OUTCHAR(' ');
+
+        while (len-- > 0)
+          OUTCHAR(*str++);
+        if (p->flags&FLAGS_LEFT)
+          while (width-- > 0)
+            OUTCHAR(' ');
+
+        if (p->flags & FLAGS_ALT)
+          OUTCHAR('"');
+      }
+      break;
+
+    case FORMAT_PTR:
+      /* Generic pointer.  */
+      {
+        void *ptr;
+        ptr = (void *) p->data.ptr;
+        if (ptr != NULL) {
+          /* If the pointer is not NULL, write it as a %#x spec.  */
+          base = 16;
+          digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
+          alt = 1;
+          num = (unsigned long) ptr;
+          is_neg = 0;
+          goto number;
+        }
+        else {
+          /* Write "(nil)" for a nil pointer.  */
+          static char strnil[] = "(nil)";
+          char *point;
+
+          width -= sizeof(strnil) - 1;
+          if (p->flags & FLAGS_LEFT)
+            while (width-- > 0)
+              OUTCHAR(' ');
+          for (point = strnil; *point != '\0'; ++point)
+            OUTCHAR(*point);
+          if (! (p->flags & FLAGS_LEFT))
+            while (width-- > 0)
+              OUTCHAR(' ');
+        }
+      }
+      break;
+
+    case FORMAT_DOUBLE:
+      {
+        char formatbuf[32]="%";
+        char *fptr;
+        size_t left = sizeof(formatbuf)-strlen(formatbuf);
+        int len;
+
+        width = -1;
+        if (p->flags & FLAGS_WIDTH)
+          width = p->width;
+        else if (p->flags & FLAGS_WIDTHPARAM)
+          width = vto[p->width].data.num;
+
+        prec = -1;
+        if (p->flags & FLAGS_PREC)
+          prec = p->precision;
+        else if (p->flags & FLAGS_PRECPARAM)
+          prec = vto[p->precision].data.num;
+
+        if (p->flags & FLAGS_LEFT)
+          strcat(formatbuf, "-");
+        if (p->flags & FLAGS_SHOWSIGN)
+          strcat(formatbuf, "+");
+        if (p->flags & FLAGS_SPACE)
+          strcat(formatbuf, " ");
+        if (p->flags & FLAGS_ALT)
+          strcat(formatbuf, "#");
+
+        fptr=&formatbuf[strlen(formatbuf)];
+
+        if(width >= 0) {
+          /* RECURSIVE USAGE */
+          len = curl_msnprintf(fptr, left, "%ld", width);
+          fptr += len;
+          left -= len;
+        }
+        if(prec >= 0) {
+          /* RECURSIVE USAGE */
+          len = curl_msnprintf(fptr, left, ".%ld", prec);
+          fptr += len;
+          left -= len;
+        }
+        (void)left;
+        if (p->flags & FLAGS_LONG)
+          *fptr++ = 'l';
+
+        if (p->flags & FLAGS_FLOATE)
+          *fptr++ = p->flags&FLAGS_UPPER ? 'E':'e';
+        else if (p->flags & FLAGS_FLOATG)
+          *fptr++ = p->flags & FLAGS_UPPER ? 'G' : 'g';
+        else
+          *fptr++ = 'f';
+
+        *fptr = 0; /* and a final zero termination */
+
+        /* NOTE NOTE NOTE!! Not all sprintf() implementations returns number
+           of output characters */
+        (sprintf)(work, formatbuf, p->data.dnum);
+
+        for(fptr=work; *fptr; fptr++)
+          OUTCHAR(*fptr);
+      }
+      break;
+
+    case FORMAT_INTPTR:
+      /* Answer the count of characters written.  */
+#ifdef ENABLE_64BIT
+      if (p->flags & FLAGS_LONGLONG)
+        *(LONG_LONG *) p->data.ptr = (LONG_LONG)done;
+      else
+#endif
+        if (p->flags & FLAGS_LONG)
+          *(long *) p->data.ptr = (long)done;
+      else if (!(p->flags & FLAGS_SHORT))
+        *(int *) p->data.ptr = (int)done;
+      else
+        *(short *) p->data.ptr = (short)done;
+      break;
+
+    default:
+      break;
+    }
+    f = *end++; /* goto end of %-code */
+
+  }
+  return done;
+}
+
+/* fputc() look-alike */
+static int addbyter(int output, FILE *data)
+{
+  struct nsprintf *infop=(struct nsprintf *)data;
+  unsigned char outc = (unsigned char)output;
+
+  if(infop->length < infop->max) {
+    /* only do this if we haven't reached max length yet */
+    infop->buffer[0] = outc; /* store */
+    infop->buffer++; /* increase pointer */
+    infop->length++; /* we are now one byte larger */
+    return outc;     /* fputc() returns like this on success */
+  }
+  return -1;
+}
+
+int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
+                    va_list ap_save)
+{
+  int retcode;
+  struct nsprintf info;
+
+  info.buffer = buffer;
+  info.length = 0;
+  info.max = maxlength;
+
+  retcode = dprintf_formatf(&info, addbyter, format, ap_save);
+  if(info.max) {
+    /* we terminate this with a zero byte */
+    if(info.max == info.length)
+      /* we're at maximum, scrap the last letter */
+      info.buffer[-1] = 0;
+    else
+      info.buffer[0] = 0;
+  }
+  return retcode;
+}
+
+int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
+{
+  int retcode;
+  va_list ap_save; /* argument pointer */
+  va_start(ap_save, format);
+  retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save);
+  va_end(ap_save);
+  return retcode;
+}
+
+/* fputc() look-alike */
+static int alloc_addbyter(int output, FILE *data)
+{
+  struct asprintf *infop=(struct asprintf *)data;
+  unsigned char outc = (unsigned char)output;
+
+  if(!infop->buffer) {
+    infop->buffer=(char *)malloc(32);
+    if(!infop->buffer) {
+      infop->fail = TRUE;
+      return -1; /* fail */
+    }
+    infop->alloc = 32;
+    infop->len =0;
+  }
+  else if(infop->len+1 >= infop->alloc) {
+    char *newptr;
+
+    newptr = (char *)realloc(infop->buffer, infop->alloc*2);
+
+    if(!newptr) {
+      infop->fail = TRUE;
+      return -1;
+    }
+    infop->buffer = newptr;
+    infop->alloc *= 2;
+  }
+
+  infop->buffer[ infop->len ] = outc;
+
+  infop->len++;
+
+  return outc; /* fputc() returns like this on success */
+}
+
+char *curl_maprintf(const char *format, ...)
+{
+  va_list ap_save; /* argument pointer */
+  int retcode;
+  struct asprintf info;
+
+  info.buffer = NULL;
+  info.len = 0;
+  info.alloc = 0;
+  info.fail = FALSE;
+
+  va_start(ap_save, format);
+  retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
+  va_end(ap_save);
+  if((-1 == retcode) || info.fail) {
+    if(info.alloc)
+      free(info.buffer);
+    return NULL;
+  }
+  if(info.alloc) {
+    info.buffer[info.len] = 0; /* we terminate this with a zero byte */
+    return info.buffer;
+  }
+  else
+    return strdup("");
+}
+
+char *curl_mvaprintf(const char *format, va_list ap_save)
+{
+  int retcode;
+  struct asprintf info;
+
+  info.buffer = NULL;
+  info.len = 0;
+  info.alloc = 0;
+  info.fail = FALSE;
+
+  retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
+  if((-1 == retcode) || info.fail) {
+    if(info.alloc)
+      free(info.buffer);
+    return NULL;
+  }
+
+  if(info.alloc) {
+    info.buffer[info.len] = 0; /* we terminate this with a zero byte */
+    return info.buffer;
+  }
+  else
+    return strdup("");
+}
+
+static int storebuffer(int output, FILE *data)
+{
+  char **buffer = (char **)data;
+  unsigned char outc = (unsigned char)output;
+  **buffer = outc;
+  (*buffer)++;
+  return outc; /* act like fputc() ! */
+}
+
+int curl_msprintf(char *buffer, const char *format, ...)
+{
+  va_list ap_save; /* argument pointer */
+  int retcode;
+  va_start(ap_save, format);
+  retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
+  va_end(ap_save);
+  *buffer=0; /* we terminate this with a zero byte */
+  return retcode;
+}
+
+#ifndef WIN32 /* not needed on win32 */
+extern int fputc(int, FILE *);
+#endif
+
+int curl_mprintf(const char *format, ...)
+{
+  int retcode;
+  va_list ap_save; /* argument pointer */
+  va_start(ap_save, format);
+  retcode = dprintf_formatf(stdout, fputc, format, ap_save);
+  va_end(ap_save);
+  return retcode;
+}
+
+int curl_mfprintf(FILE *whereto, const char *format, ...)
+{
+  int retcode;
+  va_list ap_save; /* argument pointer */
+  va_start(ap_save, format);
+  retcode = dprintf_formatf(whereto, fputc, format, ap_save);
+  va_end(ap_save);
+  return retcode;
+}
+
+int curl_mvsprintf(char *buffer, const char *format, va_list ap_save)
+{
+  int retcode;
+  retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
+  *buffer=0; /* we terminate this with a zero byte */
+  return retcode;
+}
+
+int curl_mvprintf(const char *format, va_list ap_save)
+{
+  return dprintf_formatf(stdout, fputc, format, ap_save);
+}
+
+int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save)
+{
+  return dprintf_formatf(whereto, fputc, format, ap_save);
+}
+
+#ifdef DPRINTF_DEBUG
+int main()
+{
+  char buffer[129];
+  char *ptr;
+#ifdef ENABLE_64BIT
+  long long one=99;
+  long long two=100;
+  long long test = 0x1000000000LL;
+  curl_mprintf("%lld %lld %lld\n", one, two, test);
+#endif
+
+  curl_mprintf("%3d %5d\n", 10, 1998);
+
+  ptr=curl_maprintf("test this then baby %s%s%s%s%s%s %d %d %d loser baby get a hit in yer face now!", "", "pretty long string pretty long string pretty long string pretty long string pretty long string", "/", "/", "/", "pretty long string", 1998, 1999, 2001);
+
+  puts(ptr);
+
+  memset(ptr, 55, strlen(ptr)+1);
+
+  free(ptr);
+
+#if 1
+  curl_mprintf(buffer, "%s %s %d", "daniel", "stenberg", 19988);
+  puts(buffer);
+
+  curl_mfprintf(stderr, "%s %#08x\n", "dummy", 65);
+
+  printf("%s %#08x\n", "dummy", 65);
+  {
+    double tryout = 3.14156592;
+    curl_mprintf(buffer, "%.2g %G %f %e %E", tryout, tryout, tryout, tryout, tryout);
+    puts(buffer);
+    printf("%.2g %G %f %e %E\n", tryout, tryout, tryout, tryout, tryout);
+  }
+#endif
+
+  return 0;
+}
+
+#endif
diff --git a/Utilities/cmcurl/multi.c b/Utilities/cmcurl/multi.c
new file mode 100644
index 0000000..a604af8
--- /dev/null
+++ b/Utilities/cmcurl/multi.c
@@ -0,0 +1,648 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "transfer.h"
+#include "url.h"
+#include "connect.h"
+#include "progress.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+struct Curl_message {
+  /* the 'CURLMsg' is the part that is visible to the external user */
+  struct CURLMsg extmsg;
+  struct Curl_message *next;
+};
+
+typedef enum {
+  CURLM_STATE_INIT,
+  CURLM_STATE_CONNECT,     /* resolve/connect has been sent off */
+  CURLM_STATE_WAITRESOLVE, /* we're awaiting the resolve to finalize */
+  CURLM_STATE_WAITCONNECT, /* we're awaiting the connect to finalize */
+  CURLM_STATE_DO,          /* send off the request (part 1) */
+  CURLM_STATE_DO_MORE,     /* send off the request (part 2) */
+  CURLM_STATE_PERFORM,     /* transfer data */
+  CURLM_STATE_DONE,        /* post data transfer operation */
+  CURLM_STATE_COMPLETED,   /* operation complete */
+
+  CURLM_STATE_LAST /* not a true state, never use this */
+} CURLMstate;
+
+struct Curl_one_easy {
+  /* first, two fields for the linked list of these */
+  struct Curl_one_easy *next;
+  struct Curl_one_easy *prev;
+
+  struct SessionHandle *easy_handle; /* the easy handle for this unit */
+  struct connectdata *easy_conn;     /* the "unit's" connection */
+
+  CURLMstate state;  /* the handle's state */
+  CURLcode result;   /* previous result */
+
+  struct Curl_message *msg; /* A pointer to one single posted message.
+                               Cleanup should be done on this pointer NOT on
+                               the linked list in Curl_multi.  This message
+                               will be deleted when this handle is removed
+                               from the multi-handle */
+  int msg_num; /* number of messages left in 'msg' to return */
+};
+
+
+#define CURL_MULTI_HANDLE 0x000bab1e
+
+#define GOOD_MULTI_HANDLE(x) ((x)&&(((struct Curl_multi *)x)->type == CURL_MULTI_HANDLE))
+#define GOOD_EASY_HANDLE(x) (x)
+
+/* This is the struct known as CURLM on the outside */
+struct Curl_multi {
+  /* First a simple identifier to easier detect if a user mix up
+     this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */
+  long type;
+
+  /* We have a linked list with easy handles */
+  struct Curl_one_easy easy;
+  /* This is the amount of entries in the linked list above. */
+  int num_easy;
+
+  int num_msgs; /* total amount of messages in the easy handles */
+
+  /* Hostname cache */
+  curl_hash *hostcache;
+};
+
+
+CURLM *curl_multi_init(void)
+{
+  struct Curl_multi *multi;
+
+  multi = (void *)malloc(sizeof(struct Curl_multi));
+
+  if(multi) {
+    memset(multi, 0, sizeof(struct Curl_multi));
+    multi->type = CURL_MULTI_HANDLE;
+  }
+  else
+    return NULL;
+
+  multi->hostcache = Curl_mk_dnscache();
+  if(!multi->hostcache) {
+    /* failure, free mem and bail out */
+    free(multi);
+    multi = NULL;
+  }
+  return (CURLM *) multi;
+}
+
+CURLMcode curl_multi_add_handle(CURLM *multi_handle,
+                                CURL *easy_handle)
+{
+  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+  struct Curl_one_easy *easy;
+
+  /* First, make some basic checks that the CURLM handle is a good handle */
+  if(!GOOD_MULTI_HANDLE(multi))
+    return CURLM_BAD_HANDLE;
+
+  /* Verify that we got a somewhat good easy handle too */
+  if(!GOOD_EASY_HANDLE(easy_handle))
+    return CURLM_BAD_EASY_HANDLE;
+
+  /* Now, time to add an easy handle to the multi stack */
+  easy = (struct Curl_one_easy *)malloc(sizeof(struct Curl_one_easy));
+  if(!easy)
+    return CURLM_OUT_OF_MEMORY;
+
+  /* clean it all first (just to be sure) */
+  memset(easy, 0, sizeof(struct Curl_one_easy));
+
+  /* set the easy handle */
+  easy->easy_handle = easy_handle;
+  easy->state = CURLM_STATE_INIT;
+
+  /* for multi interface connections, we share DNS cache automaticly */
+  easy->easy_handle->hostcache = multi->hostcache;
+
+  /* We add this new entry first in the list. We make our 'next' point to the
+     previous next and our 'prev' point back to the 'first' struct */
+  easy->next = multi->easy.next;
+  easy->prev = &multi->easy;
+
+  /* make 'easy' the first node in the chain */
+  multi->easy.next = easy;
+
+  /* if there was a next node, make sure its 'prev' pointer links back to
+     the new node */
+  if(easy->next)
+    easy->next->prev = easy;
+
+  /* increase the node-counter */
+  multi->num_easy++;
+
+  return CURLM_CALL_MULTI_PERFORM;
+}
+
+CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
+                                   CURL *curl_handle)
+{
+  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+  struct Curl_one_easy *easy;
+
+  /* First, make some basic checks that the CURLM handle is a good handle */
+  if(!GOOD_MULTI_HANDLE(multi))
+    return CURLM_BAD_HANDLE;
+
+  /* Verify that we got a somewhat good easy handle too */
+  if(!GOOD_EASY_HANDLE(curl_handle))
+    return CURLM_BAD_EASY_HANDLE;
+
+  /* scan through the list and remove the 'curl_handle' */
+  easy = multi->easy.next;
+  while(easy) {
+    if(easy->easy_handle == (struct SessionHandle *)curl_handle)
+      break;
+    easy=easy->next;
+  }
+  if(easy) {
+    /* If the 'state' is not INIT or COMPLETED, we might need to do something
+       nice to put the easy_handle in a good known state when this returns. */
+
+    /* clear out the usage of the shared DNS cache */
+    easy->easy_handle->hostcache = NULL;
+
+    /* make the previous node point to our next */
+    if(easy->prev)
+      easy->prev->next = easy->next;
+    /* make our next point to our previous node */
+    if(easy->next)
+      easy->next->prev = easy->prev;
+
+    /* NOTE NOTE NOTE
+       We do not touch the easy handle here! */
+    if (easy->msg)
+      free(easy->msg);
+    free(easy);
+
+    multi->num_easy--; /* one less to care about now */
+
+    return CURLM_OK;
+  }
+  else
+    return CURLM_BAD_EASY_HANDLE; /* twasn't found */
+}
+
+CURLMcode curl_multi_fdset(CURLM *multi_handle,
+                           fd_set *read_fd_set, fd_set *write_fd_set,
+                           fd_set *exc_fd_set, int *max_fd)
+{
+  /* Scan through all the easy handles to get the file descriptors set.
+     Some easy handles may not have connected to the remote host yet,
+     and then we must make sure that is done. */
+  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+  struct Curl_one_easy *easy;
+  int this_max_fd=-1;
+
+  if(!GOOD_MULTI_HANDLE(multi))
+    return CURLM_BAD_HANDLE;
+
+  *max_fd = -1; /* so far none! */
+
+  easy=multi->easy.next;
+  while(easy) {
+    switch(easy->state) {
+    default:
+      break;
+    case CURLM_STATE_WAITRESOLVE:
+      /* waiting for a resolve to complete */
+      Curl_fdset(easy->easy_conn, read_fd_set, write_fd_set, &this_max_fd);
+      if(this_max_fd > *max_fd)
+        *max_fd = this_max_fd;
+      break;
+
+    case CURLM_STATE_WAITCONNECT:
+    case CURLM_STATE_DO_MORE:
+      {
+        /* when we're waiting for a connect, we wait for the socket to
+           become writable */
+        struct connectdata *conn = easy->easy_conn;
+        curl_socket_t sockfd;
+
+        if(CURLM_STATE_WAITCONNECT == easy->state) {
+          sockfd = conn->sock[FIRSTSOCKET];
+          FD_SET(sockfd, write_fd_set);
+        }
+        else {
+          /* When in DO_MORE state, we could be either waiting for us
+             to connect to a remote site, or we could wait for that site
+             to connect to us. It makes a difference in the way: if we
+             connect to the site we wait for the socket to become writable, if
+             the site connects to us we wait for it to become readable */
+          sockfd = conn->sock[SECONDARYSOCKET];
+          FD_SET(sockfd, write_fd_set);
+        }
+
+        if((int)sockfd > *max_fd)
+          *max_fd = (int)sockfd;
+      }
+      break;
+    case CURLM_STATE_PERFORM:
+      /* This should have a set of file descriptors for us to set.  */
+      /* after the transfer is done, go DONE */
+
+      Curl_single_fdset(easy->easy_conn,
+                        read_fd_set, write_fd_set,
+                        exc_fd_set, &this_max_fd);
+
+      /* remember the maximum file descriptor */
+      if(this_max_fd > *max_fd)
+        *max_fd = this_max_fd;
+
+      break;
+    }
+    easy = easy->next; /* check next handle */
+  }
+
+  return CURLM_OK;
+}
+
+CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
+{
+  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+  struct Curl_one_easy *easy;
+  bool done;
+  CURLMcode result=CURLM_OK;
+  struct Curl_message *msg;
+  bool connected;
+  bool async;
+
+  *running_handles = 0; /* bump this once for every living handle */
+
+  if(!GOOD_MULTI_HANDLE(multi))
+    return CURLM_BAD_HANDLE;
+
+  easy=multi->easy.next;
+  while(easy) {
+#if 0
+    fprintf(stderr, "HANDLE %p: State: %x\n",
+            (char *)easy, easy->state);
+#endif
+    do {
+      if (CURLM_STATE_WAITCONNECT <= easy->state &&
+          easy->state <= CURLM_STATE_DO &&
+          easy->easy_handle->change.url_changed) {
+        char *gotourl;
+        Curl_posttransfer(easy->easy_handle);
+
+        easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
+        if(CURLE_OK == easy->result) {
+          gotourl = strdup(easy->easy_handle->change.url);
+          if(gotourl) {
+            easy->easy_handle->change.url_changed = FALSE;
+            easy->result = Curl_follow(easy->easy_handle, gotourl);
+            if(CURLE_OK == easy->result)
+              easy->state = CURLM_STATE_CONNECT;
+            else
+              free(gotourl);
+          }
+          else {
+            easy->result = CURLE_OUT_OF_MEMORY;
+            easy->state = CURLM_STATE_COMPLETED;
+            break;
+          }
+        }
+      }
+
+      easy->easy_handle->change.url_changed = FALSE;
+
+      switch(easy->state) {
+      case CURLM_STATE_INIT:
+        /* init this transfer. */
+        easy->result=Curl_pretransfer(easy->easy_handle);
+
+        if(CURLE_OK == easy->result) {
+          /* after init, go CONNECT */
+          easy->state = CURLM_STATE_CONNECT;
+          result = CURLM_CALL_MULTI_PERFORM;
+
+          easy->easy_handle->state.used_interface = Curl_if_multi;
+        }
+        break;
+
+      case CURLM_STATE_CONNECT:
+        /* Connect. We get a connection identifier filled in. */
+        Curl_pgrsTime(easy->easy_handle, TIMER_STARTSINGLE);
+        easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn,
+                                    &async);
+
+        if(CURLE_OK == easy->result) {
+          if(async)
+            /* We're now waiting for an asynchronous name lookup */
+            easy->state = CURLM_STATE_WAITRESOLVE;
+          else {
+            /* after the connect has been sent off, go WAITCONNECT */
+            easy->state = CURLM_STATE_WAITCONNECT;
+            result = CURLM_CALL_MULTI_PERFORM;
+          }
+        }
+        break;
+
+      case CURLM_STATE_WAITRESOLVE:
+        /* awaiting an asynch name resolve to complete */
+      {
+        struct Curl_dns_entry *dns = NULL;
+
+        /* check if we have the name resolved by now */
+        easy->result = Curl_is_resolved(easy->easy_conn, &dns);
+
+        if(dns) {
+          /* Perform the next step in the connection phase, and then move on
+             to the WAITCONNECT state */
+          easy->result = Curl_async_resolved(easy->easy_conn);
+
+          if(CURLE_OK != easy->result)
+            /* if Curl_async_resolved() returns failure, the connection struct
+               is already freed and gone */
+            easy->easy_conn = NULL;           /* no more connection */
+
+          easy->state = CURLM_STATE_WAITCONNECT;
+        }
+
+        if(CURLE_OK != easy->result) {
+          /* failure detected */
+          Curl_disconnect(easy->easy_conn); /* disconnect properly */
+          easy->easy_conn = NULL;           /* no more connection */
+          break;
+        }
+      }
+      break;
+
+      case CURLM_STATE_WAITCONNECT:
+        /* awaiting a completion of an asynch connect */
+        easy->result = Curl_is_connected(easy->easy_conn, FIRSTSOCKET,
+                                         &connected);
+        if(connected)
+          easy->result = Curl_protocol_connect(easy->easy_conn);
+
+        if(CURLE_OK != easy->result) {
+          /* failure detected */
+          Curl_disconnect(easy->easy_conn); /* close the connection */
+          easy->easy_conn = NULL;           /* no more connection */
+          break;
+        }
+
+        if(connected) {
+          /* after the connect has completed, go DO */
+          easy->state = CURLM_STATE_DO;
+          result = CURLM_CALL_MULTI_PERFORM;
+        }
+        break;
+
+      case CURLM_STATE_DO:
+        /* Do the fetch or put request */
+        easy->result = Curl_do(&easy->easy_conn);
+        if(CURLE_OK == easy->result) {
+
+          /* after do, go PERFORM... or DO_MORE */
+          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 */
+            easy->state = 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) {
+              easy->state = CURLM_STATE_PERFORM;
+              result = CURLM_CALL_MULTI_PERFORM;
+            }
+          }
+        }
+        break;
+
+      case CURLM_STATE_DO_MORE:
+        /*
+         * First, check if we really are ready to do more.
+         */
+        easy->result = Curl_is_connected(easy->easy_conn, SECONDARYSOCKET,
+                                         &connected);
+        if(connected) {
+          /*
+           * When we are connected, DO MORE and then go PERFORM
+           */
+          easy->result = Curl_do_more(easy->easy_conn);
+
+          if(CURLE_OK == easy->result)
+            easy->result = Curl_readwrite_init(easy->easy_conn);
+
+          if(CURLE_OK == easy->result) {
+            easy->state = CURLM_STATE_PERFORM;
+            result = CURLM_CALL_MULTI_PERFORM;
+          }
+        }
+        break;
+
+      case CURLM_STATE_PERFORM:
+        /* read/write data if it is ready to do so */
+        easy->result = Curl_readwrite(easy->easy_conn, &done);
+
+        if(easy->result)  {
+          /* The transfer phase returned error, we mark the connection to get
+           * closed to prevent being re-used. This is becasue we can't
+           * possibly know if the connection is in a good shape or not now. */
+          easy->easy_conn->bits.close = TRUE;
+
+          if(CURL_SOCKET_BAD != easy->easy_conn->sock[SECONDARYSOCKET]) {
+            /* if we failed anywhere, we must clean up the secondary socket if
+               it was used */
+            sclose(easy->easy_conn->sock[SECONDARYSOCKET]);
+            easy->easy_conn->sock[SECONDARYSOCKET]=-1;
+          }
+          Curl_posttransfer(easy->easy_handle);
+          Curl_done(&easy->easy_conn, easy->result);
+        }
+
+        /* after the transfer is done, go DONE */
+        else if(TRUE == done) {
+
+          /* call this even if the readwrite function returned error */
+          Curl_posttransfer(easy->easy_handle);
+
+          /* When we follow redirects, must to go back to the CONNECT state */
+          if(easy->easy_conn->newurl) {
+            char *newurl = easy->easy_conn->newurl;
+            easy->easy_conn->newurl = NULL;
+            easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
+            if(easy->result == CURLE_OK)
+              easy->result = Curl_follow(easy->easy_handle, newurl);
+            if(CURLE_OK == easy->result) {
+              easy->state = CURLM_STATE_CONNECT;
+              result = CURLM_CALL_MULTI_PERFORM;
+            }
+          }
+          else {
+            easy->state = CURLM_STATE_DONE;
+            result = CURLM_CALL_MULTI_PERFORM;
+          }
+        }
+        break;
+      case CURLM_STATE_DONE:
+        /* post-transfer command */
+        easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
+
+        /* after we have DONE what we're supposed to do, go COMPLETED, and
+           it doesn't matter what the Curl_done() returned! */
+        easy->state = CURLM_STATE_COMPLETED;
+        break;
+
+      case CURLM_STATE_COMPLETED:
+        /* this is a completed transfer, it is likely to still be connected */
+
+        /* This node should be delinked from the list now and we should post
+           an information message that we are complete. */
+        break;
+      default:
+        return CURLM_INTERNAL_ERROR;
+      }
+
+      if(CURLM_STATE_COMPLETED != easy->state) {
+        if(CURLE_OK != easy->result) {
+          /*
+           * If an error was returned, and we aren't in completed state now,
+           * then we go to completed and consider this transfer aborted.  */
+          easy->state = CURLM_STATE_COMPLETED;
+        }
+        else
+          /* this one still lives! */
+          (*running_handles)++;
+      }
+
+    } while (easy->easy_handle->change.url_changed);
+
+    if ((CURLM_STATE_COMPLETED == easy->state) && !easy->msg) {
+      /* clear out the usage of the shared DNS cache */
+      easy->easy_handle->hostcache = NULL;
+
+      /* now add a node to the Curl_message linked list with this info */
+      msg = (struct Curl_message *)malloc(sizeof(struct Curl_message));
+
+      if(!msg)
+        return CURLM_OUT_OF_MEMORY;
+
+      msg->extmsg.msg = CURLMSG_DONE;
+      msg->extmsg.easy_handle = easy->easy_handle;
+      msg->extmsg.data.result = easy->result;
+      msg->next=NULL;
+
+      easy->msg = msg;
+      easy->msg_num = 1; /* there is one unread message here */
+
+      multi->num_msgs++; /* increase message counter */
+    }
+
+    easy = easy->next; /* operate on next handle */
+  }
+
+  return result;
+}
+
+CURLMcode curl_multi_cleanup(CURLM *multi_handle)
+{
+  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+  struct Curl_one_easy *easy;
+  struct Curl_one_easy *nexteasy;
+
+  if(GOOD_MULTI_HANDLE(multi)) {
+    multi->type = 0; /* not good anymore */
+    Curl_hash_destroy(multi->hostcache);
+
+    /* remove all easy handles */
+    easy = multi->easy.next;
+    while(easy) {
+      nexteasy=easy->next;
+      /* clear out the usage of the shared DNS cache */
+      easy->easy_handle->hostcache = NULL;
+
+      if (easy->msg)
+        free(easy->msg);
+      free(easy);
+      easy = nexteasy;
+    }
+
+    free(multi);
+
+    return CURLM_OK;
+  }
+  else
+    return CURLM_BAD_HANDLE;
+}
+
+CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue)
+{
+  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+
+  *msgs_in_queue = 0; /* default to none */
+
+  if(GOOD_MULTI_HANDLE(multi)) {
+    struct Curl_one_easy *easy;
+
+    if(!multi->num_msgs)
+      return NULL; /* no messages left to return */
+
+    easy=multi->easy.next;
+    while(easy) {
+      if(easy->msg_num) {
+        easy->msg_num--;
+        break;
+      }
+      easy = easy->next;
+    }
+    if(!easy)
+      return NULL; /* this means internal count confusion really */
+
+    multi->num_msgs--;
+    *msgs_in_queue = multi->num_msgs;
+
+    return &easy->msg->extmsg;
+  }
+  else
+    return NULL;
+}
diff --git a/Utilities/cmcurl/netrc.c b/Utilities/cmcurl/netrc.c
new file mode 100644
index 0000000..770bfb5
--- /dev/null
+++ b/Utilities/cmcurl/netrc.c
@@ -0,0 +1,247 @@
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#ifdef VMS
+#include <unixlib.h>
+#endif
+
+#include <curl/curl.h>
+#include "netrc.h"
+
+#include "strequal.h"
+#include "strtok.h"
+#include "curl_memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* Debug this single source file with:
+   'make netrc' then run './netrc'!
+
+   Oh, make sure you have a .netrc file too ;-)
+ */
+
+/* Get user and password from .netrc when given a machine name */
+
+enum {
+  NOTHING,
+  HOSTFOUND,    /* the 'machine' keyword was found */
+  HOSTCOMPLETE, /* the machine name following the keyword was found too */
+  HOSTVALID,    /* this is "our" machine! */
+
+  HOSTEND /* LAST enum */
+};
+
+/* make sure we have room for at least this size: */
+#define LOGINSIZE 64
+#define PASSWORDSIZE 64
+
+/* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */
+int Curl_parsenetrc(char *host,
+                    char *login,
+                    char *password,
+                    char *netrcfile)
+{
+  FILE *file;
+  int retcode=1;
+  int specific_login = (login[0] != 0);
+  char *home = NULL; 
+  bool home_alloc = FALSE;
+  bool netrc_alloc = FALSE;
+  int state=NOTHING;
+
+  char state_login=0;      /* Found a login keyword */
+  char state_password=0;   /* Found a password keyword */
+  int state_our_login=FALSE;  /* With specific_login, found *our* login name */
+
+#define NETRC DOT_CHAR "netrc"
+
+#ifdef CURLDEBUG
+  {
+    /* This is a hack to allow testing.
+     * If compiled with --enable-debug and CURL_DEBUG_NETRC is defined,
+     * then it's the path to a substitute .netrc for testing purposes *only* */
+
+    char *override = curl_getenv("CURL_DEBUG_NETRC");
+
+    if (override) {
+      printf("NETRC: overridden " NETRC " file: %s\n", home);
+      netrcfile = override;
+      netrc_alloc = TRUE;
+    }
+  }
+#endif /* CURLDEBUG */
+  if(!netrcfile) {
+    home = curl_getenv("HOME"); /* portable environment reader */
+    if(home) {
+      home_alloc = TRUE;
+#if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
+    }
+    else {
+      struct passwd *pw;
+      pw= getpwuid(geteuid());
+      if (pw) {
+#ifdef  VMS
+        home = decc$translate_vms(pw->pw_dir);
+#else
+        home = pw->pw_dir;
+#endif
+      }
+#endif
+    }
+
+    if(!home)
+      return -1;
+
+    netrcfile = curl_maprintf("%s%s%s", home, DIR_CHAR, NETRC);
+    if(!netrcfile) {
+      if(home_alloc)
+        free(home);
+      return -1;
+    }
+    netrc_alloc = TRUE;
+  }
+
+  file = fopen(netrcfile, "r");
+  if(file) {
+    char *tok;
+    char *tok_buf;
+    bool done=FALSE;
+    char netrcbuffer[256];
+
+    while(!done && fgets(netrcbuffer, sizeof(netrcbuffer), file)) {
+      tok=strtok_r(netrcbuffer, " \t\n", &tok_buf);
+      while(!done && tok) {
+
+        if (login[0] && password[0]) {
+          done=TRUE;
+          break;
+        }
+
+        switch(state) {
+        case NOTHING:
+          if(strequal("machine", tok)) {
+            /* the next tok is the machine name, this is in itself the
+               delimiter that starts the stuff entered for this machine,
+               after this we need to search for 'login' and
+               'password'. */
+            state=HOSTFOUND;
+          }
+          break;
+        case HOSTFOUND:
+          if(strequal(host, tok)) {
+            /* and yes, this is our host! */
+            state=HOSTVALID;
+#ifdef _NETRC_DEBUG
+            printf("HOST: %s\n", tok);
+#endif
+            retcode=0; /* we did find our host */
+          }
+          else
+            /* not our host */
+            state=NOTHING;
+          break;
+        case HOSTVALID:
+          /* we are now parsing sub-keywords concerning "our" host */
+          if(state_login) {
+            if (specific_login) {
+              state_our_login = strequal(login, tok);
+            }
+            else {
+              strncpy(login, tok, LOGINSIZE-1);
+#ifdef _NETRC_DEBUG
+              printf("LOGIN: %s\n", login);
+#endif
+            }
+            state_login=0;
+          }
+          else if(state_password) {
+            if (state_our_login || !specific_login) {
+              strncpy(password, tok, PASSWORDSIZE-1);
+#ifdef _NETRC_DEBUG
+              printf("PASSWORD: %s\n", password);
+#endif
+            }
+            state_password=0;
+          }
+          else if(strequal("login", tok))
+            state_login=1;
+          else if(strequal("password", tok))
+            state_password=1;
+          else if(strequal("machine", tok)) {
+            /* ok, there's machine here go => */
+            state = HOSTFOUND;
+            state_our_login = FALSE;
+          }
+          break;
+        } /* switch (state) */
+
+        tok = strtok_r(NULL, " \t\n", &tok_buf);
+      } /* while (tok) */
+    } /* while fgets() */
+
+    fclose(file);
+  }
+
+  if(home_alloc)
+    free(home);
+  if(netrc_alloc)
+    free(netrcfile);
+
+  return retcode;
+}
+
+#ifdef _NETRC_DEBUG
+int main(int argc, char **argv)
+{
+  char login[64]="";
+  char password[64]="";
+
+  if(argc<2)
+    return -1;
+
+  if(0 == ParseNetrc(argv[1], login, password)) {
+    printf("HOST: %s LOGIN: %s PASSWORD: %s\n",
+           argv[1], login, password);
+  }
+}
+
+#endif
diff --git a/Utilities/cmcurl/netrc.h b/Utilities/cmcurl/netrc.h
new file mode 100644
index 0000000..939c552
--- /dev/null
+++ b/Utilities/cmcurl/netrc.h
@@ -0,0 +1,34 @@
+#ifndef __NETRC_H
+#define __NETRC_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+int Curl_parsenetrc(char *host,
+                    char *login,
+                    char *password,
+                    char *filename);
+  /* Assume: password[0]=0, host[0] != 0.
+   * If login[0] = 0, search for login and password within a machine section
+   * in the netrc.
+   * If login[0] != 0, search for password within machine and login.
+   */
+#endif
diff --git a/Utilities/cmcurl/nwlib.c b/Utilities/cmcurl/nwlib.c
new file mode 100644
index 0000000..a999dfd
--- /dev/null
+++ b/Utilities/cmcurl/nwlib.c
@@ -0,0 +1,300 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <library.h>
+#include <netware.h>
+#include <screen.h>
+#include <nks/thread.h>
+#include <nks/synch.h>
+
+#include "curl_memory.h"
+#include "memdebug.h"
+
+typedef struct
+{
+  int     _errno;
+  void    *twentybytes;
+} libthreaddata_t;
+
+typedef struct
+{
+  int         x;
+  int         y;
+  int         z;
+  void        *tenbytes;
+  NXKey_t     perthreadkey;   /* if -1, no key obtained... */
+  NXMutex_t   *lock;
+} libdata_t;
+
+int         gLibId      = -1;
+void        *gLibHandle = (void *) NULL;
+rtag_t      gAllocTag   = (rtag_t) NULL;
+NXMutex_t   *gLibLock   = (NXMutex_t *) NULL;
+
+/* internal library function prototypes... */
+int     DisposeLibraryData ( void * );
+void    DisposeThreadData ( void * );
+int     GetOrSetUpData ( int id, libdata_t **data, libthreaddata_t **threaddata );
+
+
+int _NonAppStart( void        *NLMHandle,
+                  void        *errorScreen,
+                  const char  *cmdLine,
+                  const char  *loadDirPath,
+                  size_t      uninitializedDataLength,
+                  void        *NLMFileHandle,
+                  int         (*readRoutineP)( int conn,
+                                               void *fileHandle, size_t offset,
+                                               size_t nbytes,
+                                               size_t *bytesRead,
+                                               void *buffer ),
+                  size_t      customDataOffset,
+                  size_t      customDataSize,
+                  int         messageCount,
+                  const char  **messages )
+{
+  NX_LOCK_INFO_ALLOC(liblock, "Per-Application Data Lock", 0);
+  
+#ifndef __GNUC__
+#pragma unused(cmdLine)
+#pragma unused(loadDirPath)
+#pragma unused(uninitializedDataLength)
+#pragma unused(NLMFileHandle)
+#pragma unused(readRoutineP)
+#pragma unused(customDataOffset)
+#pragma unused(customDataSize)
+#pragma unused(messageCount)
+#pragma unused(messages)
+#endif
+
+/*
+** Here we process our command line, post errors (to the error screen),
+** perform initializations and anything else we need to do before being able
+** to accept calls into us. If we succeed, we return non-zero and the NetWare
+** Loader will leave us up, otherwise we fail to load and get dumped.
+*/
+  gAllocTag = AllocateResourceTag(NLMHandle,
+                                  "<library-name> memory allocations",
+                                  AllocSignature);
+
+  if (!gAllocTag) {
+    OutputToScreen(errorScreen, "Unable to allocate resource tag for "
+                   "library memory allocations.\n");
+    return -1;
+  }
+
+  gLibId = register_library(DisposeLibraryData);
+
+  if (gLibId < -1) {
+    OutputToScreen(errorScreen, "Unable to register library with kernel.\n");
+    return -1;
+  }
+
+  gLibHandle = NLMHandle;
+
+  gLibLock = NXMutexAlloc(0, 0, &liblock);
+  
+  if (!gLibLock) {
+    OutputToScreen(errorScreen, "Unable to allocate library data lock.\n");
+    return -1;
+  }
+
+  return 0;
+}
+
+/*
+** Here we clean up any resources we allocated. Resource tags is a big part
+** of what we created, but NetWare doesn't ask us to free those.
+*/
+void _NonAppStop( void )
+{
+  (void) unregister_library(gLibId);
+  NXMutexFree(gLibLock);
+}
+
+/*
+** This function cannot be the first in the file for if the file is linked
+** first, then the check-unload function's offset will be nlmname.nlm+0
+** which is how to tell that there isn't one. When the check function is
+** first in the linked objects, it is ambiguous. For this reason, we will
+** put it inside this file after the stop function.
+**
+** Here we check to see if it's alright to ourselves to be unloaded. If not,
+** we return a non-zero value. Right now, there isn't any reason not to allow
+** it.
+*/
+int  _NonAppCheckUnload( void )
+{
+    return 0;
+}
+
+int GetOrSetUpData(int id, libdata_t **appData,
+                   libthreaddata_t **threadData )
+{
+  int                 err;
+  libdata_t           *app_data;
+  libthreaddata_t *thread_data;
+  NXKey_t             key;
+  NX_LOCK_INFO_ALLOC(liblock, "Application Data Lock", 0);
+
+  err         = 0;
+  thread_data = (libthreaddata_t *) NULL;
+
+/*
+** Attempt to get our data for the application calling us. This is where we
+** store whatever application-specific information we need to carry in support
+** of calling applications.
+*/
+  app_data = (libdata_t *) get_app_data(id);
+
+  if (!app_data) {
+/*
+** This application hasn't called us before; set up application AND per-thread
+** data. Of course, just in case a thread from this same application is calling
+** us simultaneously, we better lock our application data-creation mutex. We
+** also need to recheck for data after we acquire the lock because WE might be
+** that other thread that was too late to create the data and the first thread
+** in will have created it.
+*/
+    NXLock(gLibLock);
+
+    if (!(app_data = (libdata_t *) get_app_data(id))) {
+      app_data = (libdata_t *) malloc(sizeof(libdata_t));
+
+      if (app_data) {
+        memset(app_data, 0, sizeof(libdata_t));
+        
+        app_data->tenbytes = malloc(10);
+        app_data->lock     = NXMutexAlloc(0, 0, &liblock);
+        
+        if (!app_data->tenbytes || !app_data->lock) {
+          if (app_data->lock)
+            NXMutexFree(app_data->lock);
+          
+          free(app_data);
+          app_data = (libdata_t *) NULL;
+          err      = ENOMEM;
+        }
+        
+        if (app_data) {
+/*
+** Here we burn in the application data that we were trying to get by calling
+** get_app_data(). Next time we call the first function, we'll get this data
+** we're just now setting. We also go on here to establish the per-thread data
+** for the calling thread, something we'll have to do on each application
+** thread the first time it calls us.
+*/
+          err = set_app_data(gLibId, app_data);
+          
+          if (err) {
+            free(app_data);
+            app_data = (libdata_t *) NULL;
+            err      = ENOMEM;
+          }
+          else {
+            /* create key for thread-specific data... */
+            err = NXKeyCreate(DisposeThreadData, (void *) NULL, &key);
+            
+            if (err)                /* (no more keys left?) */
+              key = -1;
+            
+            app_data->perthreadkey = key;
+          }
+        }
+      }
+    }
+    
+    NXUnlock(gLibLock);
+  }
+
+  if (app_data) {
+    key = app_data->perthreadkey;
+    
+    if (key != -1 /* couldn't create a key? no thread data */
+        && !(err = NXKeyGetValue(key, (void **) &thread_data))
+        && !thread_data) {
+/*
+** Allocate the per-thread data for the calling thread. Regardless of whether
+** there was already application data or not, this may be the first call by a
+** a new thread. The fact that we allocation 20 bytes on a pointer is not very
+** important, this just helps to demonstrate that we can have arbitrarily
+** complex per-thread data.
+*/
+      thread_data = (libthreaddata_t *) malloc(sizeof(libthreaddata_t));
+      
+      if (thread_data) {
+        thread_data->_errno      = 0;
+        thread_data->twentybytes = malloc(20);
+          
+        if (!thread_data->twentybytes) {
+          free(thread_data);
+          thread_data = (libthreaddata_t *) NULL;
+          err         = ENOMEM;
+        }
+        
+        if ((err = NXKeySetValue(key, thread_data))) {
+          free(thread_data->twentybytes);
+          free(thread_data);
+          thread_data = (libthreaddata_t *) NULL;
+        }
+      }
+    }
+  }
+
+  if (appData)
+    *appData = app_data;
+
+  if (threadData)
+    *threadData = thread_data;
+
+  return err;
+}
+
+int DisposeLibraryData( void    *data)
+{
+  if (data) {
+    void    *tenbytes = ((libdata_t *) data)->tenbytes;
+    
+    if (tenbytes)
+      free(tenbytes);
+    
+    free(data);
+  }
+
+  return 0;
+}
+
+void DisposeThreadData(void    *data)
+{
+  if (data) {
+    void    *twentybytes = ((libthreaddata_t *) data)->twentybytes;
+    
+    if (twentybytes)
+      free(twentybytes);
+    
+    free(data);
+  }
+}
diff --git a/Utilities/cmcurl/progress.c b/Utilities/cmcurl/progress.c
new file mode 100644
index 0000000..36be56e
--- /dev/null
+++ b/Utilities/cmcurl/progress.c
@@ -0,0 +1,426 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <string.h>
+#include <time.h>
+
+#if defined(__EMX__)
+#include <stdlib.h>
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "progress.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero
+   byte) */
+static void time2str(char *r, long t)
+{
+  long h;
+  if(!t) {
+    strcpy(r, "--:--:--");
+    return;
+  }
+  h = (t/3600);
+  if(h <= 99) {
+    long m = (t-(h*3600))/60;
+    long s = (t-(h*3600)-(m*60));
+    snprintf(r, 9, "%2ld:%02ld:%02ld",h,m,s);
+  }
+  else {
+    /* this equals to more than 99 hours, switch to a more suitable output
+       format to fit within the limits. */
+    if(h/24 <= 999)
+      snprintf(r, 9, "%3ldd %02ldh", h/24, h-(h/24)*24);
+    else
+      snprintf(r, 9, "%7ldd", h/24);
+  }
+}
+
+/* The point of this function would be to return a string of the input data,
+   but never longer than 5 columns (+ one zero byte).
+   Add suffix k, M, G when suitable... */
+static char *max5data(curl_off_t bytes, char *max5)
+{
+#define ONE_KILOBYTE 1024
+#define ONE_MEGABYTE (1024* ONE_KILOBYTE)
+#define ONE_GIGABYTE (1024* ONE_MEGABYTE)
+#define ONE_TERRABYTE ((curl_off_t)1024* ONE_GIGABYTE)
+#define ONE_PETABYTE ((curl_off_t)1024* ONE_TERRABYTE)
+
+  if(bytes < 100000) {
+    snprintf(max5, 6, "%5" FORMAT_OFF_T, bytes);
+  }
+  else if(bytes < (10000*ONE_KILOBYTE)) {
+    snprintf(max5, 6, "%4" FORMAT_OFF_T "k", (curl_off_t)(bytes/ONE_KILOBYTE));
+  }
+  else if(bytes < (100*ONE_MEGABYTE)) {
+    /* 'XX.XM' is good as long as we're less than 100 megs */
+    snprintf(max5, 6, "%2d.%0dM",
+             (int)(bytes/ONE_MEGABYTE),
+             (int)(bytes%ONE_MEGABYTE)/(ONE_MEGABYTE/10) );
+  }
+#if SIZEOF_CURL_OFF_T > 4
+  else if(bytes < ( (curl_off_t)10000*ONE_MEGABYTE))
+    /* 'XXXXM' is good until we're at 10000MB or above */
+    snprintf(max5, 6, "%4" FORMAT_OFF_T "M", (curl_off_t)(bytes/ONE_MEGABYTE));
+
+  else if(bytes < (curl_off_t)100*ONE_GIGABYTE)
+    /* 10000 MB - 100 GB, we show it as XX.XG */
+    snprintf(max5, 6, "%2d.%0dG",
+             (int)(bytes/ONE_GIGABYTE),
+             (int)(bytes%ONE_GIGABYTE)/(ONE_GIGABYTE/10) );
+
+  else if(bytes < (curl_off_t)10000 * ONE_GIGABYTE)
+    /* up to 10000GB, display without decimal: XXXXG */
+    snprintf(max5, 6, "%4dG", (int)(bytes/ONE_GIGABYTE));
+
+  else if(bytes < (curl_off_t)10000 * ONE_TERRABYTE)
+    /* up to 10000TB, display without decimal: XXXXT */
+    snprintf(max5, 6, "%4dT", (int)(bytes/ONE_TERRABYTE));
+  else {
+    /* up to 10000PB, display without decimal: XXXXP */
+    snprintf(max5, 6, "%4dP", (int)(bytes/ONE_PETABYTE));
+
+    /* 16384 petabytes (16 exabytes) is maximum a 64 bit number can hold,
+       but this type is signed so 8192PB will be max.*/
+  }
+
+#else
+  else
+    snprintf(max5, 6, "%4" FORMAT_OFF_T "M", (curl_off_t)(bytes/ONE_MEGABYTE));
+#endif
+
+  return max5;
+}
+
+/*
+
+   New proposed interface, 9th of February 2000:
+
+   pgrsStartNow() - sets start time
+   pgrsSetDownloadSize(x) - known expected download size
+   pgrsSetUploadSize(x) - known expected upload size
+   pgrsSetDownloadCounter() - amount of data currently downloaded
+   pgrsSetUploadCounter() - amount of data currently uploaded
+   pgrsUpdate() - show progress
+   pgrsDone() - transfer complete
+
+*/
+
+void Curl_pgrsDone(struct connectdata *conn)
+{
+  struct SessionHandle *data = conn->data;
+  data->progress.lastshow=0;
+  Curl_pgrsUpdate(conn); /* the final (forced) update */
+  if(!(data->progress.flags & PGRS_HIDE) &&
+     !data->progress.callback)
+    /* only output if we don't use a progress callback and we're not hidden */
+    fprintf(data->set.err, "\n");
+}
+
+/* reset all times except redirect */
+void Curl_pgrsResetTimes(struct SessionHandle *data)
+{
+  data->progress.t_nslookup = 0.0;
+  data->progress.t_connect = 0.0;
+  data->progress.t_pretransfer = 0.0;
+  data->progress.t_starttransfer = 0.0;
+}
+
+void Curl_pgrsTime(struct SessionHandle *data, timerid timer)
+{
+  switch(timer) {
+  default:
+  case TIMER_NONE:
+    /* mistake filter */
+    break;
+  case TIMER_STARTSINGLE:
+    /* This is set at the start of a single fetch */
+    data->progress.t_startsingle = Curl_tvnow();
+    break;
+
+  case TIMER_NAMELOOKUP:
+    data->progress.t_nslookup =
+      Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle);
+    break;
+  case TIMER_CONNECT:
+    data->progress.t_connect =
+      Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle);
+    break;
+  case TIMER_PRETRANSFER:
+    data->progress.t_pretransfer =
+      Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle);
+    break;
+  case TIMER_STARTTRANSFER:
+    data->progress.t_starttransfer =
+      Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle);
+    break;
+  case TIMER_POSTRANSFER:
+    /* this is the normal end-of-transfer thing */
+    break;
+  case TIMER_REDIRECT:
+    data->progress.t_redirect =
+      Curl_tvdiff_secs(Curl_tvnow(), data->progress.start);
+    break;
+  }
+}
+
+void Curl_pgrsStartNow(struct SessionHandle *data)
+{
+  data->progress.speeder_c = 0; /* reset the progress meter display */
+  data->progress.start = Curl_tvnow();
+}
+
+void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size)
+{
+  data->progress.downloaded = size;
+}
+
+void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size)
+{
+  data->progress.uploaded = size;
+}
+
+void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size)
+{
+  data->progress.size_dl = size;
+  if(size > 0)
+    data->progress.flags |= PGRS_DL_SIZE_KNOWN;
+  else
+    data->progress.flags &= ~PGRS_DL_SIZE_KNOWN;
+}
+
+void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size)
+{
+  data->progress.size_ul = size;
+  if(size > 0)
+    data->progress.flags |= PGRS_UL_SIZE_KNOWN;
+  else
+    data->progress.flags &= ~PGRS_UL_SIZE_KNOWN;
+}
+
+int Curl_pgrsUpdate(struct connectdata *conn)
+{
+  struct timeval now;
+  int result;
+  char max5[6][10];
+  int dlpercen=0;
+  int ulpercen=0;
+  int total_percen=0;
+  curl_off_t total_transfer;
+  curl_off_t total_expected_transfer;
+  long timespent;
+  struct SessionHandle *data = conn->data;
+  int nowindex = data->progress.speeder_c% CURR_TIME;
+  int checkindex;
+  int countindex; /* amount of seconds stored in the speeder array */
+  char time_left[10];
+  char time_total[10];
+  char time_spent[10];
+  long ulestimate=0;
+  long dlestimate=0;
+  long total_estimate;
+
+  if(data->progress.flags & PGRS_HIDE)
+    ; /* We do enter this function even if we don't wanna see anything, since
+         this is were lots of the calculations are being made that will be used
+         even when not displayed! */
+  else if(!(data->progress.flags & PGRS_HEADERS_OUT)) {
+    if (!data->progress.callback) {
+      if(conn->resume_from)
+        fprintf(data->set.err,
+                "** Resuming transfer from byte position %" FORMAT_OFF_T
+                "\n",
+                conn->resume_from);
+      fprintf(data->set.err,
+              "  %% Total    %% Received %% Xferd  Average Speed   Time    Time     Time  Current\n"
+              "                                 Dload  Upload   Total   Spent    Left  Speed\n");
+    }
+    data->progress.flags |= PGRS_HEADERS_OUT; /* headers are shown */
+  }
+
+  now = Curl_tvnow(); /* what time is it */
+
+  /* The time spent so far (from the start) */
+  data->progress.timespent = Curl_tvdiff_secs(now, data->progress.start);
+  timespent = (long)data->progress.timespent;
+
+  /* The average download speed this far */
+  data->progress.dlspeed = (curl_off_t)
+    ((double)data->progress.downloaded/
+     (data->progress.timespent>0?data->progress.timespent:1));
+
+  /* The average upload speed this far */
+  data->progress.ulspeed = (curl_off_t)
+    ((double)data->progress.uploaded/
+     (data->progress.timespent>0?data->progress.timespent:1));
+
+  if(data->progress.lastshow == Curl_tvlong(now))
+    return 0; /* never update this more than once a second if the end isn't
+                 reached */
+  data->progress.lastshow = now.tv_sec;
+
+  /* Let's do the "current speed" thing, which should use the fastest
+     of the dl/ul speeds. Store the fasted speed at entry 'nowindex'. */
+  data->progress.speeder[ nowindex ] =
+    data->progress.downloaded>data->progress.uploaded?
+    data->progress.downloaded:data->progress.uploaded;
+
+  /* remember the exact time for this moment */
+  data->progress.speeder_time [ nowindex ] = now;
+
+  /* advance our speeder_c counter, which is increased every time we get
+     here and we expect it to never wrap as 2^32 is a lot of seconds! */
+  data->progress.speeder_c++;
+
+  /* figure out how many index entries of data we have stored in our speeder
+     array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of
+     transfer. Imagine, after one second we have filled in two entries,
+     after two seconds we've filled in three entries etc. */
+  countindex = ((data->progress.speeder_c>=CURR_TIME)?
+                CURR_TIME:data->progress.speeder_c) - 1;
+
+  /* first of all, we don't do this if there's no counted seconds yet */
+  if(countindex) {
+    long span_ms;
+
+    /* Get the index position to compare with the 'nowindex' position.
+       Get the oldest entry possible. While we have less than CURR_TIME
+       entries, the first entry will remain the oldest. */
+    checkindex = (data->progress.speeder_c>=CURR_TIME)?
+      data->progress.speeder_c%CURR_TIME:0;
+
+    /* Figure out the exact time for the time span */
+    span_ms = Curl_tvdiff(now,
+                          data->progress.speeder_time[checkindex]);
+    if(0 == span_ms)
+      span_ms=1; /* at least one millisecond MUST have passed */
+
+    /* Calculate the average speed the last 'span_ms' milliseconds */
+    {
+      curl_off_t amount = data->progress.speeder[nowindex]-
+        data->progress.speeder[checkindex];
+
+      if(amount > 0xffffffff/1000)
+        /* the 'amount' value is bigger than would fit in 32 bits if
+           multiplied with 1000, so we use the double math for this */
+        data->progress.current_speed = (curl_off_t)
+          ((double)amount/((double)span_ms/1000.0));
+      else
+        /* the 'amount' value is small enough to fit within 32 bits even
+           when multiplied with 1000 */
+        data->progress.current_speed = amount*1000/span_ms;
+    }
+  }
+  else
+    /* the first second we use the main average */
+    data->progress.current_speed =
+      (data->progress.ulspeed>data->progress.dlspeed)?
+      data->progress.ulspeed:data->progress.dlspeed;
+
+  if(data->progress.flags & PGRS_HIDE)
+    return 0;
+
+  else if(data->set.fprogress) {
+    /* There's a callback set, so we call that instead of writing
+       anything ourselves. This really is the way to go. */
+    result= data->set.fprogress(data->set.progress_client,
+                                (double)data->progress.size_dl,
+                                (double)data->progress.downloaded,
+                                (double)data->progress.size_ul,
+                                (double)data->progress.uploaded);
+    if(result)
+      failf(data, "Callback aborted");
+    return result;
+  }
+
+  /* Figure out the estimated time of arrival for the upload */
+  if((data->progress.flags & PGRS_UL_SIZE_KNOWN) &&
+     (data->progress.ulspeed>0) &&
+     (data->progress.size_ul > 100) ) {
+    ulestimate = (long)(data->progress.size_ul / data->progress.ulspeed);
+    ulpercen = (int)(100*(data->progress.uploaded/100) /
+                      (data->progress.size_ul/100) );
+  }
+
+  /* ... and the download */
+  if((data->progress.flags & PGRS_DL_SIZE_KNOWN) &&
+     (data->progress.dlspeed>0) &&
+     (data->progress.size_dl>100)) {
+    dlestimate = (long)(data->progress.size_dl / data->progress.dlspeed);
+    dlpercen = (int)(100*(data->progress.downloaded/100) /
+                      (data->progress.size_dl/100));
+  }
+
+  /* Now figure out which of them that is slower and use for the for
+     total estimate! */
+  total_estimate = ulestimate>dlestimate?ulestimate:dlestimate;
+
+  /* create the three time strings */
+  time2str(time_left, total_estimate > 0?(total_estimate - timespent):0);
+  time2str(time_total, total_estimate);
+  time2str(time_spent, timespent);
+
+  /* Get the total amount of data expected to get transfered */
+  total_expected_transfer =
+    (data->progress.flags & PGRS_UL_SIZE_KNOWN?
+     data->progress.size_ul:data->progress.uploaded)+
+    (data->progress.flags & PGRS_DL_SIZE_KNOWN?
+     data->progress.size_dl:data->progress.downloaded);
+
+  /* We have transfered this much so far */
+  total_transfer = data->progress.downloaded + data->progress.uploaded;
+
+  /* Get the percentage of data transfered so far */
+  if(total_expected_transfer > 100)
+    total_percen=(int)(100*(total_transfer/100) /
+                       (total_expected_transfer/100) );
+
+  fprintf(data->set.err,
+          "\r%3d %s  %3d %s  %3d %s  %s  %s %s %s %s %s",
+          total_percen,  /* 3 letters */                /* total % */
+          max5data(total_expected_transfer, max5[2]),   /* total size */
+          dlpercen,      /* 3 letters */                /* rcvd % */
+          max5data(data->progress.downloaded, max5[0]), /* rcvd size */
+          ulpercen,      /* 3 letters */                /* xfer % */
+          max5data(data->progress.uploaded, max5[1]),   /* xfer size */
+          max5data(data->progress.dlspeed, max5[3]),    /* avrg dl speed */
+          max5data(data->progress.ulspeed, max5[4]),    /* avrg ul speed */
+          time_total,    /* 8 letters */                /* total time */
+          time_spent,    /* 8 letters */                /* time spent */
+          time_left,     /* 8 letters */                /* time left */
+          max5data(data->progress.current_speed, max5[5]) /* current speed */
+          );
+
+  /* we flush the output stream to make it appear as soon as possible */
+  fflush(data->set.err);
+
+  return 0;
+}
diff --git a/Utilities/cmcurl/progress.h b/Utilities/cmcurl/progress.h
new file mode 100644
index 0000000..dcfcaf7
--- /dev/null
+++ b/Utilities/cmcurl/progress.h
@@ -0,0 +1,70 @@
+#ifndef __PROGRESS_H
+#define __PROGRESS_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "timeval.h"
+
+
+typedef enum {
+  TIMER_NONE,
+  TIMER_NAMELOOKUP,
+  TIMER_CONNECT,
+  TIMER_PRETRANSFER,
+  TIMER_STARTTRANSFER,
+  TIMER_POSTRANSFER,
+  TIMER_STARTSINGLE,
+  TIMER_REDIRECT,
+  TIMER_LAST /* must be last */
+} timerid;
+  
+void Curl_pgrsDone(struct connectdata *);
+void Curl_pgrsStartNow(struct SessionHandle *data);
+void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size);
+void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size);
+void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size);
+void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size);
+int Curl_pgrsUpdate(struct connectdata *);
+void Curl_pgrsResetTimes(struct SessionHandle *data);
+void Curl_pgrsTime(struct SessionHandle *data, timerid timer);
+
+
+/* Don't show progress for sizes smaller than: */
+#define LEAST_SIZE_PROGRESS BUFSIZE
+
+#define PROGRESS_DOWNLOAD (1<<0)
+#define PROGRESS_UPLOAD   (1<<1)
+#define PROGRESS_DOWN_AND_UP (PROGRESS_UPLOAD | PROGRESS_DOWNLOAD)
+
+#define PGRS_SHOW_DL (1<<0)
+#define PGRS_SHOW_UL (1<<1)
+#define PGRS_DONE_DL (1<<2)
+#define PGRS_DONE_UL (1<<3)
+#define PGRS_HIDE    (1<<4)
+#define PGRS_UL_SIZE_KNOWN (1<<5)
+#define PGRS_DL_SIZE_KNOWN (1<<6)
+
+#define PGRS_HEADERS_OUT (1<<7) /* set when the headers have been written */
+
+
+#endif /* __PROGRESS_H */
diff --git a/Utilities/cmcurl/security.c b/Utilities/cmcurl/security.c
new file mode 100644
index 0000000..861f953
--- /dev/null
+++ b/Utilities/cmcurl/security.c
@@ -0,0 +1,483 @@
+/* This source code was modified by Martin Hedenfalk <mhe@stacken.kth.se> for
+ * use in Curl. His latest changes were done 2000-09-18.
+ *
+ * It has since been patched and modified a lot by Daniel Stenberg
+ * <daniel@haxx.se> to make it better applied to curl conditions, and to make
+ * it not use globals, pollute name space and more. This source code awaits a
+ * rewrite to work around the paragraph 2 in the BSD licenses as explained
+ * below.
+ *
+ * Copyright (c) 1998, 1999 Kungliga Tekniska H�gskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.  */
+
+#include "setup.h"
+
+#ifndef CURL_DISABLE_FTP
+#ifdef HAVE_KRB4
+
+#define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */
+#include <curl/mprintf.h>
+
+#include "security.h"
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "base64.h"
+#include "sendf.h"
+#include "ftp.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#define min(a, b)   ((a) < (b) ? (a) : (b))
+
+static struct {
+    enum protection_level level;
+    const char *name;
+} level_names[] = {
+    { prot_clear, "clear" },
+    { prot_safe, "safe" },
+    { prot_confidential, "confidential" },
+    { prot_private, "private" }
+};
+
+static enum protection_level
+name_to_level(const char *name)
+{
+  int i;
+  for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++)
+    if(!strncasecmp(level_names[i].name, name, strlen(name)))
+      return level_names[i].level;
+  return (enum protection_level)-1;
+}
+
+static struct Curl_sec_client_mech *mechs[] = {
+#ifdef KRB5
+  /* not supported */
+#endif
+#ifdef HAVE_KRB4
+    &Curl_krb4_client_mech,
+#endif
+    NULL
+};
+
+int
+Curl_sec_getc(struct connectdata *conn, FILE *F)
+{
+  if(conn->sec_complete && conn->data_prot) {
+    char c;
+    if(Curl_sec_read(conn, fileno(F), &c, 1) <= 0)
+      return EOF;
+    return c;
+  }
+  else
+    return getc(F);
+}
+
+static int
+block_read(int fd, void *buf, size_t len)
+{
+  unsigned char *p = buf;
+  int b;
+  while(len) {
+    b = read(fd, p, len);
+    if (b == 0)
+      return 0;
+    else if (b < 0)
+      return -1;
+    len -= b;
+    p += b;
+  }
+  return p - (unsigned char*)buf;
+}
+
+static int
+block_write(int fd, void *buf, size_t len)
+{
+  unsigned char *p = buf;
+  int b;
+  while(len) {
+    b = write(fd, p, len);
+    if(b < 0)
+      return -1;
+    len -= b;
+    p += b;
+  }
+  return p - (unsigned char*)buf;
+}
+
+static int
+sec_get_data(struct connectdata *conn,
+             int fd, struct krb4buffer *buf)
+{
+  int len;
+  int b;
+
+  b = block_read(fd, &len, sizeof(len));
+  if (b == 0)
+    return 0;
+  else if (b < 0)
+    return -1;
+  len = ntohl(len);
+  buf->data = realloc(buf->data, len);
+  b = block_read(fd, buf->data, len);
+  if (b == 0)
+    return 0;
+  else if (b < 0)
+    return -1;
+  buf->size = (conn->mech->decode)(conn->app_data, buf->data, len,
+                                   conn->data_prot, conn);
+  buf->index = 0;
+  return 0;
+}
+
+static size_t
+buffer_read(struct krb4buffer *buf, void *data, size_t len)
+{
+    len = min(len, buf->size - buf->index);
+    memcpy(data, (char*)buf->data + buf->index, len);
+    buf->index += len;
+    return len;
+}
+
+static size_t
+buffer_write(struct krb4buffer *buf, void *data, size_t len)
+{
+    if(buf->index + len > buf->size) {
+        void *tmp;
+        if(buf->data == NULL)
+            tmp = malloc(1024);
+        else
+            tmp = realloc(buf->data, buf->index + len);
+        if(tmp == NULL)
+            return -1;
+        buf->data = tmp;
+        buf->size = buf->index + len;
+    }
+    memcpy((char*)buf->data + buf->index, data, len);
+    buf->index += len;
+    return len;
+}
+
+int
+Curl_sec_read(struct connectdata *conn, int fd, void *buffer, int length)
+{
+    size_t len;
+    int rx = 0;
+
+    if(conn->sec_complete == 0 || conn->data_prot == 0)
+      return read(fd, buffer, length);
+
+    if(conn->in_buffer.eof_flag){
+      conn->in_buffer.eof_flag = 0;
+      return 0;
+    }
+
+    len = buffer_read(&conn->in_buffer, buffer, length);
+    length -= len;
+    rx += len;
+    buffer = (char*)buffer + len;
+
+    while(length) {
+      if(sec_get_data(conn, fd, &conn->in_buffer) < 0)
+        return -1;
+      if(conn->in_buffer.size == 0) {
+        if(rx)
+          conn->in_buffer.eof_flag = 1;
+        return rx;
+      }
+      len = buffer_read(&conn->in_buffer, buffer, length);
+      length -= len;
+      rx += len;
+      buffer = (char*)buffer + len;
+    }
+    return rx;
+}
+
+static int
+sec_send(struct connectdata *conn, int fd, char *from, int length)
+{
+  int bytes;
+  void *buf;
+  bytes = (conn->mech->encode)(conn->app_data, from, length, conn->data_prot,
+                               &buf, conn);
+  bytes = htonl(bytes);
+  block_write(fd, &bytes, sizeof(bytes));
+  block_write(fd, buf, ntohl(bytes));
+  free(buf);
+  return length;
+}
+
+int
+Curl_sec_fflush_fd(struct connectdata *conn, int fd)
+{
+  if(conn->data_prot != prot_clear) {
+    if(conn->out_buffer.index > 0){
+      Curl_sec_write(conn, fd,
+                conn->out_buffer.data, conn->out_buffer.index);
+      conn->out_buffer.index = 0;
+    }
+    sec_send(conn, fd, NULL, 0);
+  }
+  return 0;
+}
+
+int
+Curl_sec_write(struct connectdata *conn, int fd, char *buffer, int length)
+{
+  int len = conn->buffer_size;
+  int tx = 0;
+
+  if(conn->data_prot == prot_clear)
+    return write(fd, buffer, length);
+
+  len -= (conn->mech->overhead)(conn->app_data, conn->data_prot, len);
+  while(length){
+    if(length < len)
+      len = length;
+    sec_send(conn, fd, buffer, len);
+    length -= len;
+    buffer += len;
+    tx += len;
+  }
+  return tx;
+}
+
+int
+Curl_sec_putc(struct connectdata *conn, int c, FILE *F)
+{
+  char ch = c;
+  if(conn->data_prot == prot_clear)
+    return putc(c, F);
+
+  buffer_write(&conn->out_buffer, &ch, 1);
+  if(c == '\n' || conn->out_buffer.index >= 1024 /* XXX */) {
+    Curl_sec_write(conn, fileno(F), conn->out_buffer.data,
+                   conn->out_buffer.index);
+    conn->out_buffer.index = 0;
+  }
+  return c;
+}
+
+int
+Curl_sec_read_msg(struct connectdata *conn, char *s, int level)
+{
+  int len;
+  char *buf;
+  int code;
+
+  buf = malloc(strlen(s));
+  len = Curl_base64_decode(s + 4, buf); /* XXX */
+
+  len = (conn->mech->decode)(conn->app_data, buf, len, level, conn);
+  if(len < 0) {
+    free(buf);
+    return -1;
+  }
+
+  buf[len] = '\0';
+
+  if(buf[3] == '-')
+    code = 0;
+  else
+    sscanf(buf, "%d", &code);
+  if(buf[len-1] == '\n')
+    buf[len-1] = '\0';
+  strcpy(s, buf);
+  free(buf);
+  return code;
+}
+
+enum protection_level
+Curl_set_command_prot(struct connectdata *conn, enum protection_level level)
+{
+  enum protection_level old = conn->command_prot;
+  conn->command_prot = level;
+  return old;
+}
+
+static int
+sec_prot_internal(struct connectdata *conn, int level)
+{
+  char *p;
+  unsigned int s = 1048576;
+  ssize_t nread;
+
+  if(!conn->sec_complete){
+    infof(conn->data, "No security data exchange has taken place.\n");
+    return -1;
+  }
+
+  if(level){
+    int code;
+    if(Curl_ftpsendf(conn, "PBSZ %u", s))
+      return -1;
+
+    if(Curl_GetFTPResponse(&nread, conn, &code))
+      return -1;
+
+    if(code/100 != '2'){
+      failf(conn->data, "Failed to set protection buffer size.");
+      return -1;
+    }
+    conn->buffer_size = s;
+
+    p = strstr(conn->data->state.buffer, "PBSZ=");
+    if(p)
+      sscanf(p, "PBSZ=%u", &s);
+    if(s < conn->buffer_size)
+      conn->buffer_size = s;
+  }
+
+  if(Curl_ftpsendf(conn, "PROT %c", level["CSEP"]))
+    return -1;
+
+  if(Curl_GetFTPResponse(&nread, conn, NULL))
+    return -1;
+
+  if(conn->data->state.buffer[0] != '2'){
+    failf(conn->data, "Failed to set protection level.");
+    return -1;
+  }
+
+  conn->data_prot = (enum protection_level)level;
+  return 0;
+}
+
+void
+Curl_sec_set_protection_level(struct connectdata *conn)
+{
+  if(conn->sec_complete && conn->data_prot != conn->request_data_prot)
+    sec_prot_internal(conn, conn->request_data_prot);
+}
+
+
+int
+Curl_sec_request_prot(struct connectdata *conn, const char *level)
+{
+  int l = name_to_level(level);
+  if(l == -1)
+    return -1;
+  conn->request_data_prot = (enum protection_level)l;
+  return 0;
+}
+
+int
+Curl_sec_login(struct connectdata *conn)
+{
+  int ret;
+  struct Curl_sec_client_mech **m;
+  ssize_t nread;
+  struct SessionHandle *data=conn->data;
+  int ftpcode;
+
+  for(m = mechs; *m && (*m)->name; m++) {
+    void *tmp;
+
+    tmp = realloc(conn->app_data, (*m)->size);
+    if (tmp == NULL) {
+      failf (data, "realloc %u failed", (*m)->size);
+      return -1;
+    }
+    conn->app_data = tmp;
+
+    if((*m)->init && (*(*m)->init)(conn->app_data) != 0) {
+      infof(data, "Skipping %s...\n", (*m)->name);
+      continue;
+    }
+    infof(data, "Trying %s...\n", (*m)->name);
+
+    if(Curl_ftpsendf(conn, "AUTH %s", (*m)->name))
+      return -1;
+
+    if(Curl_GetFTPResponse(&nread, conn, &ftpcode))
+      return -1;
+
+    if(conn->data->state.buffer[0] != '3'){
+      switch(ftpcode) {
+      case 504:
+        infof(data,
+              "%s is not supported by the server.\n", (*m)->name);
+        break;
+      case 534:
+        infof(data, "%s rejected as security mechanism.\n", (*m)->name);
+        break;
+      default:
+        if(conn->data->state.buffer[0] == '5') {
+          infof(data, "The server doesn't support the FTP "
+                "security extensions.\n");
+          return -1;
+        }
+        break;
+      }
+      continue;
+    }
+
+    ret = (*(*m)->auth)(conn->app_data, conn);
+
+    if(ret == AUTH_CONTINUE)
+      continue;
+    else if(ret != AUTH_OK){
+      /* mechanism is supposed to output error string */
+      return -1;
+    }
+    conn->mech = *m;
+    conn->sec_complete = 1;
+    conn->command_prot = prot_safe;
+    break;
+  }
+
+  return *m == NULL;
+}
+
+void
+Curl_sec_end(struct connectdata *conn)
+{
+  if (conn->mech != NULL) {
+    if(conn->mech->end)
+      (conn->mech->end)(conn->app_data);
+    memset(conn->app_data, 0, conn->mech->size);
+    free(conn->app_data);
+    conn->app_data = NULL;
+  }
+  conn->sec_complete = 0;
+  conn->data_prot = (enum protection_level)0;
+  conn->mech=NULL;
+}
+
+#endif /* HAVE_KRB4 */
+#endif /* CURL_DISABLE_FTP */
diff --git a/Utilities/cmcurl/security.h b/Utilities/cmcurl/security.h
new file mode 100644
index 0000000..5213ba5
--- /dev/null
+++ b/Utilities/cmcurl/security.h
@@ -0,0 +1,72 @@
+#ifndef __SECURITY_H
+#define __SECURITY_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/* this is a re-write */
+
+#include <stdarg.h>
+#include "urldata.h"  /* for struct connectdata * */
+
+struct Curl_sec_client_mech {
+  const char *name;
+  size_t size;
+  int (*init)(void *);
+  int (*auth)(void *, struct connectdata *);
+  void (*end)(void *);
+  int (*check_prot)(void *, int);
+  int (*overhead)(void *, int, int);
+  int (*encode)(void *, void*, int, int, void**, struct connectdata *);
+  int (*decode)(void *, void*, int, int, struct connectdata *);
+};
+
+
+#define AUTH_OK         0
+#define AUTH_CONTINUE   1
+#define AUTH_ERROR      2
+
+extern struct Curl_sec_client_mech Curl_krb4_client_mech;
+
+int Curl_sec_fflush_fd(struct connectdata *conn, int fd);
+int Curl_sec_fprintf (struct connectdata *, FILE *, const char *, ...);
+int Curl_sec_getc (struct connectdata *conn, FILE *);
+int Curl_sec_putc (struct connectdata *conn, int, FILE *);
+int Curl_sec_read (struct connectdata *conn, int, void *, int);
+int Curl_sec_read_msg (struct connectdata *conn, char *, int);
+
+int Curl_sec_vfprintf(struct connectdata *, FILE *, const char *, va_list);
+int Curl_sec_fprintf2(struct connectdata *conn, FILE *f, const char *fmt, ...);
+int Curl_sec_vfprintf2(struct connectdata *conn, FILE *, const char *, va_list);
+int Curl_sec_write (struct connectdata *conn, int, char *, int);
+
+void Curl_sec_end (struct connectdata *);
+int Curl_sec_login (struct connectdata *);
+void Curl_sec_prot (int, char **);
+int Curl_sec_request_prot (struct connectdata *conn, const char *level);
+void Curl_sec_set_protection_level(struct connectdata *conn);
+void Curl_sec_status (void);
+
+enum protection_level Curl_set_command_prot(struct connectdata *,
+                                            enum protection_level);
+
+#endif
diff --git a/Utilities/cmcurl/sendf.c b/Utilities/cmcurl/sendf.c
new file mode 100644
index 0000000..fae2ff3
--- /dev/null
+++ b/Utilities/cmcurl/sendf.c
@@ -0,0 +1,496 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h> /* required for send() & recv() prototypes */
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "connect.h" /* for the Curl_ourerrno() proto */
+
+#define _MPRINTF_REPLACE /* use the internal *printf() functions */
+#include <curl/mprintf.h>
+
+#ifdef HAVE_KRB4
+#include "security.h"
+#endif
+#include <string.h>
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* returns last node in linked list */
+static struct curl_slist *slist_get_last(struct curl_slist *list)
+{
+  struct curl_slist     *item;
+
+  /* if caller passed us a NULL, return now */
+  if (!list)
+    return NULL;
+
+  /* loop through to find the last item */
+  item = list;
+  while (item->next) {
+    item = item->next;
+  }
+  return item;
+}
+
+/*
+ * curl_slist_append() appends a string to the linked list. It always retunrs
+ * the address of the first record, so that you can sure this function as an
+ * initialization function as well as an append function. If you find this
+ * bothersome, then simply create a separate _init function and call it
+ * appropriately from within the proram.
+ */
+struct curl_slist *curl_slist_append(struct curl_slist *list,
+                                     const char *data)
+{
+  struct curl_slist     *last;
+  struct curl_slist     *new_item;
+
+  new_item = (struct curl_slist *) malloc(sizeof(struct curl_slist));
+  if (new_item) {
+    char *cuDup = strdup(data);
+    if(cuDup) {
+      new_item->next = NULL;
+      new_item->data = cuDup;
+    }
+    else {
+      free(new_item);
+      return NULL;
+    }
+  }
+  else
+    return NULL;
+
+  if (list) {
+    last = slist_get_last(list);
+    last->next = new_item;
+    return list;
+  }
+
+  /* if this is the first item, then new_item *is* the list */
+  return new_item;
+}
+
+/* be nice and clean up resources */
+void curl_slist_free_all(struct curl_slist *list)
+{
+  struct curl_slist     *next;
+  struct curl_slist     *item;
+
+  if (!list)
+    return;
+
+  item = list;
+  do {
+    next = item->next;
+
+    if (item->data) {
+      free(item->data);
+    }
+    free(item);
+    item = next;
+  } while (next);
+}
+
+/* Curl_infof() is for info message along the way */
+
+void Curl_infof(struct SessionHandle *data, const char *fmt, ...)
+{
+  if(data && data->set.verbose) {
+    va_list ap;
+    char print_buffer[1024 + 1];
+    va_start(ap, fmt);
+    vsnprintf(print_buffer, 1024, fmt, ap);
+    va_end(ap);
+    Curl_debug(data, CURLINFO_TEXT, print_buffer, strlen(print_buffer), NULL);
+  }
+}
+
+/* Curl_failf() is for messages stating why we failed.
+ * The message SHALL NOT include any LF or CR.
+ */
+
+void Curl_failf(struct SessionHandle *data, const char *fmt, ...)
+{
+  va_list ap;
+  va_start(ap, fmt);
+  if(data->set.errorbuffer && !data->state.errorbuf) {
+    vsnprintf(data->set.errorbuffer, CURL_ERROR_SIZE, fmt, ap);
+    data->state.errorbuf = TRUE; /* wrote error string */
+
+    if(data->set.verbose) {
+      size_t len = strlen(data->set.errorbuffer);
+      bool doneit=FALSE;
+      if(len < CURL_ERROR_SIZE - 1) {
+        doneit = TRUE;
+        data->set.errorbuffer[len] = '\n';
+        data->set.errorbuffer[++len] = '\0';
+      }
+      Curl_debug(data, CURLINFO_TEXT, data->set.errorbuffer, len, NULL);
+      if(doneit)
+        /* cut off the newline again */
+        data->set.errorbuffer[--len]=0;
+    }
+  }
+  va_end(ap);
+}
+
+/* Curl_sendf() sends formated data to the server */
+CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
+                    const char *fmt, ...)
+{
+  struct SessionHandle *data = conn->data;
+  ssize_t bytes_written;
+  size_t write_len;
+  CURLcode res;
+  char *s;
+  char *sptr;
+  va_list ap;
+  va_start(ap, fmt);
+  s = vaprintf(fmt, ap); /* returns an allocated string */
+  va_end(ap);
+  if(!s)
+    return CURLE_OUT_OF_MEMORY; /* failure */
+
+  bytes_written=0;
+  write_len = strlen(s);
+  sptr = s;
+
+  while (1) {
+    /* Write the buffer to the socket */
+    res = Curl_write(conn, sockfd, sptr, write_len, &bytes_written);
+
+    if(CURLE_OK != res)
+      break;
+
+    if(data->set.verbose)
+      Curl_debug(data, CURLINFO_DATA_OUT, sptr, bytes_written,
+                 conn->host.dispname);
+
+    if((size_t)bytes_written != write_len) {
+      /* if not all was written at once, we must advance the pointer, decrease
+         the size left and try again! */
+      write_len -= bytes_written;
+      sptr += bytes_written;
+    }
+    else
+      break;
+  }
+
+  free(s); /* free the output string */
+
+  return res;
+}
+
+/*
+ * Curl_write() is an internal write function that sends plain (binary) data
+ * to the server. Works with plain sockets, SSL or kerberos.
+ */
+CURLcode Curl_write(struct connectdata *conn,
+                    curl_socket_t sockfd,
+                    void *mem,
+                    size_t len,
+                    ssize_t *written)
+{
+  ssize_t bytes_written;
+  CURLcode retcode;
+
+#ifdef USE_SSLEAY
+  /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
+     If it is the second socket, we set num to 1. Otherwise to 0. This lets
+     us use the correct ssl handle. */
+  int num = (sockfd == conn->sock[SECONDARYSOCKET]);
+  /* SSL_write() is said to return 'int' while write() and send() returns
+     'size_t' */
+  if (conn->ssl[num].use) {
+    int err;
+    char error_buffer[120]; /* OpenSSL documents that this must be at least
+                               120 bytes long. */
+    unsigned long sslerror;
+    int rc = SSL_write(conn->ssl[num].handle, mem, (int)len);
+
+    if(rc < 0) {
+      err = SSL_get_error(conn->ssl[num].handle, rc);
+
+      switch(err) {
+      case SSL_ERROR_WANT_READ:
+      case SSL_ERROR_WANT_WRITE:
+        /* The operation did not complete; the same TLS/SSL I/O function
+           should be called again later. This is basicly an EWOULDBLOCK
+           equivalent. */
+        *written = 0;
+        return CURLE_OK;
+      case SSL_ERROR_SYSCALL:
+        failf(conn->data, "SSL_write() returned SYSCALL, errno = %d\n",
+              Curl_ourerrno());
+        return CURLE_SEND_ERROR;
+      case SSL_ERROR_SSL:
+        /*  A failure in the SSL library occurred, usually a protocol error.
+            The OpenSSL error queue contains more information on the error. */
+        sslerror = ERR_get_error();
+        failf(conn->data, "SSL_write() error: %s\n",
+              ERR_error_string(sslerror, error_buffer));
+        return CURLE_SEND_ERROR;
+      }
+      /* a true error */
+      failf(conn->data, "SSL_write() return error %d\n", err);
+      return CURLE_SEND_ERROR;
+    }
+    bytes_written = rc;
+  }
+  else {
+#else
+  (void)conn;
+#endif
+#ifdef HAVE_KRB4
+    if(conn->sec_complete) {
+      bytes_written = Curl_sec_write(conn, sockfd, mem, len);
+    }
+    else
+#endif /* HAVE_KRB4 */
+    {
+      bytes_written = (ssize_t)swrite(sockfd, mem, len);
+    }
+    if(-1 == bytes_written) {
+      int err = Curl_ourerrno();
+
+      if(
+#ifdef WSAEWOULDBLOCK
+        /* This is how Windows does it */
+        (WSAEWOULDBLOCK == err)
+#else
+        /* As pointed out by Christophe Demory on March 11 2003, errno
+           may be EWOULDBLOCK or on some systems EAGAIN when it returned
+           due to its inability to send off data without blocking. We
+           therefor treat both error codes the same here */
+        (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)
+#endif
+        )
+        /* this is just a case of EWOULDBLOCK */
+        bytes_written=0;
+    }
+#ifdef USE_SSLEAY
+  }
+#endif
+
+  *written = bytes_written;
+  retcode = (-1 != bytes_written)?CURLE_OK:CURLE_SEND_ERROR;
+
+  return retcode;
+}
+
+/* client_write() sends data to the write callback(s)
+
+   The bit pattern defines to what "streams" to write to. Body and/or header.
+   The defines are in sendf.h of course.
+ */
+CURLcode Curl_client_write(struct SessionHandle *data,
+                           int type,
+                           char *ptr,
+                           size_t len)
+{
+  size_t wrote;
+
+  if(0 == len)
+    len = strlen(ptr);
+
+  if(type & CLIENTWRITE_BODY) {
+    wrote = data->set.fwrite(ptr, 1, len, data->set.out);
+    if(wrote != len) {
+      failf (data, "Failed writing body");
+      return CURLE_WRITE_ERROR;
+    }
+  }
+  if((type & CLIENTWRITE_HEADER) &&
+     (data->set.fwrite_header || data->set.writeheader) ) {
+    /*
+     * Write headers to the same callback or to the especially setup
+     * header callback function (added after version 7.7.1).
+     */
+    curl_write_callback writeit=
+      data->set.fwrite_header?data->set.fwrite_header:data->set.fwrite;
+
+    wrote = writeit(ptr, 1, len, data->set.writeheader);
+    if(wrote != len) {
+      failf (data, "Failed writing header");
+      return CURLE_WRITE_ERROR;
+    }
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Internal read-from-socket function. This is meant to deal with plain
+ * sockets, SSL sockets and kerberos sockets.
+ *
+ * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
+ * a regular CURLcode value.
+ */
+int Curl_read(struct connectdata *conn, /* connection data */
+              curl_socket_t sockfd,     /* read from this socket */
+              char *buf,                /* store read data here */
+              size_t buffersize,        /* max amount to read */
+              ssize_t *n)               /* amount bytes read */
+{
+  ssize_t nread;
+#ifdef USE_SSLEAY
+  /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
+     If it is the second socket, we set num to 1. Otherwise to 0. This lets
+     us use the correct ssl handle. */
+  int num = (sockfd == conn->sock[SECONDARYSOCKET]);
+
+  *n=0; /* reset amount to zero */
+
+  if (conn->ssl[num].use) {
+    nread = (ssize_t)SSL_read(conn->ssl[num].handle, buf, (int)buffersize);
+
+    if(nread < 0) {
+      /* failed SSL_read */
+      int err = SSL_get_error(conn->ssl[num].handle, (int)nread);
+
+      switch(err) {
+      case SSL_ERROR_NONE: /* this is not an error */
+      case SSL_ERROR_ZERO_RETURN: /* no more data */
+        break;
+      case SSL_ERROR_WANT_READ:
+      case SSL_ERROR_WANT_WRITE:
+        /* there's data pending, re-invoke SSL_read() */
+        return -1; /* basicly EWOULDBLOCK */
+      default:
+        /* openssl/ssl.h says "look at error stack/return value/errno" */
+        {
+          char error_buffer[120]; /* OpenSSL documents that this must be at
+                                     least 120 bytes long. */
+          unsigned long sslerror = ERR_get_error();
+          failf(conn->data, "SSL read: %s, errno %d",
+                ERR_error_string(sslerror, error_buffer),
+                Curl_ourerrno() );
+        }
+        return CURLE_RECV_ERROR;
+      }
+    }
+  }
+  else {
+#else
+    (void)conn;
+#endif
+    *n=0; /* reset amount to zero */
+#ifdef HAVE_KRB4
+    if(conn->sec_complete)
+      nread = Curl_sec_read(conn, sockfd, buf, buffersize);
+    else
+#endif
+      nread = sread(sockfd, buf, buffersize);
+
+    if(-1 == nread) {
+      int err = Curl_ourerrno();
+#ifdef WIN32
+      if(WSAEWOULDBLOCK == err)
+#else
+      if((EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err))
+#endif
+        return -1;
+    }
+
+#ifdef USE_SSLEAY
+  }
+#endif /* USE_SSLEAY */
+  *n = nread;
+  return CURLE_OK;
+}
+
+/* return 0 on success */
+static int showit(struct SessionHandle *data, curl_infotype type,
+                  char *ptr, size_t size)
+{
+  static const char * const s_infotype[CURLINFO_END] = {
+    "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
+
+  if(data->set.fdebug)
+    return (*data->set.fdebug)(data, type, ptr, size,
+                               data->set.debugdata);
+
+  switch(type) {
+  case CURLINFO_TEXT:
+  case CURLINFO_HEADER_OUT:
+  case CURLINFO_HEADER_IN:
+    fwrite(s_infotype[type], 2, 1, data->set.err);
+    fwrite(ptr, size, 1, data->set.err);
+    break;
+  default: /* nada */
+    break;
+  }
+  return 0;
+}
+
+int Curl_debug(struct SessionHandle *data, curl_infotype type,
+               char *ptr, size_t size, char *host)
+{
+  int rc;
+  if(data->set.printhost && host) {
+    char buffer[160];
+    const char *t=NULL;
+    switch (type) {
+    case CURLINFO_HEADER_IN:
+    case CURLINFO_DATA_IN:
+      t = "from";
+      break;
+    case CURLINFO_HEADER_OUT:
+    case CURLINFO_DATA_OUT:
+      t = "to";
+      break;
+    default:
+      break;
+    }
+
+    if(t) {
+      snprintf(buffer, sizeof(buffer), "[Data %s %s]", t, host);
+      rc = showit(data, CURLINFO_TEXT, buffer, strlen(buffer));
+      if(rc)
+        return rc;
+    }
+  }
+  rc = showit(data, type, ptr, size);
+  return rc;
+}
diff --git a/Utilities/cmcurl/sendf.h b/Utilities/cmcurl/sendf.h
new file mode 100644
index 0000000..bdd3a79
--- /dev/null
+++ b/Utilities/cmcurl/sendf.h
@@ -0,0 +1,56 @@
+#ifndef __SENDF_H
+#define __SENDF_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *,
+                    const char *fmt, ...);
+void Curl_infof(struct SessionHandle *, const char *fmt, ...);
+void Curl_failf(struct SessionHandle *, const char *fmt, ...);
+
+#define infof Curl_infof
+#define failf Curl_failf
+
+#define CLIENTWRITE_BODY   1
+#define CLIENTWRITE_HEADER 2
+#define CLIENTWRITE_BOTH   (CLIENTWRITE_BODY|CLIENTWRITE_HEADER)
+
+CURLcode Curl_client_write(struct SessionHandle *data, int type, char *ptr,
+                           size_t len);
+
+/* internal read-function, does plain socket, SSL and krb4 */
+int Curl_read(struct connectdata *conn, curl_socket_t sockfd,
+              char *buf, size_t buffersize,
+              ssize_t *n);
+/* internal write-function, does plain socket, SSL and krb4 */
+CURLcode Curl_write(struct connectdata *conn,
+                    curl_socket_t sockfd,
+                    void *mem, size_t len,
+                    ssize_t *written);
+
+/* the function used to output verbose information */
+int Curl_debug(struct SessionHandle *handle, curl_infotype type,
+               char *data, size_t size, char *host);
+
+
+#endif
diff --git a/Utilities/cmcurl/setup.h b/Utilities/cmcurl/setup.h
new file mode 100644
index 0000000..fff6974
--- /dev/null
+++ b/Utilities/cmcurl/setup.h
@@ -0,0 +1,294 @@
+#ifndef __SETUP_H
+#define __SETUP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#ifdef HTTP_ONLY
+#define CURL_DISABLE_FTP
+#define CURL_DISABLE_LDAP
+#define CURL_DISABLE_TELNET
+#define CURL_DISABLE_DICT
+#define CURL_DISABLE_FILE
+#define CURL_DISABLE_GOPHER
+#endif
+
+#if !defined(WIN32) && defined(__WIN32__)
+/* This should be a good Borland fix. Alexander J. Oss told us! */
+#define WIN32
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h" /* the configure script results */
+#else
+#ifdef WIN32
+/* hand-modified win32 config.h! */
+#include "config-win32.h"
+#endif
+#endif
+
+#ifdef macintosh
+/* hand-modified MacOS config.h! */
+#include "config-mac.h"
+#endif
+#ifdef AMIGA
+/* hand-modified AmigaOS config.h! */
+#include "amigaos.h"
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#if !defined(__cplusplus) && !defined(__BEOS__)
+typedef unsigned char bool;
+#define typedef_bool
+#endif
+
+#ifdef HAVE_LONGLONG
+#define LONG_LONG long long
+#define ENABLE_64BIT
+#else
+#ifdef _MSC_VER
+#define LONG_LONG __int64
+#define ENABLE_64BIT
+#endif
+#endif /* HAVE_LONGLONG */
+
+#ifndef SIZEOF_CURL_OFF_T
+/* If we don't know the size here, we assume a conservative size: 4. When
+   building libcurl, the actual size of this variable should be define in the
+   config*.h file. */
+#define SIZEOF_CURL_OFF_T 4
+#endif
+
+/* We set up our internal prefered (CURL_)FORMAT_OFF_T here */
+#if SIZEOF_CURL_OFF_T > 4
+#define FORMAT_OFF_T "lld"
+#else
+#define FORMAT_OFF_T "ld"
+#endif
+
+#ifdef NEED_REENTRANT
+/* Solaris machines needs _REENTRANT set for a few function prototypes and
+   things to appear in the #include files. We need to #define it before all
+   #include files */
+#define _REENTRANT
+#endif
+
+#include <stdio.h>
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+#include <errno.h>
+
+#ifdef __TANDEM /* for nsr-tandem-nsk systems */
+#include <floss.h>
+#endif
+
+#if defined(HAVE_X509_H) && defined(HAVE_SSL_H) && defined(HAVE_RSA_H) && \
+defined(HAVE_PEM_H) && defined(HAVE_ERR_H) && defined(HAVE_CRYPTO_H) && \
+defined(HAVE_LIBSSL) && defined(HAVE_LIBCRYPTO)
+  /* the six important includes files all exist and so do both libs,
+     defined SSLeay usage */
+#define USE_SSLEAY 1
+#endif
+#if defined(HAVE_OPENSSL_X509_H) && defined(HAVE_OPENSSL_SSL_H) && \
+defined(HAVE_OPENSSL_RSA_H) && defined(HAVE_OPENSSL_PEM_H) && \
+defined(HAVE_OPENSSL_ERR_H) && defined(HAVE_OPENSSL_CRYPTO_H) && \
+defined(HAVE_LIBSSL) && defined(HAVE_LIBCRYPTO)
+  /* the six important includes files all exist and so do both libs,
+     defined SSLeay usage */
+#define USE_SSLEAY 1
+#define USE_OPENSSL 1
+#endif
+
+#ifndef STDC_HEADERS /* no standard C headers! */
+#include <curl/stdcheaders.h>
+#endif
+
+#if defined(CURLDEBUG) && defined(HAVE_ASSERT_H)
+#define curlassert(x) assert(x)
+#else
+/* does nothing without CURLDEBUG defined */
+#define curlassert(x)
+#endif
+
+#ifdef MSG_NOSIGNAL
+/* If we have the MSG_NOSIGNAL define, we make sure to use that in the forth
+   argument to send() and recv() */
+#define SEND_4TH_ARG MSG_NOSIGNAL
+#define HAVE_MSG_NOSIGNAL 1 /* we have MSG_NOSIGNAL */
+#else
+#define SEND_4TH_ARG 0
+#endif
+
+
+/* Below we define four functions. They should
+   1. close a socket
+   2. read from a socket
+   3. write to a socket
+
+   4. set the SIGALRM signal timeout
+   5. set dir/file naming defines
+   */
+
+#ifdef WIN32
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN  /* Prevent including <winsock*.h> in <windows.h> */
+#endif
+
+#if (defined(ENABLE_IPV6) || defined(CURLDEBUG)) && defined(_MSC_VER) && \
+    (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0500)
+/*
+ * Needed to pull in the real getaddrinfo() and not the inline version
+ * in <wspiAPI.H> which doesn't support IPv6 (IPv4 only). <wspiAPI.H> is
+ * included from <ws2tcpip.h> for <= 0x0500 SDKs.
+ */
+#undef  _WIN32_WINNT
+#define _WIN32_WINNT 0x0501
+#endif
+
+#include <winsock2.h>        /* required by telnet.c */
+
+#if defined(ENABLE_IPV6) || defined(USE_SSLEAY)
+#include <ws2tcpip.h>
+#endif
+
+#if !defined(__GNUC__) || defined(__MINGW32__)
+#define sclose(x) closesocket(x)
+#define sread(x,y,z) recv(x,y,z, SEND_4TH_ARG)
+#define swrite(x,y,z) (size_t)send(x,y,z, SEND_4TH_ARG)
+#undef HAVE_ALARM
+#else
+     /* gcc-for-win is still good :) */
+#define sclose(x) close(x)
+#define sread(x,y,z) recv(x,y,z, SEND_4TH_ARG)
+#define swrite(x,y,z) send(x,y,z, SEND_4TH_ARG)
+#define HAVE_ALARM
+#endif
+
+#define DIR_CHAR      "\\"
+#define DOT_CHAR      "_"
+
+#else
+
+#ifdef DJGPP
+#define sclose(x)         close_s(x)
+#define sread(x,y,z)      read_s(x,y,z)
+#define swrite(x,y,z)     write_s(x,y,z)
+#define select(n,r,w,x,t) select_s(n,r,w,x,t)
+#define ioctl(x,y,z) ioctlsocket(x,y,(char *)(z))
+#define IOCTL_3_ARGS
+#include <tcp.h>
+#ifdef word
+#undef word
+#endif
+
+#else
+
+#ifdef __BEOS__
+#define sclose(x) closesocket(x)
+#define sread(x,y,z) (ssize_t)recv(x,y,z, SEND_4TH_ARG)
+#define swrite(x,y,z) (ssize_t)send(x,y,z, SEND_4TH_ARG)
+#else
+#define sclose(x) close(x)
+#define sread(x,y,z) recv(x,y,z, SEND_4TH_ARG)
+#define swrite(x,y,z) send(x,y,z, SEND_4TH_ARG)
+#endif
+
+#define HAVE_ALARM
+
+#endif
+
+#ifdef _AMIGASF
+#undef HAVE_ALARM
+#undef sclose
+#define sclose(x) CloseSocket(x)
+#endif
+
+#define DIR_CHAR      "/"
+#define DOT_CHAR      "."
+
+#ifdef DJGPP
+#undef DOT_CHAR
+#define DOT_CHAR      "_"
+#endif
+
+#ifndef fileno /* sunos 4 have this as a macro! */
+int fileno( FILE *stream);
+#endif
+
+#endif
+
+/* now typedef our socket type */
+#ifdef WIN32
+typedef SOCKET curl_socket_t;
+#define CURL_SOCKET_BAD INVALID_SOCKET
+#else
+typedef int curl_socket_t;
+#define CURL_SOCKET_BAD -1
+#endif
+
+#if defined(ENABLE_IPV6) && defined(USE_ARES)
+#error "ares does not yet support IPv6. Disable IPv6 or ares and rebuild"
+#endif
+
+#if defined(WIN32) && !defined(__CYGWIN__) && !defined(USE_ARES) && \
+    !defined(__LCC__)  /* lcc-win32 doesn't have _beginthreadex() */
+#ifdef ENABLE_IPV6
+#define USE_THREADING_GETADDRINFO
+#else
+#define USE_THREADING_GETHOSTBYNAME  /* Cygwin uses alarm() function */
+#endif
+#endif
+
+#ifdef mpeix
+#define IOCTL_3_ARGS
+#endif
+
+#ifndef ECONNRESET
+#ifdef WSAECONNRESET
+#define ECONNRESET WSAECONNRESET
+#else
+/* This will effectively prevent the code from working in this particular
+   aspect, but it still compile fine! */
+#define ECONNRESET 10000
+#endif
+#endif
+
+#ifdef NETWARE
+#undef HAVE_ALARM
+#endif
+
+#ifdef HAVE_LIBIDN
+/* This could benefit from additional checks that some of the used/important
+   header files are present as well before we define the USE_* define. */
+#define USE_LIBIDN
+#define LIBIDN_REQUIRED_VERSION "0.4.1"
+#endif
+
+#endif /* __CONFIG_H */
diff --git a/Utilities/cmcurl/share.c b/Utilities/cmcurl/share.c
new file mode 100644
index 0000000..1022d97
--- /dev/null
+++ b/Utilities/cmcurl/share.c
@@ -0,0 +1,219 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <curl/curl.h>
+#include "urldata.h"
+#include "share.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+CURLSH *
+curl_share_init(void)
+{
+  struct Curl_share *share =
+    (struct Curl_share *)malloc(sizeof(struct Curl_share));
+  if (share) {
+    memset (share, 0, sizeof(struct Curl_share));
+    share->specifier |= (1<<CURL_LOCK_DATA_SHARE);
+  }
+
+  return share;
+}
+
+CURLSHcode
+curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
+{
+  struct Curl_share *share = (struct Curl_share *)sh;
+  va_list param;
+  int type;
+  curl_lock_function lockfunc;
+  curl_unlock_function unlockfunc;
+  void *ptr;
+
+  if (share->dirty)
+    /* don't allow setting options while one or more handles are already
+       using this share */
+    return CURLSHE_IN_USE;
+
+  va_start(param, option);
+
+  switch(option) {
+  case CURLSHOPT_SHARE:
+    /* this is a type this share will share */
+    type = va_arg(param, int);
+    share->specifier |= (1<<type);
+    switch( type ) {
+    case CURL_LOCK_DATA_DNS:
+      if (!share->hostcache) {
+        share->hostcache = Curl_mk_dnscache();
+        if(!share->hostcache)
+          return CURLSHE_NOMEM;
+      }
+      break;
+
+#ifndef CURL_DISABLE_HTTP
+    case CURL_LOCK_DATA_COOKIE:
+      if (!share->cookies) {
+        share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE );
+        if(!share->cookies)
+          return CURLSHE_NOMEM;
+      }
+      break;
+#endif   /* CURL_DISABLE_HTTP */
+
+    case CURL_LOCK_DATA_SSL_SESSION: /* not supported (yet) */
+    case CURL_LOCK_DATA_CONNECT:     /* not supported (yet) */
+
+    default:
+      return CURLSHE_BAD_OPTION;
+    }
+    break;
+
+  case CURLSHOPT_UNSHARE:
+    /* this is a type this share will no longer share */
+    type = va_arg(param, int);
+    share->specifier &= ~(1<<type);
+    switch( type )
+    {
+      case CURL_LOCK_DATA_DNS:
+        if (share->hostcache) {
+          Curl_hash_destroy(share->hostcache);
+          share->hostcache = NULL;
+        }
+        break;
+
+#ifndef CURL_DISABLE_HTTP
+      case CURL_LOCK_DATA_COOKIE:
+        if (share->cookies) {
+          Curl_cookie_cleanup(share->cookies);
+          share->cookies = NULL;
+        }
+        break;
+#endif   /* CURL_DISABLE_HTTP */
+
+      case CURL_LOCK_DATA_SSL_SESSION:
+        break;
+
+      case CURL_LOCK_DATA_CONNECT:
+        break;
+
+      default:
+        return CURLSHE_BAD_OPTION;
+    }
+    break;
+
+  case CURLSHOPT_LOCKFUNC:
+    lockfunc = va_arg(param, curl_lock_function);
+    share->lockfunc = lockfunc;
+    break;
+
+  case CURLSHOPT_UNLOCKFUNC:
+    unlockfunc = va_arg(param, curl_unlock_function);
+    share->unlockfunc = unlockfunc;
+    break;
+
+  case CURLSHOPT_USERDATA:
+    ptr = va_arg(param, void *);
+    share->clientdata = ptr;
+    break;
+
+  default:
+    return CURLSHE_BAD_OPTION;
+  }
+
+  return CURLSHE_OK;
+}
+
+CURLSHcode
+curl_share_cleanup(CURLSH *sh)
+{
+  struct Curl_share *share = (struct Curl_share *)sh;
+
+  if (share == NULL)
+    return CURLSHE_INVALID;
+
+  if(share->lockfunc)
+    share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE,
+                    share->clientdata);
+
+  if (share->dirty) {
+    if(share->unlockfunc)
+      share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
+    return CURLSHE_IN_USE;
+  }
+
+  if(share->hostcache)
+    Curl_hash_destroy(share->hostcache);
+
+#ifndef CURL_DISABLE_HTTP
+  if(share->cookies)
+    Curl_cookie_cleanup(share->cookies);
+#endif   /* CURL_DISABLE_HTTP */
+
+  if(share->unlockfunc)
+    share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
+  free(share);
+
+  return CURLSHE_OK;
+}
+
+
+CURLSHcode
+Curl_share_lock(struct SessionHandle *data, curl_lock_data type,
+                curl_lock_access accesstype)
+{
+  struct Curl_share *share = data->share;
+
+  if (share == NULL)
+    return CURLSHE_INVALID;
+
+  if(share->specifier & (1<<type)) {
+    if(share->lockfunc) /* only call this if set! */
+      share->lockfunc(data, type, accesstype, share->clientdata);
+  }
+  /* else if we don't share this, pretend successful lock */
+
+  return CURLSHE_OK;
+}
+
+CURLSHcode
+Curl_share_unlock(struct SessionHandle *data, curl_lock_data type)
+{
+  struct Curl_share *share = data->share;
+
+  if (share == NULL)
+    return CURLSHE_INVALID;
+
+  if(share->specifier & (1<<type)) {
+    if(share->unlockfunc) /* only call this if set! */
+      share->unlockfunc (data, type, share->clientdata);
+  }
+
+  return CURLSHE_OK;
+}
diff --git a/Utilities/cmcurl/share.h b/Utilities/cmcurl/share.h
new file mode 100644
index 0000000..5c85c80
--- /dev/null
+++ b/Utilities/cmcurl/share.h
@@ -0,0 +1,55 @@
+#ifndef __CURL_SHARE_H
+#define __CURL_SHARE_H
+
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+#include <curl/curl.h>
+#include "cookie.h"
+
+/* this struct is libcurl-private, don't export details */
+struct Curl_share {
+  unsigned int specifier;
+  volatile unsigned int dirty;
+  
+  curl_lock_function lockfunc;
+  curl_unlock_function unlockfunc;
+  void *clientdata;
+
+  curl_hash *hostcache;
+  struct CookieInfo *cookies;
+};
+
+CURLSHcode Curl_share_lock (
+    struct SessionHandle *, 
+    curl_lock_data,
+    curl_lock_access
+    );
+
+CURLSHcode Curl_share_unlock (
+    struct SessionHandle *, 
+    curl_lock_data
+    );
+
+#endif /* __CURL_SHARE_H */
diff --git a/Utilities/cmcurl/speedcheck.c b/Utilities/cmcurl/speedcheck.c
new file mode 100644
index 0000000..33a8e5d
--- /dev/null
+++ b/Utilities/cmcurl/speedcheck.c
@@ -0,0 +1,67 @@
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "speedcheck.h"
+
+void Curl_speedinit(struct SessionHandle *data)
+{
+  memset(&data->state.keeps_speed, 0, sizeof(struct timeval));
+}
+
+CURLcode Curl_speedcheck(struct SessionHandle *data,
+                         struct timeval now)
+{
+  if((data->progress.current_speed >= 0) &&
+     data->set.low_speed_time &&
+     (Curl_tvlong(data->state.keeps_speed) != 0) &&
+     (data->progress.current_speed < data->set.low_speed_limit)) {
+
+    /* We are now below the "low speed limit". If we are below it
+       for "low speed time" seconds we consider that enough reason
+       to abort the download. */
+    
+    if( (Curl_tvdiff(now, data->state.keeps_speed)/1000) >
+        data->set.low_speed_time) {
+      /* we have been this slow for long enough, now die */
+      failf(data,
+            "Operation too slow. "
+            "Less than %d bytes/sec transfered the last %d seconds",
+            data->set.low_speed_limit,
+            data->set.low_speed_time);
+      return CURLE_OPERATION_TIMEOUTED;
+    }
+  }
+  else {
+    /* we keep up the required speed all right */
+    data->state.keeps_speed = now;
+  }
+  return CURLE_OK;
+}
diff --git a/Utilities/cmcurl/speedcheck.h b/Utilities/cmcurl/speedcheck.h
new file mode 100644
index 0000000..62475f6
--- /dev/null
+++ b/Utilities/cmcurl/speedcheck.h
@@ -0,0 +1,34 @@
+#ifndef __SPEEDCHECK_H
+#define __SPEEDCHECK_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include "timeval.h"
+
+void Curl_speedinit(struct SessionHandle *data);
+CURLcode Curl_speedcheck(struct SessionHandle *data,
+                         struct timeval now);
+
+#endif
diff --git a/Utilities/cmcurl/ssluse.c b/Utilities/cmcurl/ssluse.c
new file mode 100644
index 0000000..04d1c94
--- /dev/null
+++ b/Utilities/cmcurl/ssluse.c
@@ -0,0 +1,1487 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/*
+ * The original SSL code for curl was written by
+ * Linas Vepstas <linas@linas.org> and Sampo Kellomaki <sampo@iki.fi>
+ */
+
+#include "setup.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "formdata.h" /* for the boundary function */
+#include "url.h" /* for the ssl config check function */
+#include "inet_pton.h"
+#include "ssluse.h"
+#include "connect.h" /* Curl_ourerrno() proto */
+#include "strequal.h"
+
+#define _MPRINTF_REPLACE /* use the internal *printf() functions */
+#include <curl/mprintf.h>
+
+#ifdef USE_SSLEAY
+#include <openssl/rand.h>
+#include <openssl/x509v3.h>
+
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifndef min
+#define min(a, b)   ((a) < (b) ? (a) : (b))
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x0090581fL
+#define HAVE_SSL_GET1_SESSION 1
+#else
+#undef HAVE_SSL_GET1_SESSION
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x00904100L
+#define HAVE_USERDATA_IN_PWD_CALLBACK 1
+#else
+#undef HAVE_USERDATA_IN_PWD_CALLBACK
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x00907001L
+/* ENGINE_load_private_key() takes four arguments */
+#define HAVE_ENGINE_LOAD_FOUR_ARGS
+#else
+/* ENGINE_load_private_key() takes three arguments */
+#undef HAVE_ENGINE_LOAD_FOUR_ARGS
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x00906001L
+#define HAVE_ERR_ERROR_STRING_N 1
+#endif
+
+
+#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
+static char global_passwd[64];
+#endif
+
+static int passwd_callback(char *buf, int num, int verify
+#if HAVE_USERDATA_IN_PWD_CALLBACK
+                           /* This was introduced in 0.9.4, we can set this
+                              using SSL_CTX_set_default_passwd_cb_userdata()
+                              */
+                           , void *global_passwd
+#endif
+                           )
+{
+  if(verify)
+    fprintf(stderr, "%s\n", buf);
+  else {
+    if(num > (int)strlen((char *)global_passwd)) {
+      strcpy(buf, global_passwd);
+      return (int)strlen(buf);
+    }
+  }
+  return 0;
+}
+
+/*
+ * rand_enough() is a function that returns TRUE if we have seeded the random
+ * engine properly. We use some preprocessor magic to provide a seed_enough()
+ * macro to use, just to prevent a compiler warning on this function if we
+ * pass in an argument that is never used.
+ */
+
+#ifdef HAVE_RAND_STATUS
+#define seed_enough(x) rand_enough()
+static bool rand_enough(void)
+{
+  return RAND_status()?TRUE:FALSE;
+}
+#else
+#define seed_enough(x) rand_enough(x)
+static bool rand_enough(int nread)
+{
+  /* this is a very silly decision to make */
+  return (nread > 500)?TRUE:FALSE;
+}
+#endif
+
+static
+int random_the_seed(struct SessionHandle *data)
+{
+  char *buf = data->state.buffer; /* point to the big buffer */
+  int nread=0;
+
+  /* Q: should we add support for a random file name as a libcurl option?
+     A: Yes, it is here */
+
+#ifndef RANDOM_FILE
+  /* if RANDOM_FILE isn't defined, we only perform this if an option tells
+     us to! */
+  if(data->set.ssl.random_file)
+#define RANDOM_FILE "" /* doesn't matter won't be used */
+#endif
+  {
+    /* let the option override the define */
+    nread += RAND_load_file((data->set.ssl.random_file?
+                             data->set.ssl.random_file:RANDOM_FILE),
+                            16384);
+    if(seed_enough(nread))
+      return nread;
+  }
+
+#if defined(HAVE_RAND_EGD)
+  /* only available in OpenSSL 0.9.5 and later */
+  /* EGD_SOCKET is set at configure time or not at all */
+#ifndef EGD_SOCKET
+  /* If we don't have the define set, we only do this if the egd-option
+     is set */
+  if(data->set.ssl.egdsocket)
+#define EGD_SOCKET "" /* doesn't matter won't be used */
+#endif
+  {
+    /* If there's an option and a define, the option overrides the
+       define */
+    int ret = RAND_egd(data->set.ssl.egdsocket?
+                       data->set.ssl.egdsocket:EGD_SOCKET);
+    if(-1 != ret) {
+      nread += ret;
+      if(seed_enough(nread))
+        return nread;
+    }
+  }
+#endif
+
+  /* If we get here, it means we need to seed the PRNG using a "silly"
+     approach! */
+#ifdef HAVE_RAND_SCREEN
+  /* This one gets a random value by reading the currently shown screen */
+  RAND_screen();
+  nread = 100; /* just a value */
+#else
+  {
+    int len;
+    char *area;
+
+    /* Changed call to RAND_seed to use the underlying RAND_add implementation
+     * directly.  Do this in a loop, with the amount of additional entropy
+     * being dependent upon the algorithm used by Curl_FormBoundary(): N bytes
+     * of a 7-bit ascii set. -- Richard Gorton, March 11 2003.
+     */
+
+    do {
+      area = Curl_FormBoundary();
+      if(!area)
+        return 3; /* out of memory */
+
+      len = (int)strlen(area);
+      RAND_add(area, len, (len >> 1));
+
+      free(area); /* now remove the random junk */
+    } while (!RAND_status());
+  }
+#endif
+
+  /* generates a default path for the random seed file */
+  buf[0]=0; /* blank it first */
+  RAND_file_name(buf, BUFSIZE);
+  if(buf[0]) {
+    /* we got a file name to try */
+    nread += RAND_load_file(buf, 16384);
+    if(seed_enough(nread))
+      return nread;
+  }
+
+  infof(data, "libcurl is now using a weak random seed!\n");
+  return nread;
+}
+
+#ifndef SSL_FILETYPE_ENGINE
+#define SSL_FILETYPE_ENGINE 42
+#endif
+static int do_file_type(const char *type)
+{
+  if(!type || !type[0])
+    return SSL_FILETYPE_PEM;
+  if(curl_strequal(type, "PEM"))
+    return SSL_FILETYPE_PEM;
+  if(curl_strequal(type, "DER"))
+    return SSL_FILETYPE_ASN1;
+  if(curl_strequal(type, "ENG"))
+    return SSL_FILETYPE_ENGINE;
+  return -1;
+}
+
+static
+int cert_stuff(struct connectdata *conn,
+               SSL_CTX* ctx,
+               char *cert_file,
+               const char *cert_type,
+               char *key_file,
+               const char *key_type)
+{
+  struct SessionHandle *data = conn->data;
+  int file_type;
+
+  if(cert_file != NULL) {
+    SSL *ssl;
+    X509 *x509;
+
+    if(data->set.key_passwd) {
+#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
+      /*
+       * If password has been given, we store that in the global
+       * area (*shudder*) for a while:
+       */
+      size_t len = strlen(data->set.key_passwd);
+      if(len < sizeof(global_passwd))
+        memcpy(global_passwd, data->set.key_passwd, len+1);
+#else
+      /*
+       * We set the password in the callback userdata
+       */
+      SSL_CTX_set_default_passwd_cb_userdata(ctx,
+                                             data->set.key_passwd);
+#endif
+      /* Set passwd callback: */
+      SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
+    }
+
+    file_type = do_file_type(cert_type);
+
+    switch(file_type) {
+    case SSL_FILETYPE_PEM:
+      /* SSL_CTX_use_certificate_chain_file() only works on PEM files */
+      if(SSL_CTX_use_certificate_chain_file(ctx,
+                                            cert_file) != 1) {
+        failf(data, "unable to set certificate file (wrong password?)");
+        return 0;
+      }
+      break;
+
+    case SSL_FILETYPE_ASN1:
+      /* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but
+         we use the case above for PEM so this can only be performed with
+         ASN1 files. */
+      if(SSL_CTX_use_certificate_file(ctx,
+                                      cert_file,
+                                      file_type) != 1) {
+        failf(data, "unable to set certificate file (wrong password?)");
+        return 0;
+      }
+      break;
+    case SSL_FILETYPE_ENGINE:
+      failf(data, "file type ENG for certificate not implemented");
+      return 0;
+
+    default:
+      failf(data, "not supported file type '%s' for certificate", cert_type);
+      return 0;
+    }
+
+    file_type = do_file_type(key_type);
+
+    switch(file_type) {
+    case SSL_FILETYPE_PEM:
+      if(key_file == NULL)
+        /* cert & key can only be in PEM case in the same file */
+        key_file=cert_file;
+    case SSL_FILETYPE_ASN1:
+      if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) {
+        failf(data, "unable to set private key file: '%s' type %s\n",
+              key_file, key_type?key_type:"PEM");
+        return 0;
+      }
+      break;
+    case SSL_FILETYPE_ENGINE:
+#ifdef HAVE_OPENSSL_ENGINE_H
+      {                         /* XXXX still needs some work */
+        EVP_PKEY *priv_key = NULL;
+        if(conn && conn->data && conn->data->engine) {
+#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
+          UI_METHOD *ui_method = UI_OpenSSL();
+#endif
+          if(!key_file || !key_file[0]) {
+            failf(data, "no key set to load from crypto engine\n");
+            return 0;
+          }
+          /* the typecast below was added to please mingw32 */
+          priv_key = (EVP_PKEY *)
+            ENGINE_load_private_key(conn->data->engine,key_file,
+#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
+                                    ui_method,
+#endif
+                                    data->set.key_passwd);
+          if(!priv_key) {
+            failf(data, "failed to load private key from crypto engine\n");
+            return 0;
+          }
+          if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) {
+            failf(data, "unable to set private key\n");
+            EVP_PKEY_free(priv_key);
+            return 0;
+          }
+          EVP_PKEY_free(priv_key);  /* we don't need the handle any more... */
+        }
+        else {
+          failf(data, "crypto engine not set, can't load private key\n");
+          return 0;
+        }
+      }
+      break;
+#else
+      failf(data, "file type ENG for private key not supported\n");
+      return 0;
+#endif
+    default:
+      failf(data, "not supported file type for private key\n");
+      return 0;
+    }
+
+    ssl=SSL_new(ctx);
+    x509=SSL_get_certificate(ssl);
+
+    /* This version was provided by Evan Jordan and is supposed to not
+       leak memory as the previous version: */
+    if(x509 != NULL) {
+      EVP_PKEY *pktmp = X509_get_pubkey(x509);
+      EVP_PKEY_copy_parameters(pktmp,SSL_get_privatekey(ssl));
+      EVP_PKEY_free(pktmp);
+    }
+
+    SSL_free(ssl);
+
+    /* If we are using DSA, we can copy the parameters from
+     * the private key */
+
+
+    /* Now we know that a key and cert have been set against
+     * the SSL context */
+    if(!SSL_CTX_check_private_key(ctx)) {
+      failf(data, "Private key does not match the certificate public key");
+      return(0);
+    }
+#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
+    /* erase it now */
+    memset(global_passwd, 0, sizeof(global_passwd));
+#endif
+  }
+  return(1);
+}
+
+static
+int cert_verify_callback(int ok, X509_STORE_CTX *ctx)
+{
+  X509 *err_cert;
+  char buf[256];
+
+  err_cert=X509_STORE_CTX_get_current_cert(ctx);
+  X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
+  return ok;
+}
+
+/* "global" init done? */
+static int init_ssl=0;
+
+/* we have the "SSL is seeded" boolean global for the application to
+   prevent multiple time-consuming seedings in vain */
+static bool ssl_seeded = FALSE;
+#endif /* USE_SSLEAY */
+
+/* Global init */
+void Curl_SSL_init(void)
+{
+#ifdef USE_SSLEAY
+  /* make sure this is only done once */
+  if(0 != init_ssl)
+    return;
+
+  init_ssl++; /* never again */
+
+#ifdef HAVE_ENGINE_LOAD_BUILTIN_ENGINES
+  ENGINE_load_builtin_engines();
+#endif
+
+  /* Lets get nice error messages */
+  SSL_load_error_strings();
+
+  /* Setup all the global SSL stuff */
+  SSLeay_add_ssl_algorithms();
+#else
+  /* SSL disabled, do nothing */
+#endif
+}
+
+/* Global cleanup */
+void Curl_SSL_cleanup(void)
+{
+#ifdef USE_SSLEAY
+  if(init_ssl) {
+    /* only cleanup if we did a previous init */
+
+    /* Free the SSL error strings */
+    ERR_free_strings();
+
+    /* EVP_cleanup() removes all ciphers and digests from the
+       table. */
+    EVP_cleanup();
+
+#ifdef HAVE_ENGINE_cleanup
+    ENGINE_cleanup();
+#endif
+
+#ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA
+    /* this function was not present in 0.9.6b, but was added sometimes
+       later */
+    CRYPTO_cleanup_all_ex_data();
+#endif
+
+    init_ssl=0; /* not inited any more */
+  }
+#else
+  /* SSL disabled, do nothing */
+#endif
+}
+
+#ifndef USE_SSLEAY
+void Curl_SSL_Close(struct connectdata *conn)
+{
+  (void)conn;
+}
+#endif
+
+#ifdef USE_SSLEAY
+
+/*
+ * This function is called when an SSL connection is closed.
+ */
+void Curl_SSL_Close(struct connectdata *conn)
+{
+  if(conn->ssl[FIRSTSOCKET].use) {
+    int i;
+    /*
+      ERR_remove_state() frees the error queue associated with
+      thread pid.  If pid == 0, the current thread will have its
+      error queue removed.
+
+      Since error queue data structures are allocated
+      automatically for new threads, they must be freed when
+      threads are terminated in oder to avoid memory leaks.
+    */
+    ERR_remove_state(0);
+
+    for(i=0; i<2; i++) {
+      struct ssl_connect_data *connssl = &conn->ssl[i];
+
+      if(connssl->handle) {
+        (void)SSL_shutdown(connssl->handle);
+        SSL_set_connect_state(connssl->handle);
+
+        SSL_free (connssl->handle);
+        connssl->handle = NULL;
+      }
+      if(connssl->ctx) {
+        SSL_CTX_free (connssl->ctx);
+        connssl->ctx = NULL;
+      }
+      connssl->use = FALSE; /* get back to ordinary socket usage */
+    }
+  }
+}
+
+
+/*
+ * This sets up a session cache to the specified size.
+ */
+CURLcode Curl_SSL_InitSessions(struct SessionHandle *data, long amount)
+{
+  struct curl_ssl_session *session;
+
+  if(data->state.session)
+    /* this is just a precaution to prevent multiple inits */
+    return CURLE_OK;
+
+  session = (struct curl_ssl_session *)
+    malloc(amount * sizeof(struct curl_ssl_session));
+  if(!session)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* "blank out" the newly allocated memory */
+  memset(session, 0, amount * sizeof(struct curl_ssl_session));
+
+  /* store the info in the SSL section */
+  data->set.ssl.numsessions = amount;
+  data->state.session = session;
+  data->state.sessionage = 1; /* this is brand new */
+
+  return CURLE_OK;
+}
+
+/*
+ * Check if there's a session ID for the given connection in the cache,
+ * and if there's one suitable, it is returned.
+ */
+static int Get_SSL_Session(struct connectdata *conn,
+                           SSL_SESSION **ssl_sessionid)
+{
+  struct curl_ssl_session *check;
+  struct SessionHandle *data = conn->data;
+  long i;
+
+  for(i=0; i< data->set.ssl.numsessions; i++) {
+    check = &data->state.session[i];
+    if(!check->sessionid)
+      /* not session ID means blank entry */
+      continue;
+    if(curl_strequal(conn->host.name, check->name) &&
+       (conn->remote_port == check->remote_port) &&
+       Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) {
+      /* yes, we have a session ID! */
+      data->state.sessionage++;            /* increase general age */
+      check->age = data->state.sessionage; /* set this as used in this age */
+      *ssl_sessionid = check->sessionid;
+      return FALSE;
+    }
+  }
+  *ssl_sessionid = (SSL_SESSION *)NULL;
+  return TRUE;
+}
+
+/*
+ * Kill a single session ID entry in the cache.
+ */
+static int Kill_Single_Session(struct curl_ssl_session *session)
+{
+  if(session->sessionid) {
+    /* defensive check */
+
+    /* free the ID */
+    SSL_SESSION_free(session->sessionid);
+    session->sessionid=NULL;
+    session->age = 0; /* fresh */
+
+    Curl_free_ssl_config(&session->ssl_config);
+
+    Curl_safefree(session->name);
+    session->name = NULL; /* no name */
+
+    return 0; /* ok */
+  }
+  else
+    return 1;
+}
+
+/*
+ * This function is called when the 'data' struct is going away. Close
+ * down everything and free all resources!
+ */
+int Curl_SSL_Close_All(struct SessionHandle *data)
+{
+  int i;
+
+  if(data->state.session) {
+    for(i=0; i< data->set.ssl.numsessions; i++)
+      /* the single-killer function handles empty table slots */
+      Kill_Single_Session(&data->state.session[i]);
+
+    /* free the cache data */
+    free(data->state.session);
+  }
+#ifdef HAVE_OPENSSL_ENGINE_H
+  if(data->engine)
+  {
+    ENGINE_free(data->engine);
+    data->engine = NULL;
+  }
+#endif
+  return 0;
+}
+
+/*
+ * Extract the session id and store it in the session cache.
+ */
+static int Store_SSL_Session(struct connectdata *conn,
+                             struct ssl_connect_data *ssl)
+{
+  SSL_SESSION *ssl_sessionid;
+  int i;
+  struct SessionHandle *data=conn->data; /* the mother of all structs */
+  struct curl_ssl_session *store = &data->state.session[0];
+  long oldest_age=data->state.session[0].age; /* zero if unused */
+  char *clone_host;
+
+  clone_host = strdup(conn->host.name);
+  if(!clone_host)
+    return -1; /* bail out */
+
+  /* ask OpenSSL, say please */
+
+#ifdef HAVE_SSL_GET1_SESSION
+  ssl_sessionid = SSL_get1_session(ssl->handle);
+
+  /* SSL_get1_session() will increment the reference
+     count and the session will stay in memory until explicitly freed with
+     SSL_SESSION_free(3), regardless of its state.
+     This function was introduced in openssl 0.9.5a. */
+#else
+  ssl_sessionid = SSL_get_session(ssl->handle);
+
+  /* if SSL_get1_session() is unavailable, use SSL_get_session().
+     This is an inferior option because the session can be flushed
+     at any time by openssl. It is included only so curl compiles
+     under versions of openssl < 0.9.5a.
+
+     WARNING: How curl behaves if it's session is flushed is
+     untested.
+  */
+#endif
+
+  /* Now we should add the session ID and the host name to the cache, (remove
+     the oldest if necessary) */
+
+  /* find an empty slot for us, or find the oldest */
+  for(i=1; (i<data->set.ssl.numsessions) &&
+        data->state.session[i].sessionid; i++) {
+    if(data->state.session[i].age < oldest_age) {
+      oldest_age = data->state.session[i].age;
+      store = &data->state.session[i];
+    }
+  }
+  if(i == data->set.ssl.numsessions)
+    /* cache is full, we must "kill" the oldest entry! */
+    Kill_Single_Session(store);
+  else
+    store = &data->state.session[i]; /* use this slot */
+
+  /* now init the session struct wisely */
+  store->sessionid = ssl_sessionid;
+  store->age = data->state.sessionage;    /* set current age */
+  store->name = clone_host;               /* clone host name */
+  store->remote_port = conn->remote_port; /* port number */
+
+  Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config);
+
+  return 0;
+}
+
+static int Curl_ASN1_UTCTIME_output(struct connectdata *conn,
+                                    const char *prefix,
+                                    ASN1_UTCTIME *tm)
+{
+  char *asn1_string;
+  int gmt=FALSE;
+  int i;
+  int year=0,month=0,day=0,hour=0,minute=0,second=0;
+  struct SessionHandle *data = conn->data;
+
+  if(!data->set.verbose)
+    return 0;
+
+  i=tm->length;
+  asn1_string=(char *)tm->data;
+
+  if(i < 10)
+    return 1;
+  if(asn1_string[i-1] == 'Z')
+    gmt=TRUE;
+  for (i=0; i<10; i++)
+    if((asn1_string[i] > '9') || (asn1_string[i] < '0'))
+      return 2;
+
+  year= (asn1_string[0]-'0')*10+(asn1_string[1]-'0');
+  if(year < 50)
+    year+=100;
+
+  month= (asn1_string[2]-'0')*10+(asn1_string[3]-'0');
+  if((month > 12) || (month < 1))
+    return 3;
+
+  day= (asn1_string[4]-'0')*10+(asn1_string[5]-'0');
+  hour= (asn1_string[6]-'0')*10+(asn1_string[7]-'0');
+  minute=  (asn1_string[8]-'0')*10+(asn1_string[9]-'0');
+
+  if((asn1_string[10] >= '0') && (asn1_string[10] <= '9') &&
+     (asn1_string[11] >= '0') && (asn1_string[11] <= '9'))
+    second= (asn1_string[10]-'0')*10+(asn1_string[11]-'0');
+
+  infof(data,
+        "%s%04d-%02d-%02d %02d:%02d:%02d %s\n",
+        prefix, year+1900, month, day, hour, minute, second, (gmt?"GMT":""));
+
+  return 0;
+}
+
+#endif
+
+/* ====================================================== */
+#ifdef USE_SSLEAY
+
+/*
+ * Match a hostname against a wildcard pattern.
+ * E.g.
+ *  "foo.host.com" matches "*.host.com".
+ *
+ * We are a bit more liberal than RFC2818 describes in that we
+ * accept multiple "*" in pattern (similar to what some other browsers do).
+ * E.g.
+ *  "abc.def.domain.com" should strickly not match "*.domain.com", but we
+ *  don't consider "." to be important in CERT checking.
+ */
+#define HOST_NOMATCH 0
+#define HOST_MATCH   1
+
+static int hostmatch(const char *hostname, const char *pattern)
+{
+  while (1) {
+    int c = *pattern++;
+
+    if (c == '\0')
+      return (*hostname ? HOST_NOMATCH : HOST_MATCH);
+
+    if (c == '*') {
+      c = *pattern;
+      if (c == '\0')      /* "*\0" matches anything remaining */
+        return HOST_MATCH;
+
+      while (*hostname) {
+        /* The only recursive function in libcurl! */
+        if (hostmatch(hostname++,pattern) == HOST_MATCH)
+          return HOST_MATCH;
+      }
+      return HOST_NOMATCH;
+    }
+
+    if (toupper(c) != toupper(*hostname++))
+      return HOST_NOMATCH;
+  }
+}
+
+static int
+cert_hostcheck(const char *match_pattern, const char *hostname)
+{
+  if (!match_pattern || !*match_pattern ||
+      !hostname || !*hostname) /* sanity check */
+    return 0;
+
+  if(curl_strequal(hostname,match_pattern)) /* trivial case */
+    return 1;
+
+  if (hostmatch(hostname,match_pattern) == HOST_MATCH)
+    return 1;
+  return 0;
+}
+
+/* Quote from RFC2818 section 3.1 "Server Identity"
+
+   If a subjectAltName extension of type dNSName is present, that MUST
+   be used as the identity. Otherwise, the (most specific) Common Name
+   field in the Subject field of the certificate MUST be used. Although
+   the use of the Common Name is existing practice, it is deprecated and
+   Certification Authorities are encouraged to use the dNSName instead.
+
+   Matching is performed using the matching rules specified by
+   [RFC2459].  If more than one identity of a given type is present in
+   the certificate (e.g., more than one dNSName name, a match in any one
+   of the set is considered acceptable.) Names may contain the wildcard
+   character * which is considered to match any single domain name
+   component or component fragment. E.g., *.a.com matches foo.a.com but
+   not bar.foo.a.com. f*.com matches foo.com but not bar.com.
+
+   In some cases, the URI is specified as an IP address rather than a
+   hostname. In this case, the iPAddress subjectAltName must be present
+   in the certificate and must exactly match the IP in the URI.
+
+*/
+static CURLcode verifyhost(struct connectdata *conn,
+                           X509 *server_cert)
+{
+  bool matched = FALSE; /* no alternative match yet */
+  int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */
+  int addrlen = 0;
+  struct SessionHandle *data = conn->data;
+  STACK_OF(GENERAL_NAME) *altnames;
+#ifdef ENABLE_IPV6
+  struct in6_addr addr;
+#else
+  struct in_addr addr;
+#endif
+
+#ifdef ENABLE_IPV6
+  if(conn->bits.ipv6_ip &&
+     Curl_inet_pton(AF_INET6, conn->host.name, &addr)) {
+    target = GEN_IPADD;
+    addrlen = sizeof(struct in6_addr);
+  }
+  else
+#endif
+    if(Curl_inet_pton(AF_INET, conn->host.name, &addr)) {
+      target = GEN_IPADD;
+      addrlen = sizeof(struct in_addr);
+    }
+
+  /* get a "list" of alternative names */
+  altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL);
+
+  if(altnames) {
+    int numalts;
+    int i;
+
+    /* get amount of alternatives, RFC2459 claims there MUST be at least
+       one, but we don't depend on it... */
+    numalts = sk_GENERAL_NAME_num(altnames);
+
+    /* loop through all alternatives while none has matched */
+    for (i=0; (i<numalts) && !matched; i++) {
+      /* get a handle to alternative name number i */
+      const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i);
+
+      /* only check alternatives of the same type the target is */
+      if(check->type == target) {
+        /* get data and length */
+        const char *altptr = (char *)ASN1_STRING_data(check->d.ia5);
+        int altlen;
+
+        switch(target) {
+        case GEN_DNS: /* name/pattern comparison */
+          /* The OpenSSL man page explicitly says: "In general it cannot be
+             assumed that the data returned by ASN1_STRING_data() is null
+             terminated or does not contain embedded nulls." But also that
+             "The actual format of the data will depend on the actual string
+             type itself: for example for and IA5String the data will be ASCII"
+
+             Gisle researched the OpenSSL sources:
+             "I checked the 0.9.6 and 0.9.8 sources before my patch and
+             it always 0-terminates an IA5String."
+          */
+          if (cert_hostcheck(altptr, conn->host.name))
+            matched = TRUE;
+          break;
+
+        case GEN_IPADD: /* IP address comparison */
+          /* compare alternative IP address if the data chunk is the same size
+             our server IP address is */
+          altlen = ASN1_STRING_length(check->d.ia5);
+          if((altlen == addrlen) && !memcmp(altptr, &addr, altlen))
+            matched = TRUE;
+          break;
+        }
+      }
+    }
+    GENERAL_NAMES_free(altnames);
+  }
+
+  if(matched)
+    /* an alternative name matched the server hostname */
+    infof(data, "\t subjectAltName: %s matched\n", conn->host.dispname);
+  else {
+    /* we have to look to the last occurence of a commonName in the
+       distinguished one to get the most significant one. */
+    int j,i=-1 ;
+
+/* The following is done because of a bug in 0.9.6b */
+
+    unsigned char *nulstr = (unsigned char *)"";
+    unsigned char *peer_CN = nulstr;
+
+    X509_NAME *name = X509_get_subject_name(server_cert) ;
+    if (name)
+      while ((j=X509_NAME_get_index_by_NID(name,NID_commonName,i))>=0)
+        i=j;
+
+    /* we have the name entry and we will now convert this to a string
+       that we can use for comparison. Doing this we support BMPstring,
+       UTF8 etc. */
+
+    if (i>=0) {
+      ASN1_STRING *tmp = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name,i));
+
+      /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input
+         is already UTF-8 encoded. We check for this case and copy the raw
+         string manually to avoid the problem. This code can be made
+         conditional in the future when OpenSSL has been fixed. Work-around
+         brought by Alexis S. L. Carvalho. */
+      if (tmp && ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
+        j = ASN1_STRING_length(tmp);
+        if (j >= 0) {
+          peer_CN = OPENSSL_malloc(j+1);
+          if (peer_CN) {
+            memcpy(peer_CN, ASN1_STRING_data(tmp), j);
+            peer_CN[j] = '\0';
+          }
+        }
+      }
+      else /* not a UTF8 name */
+        j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
+    }
+
+    if (peer_CN == nulstr)
+       peer_CN = NULL;
+
+    if (!peer_CN) {
+      if(data->set.ssl.verifyhost > 1) {
+        failf(data,
+              "SSL: unable to obtain common name from peer certificate");
+        return CURLE_SSL_PEER_CERTIFICATE;
+      }
+      else {
+        /* Consider verifyhost == 1 as an "OK" for a missing CN field, but we
+           output a note about the situation */
+        infof(data, "\t common name: WARNING couldn't obtain\n");
+      }
+    }
+    else if(!cert_hostcheck((const char *)peer_CN, conn->host.name)) {
+      if(data->set.ssl.verifyhost > 1) {
+        failf(data, "SSL: certificate subject name '%s' does not match "
+              "target host name '%s'", peer_CN, conn->host.dispname);
+        OPENSSL_free(peer_CN);
+        return CURLE_SSL_PEER_CERTIFICATE ;
+      }
+      else
+        infof(data, "\t common name: %s (does not match '%s')\n",
+              peer_CN, conn->host.dispname);
+    }
+    else {
+      infof(data, "\t common name: %s (matched)\n", peer_CN);
+      OPENSSL_free(peer_CN);
+    }
+  }
+  return CURLE_OK;
+}
+#endif
+
+/* The SSL_CTRL_SET_MSG_CALLBACK doesn't exist in ancient OpenSSL versions
+   and thus this cannot be done there. */
+#ifdef SSL_CTRL_SET_MSG_CALLBACK
+
+static const char *ssl_msg_type(int ssl_ver, int msg)
+{
+  if (ssl_ver == SSL2_VERSION_MAJOR) {
+    switch (msg) {
+      case SSL2_MT_ERROR:
+        return "Error";
+      case SSL2_MT_CLIENT_HELLO:
+        return "Client hello";
+      case SSL2_MT_CLIENT_MASTER_KEY:
+        return "Client key";
+      case SSL2_MT_CLIENT_FINISHED:
+        return "Client finished";
+      case SSL2_MT_SERVER_HELLO:
+        return "Server hello";
+      case SSL2_MT_SERVER_VERIFY:
+        return "Server verify";
+      case SSL2_MT_SERVER_FINISHED:
+        return "Server finished";
+      case SSL2_MT_REQUEST_CERTIFICATE:
+        return "Request CERT";
+      case SSL2_MT_CLIENT_CERTIFICATE:
+        return "Client CERT";
+    }
+  }
+  else if (ssl_ver == SSL3_VERSION_MAJOR) {
+    switch (msg) {
+      case SSL3_MT_HELLO_REQUEST:
+        return "Hello request";
+      case SSL3_MT_CLIENT_HELLO:
+        return "Client hello";
+      case SSL3_MT_SERVER_HELLO:
+        return "Server hello";
+      case SSL3_MT_CERTIFICATE:
+        return "CERT";
+      case SSL3_MT_SERVER_KEY_EXCHANGE:
+        return "Server key exchange";
+      case SSL3_MT_CLIENT_KEY_EXCHANGE:
+        return "Client key exchange";
+      case SSL3_MT_CERTIFICATE_REQUEST:
+        return "Request CERT";
+      case SSL3_MT_SERVER_DONE:
+        return "Server finished";
+      case SSL3_MT_CERTIFICATE_VERIFY:
+        return "CERT verify";
+      case SSL3_MT_FINISHED:
+        return "Finished";
+    }
+  }
+  return "Unknown";
+}
+
+static const char *tls_rt_type(int type)
+{
+  return (
+    type == SSL3_RT_CHANGE_CIPHER_SPEC ? "TLS change cipher, " :
+    type == SSL3_RT_ALERT              ? "TLS alert, "         :
+    type == SSL3_RT_HANDSHAKE          ? "TLS handshake, "     :
+    type == SSL3_RT_APPLICATION_DATA   ? "TLS app data, "      :
+                                         "TLS Unknown, ");
+}
+
+
+/*
+ * Our callback from the SSL/TLS layers.
+ */
+static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
+                          const void *buf, size_t len, const SSL *ssl,
+                          struct connectdata *conn)
+{
+  struct SessionHandle *data = conn->data;
+  const char *msg_name, *tls_rt_name;
+  char ssl_buf[1024];
+  int  ver, msg_type, txt_len;
+
+  if (!conn || !conn->data || !conn->data->set.fdebug ||
+      (direction != 0 && direction != 1))
+    return;
+
+  data = conn->data;
+  ssl_ver >>= 8;
+  ver = (ssl_ver == SSL2_VERSION_MAJOR ? '2' :
+         ssl_ver == SSL3_VERSION_MAJOR ? '3' : '?');
+
+  /* SSLv2 doesn't seem to have TLS record-type headers, so OpenSSL
+   * always pass-up content-type as 0. But the interesting message-type
+   * is at 'buf[0]'.
+   */
+  if (ssl_ver == SSL3_VERSION_MAJOR && content_type != 0)
+    tls_rt_name = tls_rt_type(content_type);
+  else
+    tls_rt_name = "";
+
+  msg_type = *(char*)buf;
+  msg_name = ssl_msg_type(ssl_ver, msg_type);
+
+  txt_len = 1 + snprintf(ssl_buf, sizeof(ssl_buf), "SSLv%c, %s%s (%d):\n",
+                         ver, tls_rt_name, msg_name, msg_type);
+  Curl_debug(data, CURLINFO_TEXT, ssl_buf, txt_len, NULL);
+
+  Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT :
+             CURLINFO_SSL_DATA_IN, (char *)buf, len, NULL);
+  (void) ssl;
+}
+#endif
+
+/* ====================================================== */
+CURLcode
+Curl_SSLConnect(struct connectdata *conn,
+                int sockindex)
+{
+  CURLcode retcode = CURLE_OK;
+
+#ifdef USE_SSLEAY
+  struct SessionHandle *data = conn->data;
+  int err;
+  long lerr;
+  int what;
+  char * str;
+  SSL_METHOD *req_method;
+  SSL_SESSION *ssl_sessionid=NULL;
+  ASN1_TIME *certdate;
+  curl_socket_t sockfd = conn->sock[sockindex];
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+  /* mark this is being ssl enabled from here on out. */
+  connssl->use = TRUE;
+
+  if(!ssl_seeded || data->set.ssl.random_file || data->set.ssl.egdsocket) {
+    /* Make funny stuff to get random input */
+    random_the_seed(data);
+
+    ssl_seeded = TRUE;
+  }
+
+  /* check to see if we've been told to use an explicit SSL/TLS version */
+  switch(data->set.ssl.version) {
+  default:
+  case CURL_SSLVERSION_DEFAULT:
+    /* we try to figure out version */
+    req_method = SSLv23_client_method();
+    break;
+  case CURL_SSLVERSION_TLSv1:
+    req_method = TLSv1_client_method();
+    break;
+  case CURL_SSLVERSION_SSLv2:
+    req_method = SSLv2_client_method();
+    break;
+  case CURL_SSLVERSION_SSLv3:
+    req_method = SSLv3_client_method();
+    break;
+  }
+
+  connssl->ctx = SSL_CTX_new(req_method);
+
+  if(!connssl->ctx) {
+    failf(data, "SSL: couldn't create a context!");
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+#ifdef SSL_CTRL_SET_MSG_CALLBACK
+  if (data->set.fdebug) {
+    SSL_CTX_callback_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK,
+                          ssl_tls_trace);
+    SSL_CTX_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK_ARG, 0, conn);
+  }
+#endif
+
+  /* OpenSSL contains code to work-around lots of bugs and flaws in various
+     SSL-implementations. SSL_CTX_set_options() is used to enabled those
+     work-arounds. The man page for this option states that SSL_OP_ALL enables
+     ll the work-arounds and that "It is usually safe to use SSL_OP_ALL to
+     enable the bug workaround options if compatibility with somewhat broken
+     implementations is desired."
+
+  */
+  SSL_CTX_set_options(connssl->ctx, SSL_OP_ALL);
+
+#if 0
+  /*
+   * Not sure it's needed to tell SSL_connect() that socket is
+   * non-blocking. It doesn't seem to care, but just return with
+   * SSL_ERROR_WANT_x.
+   */
+  if (data->state.used_interface == Curl_if_multi)
+    SSL_CTX_ctrl(connssl->ctx, BIO_C_SET_NBIO, 1, NULL);
+#endif
+
+  if(data->set.cert) {
+    if(!cert_stuff(conn,
+                   connssl->ctx,
+                   data->set.cert,
+                   data->set.cert_type,
+                   data->set.key,
+                   data->set.key_type)) {
+      /* failf() is already done in cert_stuff() */
+      return CURLE_SSL_CERTPROBLEM;
+    }
+  }
+
+  if(data->set.ssl.cipher_list) {
+    if(!SSL_CTX_set_cipher_list(connssl->ctx,
+                                data->set.ssl.cipher_list)) {
+      failf(data, "failed setting cipher list");
+      return CURLE_SSL_CIPHER;
+    }
+  }
+
+  if (data->set.ssl.CAfile || data->set.ssl.CApath) {
+    /* tell SSL where to find CA certificates that are used to verify
+       the servers certificate. */
+    if (!SSL_CTX_load_verify_locations(connssl->ctx, data->set.ssl.CAfile,
+                                       data->set.ssl.CApath)) {
+      if (data->set.ssl.verifypeer) {
+        /* Fail if we insist on successfully verifying the server. */
+        failf(data,"error setting certificate verify locations:\n"
+              "  CAfile: %s\n  CApath: %s\n",
+              data->set.ssl.CAfile ? data->set.ssl.CAfile : "none",
+              data->set.ssl.CApath ? data->set.ssl.CApath : "none");
+        return CURLE_SSL_CACERT;
+      }
+      else {
+        /* Just continue with a warning if no strict  certificate verification
+           is required. */
+        infof(data, "error setting certificate verify locations,"
+              " continuing anyway:\n");
+      }
+    }
+    else {
+      /* Everything is fine. */
+      infof(data, "successfully set certificate verify locations:\n");
+    }
+    infof(data,
+          "  CAfile: %s\n"
+          "  CApath: %s\n",
+          data->set.ssl.CAfile ? data->set.ssl.CAfile : "none",
+          data->set.ssl.CApath ? data->set.ssl.CApath : "none");
+  }
+  /* SSL always tries to verify the peer, this only says whether it should
+   * fail to connect if the verification fails, or if it should continue
+   * anyway. In the latter case the result of the verification is checked with
+   * SSL_get_verify_result() below. */
+  SSL_CTX_set_verify(connssl->ctx,
+                     data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE,
+                     cert_verify_callback);
+
+  /* give application a chance to interfere with SSL set up. */
+  if(data->set.ssl.fsslctx) {
+    retcode = (*data->set.ssl.fsslctx)(data, connssl->ctx,
+                                       data->set.ssl.fsslctxp);
+    if(retcode) {
+      failf(data,"error signaled by ssl ctx callback");
+      return retcode;
+    }
+  }
+
+  /* Lets make an SSL structure */
+  connssl->handle = SSL_new(connssl->ctx);
+  SSL_set_connect_state(connssl->handle);
+
+  connssl->server_cert = 0x0;
+
+  if(!conn->bits.reuse) {
+    /* We're not re-using a connection, check if there's a cached ID we
+       can/should use here! */
+    if(!Get_SSL_Session(conn, &ssl_sessionid)) {
+      /* we got a session id, use it! */
+      SSL_set_session(connssl->handle, ssl_sessionid);
+      /* Informational message */
+      infof (data, "SSL re-using session ID\n");
+    }
+  }
+
+  /* pass the raw socket into the SSL layers */
+  SSL_set_fd(connssl->handle, sockfd);
+
+  while(1) {
+    fd_set writefd;
+    fd_set readfd;
+    struct timeval interval;
+    long timeout_ms;
+
+    /* Find out if any timeout is set. If not, use 300 seconds.
+       Otherwise, figure out the most strict timeout of the two possible one
+       and then how much time that has elapsed to know how much time we
+       allow for the connect call */
+    if(data->set.timeout || data->set.connecttimeout) {
+      long has_passed;
+
+      /* Evaluate in milliseconds how much time that has passed */
+      has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);
+
+      /* get the most strict timeout of the ones converted to milliseconds */
+      if(data->set.timeout &&
+         (data->set.timeout>data->set.connecttimeout))
+        timeout_ms = data->set.timeout*1000;
+      else
+        timeout_ms = data->set.connecttimeout*1000;
+
+      /* subtract the passed time */
+      timeout_ms -= has_passed;
+
+      if(timeout_ms < 0) {
+        /* a precaution, no need to continue if time already is up */
+        failf(data, "SSL connection timeout");
+        return CURLE_OPERATION_TIMEOUTED;
+      }
+    }
+    else
+      /* no particular time-out has been set */
+      timeout_ms= DEFAULT_CONNECT_TIMEOUT;
+
+
+    FD_ZERO(&writefd);
+    FD_ZERO(&readfd);
+
+    err = SSL_connect(connssl->handle);
+
+    /* 1  is fine
+       0  is "not successful but was shut down controlled"
+       <0 is "handshake was not successful, because a fatal error occurred" */
+    if(1 != err) {
+      int detail = SSL_get_error(connssl->handle, err);
+
+      if(SSL_ERROR_WANT_READ == detail)
+        FD_SET(sockfd, &readfd);
+      else if(SSL_ERROR_WANT_WRITE == detail)
+        FD_SET(sockfd, &writefd);
+      else {
+        /* untreated error */
+        unsigned long errdetail;
+        char error_buffer[120]; /* OpenSSL documents that this must be at least
+                                   120 bytes long. */
+        CURLcode rc;
+        const char *cert_problem = NULL;
+
+        errdetail = ERR_get_error(); /* Gets the earliest error code from the
+                                        thread's error queue and removes the
+                                        entry. */
+
+        switch(errdetail) {
+        case 0x1407E086:
+          /* 1407E086:
+             SSL routines:
+             SSL2_SET_CERTIFICATE:
+             certificate verify failed */
+          /* fall-through */
+        case 0x14090086:
+          /* 14090086:
+             SSL routines:
+             SSL3_GET_SERVER_CERTIFICATE:
+             certificate verify failed */
+          cert_problem = "SSL certificate problem, verify that the CA cert is"
+                         " OK. Details:\n";
+          rc = CURLE_SSL_CACERT;
+          break;
+        default:
+          rc = CURLE_SSL_CONNECT_ERROR;
+          break;
+        }
+
+          /* detail is already set to the SSL error above */
+
+        /* If we e.g. use SSLv2 request-method and the server doesn't like us
+         * (RST connection etc.), OpenSSL gives no explanation whatsoever and
+         * the SO_ERROR is also lost.
+         */
+        if (CURLE_SSL_CONNECT_ERROR == rc && errdetail == 0) {
+          failf(data, "Unknown SSL protocol error in connection to %s:%d ",
+                conn->host.name, conn->port);
+          return rc;
+        }
+        /* Could be a CERT problem */
+
+#ifdef HAVE_ERR_ERROR_STRING_N
+          /* OpenSSL 0.9.6 and later has a function named
+             ERRO_error_string_n() that takes the size of the buffer as a
+             third argument */
+          ERR_error_string_n(errdetail, error_buffer, sizeof(error_buffer));
+#else
+          ERR_error_string(errdetail, error_buffer);
+#endif
+        failf(data, "%s%s", cert_problem ? cert_problem : "", error_buffer);
+        return rc;
+      }
+    }
+    else
+      /* we have been connected fine, get out of the connect loop */
+      break;
+
+    interval.tv_sec = (int)(timeout_ms/1000);
+    timeout_ms -= interval.tv_sec*1000;
+
+    interval.tv_usec = timeout_ms*1000;
+
+    while(1) {
+      what = select(sockfd+1, &readfd, &writefd, NULL, &interval);
+      if(what > 0)
+        /* reabable or writable, go loop in the outer loop */
+        break;
+      else if(0 == what) {
+        /* timeout */
+        failf(data, "SSL connection timeout");
+        return CURLE_OPERATION_TIMEDOUT;
+      }
+      else {
+#if !defined(WIN32) && defined(EINTR)
+        /* For platforms without EINTR all errnos are bad */
+        if (errno == EINTR)
+          continue; /* retry the select() */
+#endif
+        /* anything other than the unimportant EINTR is fatally bad */
+        failf(data, "select on SSL socket, errno: %d", Curl_ourerrno());
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+    } /* while()-loop for the select() */
+  } /* while()-loop for the SSL_connect() */
+
+  /* Informational message */
+  infof (data, "SSL connection using %s\n",
+         SSL_get_cipher(connssl->handle));
+
+  if(!ssl_sessionid) {
+    /* Since this is not a cached session ID, then we want to stach this one
+       in the cache! */
+    Store_SSL_Session(conn, connssl);
+  }
+
+
+  /* Get server's certificate (note: beware of dynamic allocation) - opt */
+  /* major serious hack alert -- we should check certificates
+   * to authenticate the server; otherwise we risk man-in-the-middle
+   * attack
+   */
+
+  connssl->server_cert = SSL_get_peer_certificate(connssl->handle);
+  if(!connssl->server_cert) {
+    failf(data, "SSL: couldn't get peer certificate!");
+    return CURLE_SSL_PEER_CERTIFICATE;
+  }
+  infof (data, "Server certificate:\n");
+
+  str = X509_NAME_oneline(X509_get_subject_name(connssl->server_cert),
+                          NULL, 0);
+  if(!str) {
+    failf(data, "SSL: couldn't get X509-subject!");
+    X509_free(connssl->server_cert);
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+  infof(data, "\t subject: %s\n", str);
+  CRYPTO_free(str);
+
+  certdate = X509_get_notBefore(connssl->server_cert);
+  Curl_ASN1_UTCTIME_output(conn, "\t start date: ", certdate);
+
+  certdate = X509_get_notAfter(connssl->server_cert);
+  Curl_ASN1_UTCTIME_output(conn, "\t expire date: ", certdate);
+
+  if(data->set.ssl.verifyhost) {
+    retcode = verifyhost(conn, connssl->server_cert);
+    if(retcode) {
+      X509_free(connssl->server_cert);
+      return retcode;
+    }
+  }
+
+  str = X509_NAME_oneline(X509_get_issuer_name(connssl->server_cert),
+                          NULL, 0);
+  if(!str) {
+    failf(data, "SSL: couldn't get X509-issuer name!");
+    retcode = CURLE_SSL_CONNECT_ERROR;
+  }
+  else {
+    infof(data, "\t issuer: %s\n", str);
+    CRYPTO_free(str);
+
+    /* We could do all sorts of certificate verification stuff here before
+       deallocating the certificate. */
+
+    lerr = data->set.ssl.certverifyresult=
+      SSL_get_verify_result(connssl->handle);
+    if(data->set.ssl.certverifyresult != X509_V_OK) {
+      if(data->set.ssl.verifypeer) {
+        /* We probably never reach this, because SSL_connect() will fail
+           and we return earlyer if verifypeer is set? */
+        failf(data, "SSL certificate verify result: %s (%ld)",
+              X509_verify_cert_error_string(lerr), lerr);
+        retcode = CURLE_SSL_PEER_CERTIFICATE;
+      }
+      else
+        infof(data, "SSL certificate verify result: %s (%ld),"
+              " continuing anyway.\n",
+              X509_verify_cert_error_string(err), lerr);
+    }
+    else
+      infof(data, "SSL certificate verify ok.\n");
+  }
+
+  X509_free(connssl->server_cert);
+#else /* USE_SSLEAY */
+  (void)conn;
+  (void)sockindex;
+#endif
+  return retcode;
+}
diff --git a/Utilities/cmcurl/ssluse.h b/Utilities/cmcurl/ssluse.h
new file mode 100644
index 0000000..886d2ca
--- /dev/null
+++ b/Utilities/cmcurl/ssluse.h
@@ -0,0 +1,38 @@
+#ifndef __SSLUSE_H
+#define __SSLUSE_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+#include "urldata.h"
+CURLcode Curl_SSLConnect(struct connectdata *conn, int sockindex);
+
+void Curl_SSL_init(void);    /* Global SSL init */
+void Curl_SSL_cleanup(void); /* Global SSL cleanup */
+
+/* init the SSL session ID cache */
+CURLcode Curl_SSL_InitSessions(struct SessionHandle *, long);
+void Curl_SSL_Close(struct connectdata *conn); /* close a SSL connection */
+
+/* tell the SSL stuff to close down all open information regarding 
+   connections (and thus session ID caching etc) */
+int Curl_SSL_Close_All(struct SessionHandle *data);
+#endif
diff --git a/Utilities/cmcurl/strequal.c b/Utilities/cmcurl/strequal.c
new file mode 100644
index 0000000..66e2e4f
--- /dev/null
+++ b/Utilities/cmcurl/strequal.c
@@ -0,0 +1,140 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <string.h>
+#include <ctype.h>
+
+#include "strequal.h"
+
+#ifdef HAVE_STRCASECMP
+/* this is for "-ansi -Wall -pedantic" to stop complaining! */
+extern int (strcasecmp)(const char *s1, const char *s2);
+extern int (strncasecmp)(const char *s1, const char *s2, size_t n);
+#endif
+
+int curl_strequal(const char *first, const char *second)
+{
+#if defined(HAVE_STRCASECMP)
+  return !(strcasecmp)(first, second);
+#elif defined(HAVE_STRICMP)
+  return !(stricmp)(first, second);
+#elif defined(HAVE_STRCMPI)
+  return !(strcmpi)(first, second);
+#else
+  while (*first && *second) {
+    if (toupper(*first) != toupper(*second)) {
+      break;
+    }
+    first++;
+    second++;
+  }
+  return toupper(*first) == toupper(*second);
+#endif
+}
+
+int curl_strnequal(const char *first, const char *second, size_t max)
+{
+#if defined(HAVE_STRCASECMP)
+  return !strncasecmp(first, second, max);
+#elif defined(HAVE_STRICMP)
+  return !strnicmp(first, second, max);
+#elif defined(HAVE_STRCMPI)
+  return !strncmpi(first, second, max);
+#else
+  while (*first && *second && max) {
+    if (toupper(*first) != toupper(*second)) {
+      break;
+    }
+    max--;
+    first++;
+    second++;
+  }
+  if(0 == max)
+    return 1; /* they are equal this far */
+
+  return toupper(*first) == toupper(*second);
+#endif
+}
+
+/*
+ * Curl_strcasestr() finds the first occurrence of the substring needle in the
+ * string haystack.  The terminating `\0' characters are not compared. The
+ * matching is done CASE INSENSITIVE, which thus is the difference between
+ * this and strstr().
+ */
+char *Curl_strcasestr(const char *haystack, const char *needle)
+{
+  size_t nlen = strlen(needle);
+  size_t hlen = strlen(haystack);
+
+  while(hlen-- >= nlen) {
+    if(curl_strnequal(haystack, needle, nlen))
+      return (char *)haystack;
+    haystack++;
+  }
+  return NULL;
+}
+
+#ifndef HAVE_STRLCAT
+/*
+ * The strlcat() function appends the NUL-terminated string src to the end
+ * of dst. It will append at most size - strlen(dst) - 1 bytes, NUL-termi-
+ * nating the result.
+ *
+ * The strlcpy() and strlcat() functions return the total length of the
+ * string they tried to create.  For strlcpy() that means the length of src.
+ * For strlcat() that means the initial length of dst plus the length of
+ * src. While this may seem somewhat confusing it was done to make trunca-
+ * tion detection simple.
+ *
+ *
+ */
+size_t Curl_strlcat(char *dst, const char *src, size_t siz)
+{
+  char *d = dst;
+  const char *s = src;
+  size_t n = siz;
+  size_t dlen;
+
+  /* Find the end of dst and adjust bytes left but don't go past end */
+  while (n-- != 0 && *d != '\0')
+    d++;
+  dlen = d - dst;
+  n = siz - dlen;
+
+  if (n == 0)
+    return(dlen + strlen(s));
+  while (*s != '\0') {
+    if (n != 1) {
+      *d++ = *s;
+      n--;
+    }
+    s++;
+  }
+  *d = '\0';
+
+  return(dlen + (s - src));     /* count does not include NUL */
+}
+#endif
diff --git a/Utilities/cmcurl/strequal.h b/Utilities/cmcurl/strequal.h
new file mode 100644
index 0000000..5865211
--- /dev/null
+++ b/Utilities/cmcurl/strequal.h
@@ -0,0 +1,47 @@
+#ifndef __STREQUAL_H
+#define __STREQUAL_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/*
+ * These two actually are public functions.
+ */
+int curl_strequal(const char *first, const char *second);
+int curl_strnequal(const char *first, const char *second, size_t max);
+
+#define strequal(a,b) curl_strequal(a,b)
+#define strnequal(a,b,c) curl_strnequal(a,b,c)
+
+/* checkprefix() is a shorter version of the above, used when the first
+   argument is zero-byte terminated */
+#define checkprefix(a,b)    strnequal(a,b,strlen(a))
+
+/* case insensitive strstr() */
+char *Curl_strcasestr(const char *haystack, const char *needle);
+
+#ifndef HAVE_STRLCAT
+#define strlcat(x,y,z) Curl_strlcat(x,y,z)
+size_t Curl_strlcat(char *dst, const char *src, size_t siz);
+#endif
+
+#endif
diff --git a/Utilities/cmcurl/strerror.c b/Utilities/cmcurl/strerror.c
new file mode 100644
index 0000000..ea5bcd8
--- /dev/null
+++ b/Utilities/cmcurl/strerror.c
@@ -0,0 +1,569 @@
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <curl/curl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "strerror.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#ifdef HAVE_NO_STRERROR_R_DECL
+#ifdef HAVE_POSIX_STRERROR_R
+/* seen on AIX 5100-02 gcc 2.9 */
+extern int strerror_r(int errnum, char *strerrbuf, size_t buflen);
+#else
+extern char *strerror_r(int errnum, char *buf, size_t buflen);
+#endif
+#endif
+
+const char *
+curl_easy_strerror(CURLcode error)
+{
+  switch (error) {
+  case CURLE_OK:
+    return "no error";
+
+  case CURLE_UNSUPPORTED_PROTOCOL:
+    return "unsupported protocol";
+
+  case CURLE_FAILED_INIT:
+    return "failed init";
+
+  case CURLE_URL_MALFORMAT:
+    return "URL using bad/illegal format or missing URL";
+
+  case CURLE_COULDNT_RESOLVE_PROXY:
+    return "couldnt resolve proxy";
+
+  case CURLE_COULDNT_RESOLVE_HOST:
+    return "couldnt resolve host";
+
+  case CURLE_COULDNT_CONNECT:
+    return "couldn't connect";
+
+  case CURLE_FTP_WEIRD_SERVER_REPLY:
+    return "FTP: weird server reply";
+
+  case CURLE_FTP_ACCESS_DENIED:
+    return "FTP: access denied";
+
+  case CURLE_FTP_USER_PASSWORD_INCORRECT:
+    return "FTP: user and/or password incorrect";
+
+  case CURLE_FTP_WEIRD_PASS_REPLY:
+    return "FTP: unknown PASS reply";
+
+  case CURLE_FTP_WEIRD_USER_REPLY:
+    return "FTP: unknown USER reply";
+
+  case CURLE_FTP_WEIRD_PASV_REPLY:
+    return "FTP: unknown PASV reply";
+
+  case CURLE_FTP_WEIRD_227_FORMAT:
+    return "FTP: unknown 227 response format";
+
+  case CURLE_FTP_CANT_GET_HOST:
+    return "FTP: can't figure out the host in the PASV response";
+
+  case CURLE_FTP_CANT_RECONNECT:
+    return "FTP: can't connect to server the response code is unknown";
+
+  case CURLE_FTP_COULDNT_SET_BINARY:
+    return "FTP: couldn't set binary mode";
+
+  case CURLE_PARTIAL_FILE:
+    return "Transferred a partial file";
+
+  case CURLE_FTP_COULDNT_RETR_FILE:
+    return "FTP: couldn't retrieve (RETR failed) the specified file";
+
+  case CURLE_FTP_WRITE_ERROR:
+    return "FTP: the post-transfer acknowledge response was not OK";
+
+  case CURLE_FTP_QUOTE_ERROR:
+    return "FTP: a quote command returned error";
+
+  case CURLE_HTTP_RETURNED_ERROR:
+    return "HTTP response code said error";
+
+  case CURLE_WRITE_ERROR:
+    return "failed writing received data to disk/application";
+
+  case CURLE_FTP_COULDNT_STOR_FILE:
+    return "failed FTP upload (the STOR command)";
+
+  case CURLE_READ_ERROR:
+    return "failed to open/read local data from file/application";
+
+  case CURLE_OUT_OF_MEMORY:
+    return "out of memory";
+
+  case CURLE_OPERATION_TIMEOUTED:
+    return "a timeout was reached";
+
+  case CURLE_FTP_COULDNT_SET_ASCII:
+    return "FTP could not set ASCII mode (TYPE A)";
+
+  case CURLE_FTP_PORT_FAILED:
+    return "FTP command PORT failed";
+
+  case CURLE_FTP_COULDNT_USE_REST:
+    return "FTP command REST failed";
+
+  case CURLE_FTP_COULDNT_GET_SIZE:
+    return "FTP command SIZE failed";
+
+  case CURLE_HTTP_RANGE_ERROR:
+    return "a range was requested but the server did not deliver it";
+
+  case CURLE_HTTP_POST_ERROR:
+    return "internal problem setting up the POST";
+
+  case CURLE_SSL_CONNECT_ERROR:
+    return "SSL connect error";
+
+  case CURLE_FTP_BAD_DOWNLOAD_RESUME:
+    return "couldn't resume FTP download";
+
+  case CURLE_FILE_COULDNT_READ_FILE:
+    return "couldn't read a file:// file";
+
+  case CURLE_LDAP_CANNOT_BIND:
+    return "LDAP: cannot bind";
+
+  case CURLE_LDAP_SEARCH_FAILED:
+    return "LDAP: search failed";
+
+  case CURLE_LIBRARY_NOT_FOUND:
+    return "a required shared library was not found";
+
+  case CURLE_FUNCTION_NOT_FOUND:
+    return "a required function in the shared library was not found";
+
+  case CURLE_ABORTED_BY_CALLBACK:
+    return "the operation was aborted by an application callback";
+
+  case CURLE_BAD_FUNCTION_ARGUMENT:
+    return "a libcurl function was given a bad argument";
+
+  case CURLE_INTERFACE_FAILED:
+    return "failed binding local connection end";
+
+  case CURLE_TOO_MANY_REDIRECTS :
+    return "number of redirects hit maximum amount";
+
+  case CURLE_UNKNOWN_TELNET_OPTION:
+    return "User specified an unknown option";
+
+  case CURLE_TELNET_OPTION_SYNTAX :
+    return "Malformed telnet option";
+
+  case CURLE_SSL_PEER_CERTIFICATE:
+    return "SSL peer certificate was not ok";
+
+  case CURLE_GOT_NOTHING:
+    return "server returned nothing (no headers, no data)";
+
+  case CURLE_SSL_ENGINE_NOTFOUND:
+    return "SSL crypto engine not found";
+
+  case CURLE_SSL_ENGINE_SETFAILED:
+    return "can not set SSL crypto engine as default";
+
+  case CURLE_SEND_ERROR:
+    return "failed sending data to the peer";
+
+  case CURLE_RECV_ERROR:
+    return "failure when receiving data from the peer";
+
+  case CURLE_SHARE_IN_USE:
+    return "share is already in use";
+
+  case CURLE_SSL_CERTPROBLEM:
+    return "problem with the local SSL certificate";
+
+  case CURLE_SSL_CIPHER:
+    return "couldn't use specified SSL cipher";
+
+  case CURLE_SSL_CACERT:
+    return "problem with the SSL CA cert (path? access rights?)";
+
+  case CURLE_BAD_CONTENT_ENCODING:
+    return "Unrecognized HTTP Content-Encoding";
+
+  case CURLE_LDAP_INVALID_URL:
+    return "Invalid LDAP URL";
+
+  case CURLE_FILESIZE_EXCEEDED:
+    return "Maximum file size exceeded";
+
+  case CURLE_FTP_SSL_FAILED:
+    return "Requested FTP SSL level failed";
+
+  case CURLE_URL_MALFORMAT_USER: /* not used by current libcurl */
+  case CURLE_MALFORMAT_USER:     /* not used by current libcurl */
+  case CURLE_BAD_CALLING_ORDER:  /* not used by current libcurl */
+  case CURLE_BAD_PASSWORD_ENTERED:/* not used by current libcurl */
+  case CURLE_OBSOLETE:           /* not used by current libcurl */
+  case CURL_LAST:
+    break;
+  }
+  /*
+   * By using a switch, gcc -Wall will complain about enum values
+   * which do not appear, helping keep this function up-to-date.
+   * By using gcc -Wall -Werror, you can't forget.
+   *
+   * A table would not have the same benefit.  Most compilers will
+   * generate code very similar to a table in any case, so there
+   * is little performance gain from a table.  And something is broken
+   * for the user's application, anyways, so does it matter how fast
+   * it _doesn't_ work?
+   *
+   * The line number for the error will be near this comment, which
+   * is why it is here, and not at the start of the switch.
+   */
+  return "unknown error";
+}
+
+const char *
+curl_multi_strerror(CURLMcode error)
+{
+  switch (error) {
+  case CURLM_CALL_MULTI_PERFORM:
+    return "please call curl_multi_perform() soon";
+    
+  case CURLM_OK:
+    return "no error";
+    
+  case CURLM_BAD_HANDLE:
+    return "invalid multi handle";
+
+  case CURLM_BAD_EASY_HANDLE:
+    return "invalid easy handle";
+
+  case CURLM_OUT_OF_MEMORY:
+    return "out of memory";
+
+  case CURLM_INTERNAL_ERROR:
+    return "internal error";
+
+  case CURLM_LAST:
+    break;
+  }
+
+  return "unknown error";
+}
+
+const char *
+curl_share_strerror(CURLSHcode error)
+{
+  switch (error) {
+  case CURLSHE_OK:
+    return "no error";
+
+  case CURLSHE_BAD_OPTION:
+    return "unknown share option";
+
+  case CURLSHE_IN_USE:
+    return "share currently in use";
+
+  case CURLSHE_INVALID:
+    return "invalid share handle";
+
+  case CURLSHE_NOMEM:
+    return "out of memory";
+
+  case CURLSHE_LAST:
+    break;
+  }
+
+  return "CURLSH unknown";
+}
+
+#if defined(WIN32) && !defined(__CYGWIN__)
+
+/* This function handles most / all (?) Winsock errors cURL is able to produce.
+ */
+static const char *
+get_winsock_error (int err, char *buf, size_t len)
+{
+  char *p;
+
+  switch (err) {
+  case WSAEINTR:
+    p = "Call interrupted.";
+    break;
+  case WSAEBADF:
+    p = "Bad file";
+    break;
+  case WSAEACCES:
+    p = "Bad access";
+    break;
+  case WSAEFAULT:
+    p = "Bad argument";
+    break;
+  case WSAEINVAL:
+    p = "Invalid arguments";
+    break;
+  case WSAEMFILE:
+    p = "Out of file descriptors";
+    break;
+  case WSAEWOULDBLOCK:
+    p = "Call would block";
+    break;
+  case WSAEINPROGRESS:
+  case WSAEALREADY:
+    p = "Blocking call in progress";
+    break;
+  case WSAENOTSOCK:
+    p = "Descriptor is not a socket.";
+    break;
+  case WSAEDESTADDRREQ:
+    p = "Need destination address";
+    break;
+  case WSAEMSGSIZE:
+    p = "Bad message size";
+    break;
+  case WSAEPROTOTYPE:
+    p = "Bad protocol";
+    break;
+  case WSAENOPROTOOPT:
+    p = "Protocol option is unsupported";
+    break;
+  case WSAEPROTONOSUPPORT:
+    p = "Protocol is unsupported";
+    break;
+  case WSAESOCKTNOSUPPORT:
+    p = "Socket is unsupported";
+    break;
+  case WSAEOPNOTSUPP:
+    p = "Operation not supported";
+    break;
+  case WSAEAFNOSUPPORT:
+    p = "Address family not supported";
+    break;
+  case WSAEPFNOSUPPORT:
+    p = "Protocol family not supported";
+    break;
+  case WSAEADDRINUSE:
+    p = "Address already in use";
+    break;
+  case WSAEADDRNOTAVAIL:
+    p = "Address not available";
+    break;
+  case WSAENETDOWN:
+    p = "Network down";
+    break;
+  case WSAENETUNREACH:
+    p = "Network unreachable";
+    break;
+  case WSAENETRESET:
+    p = "Network has been reset";
+    break;
+  case WSAECONNABORTED:
+    p = "Connection was aborted";
+    break;
+  case WSAECONNRESET:
+    p = "Connection was reset";
+    break;
+  case WSAENOBUFS:
+    p = "No buffer space";
+    break;
+  case WSAEISCONN:
+    p = "Socket is already connected";
+    break;
+  case WSAENOTCONN:
+    p = "Socket is not connected";
+    break;
+  case WSAESHUTDOWN:
+    p = "Socket has been shut down";
+    break;
+  case WSAETOOMANYREFS:
+    p = "Too many references";
+    break;
+  case WSAETIMEDOUT:
+    p = "Timed out";
+    break;
+  case WSAECONNREFUSED:
+    p = "Connection refused";
+    break;
+  case WSAELOOP:
+    p = "Loop??";
+    break;
+  case WSAENAMETOOLONG:
+    p = "Name too long";
+    break;
+  case WSAEHOSTDOWN:
+    p = "Host down";
+    break;
+  case WSAEHOSTUNREACH:
+    p = "Host unreachable";
+    break;
+  case WSAENOTEMPTY:
+    p = "Not empty";
+    break;
+  case WSAEPROCLIM:
+    p = "Process limit reached";
+    break;
+  case WSAEUSERS:
+    p = "Too many users";
+    break;
+  case WSAEDQUOT:
+    p = "Bad quota";
+    break;
+  case WSAESTALE:
+    p = "Something is stale";
+    break;
+  case WSAEREMOTE:
+    p = "Remote error";
+    break;
+  case WSAEDISCON:
+    p = "Disconnected";
+    break;
+
+    /* Extended Winsock errors */
+  case WSASYSNOTREADY:
+    p = "Winsock library is not ready";
+    break;
+  case WSANOTINITIALISED:
+    p = "Winsock library not initalised";
+    break;
+  case WSAVERNOTSUPPORTED:
+    p = "Winsock version not supported.";
+    break;
+
+    /* getXbyY() errors (already handled in herrmsg):
+     * Authoritative Answer: Host not found */
+  case WSAHOST_NOT_FOUND:
+    p = "Host not found";
+    break;
+
+    /* Non-Authoritative: Host not found, or SERVERFAIL */
+  case WSATRY_AGAIN:
+    p = "Host not found, try again";
+    break;
+
+    /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
+  case WSANO_RECOVERY:
+    p = "Unrecoverable error in call to nameserver";
+    break;
+
+    /* Valid name, no data record of requested type */
+  case WSANO_DATA:
+    p = "No data record of requested type";
+    break;
+
+  default:
+    return NULL;
+  }
+  strncpy (buf, p, len);
+  buf [len-1] = '\0';
+  return buf;
+}
+#endif   /* WIN32 && !__CYGWIN__ */
+
+/*
+ * Our thread-safe and smart strerror() replacement.
+ *
+ * The 'err' argument passed in to this function MUST be a true errno number
+ * as reported on this system. We do no range checking on the number before
+ * we pass it to the "number-to-message" convertion function and there might
+ * be systems that don't do proper range checking in there themselves.
+ *
+ * We don't do range checking (on systems other than Windows) since there is
+ * no good reliable and portable way to do it.
+ */
+const char *Curl_strerror(struct connectdata *conn, int err)
+{
+  char *buf, *p;
+  size_t max;
+
+  curlassert(conn);
+  curlassert(err >= 0);
+
+  buf = conn->syserr_buf;
+  max = sizeof(conn->syserr_buf)-1;
+  *buf = '\0';
+
+#if defined(WIN32) && !defined(__CYGWIN__)
+  /* 'sys_nerr' is the maximum errno number, it is not widely portable */
+  if (err >= 0 && err < sys_nerr)
+    strncpy(buf, strerror(err), max);
+  else {
+    if (!get_winsock_error (err, buf, max) &&
+        !FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
+                        LANG_NEUTRAL, buf, max, NULL))
+      snprintf(buf, max, "Unknown error %d (%#x)", err, err);
+  }
+#else /* not native Windows coming up */
+    
+  /* These should be atomic and hopefully thread-safe */
+#ifdef HAVE_STRERROR_R
+  /* There are two different APIs for strerror_r(). The POSIX and the GLIBC
+     versions. */
+#ifdef HAVE_POSIX_STRERROR_R
+  strerror_r(err, buf, max); 
+  /* this may set errno to ERANGE if insufficient storage was supplied via
+     'strerrbuf' and 'buflen' to contain the generated message string, or
+     EINVAL if the value of 'errnum' is not a valid error number.*/
+#else
+  {
+    /* HAVE_GLIBC_STRERROR_R */
+    char buffer[256];
+    char *msg = strerror_r(err, buffer, sizeof(buffer));
+    /* this version of strerror_r() only *might* use the buffer we pass to
+       the function, but it always returns the error message as a pointer,
+       so we must copy that string unconditionally */
+    if ( !msg )
+      {
+      msg = "Unknown System Error";
+      }
+    strncpy(buf, msg, max);
+  }
+#endif /* end of HAVE_GLIBC_STRERROR_R */
+#else /* HAVE_STRERROR_R */
+  {
+    char *msg = strerror(err);
+    if ( !msg )
+      {
+      msg = "Unknown System Error";
+      }
+    strncpy(buf, msg, max);
+  }
+#endif /* end of HAVE_STRERROR_R */
+#endif /* end of ! Windows */
+
+  buf[max] = '\0'; /* make sure the string is zero terminated */
+
+  /* strip trailing '\r\n' or '\n'. */
+  if ((p = strrchr(buf,'\n')) != NULL && (p - buf) >= 2)
+     *p = '\0';
+  if ((p = strrchr(buf,'\r')) != NULL && (p - buf) >= 1)
+     *p = '\0';
+  return buf;
+}
diff --git a/Utilities/cmcurl/strerror.h b/Utilities/cmcurl/strerror.h
new file mode 100644
index 0000000..7d68723
--- /dev/null
+++ b/Utilities/cmcurl/strerror.h
@@ -0,0 +1,30 @@
+#ifndef __CURL_STRERROR_H
+#define __CURL_STRERROR_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "urldata.h"
+
+const char *Curl_strerror (struct connectdata *conn, int err);
+
+#endif
diff --git a/Utilities/cmcurl/strtok.c b/Utilities/cmcurl/strtok.c
new file mode 100644
index 0000000..630e4e0
--- /dev/null
+++ b/Utilities/cmcurl/strtok.c
@@ -0,0 +1,68 @@
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#ifndef HAVE_STRTOK_R
+#include <stddef.h>
+#include <string.h>
+
+#include "strtok.h"
+
+char *
+Curl_strtok_r(char *ptr, const char *sep, char **end)
+{
+  if (!ptr)
+    /* we got NULL input so then we get our last position instead */
+    ptr = *end;
+
+  /* pass all letters that are including in the separator string */
+  while (*ptr && strchr(sep, *ptr))
+    ++ptr;
+
+  if (*ptr) {
+    /* so this is where the next piece of string starts */
+    char *start = ptr;
+
+    /* set the end pointer to the first byte after the start */
+    *end = start + 1;
+
+    /* scan through the string to find where it ends, it ends on a
+       null byte or a character that exists in the separator string */
+    while (**end && !strchr(sep, **end))
+      ++*end;
+
+    if (**end) {
+      /* the end is not a null byte */
+      **end = '\0';  /* zero terminate it! */
+      ++*end;        /* advance the last pointer to beyond the null byte */
+    }
+
+    return start; /* return the position where the string starts */
+  }
+
+  /* we ended up on a null byte, there are no more strings to find! */
+  return NULL;
+}
+
+#endif /* this was only compiled if strtok_r wasn't present */
diff --git a/Utilities/cmcurl/strtok.h b/Utilities/cmcurl/strtok.h
new file mode 100644
index 0000000..cf9fac8
--- /dev/null
+++ b/Utilities/cmcurl/strtok.h
@@ -0,0 +1,38 @@
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#ifndef _CURL_STRTOK_R_H
+#define _CURL_STRTOK_R_H
+
+#include "setup.h"
+#include <stddef.h>
+
+#ifndef HAVE_STRTOK_R
+char *Curl_strtok_r(char *s, const char *delim, char **last);
+#define strtok_r Curl_strtok_r
+#else
+#include <string.h>
+#endif
+
+#endif
+
diff --git a/Utilities/cmcurl/strtoofft.c b/Utilities/cmcurl/strtoofft.c
new file mode 100644
index 0000000..e2b02c4
--- /dev/null
+++ b/Utilities/cmcurl/strtoofft.c
@@ -0,0 +1,164 @@
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+#include "strtoofft.h"
+
+#ifdef NEED_CURL_STRTOLL
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+static int get_char(char c, int base);
+
+/**
+ * Emulated version of the strtoll function.  This extracts a long long
+ * value from the given input string and returns it.
+ */
+curl_off_t
+curlx_strtoll(const char *nptr, char **endptr, int base)
+{
+  char *end;
+  int is_negative = 0;
+  int overflow;
+  int i;
+  curl_off_t value = 0;
+  curl_off_t newval;
+
+  /* Skip leading whitespace. */
+  end = (char *)nptr;
+  while (isspace((int)end[0])) {
+    end++;
+  }
+
+  /* Handle the sign, if any. */
+  if (end[0] == '-') {
+    is_negative = 1;
+    end++;
+  }
+  else if (end[0] == '+') {
+    end++;
+  }
+  else if (end[0] == '\0') {
+    /* We had nothing but perhaps some whitespace -- there was no number. */
+    if (endptr) {
+      *endptr = end;
+    }
+    return 0;
+  }
+
+  /* Handle special beginnings, if present and allowed. */
+  if (end[0] == '0' && end[1] == 'x') {
+    if (base == 16 || base == 0) {
+      end += 2;
+      base = 16;
+    }
+  }
+  else if (end[0] == '0') {
+    if (base == 8 || base == 0) {
+      end++;
+      base = 8;
+    }
+  }
+
+  /* Matching strtol, if the base is 0 and it doesn't look like
+   * the number is octal or hex, we assume it's base 10.
+   */
+  if (base == 0) {
+    base = 10;
+  }
+
+  /* Loop handling digits. */
+  value = 0;
+  overflow = 0;
+  for (i = get_char(end[0], base);
+       i != -1;
+       end++, i = get_char(end[0], base)) {
+    newval = base * value + i;
+    if (newval < value) {
+      /* We've overflowed. */
+      overflow = 1;
+      break;
+    }
+    else
+      value = newval;
+  }
+
+  if (!overflow) {
+    if (is_negative) {
+      /* Fix the sign. */
+      value *= -1;
+    }
+  }
+  else {
+#ifdef HAVE_LONG_LONG_CONSTANT
+    if (is_negative)
+      value = 0x8000000000000000LL;
+    else
+      value = 0x7FFFFFFFFFFFFFFFLL;
+#else
+    if (is_negative)
+      value = 0x8000000000000000L;
+    else
+      value = 0x7FFFFFFFFFFFFFFFL;
+#endif
+
+    errno = ERANGE;
+  }
+
+  if (endptr)
+    *endptr = end;
+
+  return value;
+}
+
+/**
+ * Returns the value of c in the given base, or -1 if c cannot
+ * be interpreted properly in that base (i.e., is out of range,
+ * is a null, etc.).
+ *
+ * @param c     the character to interpret according to base
+ * @param base  the base in which to interpret c
+ *
+ * @return  the value of c in base, or -1 if c isn't in range
+ */
+static int get_char(char c, int base)
+{
+  int value = -1;
+  if (c <= '9' && c >= '0') {
+    value = c - '0';
+  }
+  else if (c <= 'Z' && c >= 'A') {
+    value = c - 'A' + 10;
+  }
+  else if (c <= 'z' && c >= 'a') {
+    value = c - 'a' + 10;
+  }
+
+  if (value >= base) {
+    value = -1;
+  }
+
+  return value;
+}
+#endif  /* Only present if we need strtoll, but don't have it. */
diff --git a/Utilities/cmcurl/strtoofft.h b/Utilities/cmcurl/strtoofft.h
new file mode 100644
index 0000000..4c5d265
--- /dev/null
+++ b/Utilities/cmcurl/strtoofft.h
@@ -0,0 +1,62 @@
+#ifndef _CURL_STRTOOFFT_H
+#define _CURL_STRTOOFFT_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/*
+ * CAUTION: this header is designed to work when included by the app-side
+ * as well as the library. Do not mix with library internals!
+ */
+
+#include "setup.h"
+#include <stddef.h>
+#include <curl/curl.h> /* for the curl_off_t type */
+
+/* Determine what type of file offset conversion handling we wish to use.  For
+ * systems with a 32-bit curl_off_t type, we should use strtol.  For systems
+ * with a 64-bit curl_off_t type, we should use strtoll if it exists, and if
+ * not, should try to emulate its functionality.  At any rate, we define
+ * 'strtoofft' such that it can be used to work with curl_off_t's regardless.
+ */
+#if SIZEOF_CURL_OFF_T > 4
+#if HAVE_STRTOLL
+#define curlx_strtoofft strtoll
+#else /* HAVE_STRTOLL */
+
+/* For MSVC7 we can use _strtoi64() which seems to be a strtoll() clone */
+#if defined(_MSC_VER) && (_MSC_VER >= 1300)
+#define curlx_strtoofft _strtoi64
+#else /* MSVC7 or later */
+curl_off_t curlx_strtoll(const char *nptr, char **endptr, int base);
+#define curlx_strtoofft curlx_strtoll
+#define NEED_CURL_STRTOLL
+#endif /* MSVC7 or later */
+
+#endif /* HAVE_STRTOLL */
+#else /* SIZEOF_CURL_OFF_T > 4 */
+/* simply use strtol() to get 32bit numbers */
+#define curlx_strtoofft strtol
+#endif
+
+#endif
+
diff --git a/Utilities/cmcurl/telnet.c b/Utilities/cmcurl/telnet.c
new file mode 100644
index 0000000..98a1adf
--- /dev/null
+++ b/Utilities/cmcurl/telnet.c
@@ -0,0 +1,1389 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#ifndef CURL_DISABLE_TELNET
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+
+#if defined(WIN32)
+#include <time.h>
+#include <io.h>
+#else
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <netinet/in.h>
+#include <sys/time.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <netdb.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#include <sys/ioctl.h>
+#include <signal.h>
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "telnet.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#define  TELOPTS
+#define  TELCMDS
+
+#include "arpa_telnet.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#define SUBBUFSIZE 512
+
+#define CURL_SB_CLEAR(x)  x->subpointer = x->subbuffer;
+#define CURL_SB_TERM(x)   { x->subend = x->subpointer; CURL_SB_CLEAR(x); }
+#define CURL_SB_ACCUM(x,c) \
+  if (x->subpointer < (x->subbuffer+sizeof x->subbuffer)) { \
+    *x->subpointer++ = (c); \
+  }
+
+#define  CURL_SB_GET(x) ((*x->subpointer++)&0xff)
+#define  CURL_SB_PEEK(x)   ((*x->subpointer)&0xff)
+#define  CURL_SB_EOF(x) (x->subpointer >= x->subend)
+#define  CURL_SB_LEN(x) (x->subend - x->subpointer)
+
+#ifdef WIN32
+typedef FARPROC WSOCK2_FUNC;
+static CURLcode check_wsock2 ( struct SessionHandle *data );
+#endif
+
+static
+void telrcv(struct connectdata *,
+            unsigned char *inbuf,       /* Data received from socket */
+            ssize_t count);             /* Number of bytes received */
+
+static void printoption(struct SessionHandle *data,
+                        const char *direction,
+                        int cmd, int option);
+
+static void negotiate(struct connectdata *);
+static void send_negotiation(struct connectdata *, int cmd, int option);
+static void set_local_option(struct connectdata *, int cmd, int option);
+static void set_remote_option(struct connectdata *, int cmd, int option);
+
+static void printsub(struct SessionHandle *data,
+                     int direction, unsigned char *pointer,
+                     size_t length);
+static void suboption(struct connectdata *);
+
+/* For negotiation compliant to RFC 1143 */
+#define CURL_NO          0
+#define CURL_YES         1
+#define CURL_WANTYES     2
+#define CURL_WANTNO      3
+
+#define CURL_EMPTY       0
+#define CURL_OPPOSITE    1
+
+/*
+ * Telnet receiver states for fsm
+ */
+typedef enum
+{
+   CURL_TS_DATA = 0,
+   CURL_TS_IAC,
+   CURL_TS_WILL,
+   CURL_TS_WONT,
+   CURL_TS_DO,
+   CURL_TS_DONT,
+   CURL_TS_CR,
+   CURL_TS_SB,   /* sub-option collection */
+   CURL_TS_SE   /* looking for sub-option end */
+} TelnetReceive;
+
+struct TELNET {
+  int please_negotiate;
+  int already_negotiated;
+  int us[256];
+  int usq[256];
+  int us_preferred[256];
+  int him[256];
+  int himq[256];
+  int him_preferred[256];
+  char subopt_ttype[32];             /* Set with suboption TTYPE */
+  char subopt_xdisploc[128];          /* Set with suboption XDISPLOC */
+  struct curl_slist *telnet_vars; /* Environment variables */
+
+  /* suboptions */
+  char subbuffer[SUBBUFSIZE];
+  char *subpointer, *subend;      /* buffer for sub-options */
+
+  TelnetReceive telrcv_state;
+};
+
+#ifdef WIN32
+static CURLcode
+check_wsock2 ( struct SessionHandle *data )
+{
+  int err;
+  WORD wVersionRequested;
+  WSADATA wsaData;
+
+  curlassert(data);
+
+  /* telnet requires at least WinSock 2.0 so ask for it. */
+  wVersionRequested = MAKEWORD(2, 0);
+
+  err = WSAStartup(wVersionRequested, &wsaData);
+
+  /* We must've called this once already, so this call */
+  /* should always succeed.  But, just in case... */
+  if (err != 0) {
+    failf(data,"WSAStartup failed (%d)",err);
+    return CURLE_FAILED_INIT;
+  }
+
+  /* We have to have a WSACleanup call for every successful */
+  /* WSAStartup call. */
+  WSACleanup();
+
+  /* Check that our version is supported */
+  if (LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
+      HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) {
+      /* Our version isn't supported */
+      failf(data,"insufficient winsock version to support "
+            "telnet");
+      return CURLE_FAILED_INIT;
+  }
+
+  /* Our version is supported */
+  return CURLE_OK;
+}
+#endif
+static
+CURLcode init_telnet(struct connectdata *conn)
+{
+  struct TELNET *tn;
+
+  tn = (struct TELNET *)calloc(1, sizeof(struct TELNET));
+  if(!tn)
+    return CURLE_OUT_OF_MEMORY;
+
+  conn->proto.telnet = (void *)tn; /* make us known */
+
+  tn->telrcv_state = CURL_TS_DATA;
+
+  /* Init suboptions */
+  CURL_SB_CLEAR(tn);
+
+  /* Set the options we want by default */
+  tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
+  tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
+  tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
+  tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
+
+  return CURLE_OK;
+}
+
+static void negotiate(struct connectdata *conn)
+{
+  int i;
+  struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
+
+  for(i = 0;i < CURL_NTELOPTS;i++)
+  {
+    if(tn->us_preferred[i] == CURL_YES)
+      set_local_option(conn, i, CURL_YES);
+
+    if(tn->him_preferred[i] == CURL_YES)
+      set_remote_option(conn, i, CURL_YES);
+  }
+}
+
+static void printoption(struct SessionHandle *data,
+                        const char *direction, int cmd, int option)
+{
+  const char *fmt;
+  const char *opt;
+
+  if (data->set.verbose)
+  {
+    if (cmd == CURL_IAC)
+    {
+      if (CURL_TELCMD_OK(option))
+        Curl_infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
+      else
+        Curl_infof(data, "%s IAC %d\n", direction, option);
+    }
+    else
+    {
+      fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" :
+        (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0;
+      if (fmt)
+      {
+        if (CURL_TELOPT_OK(option))
+          opt = CURL_TELOPT(option);
+        else if (option == CURL_TELOPT_EXOPL)
+          opt = "EXOPL";
+        else
+          opt = NULL;
+
+        if(opt)
+          Curl_infof(data, "%s %s %s\n", direction, fmt, opt);
+        else
+          Curl_infof(data, "%s %s %d\n", direction, fmt, option);
+      }
+      else
+        Curl_infof(data, "%s %d %d\n", direction, cmd, option);
+    }
+  }
+}
+
+static void send_negotiation(struct connectdata *conn, int cmd, int option)
+{
+   unsigned char buf[3];
+
+   buf[0] = CURL_IAC;
+   buf[1] = cmd;
+   buf[2] = option;
+
+   (void)swrite(conn->sock[FIRSTSOCKET], buf, 3);
+
+   printoption(conn->data, "SENT", cmd, option);
+}
+
+static
+void set_remote_option(struct connectdata *conn, int option, int newstate)
+{
+  struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
+  if(newstate == CURL_YES)
+  {
+    switch(tn->him[option])
+    {
+      case CURL_NO:
+        tn->him[option] = CURL_WANTYES;
+        send_negotiation(conn, CURL_DO, option);
+        break;
+
+      case CURL_YES:
+        /* Already enabled */
+        break;
+
+      case CURL_WANTNO:
+        switch(tn->himq[option])
+        {
+          case CURL_EMPTY:
+            /* Already negotiating for CURL_YES, queue the request */
+            tn->himq[option] = CURL_OPPOSITE;
+            break;
+          case CURL_OPPOSITE:
+            /* Error: already queued an enable request */
+            break;
+        }
+        break;
+
+      case CURL_WANTYES:
+        switch(tn->himq[option])
+        {
+          case CURL_EMPTY:
+            /* Error: already negotiating for enable */
+            break;
+          case CURL_OPPOSITE:
+            tn->himq[option] = CURL_EMPTY;
+            break;
+        }
+        break;
+    }
+  }
+  else /* NO */
+  {
+    switch(tn->him[option])
+    {
+      case CURL_NO:
+        /* Already disabled */
+        break;
+
+      case CURL_YES:
+        tn->him[option] = CURL_WANTNO;
+        send_negotiation(conn, CURL_DONT, option);
+        break;
+
+      case CURL_WANTNO:
+        switch(tn->himq[option])
+        {
+          case CURL_EMPTY:
+            /* Already negotiating for NO */
+            break;
+          case CURL_OPPOSITE:
+            tn->himq[option] = CURL_EMPTY;
+            break;
+        }
+        break;
+
+      case CURL_WANTYES:
+        switch(tn->himq[option])
+        {
+          case CURL_EMPTY:
+            tn->himq[option] = CURL_OPPOSITE;
+            break;
+          case CURL_OPPOSITE:
+            break;
+        }
+        break;
+    }
+  }
+}
+
+static
+void rec_will(struct connectdata *conn, int option)
+{
+  struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
+  switch(tn->him[option])
+  {
+    case CURL_NO:
+      if(tn->him_preferred[option] == CURL_YES)
+      {
+        tn->him[option] = CURL_YES;
+        send_negotiation(conn, CURL_DO, option);
+      }
+      else
+      {
+        send_negotiation(conn, CURL_DONT, option);
+      }
+      break;
+
+    case CURL_YES:
+      /* Already enabled */
+      break;
+
+    case CURL_WANTNO:
+      switch(tn->himq[option])
+      {
+        case CURL_EMPTY:
+          /* Error: DONT answered by WILL */
+          tn->him[option] = CURL_NO;
+          break;
+        case CURL_OPPOSITE:
+          /* Error: DONT answered by WILL */
+          tn->him[option] = CURL_YES;
+          tn->himq[option] = CURL_EMPTY;
+          break;
+      }
+      break;
+
+    case CURL_WANTYES:
+      switch(tn->himq[option])
+      {
+        case CURL_EMPTY:
+          tn->him[option] = CURL_YES;
+          break;
+        case CURL_OPPOSITE:
+          tn->him[option] = CURL_WANTNO;
+          tn->himq[option] = CURL_EMPTY;
+          send_negotiation(conn, CURL_DONT, option);
+          break;
+      }
+      break;
+  }
+}
+
+static
+void rec_wont(struct connectdata *conn, int option)
+{
+  struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
+  switch(tn->him[option])
+  {
+    case CURL_NO:
+      /* Already disabled */
+      break;
+
+    case CURL_YES:
+      tn->him[option] = CURL_NO;
+      send_negotiation(conn, CURL_DONT, option);
+      break;
+
+    case CURL_WANTNO:
+      switch(tn->himq[option])
+      {
+        case CURL_EMPTY:
+          tn->him[option] = CURL_NO;
+          break;
+
+        case CURL_OPPOSITE:
+          tn->him[option] = CURL_WANTYES;
+          tn->himq[option] = CURL_EMPTY;
+          send_negotiation(conn, CURL_DO, option);
+          break;
+      }
+      break;
+
+    case CURL_WANTYES:
+      switch(tn->himq[option])
+      {
+        case CURL_EMPTY:
+          tn->him[option] = CURL_NO;
+          break;
+        case CURL_OPPOSITE:
+          tn->him[option] = CURL_NO;
+          tn->himq[option] = CURL_EMPTY;
+          break;
+      }
+      break;
+  }
+}
+
+static void
+set_local_option(struct connectdata *conn, int option, int newstate)
+{
+  struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
+  if(newstate == CURL_YES)
+  {
+    switch(tn->us[option])
+    {
+      case CURL_NO:
+        tn->us[option] = CURL_WANTYES;
+        send_negotiation(conn, CURL_WILL, option);
+        break;
+
+      case CURL_YES:
+        /* Already enabled */
+        break;
+
+      case CURL_WANTNO:
+        switch(tn->usq[option])
+        {
+          case CURL_EMPTY:
+            /* Already negotiating for CURL_YES, queue the request */
+            tn->usq[option] = CURL_OPPOSITE;
+            break;
+          case CURL_OPPOSITE:
+            /* Error: already queued an enable request */
+            break;
+        }
+        break;
+
+      case CURL_WANTYES:
+        switch(tn->usq[option])
+        {
+          case CURL_EMPTY:
+            /* Error: already negotiating for enable */
+            break;
+          case CURL_OPPOSITE:
+            tn->usq[option] = CURL_EMPTY;
+            break;
+        }
+        break;
+    }
+  }
+  else /* NO */
+  {
+    switch(tn->us[option])
+    {
+      case CURL_NO:
+        /* Already disabled */
+        break;
+
+      case CURL_YES:
+        tn->us[option] = CURL_WANTNO;
+        send_negotiation(conn, CURL_WONT, option);
+        break;
+
+      case CURL_WANTNO:
+        switch(tn->usq[option])
+        {
+          case CURL_EMPTY:
+            /* Already negotiating for NO */
+            break;
+          case CURL_OPPOSITE:
+            tn->usq[option] = CURL_EMPTY;
+            break;
+        }
+        break;
+
+      case CURL_WANTYES:
+        switch(tn->usq[option])
+        {
+          case CURL_EMPTY:
+            tn->usq[option] = CURL_OPPOSITE;
+            break;
+          case CURL_OPPOSITE:
+            break;
+        }
+        break;
+    }
+  }
+}
+
+static
+void rec_do(struct connectdata *conn, int option)
+{
+  struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
+  switch(tn->us[option])
+  {
+    case CURL_NO:
+      if(tn->us_preferred[option] == CURL_YES)
+      {
+        tn->us[option] = CURL_YES;
+        send_negotiation(conn, CURL_WILL, option);
+      }
+      else
+      {
+        send_negotiation(conn, CURL_WONT, option);
+      }
+      break;
+
+    case CURL_YES:
+      /* Already enabled */
+      break;
+
+    case CURL_WANTNO:
+      switch(tn->usq[option])
+      {
+        case CURL_EMPTY:
+          /* Error: DONT answered by WILL */
+          tn->us[option] = CURL_NO;
+          break;
+        case CURL_OPPOSITE:
+          /* Error: DONT answered by WILL */
+          tn->us[option] = CURL_YES;
+          tn->usq[option] = CURL_EMPTY;
+          break;
+      }
+      break;
+
+    case CURL_WANTYES:
+      switch(tn->usq[option])
+      {
+        case CURL_EMPTY:
+          tn->us[option] = CURL_YES;
+          break;
+        case CURL_OPPOSITE:
+          tn->us[option] = CURL_WANTNO;
+          tn->himq[option] = CURL_EMPTY;
+          send_negotiation(conn, CURL_WONT, option);
+          break;
+      }
+      break;
+  }
+}
+
+static
+void rec_dont(struct connectdata *conn, int option)
+{
+  struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
+  switch(tn->us[option])
+  {
+    case CURL_NO:
+      /* Already disabled */
+      break;
+
+    case CURL_YES:
+      tn->us[option] = CURL_NO;
+      send_negotiation(conn, CURL_WONT, option);
+      break;
+
+    case CURL_WANTNO:
+      switch(tn->usq[option])
+      {
+        case CURL_EMPTY:
+          tn->us[option] = CURL_NO;
+          break;
+
+        case CURL_OPPOSITE:
+          tn->us[option] = CURL_WANTYES;
+          tn->usq[option] = CURL_EMPTY;
+          send_negotiation(conn, CURL_WILL, option);
+          break;
+      }
+      break;
+
+    case CURL_WANTYES:
+      switch(tn->usq[option])
+      {
+        case CURL_EMPTY:
+          tn->us[option] = CURL_NO;
+          break;
+        case CURL_OPPOSITE:
+          tn->us[option] = CURL_NO;
+          tn->usq[option] = CURL_EMPTY;
+          break;
+      }
+      break;
+  }
+}
+
+
+static void printsub(struct SessionHandle *data,
+                     int direction,             /* '<' or '>' */
+                     unsigned char *pointer,    /* where suboption data is */
+                     size_t length)             /* length of suboption data */
+{
+  unsigned int i = 0;
+
+  if (data->set.verbose)
+  {
+    if (direction)
+    {
+      Curl_infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
+      if (length >= 3)
+      {
+        int j;
+
+        i = pointer[length-2];
+        j = pointer[length-1];
+
+        if (i != CURL_IAC || j != CURL_SE)
+        {
+          Curl_infof(data, "(terminated by ");
+          if (CURL_TELOPT_OK(i))
+            Curl_infof(data, "%s ", CURL_TELOPT(i));
+          else if (CURL_TELCMD_OK(i))
+            Curl_infof(data, "%s ", CURL_TELCMD(i));
+          else
+            Curl_infof(data, "%d ", i);
+          if (CURL_TELOPT_OK(j))
+            Curl_infof(data, "%s", CURL_TELOPT(j));
+          else if (CURL_TELCMD_OK(j))
+            Curl_infof(data, "%s", CURL_TELCMD(j));
+          else
+            Curl_infof(data, "%d", j);
+          Curl_infof(data, ", not IAC SE!) ");
+        }
+      }
+      length -= 2;
+    }
+    if (length < 1)
+    {
+      Curl_infof(data, "(Empty suboption?)");
+      return;
+    }
+
+    if (CURL_TELOPT_OK(pointer[0])) {
+      switch(pointer[0]) {
+        case CURL_TELOPT_TTYPE:
+        case CURL_TELOPT_XDISPLOC:
+        case CURL_TELOPT_NEW_ENVIRON:
+          Curl_infof(data, "%s", CURL_TELOPT(pointer[0]));
+          break;
+        default:
+          Curl_infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
+          break;
+      }
+    }
+    else
+      Curl_infof(data, "%d (unknown)", pointer[i]);
+
+    switch(pointer[1]) {
+      case CURL_TELQUAL_IS:
+        Curl_infof(data, " IS");
+        break;
+      case CURL_TELQUAL_SEND:
+        Curl_infof(data, " SEND");
+        break;
+      case CURL_TELQUAL_INFO:
+        Curl_infof(data, " INFO/REPLY");
+        break;
+      case CURL_TELQUAL_NAME:
+        Curl_infof(data, " NAME");
+        break;
+    }
+
+    switch(pointer[0]) {
+      case CURL_TELOPT_TTYPE:
+      case CURL_TELOPT_XDISPLOC:
+        pointer[length] = 0;
+        Curl_infof(data, " \"%s\"", &pointer[2]);
+        break;
+      case CURL_TELOPT_NEW_ENVIRON:
+        if(pointer[1] == CURL_TELQUAL_IS) {
+          Curl_infof(data, " ");
+          for(i = 3;i < length;i++) {
+            switch(pointer[i]) {
+              case CURL_NEW_ENV_VAR:
+                Curl_infof(data, ", ");
+                break;
+              case CURL_NEW_ENV_VALUE:
+                Curl_infof(data, " = ");
+                break;
+              default:
+                Curl_infof(data, "%c", pointer[i]);
+                break;
+            }
+          }
+        }
+        break;
+      default:
+        for (i = 2; i < length; i++)
+          Curl_infof(data, " %.2x", pointer[i]);
+        break;
+    }
+
+    if (direction)
+    {
+      Curl_infof(data, "\n");
+    }
+  }
+}
+
+static CURLcode check_telnet_options(struct connectdata *conn)
+{
+  struct curl_slist *head;
+  char option_keyword[128];
+  char option_arg[256];
+  char *buf;
+  struct SessionHandle *data = conn->data;
+  struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
+
+  /* Add the user name as an environment variable if it
+     was given on the command line */
+  if(conn->bits.user_passwd)
+  {
+    snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
+    tn->telnet_vars = curl_slist_append(tn->telnet_vars, option_arg);
+
+    tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
+  }
+
+  for(head = data->set.telnet_options; head; head=head->next) {
+    if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
+              option_keyword, option_arg) == 2) {
+
+      /* Terminal type */
+      if(curl_strequal(option_keyword, "TTYPE")) {
+        strncpy(tn->subopt_ttype, option_arg, 31);
+        tn->subopt_ttype[31] = 0; /* String termination */
+        tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
+        continue;
+      }
+
+      /* Display variable */
+      if(curl_strequal(option_keyword, "XDISPLOC")) {
+        strncpy(tn->subopt_xdisploc, option_arg, 127);
+        tn->subopt_xdisploc[127] = 0; /* String termination */
+        tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
+        continue;
+      }
+
+      /* Environment variable */
+      if(curl_strequal(option_keyword, "NEW_ENV")) {
+        buf = strdup(option_arg);
+        if(!buf)
+          return CURLE_OUT_OF_MEMORY;
+        tn->telnet_vars = curl_slist_append(tn->telnet_vars, buf);
+        tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
+        continue;
+      }
+
+      failf(data, "Unknown telnet option %s", head->data);
+      return CURLE_UNKNOWN_TELNET_OPTION;
+    } else {
+      failf(data, "Syntax error in telnet option: %s", head->data);
+      return CURLE_TELNET_OPTION_SYNTAX;
+    }
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * suboption()
+ *
+ * Look at the sub-option buffer, and try to be helpful to the other
+ * side.
+ */
+
+static void suboption(struct connectdata *conn)
+{
+  struct curl_slist *v;
+  unsigned char temp[2048];
+  size_t len;
+  size_t tmplen;
+  char varname[128];
+  char varval[128];
+  struct SessionHandle *data = conn->data;
+  struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
+
+  printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2);
+  switch (CURL_SB_GET(tn)) {
+    case CURL_TELOPT_TTYPE:
+      len = strlen(tn->subopt_ttype) + 4 + 2;
+      snprintf((char *)temp, sizeof(temp),
+               "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
+               CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
+      (void)swrite(conn->sock[FIRSTSOCKET], temp, len);
+      printsub(data, '>', &temp[2], len-2);
+      break;
+    case CURL_TELOPT_XDISPLOC:
+      len = strlen(tn->subopt_xdisploc) + 4 + 2;
+      snprintf((char *)temp, sizeof(temp),
+               "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
+               CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
+      (void)swrite(conn->sock[FIRSTSOCKET], temp, len);
+      printsub(data, '>', &temp[2], len-2);
+      break;
+    case CURL_TELOPT_NEW_ENVIRON:
+      snprintf((char *)temp, sizeof(temp),
+               "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
+               CURL_TELQUAL_IS);
+      len = 4;
+
+      for(v = tn->telnet_vars;v;v = v->next) {
+        tmplen = (strlen(v->data) + 1);
+        /* Add the variable only if it fits */
+        if(len + tmplen < (int)sizeof(temp)-6) {
+          sscanf(v->data, "%127[^,],%127s", varname, varval);
+          snprintf((char *)&temp[len], sizeof(temp) - len,
+                   "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
+                   CURL_NEW_ENV_VALUE, varval);
+          len += tmplen;
+        }
+      }
+      snprintf((char *)&temp[len], sizeof(temp) - len,
+               "%c%c", CURL_IAC, CURL_SE);
+      len += 2;
+      (void)swrite(conn->sock[FIRSTSOCKET], temp, len);
+      printsub(data, '>', &temp[2], len-2);
+      break;
+  }
+  return;
+}
+
+static
+void telrcv(struct connectdata *conn,
+            unsigned char *inbuf,       /* Data received from socket */
+            ssize_t count)              /* Number of bytes received */
+{
+  unsigned char c;
+  int in = 0;
+  struct SessionHandle *data = conn->data;
+  struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
+
+  while(count--)
+  {
+    c = inbuf[in++];
+
+    switch (tn->telrcv_state)
+    {
+      case CURL_TS_CR:
+        tn->telrcv_state = CURL_TS_DATA;
+        if (c == '\0')
+        {
+          break;   /* Ignore \0 after CR */
+        }
+
+        Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
+        continue;
+
+      case CURL_TS_DATA:
+        if (c == CURL_IAC)
+        {
+          tn->telrcv_state = CURL_TS_IAC;
+          break;
+        }
+        else if(c == '\r')
+        {
+          tn->telrcv_state = CURL_TS_CR;
+        }
+
+        Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
+        continue;
+
+      case CURL_TS_IAC:
+      process_iac:
+      switch (c)
+      {
+        case CURL_WILL:
+          tn->telrcv_state = CURL_TS_WILL;
+          continue;
+        case CURL_WONT:
+          tn->telrcv_state = CURL_TS_WONT;
+          continue;
+        case CURL_DO:
+          tn->telrcv_state = CURL_TS_DO;
+          continue;
+        case CURL_DONT:
+          tn->telrcv_state = CURL_TS_DONT;
+          continue;
+        case CURL_SB:
+          CURL_SB_CLEAR(tn);
+          tn->telrcv_state = CURL_TS_SB;
+          continue;
+        case CURL_IAC:
+          Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
+          break;
+        case CURL_DM:
+        case CURL_NOP:
+        case CURL_GA:
+        default:
+          printoption(data, "RCVD", CURL_IAC, c);
+          break;
+      }
+      tn->telrcv_state = CURL_TS_DATA;
+      continue;
+
+      case CURL_TS_WILL:
+        printoption(data, "RCVD", CURL_WILL, c);
+        tn->please_negotiate = 1;
+        rec_will(conn, c);
+        tn->telrcv_state = CURL_TS_DATA;
+        continue;
+
+      case CURL_TS_WONT:
+        printoption(data, "RCVD", CURL_WONT, c);
+        tn->please_negotiate = 1;
+        rec_wont(conn, c);
+        tn->telrcv_state = CURL_TS_DATA;
+        continue;
+
+      case CURL_TS_DO:
+        printoption(data, "RCVD", CURL_DO, c);
+        tn->please_negotiate = 1;
+        rec_do(conn, c);
+        tn->telrcv_state = CURL_TS_DATA;
+        continue;
+
+      case CURL_TS_DONT:
+        printoption(data, "RCVD", CURL_DONT, c);
+        tn->please_negotiate = 1;
+        rec_dont(conn, c);
+        tn->telrcv_state = CURL_TS_DATA;
+        continue;
+
+      case CURL_TS_SB:
+        if (c == CURL_IAC)
+        {
+          tn->telrcv_state = CURL_TS_SE;
+        }
+        else
+        {
+          CURL_SB_ACCUM(tn,c);
+        }
+        continue;
+
+      case CURL_TS_SE:
+        if (c != CURL_SE)
+        {
+          if (c != CURL_IAC)
+          {
+            /*
+             * This is an error.  We only expect to get
+             * "IAC IAC" or "IAC SE".  Several things may
+             * have happend.  An IAC was not doubled, the
+             * IAC SE was left off, or another option got
+             * inserted into the suboption are all possibilities.
+             * If we assume that the IAC was not doubled,
+             * and really the IAC SE was left off, we could
+             * get into an infinate loop here.  So, instead,
+             * we terminate the suboption, and process the
+             * partial suboption if we can.
+             */
+            CURL_SB_ACCUM(tn, (unsigned char)CURL_IAC);
+            CURL_SB_ACCUM(tn, c);
+            tn->subpointer -= 2;
+            CURL_SB_TERM(tn);
+
+            printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
+            suboption(conn);   /* handle sub-option */
+            tn->telrcv_state = CURL_TS_IAC;
+            goto process_iac;
+          }
+          CURL_SB_ACCUM(tn,c);
+          tn->telrcv_state = CURL_TS_SB;
+        }
+        else
+        {
+          CURL_SB_ACCUM(tn, (unsigned char)CURL_IAC);
+          CURL_SB_ACCUM(tn, (unsigned char)CURL_SE);
+          tn->subpointer -= 2;
+          CURL_SB_TERM(tn);
+          suboption(conn);   /* handle sub-option */
+          tn->telrcv_state = CURL_TS_DATA;
+        }
+        break;
+    }
+  }
+}
+
+CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode status)
+{
+  struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
+  (void)status; /* unused */
+
+  curl_slist_free_all(tn->telnet_vars);
+
+  free(conn->proto.telnet);
+  conn->proto.telnet = NULL;
+
+  return CURLE_OK;
+}
+
+CURLcode Curl_telnet(struct connectdata *conn)
+{
+  CURLcode code;
+  struct SessionHandle *data = conn->data;
+  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+#ifdef WIN32
+  HMODULE wsock2;
+  WSOCK2_FUNC close_event_func;
+  WSOCK2_FUNC create_event_func;
+  WSOCK2_FUNC event_select_func;
+  WSOCK2_FUNC enum_netevents_func;
+  WSAEVENT event_handle;
+  WSANETWORKEVENTS events;
+  HANDLE stdin_handle;
+  HANDLE objs[2];
+  DWORD  obj_count;
+  DWORD  wait_timeout;
+  DWORD waitret;
+  DWORD readfile_read;
+#else
+  fd_set readfd;
+  fd_set keepfd;
+#endif
+  ssize_t nread;
+  bool keepon = TRUE;
+  char *buf = data->state.buffer;
+  struct TELNET *tn;
+
+  code = init_telnet(conn);
+  if(code)
+    return code;
+
+  tn = (struct TELNET *)conn->proto.telnet;
+
+  code = check_telnet_options(conn);
+  if(code)
+    return code;
+
+#ifdef WIN32
+  /*
+  ** This functionality only works with WinSock >= 2.0.  So,
+  ** make sure have it.
+  */
+  code = check_wsock2(data);
+  if (code)
+    return code;
+
+  /* OK, so we have WinSock 2.0.  We need to dynamically */
+  /* load ws2_32.dll and get the function pointers we need. */
+  wsock2 = LoadLibrary("WS2_32.DLL");
+  if (wsock2 == NULL) {
+    failf(data,"failed to load WS2_32.DLL (%d)",GetLastError());
+    return CURLE_FAILED_INIT;
+  }
+
+  /* Grab a pointer to WSACreateEvent */
+  create_event_func = GetProcAddress(wsock2,"WSACreateEvent");
+  if (create_event_func == NULL) {
+    failf(data,"failed to find WSACreateEvent function (%d)",
+          GetLastError());
+    FreeLibrary(wsock2);
+    return CURLE_FAILED_INIT;
+  }
+
+  /* And WSACloseEvent */
+  close_event_func = GetProcAddress(wsock2,"WSACloseEvent");
+  if (create_event_func == NULL) {
+    failf(data,"failed to find WSACloseEvent function (%d)",
+          GetLastError());
+    FreeLibrary(wsock2);
+    return CURLE_FAILED_INIT;
+  }
+
+  /* And WSAEventSelect */
+  event_select_func = GetProcAddress(wsock2,"WSAEventSelect");
+  if (event_select_func == NULL) {
+    failf(data,"failed to find WSAEventSelect function (%d)",
+          GetLastError());
+    FreeLibrary(wsock2);
+    return CURLE_FAILED_INIT;
+  }
+
+  /* And WSAEnumNetworkEvents */
+  enum_netevents_func = GetProcAddress(wsock2,"WSAEnumNetworkEvents");
+  if (enum_netevents_func == NULL) {
+    failf(data,"failed to find WSAEnumNetworkEvents function (%d)",
+          GetLastError());
+    FreeLibrary(wsock2);
+    return CURLE_FAILED_INIT;
+  }
+
+  /* We want to wait for both stdin and the socket. Since
+  ** the select() function in winsock only works on sockets
+  ** we have to use the WaitForMultipleObjects() call.
+  */
+
+  /* First, create a sockets event object */
+  event_handle = (WSAEVENT)create_event_func();
+  if (event_handle == WSA_INVALID_EVENT) {
+    failf(data,"WSACreateEvent failed (%d)",WSAGetLastError());
+    FreeLibrary(wsock2);
+    return CURLE_FAILED_INIT;
+  }
+
+  /* The get the Windows file handle for stdin */
+  stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
+
+  /* Create the list of objects to wait for */
+  objs[0] = event_handle;
+  objs[1] = stdin_handle;
+
+  /* Tell winsock what events we want to listen to */
+  if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) {
+    close_event_func(event_handle);
+    FreeLibrary(wsock2);
+    return 0;
+  }
+
+  /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
+     else use the old WaitForMultipleObjects() way */
+  if(GetFileType(stdin_handle) == FILE_TYPE_PIPE) {
+    /* Don't wait for stdin_handle, just wait for event_handle */
+    obj_count = 1;
+    /* Check stdin_handle per 100 milliseconds */
+    wait_timeout = 100;
+  } else {
+    obj_count = 2;
+    wait_timeout = INFINITE;
+  }
+
+  /* Keep on listening and act on events */
+  while(keepon) {
+    waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
+    switch(waitret) {
+    case WAIT_TIMEOUT:
+    {
+      unsigned char outbuf[2];
+      int out_count;
+      ssize_t bytes_written;
+      char *buffer = buf;
+
+      for(;;) {
+        if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) {
+          keepon = FALSE;
+          break;
+        }
+        nread = readfile_read;
+
+        if(!nread)
+          break;
+
+        if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
+                     &readfile_read, NULL)) {
+          keepon = FALSE;
+          break;
+        }
+        nread = readfile_read;
+
+        while(nread--) {
+          outbuf[0] = *buffer++;
+          out_count = 1;
+          if(outbuf[0] == CURL_IAC)
+            outbuf[out_count++] = CURL_IAC;
+
+          Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
+                     out_count, &bytes_written);
+        }
+      }
+    }
+    break;
+
+    case WAIT_OBJECT_0 + 1:
+    {
+      unsigned char outbuf[2];
+      int out_count;
+      ssize_t bytes_written;
+      char *buffer = buf;
+
+      if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
+                   &readfile_read, NULL)) {
+        keepon = FALSE;
+        break;
+      }
+      nread = readfile_read;
+
+      while(nread--) {
+        outbuf[0] = *buffer++;
+        out_count = 1;
+        if(outbuf[0] == CURL_IAC)
+          outbuf[out_count++] = CURL_IAC;
+
+        Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
+                   out_count, &bytes_written);
+      }
+    }
+    break;
+
+    case WAIT_OBJECT_0:
+      if(enum_netevents_func(sockfd, event_handle, &events)
+         != SOCKET_ERROR) {
+        if(events.lNetworkEvents & FD_READ) {
+          /* This reallu OUGHT to check its return code. */
+          (void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
+
+          telrcv(conn, (unsigned char *)buf, nread);
+
+          fflush(stdout);
+
+          /* Negotiate if the peer has started negotiating,
+             otherwise don't. We don't want to speak telnet with
+             non-telnet servers, like POP or SMTP. */
+          if(tn->please_negotiate && !tn->already_negotiated) {
+            negotiate(conn);
+            tn->already_negotiated = 1;
+          }
+        }
+
+        if(events.lNetworkEvents & FD_CLOSE) {
+          keepon = FALSE;
+        }
+      }
+      break;
+    }
+  }
+
+  /* We called WSACreateEvent, so call WSACloseEvent */
+  if (close_event_func(event_handle) == FALSE) {
+    infof(data,"WSACloseEvent failed (%d)",WSAGetLastError());
+  }
+
+  /* "Forget" pointers into the library we're about to free */
+  create_event_func = NULL;
+  close_event_func = NULL;
+  event_select_func = NULL;
+  enum_netevents_func = NULL;
+  (void)create_event_func;
+  (void)close_event_func;
+  (void)event_select_func;
+  (void)enum_netevents_func;
+
+  /* We called LoadLibrary, so call FreeLibrary */
+  if (!FreeLibrary(wsock2))
+    infof(data,"FreeLibrary(wsock2) failed (%d)",GetLastError());
+#else
+  FD_ZERO (&readfd);            /* clear it */
+  FD_SET (sockfd, &readfd);
+  FD_SET (0, &readfd);
+
+  keepfd = readfd;
+
+  while (keepon) {
+    struct timeval interval;
+
+    readfd = keepfd;            /* set this every lap in the loop */
+    interval.tv_sec = 1;
+    interval.tv_usec = 0;
+
+    switch (select (sockfd + 1, &readfd, NULL, NULL, &interval)) {
+    case -1:                    /* error, stop reading */
+      keepon = FALSE;
+      continue;
+    case 0:                     /* timeout */
+      break;
+    default:                    /* read! */
+      if(FD_ISSET(0, &readfd)) { /* read from stdin */
+        unsigned char outbuf[2];
+        int out_count = 0;
+        ssize_t bytes_written;
+        char *buffer = buf;
+
+        nread = read(0, buf, 255);
+
+        while(nread--) {
+          outbuf[0] = *buffer++;
+          out_count = 1;
+          if(outbuf[0] == CURL_IAC)
+            outbuf[out_count++] = CURL_IAC;
+
+          Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
+                     out_count, &bytes_written);
+        }
+      }
+
+      if(FD_ISSET(sockfd, &readfd)) {
+        /* This OUGHT to check the return code... */
+        (void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
+
+        /* if we receive 0 or less here, the server closed the connection and
+           we bail out from this! */
+        if (nread <= 0) {
+          keepon = FALSE;
+          break;
+        }
+
+        telrcv(conn, (unsigned char *)buf, nread);
+
+        /* Negotiate if the peer has started negotiating,
+           otherwise don't. We don't want to speak telnet with
+           non-telnet servers, like POP or SMTP. */
+        if(tn->please_negotiate && !tn->already_negotiated) {
+          negotiate(conn);
+          tn->already_negotiated = 1;
+        }
+      }
+    }
+    if(data->set.timeout) {
+      struct timeval now;           /* current time */
+      now = Curl_tvnow();
+      if(Curl_tvdiff(now, conn->created)/1000 >= data->set.timeout) {
+        failf(data, "Time-out");
+        code = CURLE_OPERATION_TIMEOUTED;
+        keepon = FALSE;
+      }
+    }
+  }
+#endif
+  /* mark this as "no further transfer wanted" */
+  Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+
+  return code;
+}
+#endif
diff --git a/Utilities/cmcurl/telnet.h b/Utilities/cmcurl/telnet.h
new file mode 100644
index 0000000..86dd99b
--- /dev/null
+++ b/Utilities/cmcurl/telnet.h
@@ -0,0 +1,30 @@
+#ifndef __TELNET_H
+#define __TELNET_H
+
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+#ifndef CURL_DISABLE_TELNET
+CURLcode Curl_telnet(struct connectdata *conn);
+CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode);
+#endif
+#endif
diff --git a/Utilities/cmcurl/timeval.c b/Utilities/cmcurl/timeval.c
new file mode 100644
index 0000000..499fba5
--- /dev/null
+++ b/Utilities/cmcurl/timeval.c
@@ -0,0 +1,116 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "timeval.h"
+
+#ifndef HAVE_GETTIMEOFDAY
+
+#ifdef WIN32
+#include <mmsystem.h>
+
+static int gettimeofday(struct timeval *tp, void *nothing)
+{
+#ifdef WITHOUT_MM_LIB
+  SYSTEMTIME st;
+  time_t tt;
+  struct tm tmtm;
+  /* mktime converts local to UTC */
+  GetLocalTime (&st);
+  tmtm.tm_sec = st.wSecond;
+  tmtm.tm_min = st.wMinute;
+  tmtm.tm_hour = st.wHour;
+  tmtm.tm_mday = st.wDay;
+  tmtm.tm_mon = st.wMonth - 1;
+  tmtm.tm_year = st.wYear - 1900;
+  tmtm.tm_isdst = -1;
+  tt = mktime (&tmtm);
+  tp->tv_sec = tt;
+  tp->tv_usec = st.wMilliseconds * 1000;
+#else
+  /**
+   ** The earlier time calculations using GetLocalTime
+   ** had a time resolution of 10ms.The timeGetTime, part
+   ** of multimedia apis offer a better time resolution
+   ** of 1ms.Need to link against winmm.lib for this
+   **/
+  unsigned long Ticks;
+  unsigned long Sec;
+  unsigned long Usec;
+  Ticks = timeGetTime();
+
+  Sec = Ticks/1000;
+  Usec = (Ticks - (Sec*1000))*1000;
+  tp->tv_sec = Sec;
+  tp->tv_usec = Usec;
+#endif /* WITHOUT_MM_LIB */
+  (void)nothing;
+  return 0;
+}
+#else /* WIN32 */
+/* non-win32 version of Curl_gettimeofday() */
+static int gettimeofday(struct timeval *tp, void *nothing)
+{
+  (void)nothing; /* we don't support specific time-zones */
+  tp->tv_sec = (long)time(NULL);
+  tp->tv_usec = 0;
+  return 0;
+}
+#endif /* WIN32 */
+#endif /* HAVE_GETTIMEOFDAY */
+
+/* Return the current time in a timeval struct */
+struct timeval curlx_tvnow(void)
+{
+  struct timeval now;
+  (void)gettimeofday(&now, NULL);
+  return now;
+}
+
+/*
+ * Make sure that the first argument is the more recent time, as otherwise
+ * we'll get a weird negative time-diff back...
+ *
+ * Returns: the time difference in number of milliseconds.
+ */
+long curlx_tvdiff(struct timeval newer, struct timeval older)
+{
+  return (newer.tv_sec-older.tv_sec)*1000+
+    (newer.tv_usec-older.tv_usec)/1000;
+}
+
+/*
+ * Same as curlx_tvdiff but with full usec resolution.
+ *
+ * Returns: the time difference in seconds with subsecond resolution.
+ */
+double curlx_tvdiff_secs(struct timeval newer, struct timeval older)
+{
+  return (double)(newer.tv_sec-older.tv_sec)+
+    (double)(newer.tv_usec-older.tv_usec)/1000000.0;
+}
+
+/* return the number of seconds in the given input timeval struct */
+long Curl_tvlong(struct timeval t1)
+{
+  return t1.tv_sec;
+}
diff --git a/Utilities/cmcurl/timeval.h b/Utilities/cmcurl/timeval.h
new file mode 100644
index 0000000..67b885a
--- /dev/null
+++ b/Utilities/cmcurl/timeval.h
@@ -0,0 +1,74 @@
+#ifndef __TIMEVAL_H
+#define __TIMEVAL_H
+/***************************************************************************
+ *                                  _   _ ____  _     
+ *  Project                     ___| | | |  _ \| |    
+ *                             / __| | | | |_) | |    
+ *                            | (__| |_| |  _ <| |___ 
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ * 
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/*
+ * CAUTION: this header is designed to work when included by the app-side
+ * as well as the library. Do not mix with library internals!
+ */
+
+#include "setup.h"
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif
+
+#ifndef HAVE_GETTIMEOFDAY
+#if !defined(_WINSOCKAPI_) && !defined(__MINGW32__) && !defined(_AMIGASF) && \
+    !defined(__LCC__)
+struct timeval {
+ long tv_sec;
+ long tv_usec;
+};
+#endif
+#endif
+
+struct timeval curlx_tvnow(void);
+
+/*
+ * Make sure that the first argument (t1) is the more recent time and t2 is
+ * the older time, as otherwise you get a weird negative time-diff back...
+ *
+ * Returns: the time difference in number of milliseconds.
+ */
+long curlx_tvdiff(struct timeval t1, struct timeval t2);
+
+/*
+ * Same as curlx_tvdiff but with full usec resolution.
+ *
+ * Returns: the time difference in seconds with subsecond resolution.
+ */
+double curlx_tvdiff_secs(struct timeval t1, struct timeval t2);
+
+long Curl_tvlong(struct timeval t1);
+
+/* These two defines below exist to provide the older API for library
+   internals only. */
+#define Curl_tvnow() curlx_tvnow()
+#define Curl_tvdiff(x,y) curlx_tvdiff(x,y)
+#define Curl_tvdiff_secs(x,y) curlx_tvdiff_secs(x,y)
+
+#endif
diff --git a/Utilities/cmcurl/transfer.c b/Utilities/cmcurl/transfer.c
new file mode 100644
index 0000000..4a108cc
--- /dev/null
+++ b/Utilities/cmcurl/transfer.c
@@ -0,0 +1,2191 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#include <sys/stat.h>
+
+#include <errno.h>
+
+#include "strtoofft.h"
+#include "strequal.h"
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#include <time.h>
+#include <io.h>
+#else
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#include <sys/time.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <netdb.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#include <signal.h>
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifndef HAVE_SELECT
+#error "We can't compile without select() support!"
+#endif
+#ifndef HAVE_SOCKET
+#error "We can't compile without socket() support!"
+#endif
+
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "netrc.h"
+
+#include "content_encoding.h"
+#include "hostip.h"
+#include "transfer.h"
+#include "sendf.h"
+#include "speedcheck.h"
+#include "progress.h"
+#include "getdate.h"
+#include "http.h"
+#include "url.h"
+#include "getinfo.h"
+#include "ssluse.h"
+#include "http_digest.h"
+#include "http_ntlm.h"
+#include "http_negotiate.h"
+#include "share.h"
+#include "curl_memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#define CURL_TIMEOUT_EXPECT_100 1000 /* counting ms here */
+
+enum {
+  KEEP_NONE,
+  KEEP_READ,
+  KEEP_WRITE
+};
+
+/* We keep this static and global since this is read-only and NEVER
+   changed. It should just remain a blanked-out timeout value. */
+static struct timeval notimeout={0,0};
+
+/*
+ * This function will call the read callback to fill our buffer with data
+ * to upload.
+ */
+CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
+{
+  struct SessionHandle *data = conn->data;
+  size_t buffersize = (size_t)bytes;
+  int nread;
+
+  if(conn->bits.upload_chunky) {
+    /* if chunked Transfer-Encoding */
+    buffersize -= (8 + 2 + 2);   /* 32bit hex + CRLF + CRLF */
+    conn->upload_fromhere += 10; /* 32bit hex + CRLF */
+  }
+
+  /* this function returns a size_t, so we typecast to int to prevent warnings
+     with picky compilers */
+  nread = (int)conn->fread(conn->upload_fromhere, 1,
+                           buffersize, conn->fread_in);
+
+  if(nread == CURL_READFUNC_ABORT) {
+    failf(data, "operation aborted by callback\n");
+    return CURLE_ABORTED_BY_CALLBACK;
+  }
+
+  if(!conn->bits.forbidchunk && conn->bits.upload_chunky) {
+    /* if chunked Transfer-Encoding */
+    char hexbuffer[11];
+    int hexlen = snprintf(hexbuffer, sizeof(hexbuffer),
+                          "%x\r\n", nread);
+    /* move buffer pointer */
+    conn->upload_fromhere -= hexlen;
+    nread += hexlen;
+
+    /* copy the prefix to the buffer */
+    memcpy(conn->upload_fromhere, hexbuffer, hexlen);
+
+    /* always append CRLF to the data */
+    memcpy(conn->upload_fromhere + nread, "\r\n", 2);
+
+    if((nread - hexlen) == 0) {
+      /* mark this as done once this chunk is transfered */
+      conn->keep.upload_done = TRUE;
+    }
+
+    nread+=2; /* for the added CRLF */
+  }
+
+  *nreadp = nread;
+
+  return CURLE_OK;
+}
+
+/*
+ * checkhttpprefix()
+ *
+ * Returns TRUE if member of the list matches prefix of string
+ */
+static bool
+checkhttpprefix(struct SessionHandle *data,
+                const char *s)
+{
+  struct curl_slist *head = data->set.http200aliases;
+
+  while (head) {
+    if (checkprefix(head->data, s))
+      return TRUE;
+    head = head->next;
+  }
+
+  if(checkprefix("HTTP/", s))
+    return TRUE;
+
+  return FALSE;
+}
+
+
+/*
+ * Curl_readwrite() is the low-level function to be called when data is to
+ * be read and written to/from the connection.
+ */
+CURLcode Curl_readwrite(struct connectdata *conn,
+                        bool *done)
+{
+  struct Curl_transfer_keeper *k = &conn->keep;
+  struct SessionHandle *data = conn->data;
+  CURLcode result;
+  ssize_t nread; /* number of bytes read */
+  int didwhat=0;
+
+  /* These two are used only if no other select() or _fdset() have been
+     invoked before this. This typicly happens if you use the multi interface
+     and call curl_multi_perform() without calling curl_multi_fdset()
+     first. */
+  fd_set extrareadfd;
+  fd_set extrawritefd;
+
+  fd_set *readfdp = k->readfdp;
+  fd_set *writefdp = k->writefdp;
+  curl_off_t contentlength;
+
+  if((k->keepon & KEEP_READ) && !readfdp) {
+    /* reading is requested, but no socket descriptor pointer was set */
+    FD_ZERO(&extrareadfd);
+    FD_SET(conn->sockfd, &extrareadfd);
+    readfdp = &extrareadfd;
+
+    /* no write, no exceptions, no timeout */
+    select(conn->sockfd+1, readfdp, NULL, NULL, &notimeout);
+  }
+  if((k->keepon & KEEP_WRITE) && !writefdp) {
+    /* writing is requested, but no socket descriptor pointer was set */
+    FD_ZERO(&extrawritefd);
+    FD_SET(conn->writesockfd, &extrawritefd);
+    writefdp = &extrawritefd;
+
+    /* no read, no exceptions, no timeout */
+    select(conn->writesockfd+1, NULL, writefdp, NULL, &notimeout);
+  }
+
+  do {
+    /* If we still have reading to do, we check if we have a readable
+       socket. Sometimes the reafdp is NULL, if no fd_set was done using
+       the multi interface and then we can do nothing but to attempt a
+       read to be sure. */
+    if((k->keepon & KEEP_READ) &&
+       (!readfdp || FD_ISSET(conn->sockfd, readfdp))) {
+
+      bool readdone = TRUE;
+
+      /* This is where we loop until we have read everything there is to
+         read or we get a EWOULDBLOCK */
+      do {
+        size_t buffersize = data->set.buffer_size?
+          data->set.buffer_size:BUFSIZE -1;
+
+        /* receive data from the network! */
+        int readrc = Curl_read(conn, conn->sockfd, k->buf, buffersize, &nread);
+
+        /* subzero, this would've blocked */
+        if(0>readrc)
+          break; /* get out of loop */
+
+        /* get the CURLcode from the int */
+        result = (CURLcode)readrc;
+
+        if(result>0)
+          return result;
+
+        if ((k->bytecount == 0) && (k->writebytecount == 0)) {
+          Curl_pgrsTime(data, TIMER_STARTTRANSFER);
+          if(k->wait100_after_headers)
+            /* set time stamp to compare with when waiting for the 100 */
+            k->start100 = Curl_tvnow();
+        }
+
+        didwhat |= KEEP_READ;
+
+        /* NULL terminate, allowing string ops to be used */
+        if (0 < nread)
+          k->buf[nread] = 0;
+
+        /* if we receive 0 or less here, the server closed the connection and
+           we bail out from this! */
+        else if (0 >= nread) {
+          k->keepon &= ~KEEP_READ;
+          FD_ZERO(&k->rkeepfd);
+          readdone = TRUE;
+          break;
+        }
+
+        /* Default buffer to use when we write the buffer, it may be changed
+           in the flow below before the actual storing is done. */
+        k->str = k->buf;
+
+        /* Since this is a two-state thing, we check if we are parsing
+           headers at the moment or not. */
+        if (k->header) {
+          /* we are in parse-the-header-mode */
+          bool stop_reading = FALSE;
+
+          /* header line within buffer loop */
+          do {
+            size_t hbufp_index;
+            size_t rest_length;
+            size_t full_length;
+            int writetype;
+
+            /* str_start is start of line within buf */
+            k->str_start = k->str;
+
+            k->end_ptr = strchr (k->str_start, '\n');
+
+            if (!k->end_ptr) {
+              /* Not a complete header line within buffer, append the data to
+                 the end of the headerbuff. */
+
+              if (k->hbuflen + nread >= data->state.headersize) {
+                /* We enlarge the header buffer as it is too small */
+                char *newbuff;
+                size_t newsize=CURLMAX((k->hbuflen+nread)*3/2,
+                                       data->state.headersize*2);
+                hbufp_index = k->hbufp - data->state.headerbuff;
+                newbuff = (char *)realloc(data->state.headerbuff, newsize);
+                if(!newbuff) {
+                  failf (data, "Failed to alloc memory for big header!");
+                  return CURLE_OUT_OF_MEMORY;
+                }
+                data->state.headersize=newsize;
+                data->state.headerbuff = newbuff;
+                k->hbufp = data->state.headerbuff + hbufp_index;
+              }
+              memcpy(k->hbufp, k->str, nread);
+              k->hbufp += nread;
+              k->hbuflen += nread;
+              if (!k->headerline && (k->hbuflen>5)) {
+                /* make a first check that this looks like a HTTP header */
+                if(!checkhttpprefix(data, data->state.headerbuff)) {
+                  /* this is not the beginning of a HTTP first header line */
+                  k->header = FALSE;
+                  k->badheader = HEADER_ALLBAD;
+                  break;
+                }
+              }
+
+              break; /* read more and try again */
+            }
+
+            /* decrease the size of the remaining (supposed) header line */
+            rest_length = (k->end_ptr - k->str)+1;
+            nread -= rest_length;
+
+            k->str = k->end_ptr + 1; /* move past new line */
+
+            full_length = k->str - k->str_start;
+
+            /*
+             * We're about to copy a chunk of data to the end of the
+             * already received header. We make sure that the full string
+             * fit in the allocated header buffer, or else we enlarge
+             * it.
+             */
+            if (k->hbuflen + full_length >=
+                data->state.headersize) {
+              char *newbuff;
+              size_t newsize=CURLMAX((k->hbuflen+full_length)*3/2,
+                                     data->state.headersize*2);
+              hbufp_index = k->hbufp - data->state.headerbuff;
+              newbuff = (char *)realloc(data->state.headerbuff, newsize);
+              if(!newbuff) {
+                failf (data, "Failed to alloc memory for big header!");
+                return CURLE_OUT_OF_MEMORY;
+              }
+              data->state.headersize= newsize;
+              data->state.headerbuff = newbuff;
+              k->hbufp = data->state.headerbuff + hbufp_index;
+            }
+
+            /* copy to end of line */
+            strncpy (k->hbufp, k->str_start, full_length);
+            k->hbufp += full_length;
+            k->hbuflen += full_length;
+            *k->hbufp = 0;
+            k->end_ptr = k->hbufp;
+
+            k->p = data->state.headerbuff;
+
+            /****
+             * We now have a FULL header line that p points to
+             *****/
+
+            if(!k->headerline) {
+              /* the first read header */
+              if((k->hbuflen>5) &&
+                 !checkhttpprefix(data, data->state.headerbuff)) {
+                /* this is not the beginning of a HTTP first header line */
+                k->header = FALSE;
+                if(nread)
+                  /* since there's more, this is a partial bad header */
+                  k->badheader = HEADER_PARTHEADER;
+                else {
+                  /* this was all we read so its all a bad header */
+                  k->badheader = HEADER_ALLBAD;
+                  nread = (ssize_t)rest_length;
+                }
+                break;
+              }
+            }
+
+            if (('\n' == *k->p) || ('\r' == *k->p)) {
+              size_t headerlen;
+              /* Zero-length header line means end of headers! */
+
+              if ('\r' == *k->p)
+                k->p++; /* pass the \r byte */
+              if ('\n' == *k->p)
+                k->p++; /* pass the \n byte */
+
+              if(100 == k->httpcode) {
+                /*
+                 * We have made a HTTP PUT or POST and this is 1.1-lingo
+                 * that tells us that the server is OK with this and ready
+                 * to receive the data.
+                 * However, we'll get more headers now so we must get
+                 * back into the header-parsing state!
+                 */
+                k->header = TRUE;
+                k->headerline = 0; /* restart the header line counter */
+                /* if we did wait for this do enable write now! */
+                if (k->write_after_100_header) {
+
+                  k->write_after_100_header = FALSE;
+                  FD_SET (conn->writesockfd, &k->writefd); /* write */
+                  k->keepon |= KEEP_WRITE;
+                  k->wkeepfd = k->writefd;
+                }
+              }
+              else
+                k->header = FALSE; /* no more header to parse! */
+
+              if (417 == k->httpcode) {
+                /*
+                 * we got: "417 Expectation Failed" this means:
+                 * we have made a HTTP call and our Expect Header
+                 * seems to cause a problem => abort the write operations
+                 * (or prevent them from starting).
+                 */
+                k->write_after_100_header = FALSE;
+                k->keepon &= ~KEEP_WRITE;
+                FD_ZERO(&k->wkeepfd);
+              }
+
+#ifndef CURL_DISABLE_HTTP
+              /*
+               * When all the headers have been parsed, see if we should give
+               * up and return an error.
+               */
+              if (Curl_http_should_fail(conn)) {
+                failf (data, "The requested URL returned error: %d",
+                       k->httpcode);
+                return CURLE_HTTP_RETURNED_ERROR;
+              }
+#endif   /* CURL_DISABLE_HTTP */
+
+              /* now, only output this if the header AND body are requested:
+               */
+              writetype = CLIENTWRITE_HEADER;
+              if (data->set.include_header)
+                writetype |= CLIENTWRITE_BODY;
+
+              headerlen = k->p - data->state.headerbuff;
+
+              result = Curl_client_write(data, writetype,
+                                         data->state.headerbuff,
+                                         headerlen);
+              if(result)
+                return result;
+
+              data->info.header_size += headerlen;
+              conn->headerbytecount += headerlen;
+
+              conn->deductheadercount =
+                (100 == k->httpcode)?conn->headerbytecount:0;
+
+              if (conn->resume_from &&
+                  !k->content_range &&
+                  (data->set.httpreq==HTTPREQ_GET)) {
+                if(k->httpcode == 416) {
+                  /* "Requested Range Not Satisfiable" */
+                  stop_reading = TRUE;
+                }
+                else {
+                  /* we wanted to resume a download, although the server
+                   * doesn't seem to support this and we did this with a GET
+                   * (if it wasn't a GET we did a POST or PUT resume) */
+                  failf (data, "HTTP server doesn't seem to support "
+                         "byte ranges. Cannot resume.");
+                  return CURLE_HTTP_RANGE_ERROR;
+                }
+              }
+#ifndef CURL_DISABLE_HTTP
+              if(!stop_reading) {
+                /* Curl_http_auth_act() checks what authentication methods
+                 * that are available and decides which one (if any) to
+                 * use. It will set 'newurl' if an auth metod was picked. */
+                result = Curl_http_auth_act(conn);
+
+                if(result)
+                  return result;
+              }
+#endif   /* CURL_DISABLE_HTTP */
+
+              if(!k->header) {
+                /*
+                 * really end-of-headers.
+                 *
+                 * If we requested a "no body", this is a good time to get
+                 * out and return home.
+                 */
+                if(conn->bits.no_body)
+                  stop_reading = TRUE;
+                else {
+                  /* If we know the expected size of this document, we set the
+                     maximum download size to the size of the expected
+                     document or else, we won't know when to stop reading!
+
+                     Note that we set the download maximum even if we read a
+                     "Connection: close" header, to make sure that
+                     "Content-Length: 0" still prevents us from attempting to
+                     read the (missing) response-body.
+                  */
+                  /* According to RFC2616 section 4.4, we MUST ignore
+                     Content-Length: headers if we are now receiving data
+                     using chunked Transfer-Encoding.
+                  */
+                  if(conn->bits.chunk)
+                    conn->size=-1;
+
+                }
+                if(-1 != conn->size) {
+                  /* We do this operation even if no_body is true, since this
+                     data might be retrieved later with curl_easy_getinfo()
+                     and its CURLINFO_CONTENT_LENGTH_DOWNLOAD option. */
+
+                  Curl_pgrsSetDownloadSize(data, conn->size);
+                  conn->maxdownload = conn->size;
+                }
+                /* If max download size is *zero* (nothing) we already
+                   have nothing and can safely return ok now! */
+                if(0 == conn->maxdownload)
+                  stop_reading = TRUE;
+
+                if(stop_reading) {
+                  /* we make sure that this socket isn't read more now */
+                  k->keepon &= ~KEEP_READ;
+                  FD_ZERO(&k->rkeepfd);
+                }
+
+                break;          /* exit header line loop */
+              }
+
+              /* We continue reading headers, so reset the line-based
+                 header parsing variables hbufp && hbuflen */
+              k->hbufp = data->state.headerbuff;
+              k->hbuflen = 0;
+              continue;
+            }
+
+            /*
+             * Checks for special headers coming up.
+             */
+
+            if (!k->headerline++) {
+              /* This is the first header, it MUST be the error code line
+                 or else we consiser this to be the body right away! */
+              int httpversion_major;
+              int nc=sscanf(k->p, " HTTP/%d.%d %3d",
+                            &httpversion_major,
+                            &k->httpversion,
+                            &k->httpcode);
+              if (nc==3) {
+                k->httpversion += 10 * httpversion_major;
+              }
+              else {
+                /* this is the real world, not a Nirvana
+                   NCSA 1.5.x returns this crap when asked for HTTP/1.1
+                */
+                nc=sscanf(k->p, " HTTP %3d", &k->httpcode);
+                k->httpversion = 10;
+
+               /* If user has set option HTTP200ALIASES,
+                  compare header line against list of aliases
+               */
+                if (!nc) {
+                  if (checkhttpprefix(data, k->p)) {
+                    nc = 1;
+                    k->httpcode = 200;
+                    k->httpversion =
+                      (data->set.httpversion==CURL_HTTP_VERSION_1_0)? 10 : 11;
+                  }
+                }
+              }
+
+              if (nc) {
+                data->info.httpcode = k->httpcode;
+                data->info.httpversion = k->httpversion;
+
+                /*
+                 * This code executes as part of processing the header.  As a
+                 * result, it's not totally clear how to interpret the
+                 * response code yet as that depends on what other headers may
+                 * be present.  401 and 407 may be errors, but may be OK
+                 * depending on how authentication is working.  Other codes
+                 * are definitely errors, so give up here.
+                 */
+                if (data->set.http_fail_on_error &&
+                    (k->httpcode >= 400) &&
+                    (k->httpcode != 401) &&
+                    (k->httpcode != 407)) {
+                  /* serious error, go home! */
+                  failf (data, "The requested URL returned error: %d",
+                         k->httpcode);
+                  return CURLE_HTTP_RETURNED_ERROR;
+                }
+
+                if(k->httpversion == 10)
+                  /* Default action for HTTP/1.0 must be to close, unless
+                     we get one of those fancy headers that tell us the
+                     server keeps it open for us! */
+                  conn->bits.close = TRUE;
+
+                switch(k->httpcode) {
+                case 204:
+                  /* (quote from RFC2616, section 10.2.5): The server has
+                   * fulfilled the request but does not need to return an
+                   * entity-body ... The 204 response MUST NOT include a
+                   * message-body, and thus is always terminated by the first
+                   * empty line after the header fields. */
+                  /* FALLTHROUGH */
+                case 416: /* Requested Range Not Satisfiable, it has the
+                             Content-Length: set as the "real" document but no
+                             actual response is sent. */
+                case 304:
+                  /* (quote from RFC2616, section 10.3.5): The 304 response
+                   * MUST NOT contain a message-body, and thus is always
+                   * terminated by the first empty line after the header
+                   * fields.  */
+                  conn->size=0;
+                  conn->maxdownload=0;
+                  break;
+                default:
+                  /* nothing */
+                  break;
+                }
+              }
+              else {
+                k->header = FALSE;   /* this is not a header line */
+                break;
+              }
+            }
+
+            /* Check for Content-Length: header lines to get size. Ignore
+               the header completely if we get a 416 response as then we're
+               resuming a document that we don't get, and this header contains
+               info about the true size of the document we didn't get now. */
+            if ((k->httpcode != 416) &&
+                checkprefix("Content-Length:", k->p)) {
+              contentlength = curlx_strtoofft(k->p+15, NULL, 10);
+              if (data->set.max_filesize &&
+                  contentlength > data->set.max_filesize) {
+                failf(data, "Maximum file size exceeded");
+                return CURLE_FILESIZE_EXCEEDED;
+              }
+              if(contentlength >= 0)
+                conn->size = contentlength;
+              else {
+                /* Negative Content-Length is really odd, and we know it
+                   happens for example when older Apache servers send large
+                   files */
+                conn->bits.close = TRUE;
+                infof(data, "Negative content-length: %" FORMAT_OFF_T
+                      ", closing after transfer\n", contentlength);
+              }
+            }
+            /* check for Content-Type: header lines to get the mime-type */
+            else if (checkprefix("Content-Type:", k->p)) {
+              char *start;
+              char *end;
+              size_t len;
+
+              /* Find the first non-space letter */
+              for(start=k->p+13;
+                  *start && isspace((int)*start);
+                  start++);
+
+              end = strchr(start, '\r');
+              if(!end)
+                end = strchr(start, '\n');
+
+              if(end) {
+                /* skip all trailing space letters */
+                for(; isspace((int)*end) && (end > start); end--);
+
+                /* get length of the type */
+                len = end-start+1;
+
+                /* allocate memory of a cloned copy */
+                Curl_safefree(data->info.contenttype);
+
+                data->info.contenttype = malloc(len + 1);
+                if (NULL == data->info.contenttype)
+                  return CURLE_OUT_OF_MEMORY;
+
+                /* copy the content-type string */
+                memcpy(data->info.contenttype, start, len);
+                data->info.contenttype[len] = 0; /* zero terminate */
+              }
+            }
+#ifndef CURL_DISABLE_HTTP
+            else if((k->httpversion == 10) &&
+                    conn->bits.httpproxy &&
+                    Curl_compareheader(k->p,
+                                       "Proxy-Connection:", "keep-alive")) {
+              /*
+               * When a HTTP/1.0 reply comes when using a proxy, the
+               * 'Proxy-Connection: keep-alive' line tells us the
+               * connection will be kept alive for our pleasure.
+               * Default action for 1.0 is to close.
+               */
+              conn->bits.close = FALSE; /* don't close when done */
+              infof(data, "HTTP/1.0 proxy connection set to keep alive!\n");
+            }
+            else if((k->httpversion == 10) &&
+                    Curl_compareheader(k->p, "Connection:", "keep-alive")) {
+              /*
+               * A HTTP/1.0 reply with the 'Connection: keep-alive' line
+               * tells us the connection will be kept alive for our
+               * pleasure.  Default action for 1.0 is to close.
+               *
+               * [RFC2068, section 19.7.1] */
+              conn->bits.close = FALSE; /* don't close when done */
+              infof(data, "HTTP/1.0 connection set to keep alive!\n");
+            }
+            else if (Curl_compareheader(k->p, "Connection:", "close")) {
+              /*
+               * [RFC 2616, section 8.1.2.1]
+               * "Connection: close" is HTTP/1.1 language and means that
+               * the connection will close when this request has been
+               * served.
+               */
+              conn->bits.close = TRUE; /* close when done */
+            }
+            else if (Curl_compareheader(k->p,
+                                        "Transfer-Encoding:", "chunked")) {
+              /*
+               * [RFC 2616, section 3.6.1] A 'chunked' transfer encoding
+               * means that the server will send a series of "chunks". Each
+               * chunk starts with line with info (including size of the
+               * coming block) (terminated with CRLF), then a block of data
+               * with the previously mentioned size. There can be any amount
+               * of chunks, and a chunk-data set to zero signals the
+               * end-of-chunks. */
+              conn->bits.chunk = TRUE; /* chunks coming our way */
+
+              /* init our chunky engine */
+              Curl_httpchunk_init(conn);
+            }
+            else if (checkprefix("Content-Encoding:", k->p) &&
+                     data->set.encoding) {
+              /*
+               * Process Content-Encoding. Look for the values: identity,
+               * gzip, deflate, compress, x-gzip and x-compress. x-gzip and
+               * x-compress are the same as gzip and compress. (Sec 3.5 RFC
+               * 2616). zlib cannot handle compress.  However, errors are
+               * handled further down when the response body is processed
+               */
+              char *start;
+
+              /* Find the first non-space letter */
+              for(start=k->p+17;
+                  *start && isspace((int)*start);
+                  start++);
+
+              /* Record the content-encoding for later use */
+              if (checkprefix("identity", start))
+                k->content_encoding = IDENTITY;
+              else if (checkprefix("deflate", start))
+                k->content_encoding = DEFLATE;
+              else if (checkprefix("gzip", start)
+                       || checkprefix("x-gzip", start))
+                k->content_encoding = GZIP;
+              else if (checkprefix("compress", start)
+                       || checkprefix("x-compress", start))
+                k->content_encoding = COMPRESS;
+            }
+            else if (Curl_compareheader(k->p, "Content-Range:", "bytes")) {
+              /* Content-Range: bytes [num]-
+                 Content-Range: bytes: [num]-
+
+                 The second format was added August 1st 2000 by Igor
+                 Khristophorov since Sun's webserver JavaWebServer/1.1.1
+                 obviously sends the header this way! :-( */
+
+              char *ptr = strstr(k->p, "bytes");
+              ptr+=5;
+
+              if(*ptr == ':')
+                /* stupid colon skip */
+                ptr++;
+
+              k->offset = curlx_strtoofft(ptr, NULL, 10);
+
+              if (conn->resume_from == k->offset)
+                /* we asked for a resume and we got it */
+                k->content_range = TRUE;
+            }
+            else if(data->cookies &&
+                    checkprefix("Set-Cookie:", k->p)) {
+              Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
+                              CURL_LOCK_ACCESS_SINGLE);
+              Curl_cookie_add(data,
+                              data->cookies, TRUE, k->p+11,
+                              /* If there is a custom-set Host: name, use it
+                                 here, or else use real peer host name. */
+                              conn->allocptr.cookiehost?
+                              conn->allocptr.cookiehost:conn->host.name,
+                              conn->path);
+              Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+            }
+            else if(checkprefix("Last-Modified:", k->p) &&
+                    (data->set.timecondition || data->set.get_filetime) ) {
+              time_t secs=time(NULL);
+              k->timeofdoc = curl_getdate(k->p+strlen("Last-Modified:"),
+                                          &secs);
+              if(data->set.get_filetime)
+                data->info.filetime = k->timeofdoc;
+            }
+            else if((checkprefix("WWW-Authenticate:", k->p) &&
+                     (401 == k->httpcode)) ||
+                    (checkprefix("Proxy-authenticate:", k->p) &&
+                     (407 == k->httpcode))) {
+              result = Curl_http_input_auth(conn, k->httpcode, k->p);
+              if(result)
+                return result;
+            }
+            else if ((k->httpcode >= 300 && k->httpcode < 400) &&
+                     checkprefix("Location:", k->p)) {
+              if(data->set.http_follow_location) {
+                /* this is the URL that the server advices us to get instead */
+                char *ptr;
+                char *start=k->p;
+                char backup;
+
+                start += 9; /* pass "Location:" */
+
+                /* Skip spaces and tabs. We do this to support multiple
+                   white spaces after the "Location:" keyword. */
+                while(*start && isspace((int)*start ))
+                  start++;
+
+                /* Scan through the string from the end to find the last
+                   non-space. k->end_ptr points to the actual terminating zero
+                   letter, move pointer one letter back and start from
+                   there. This logic strips off trailing whitespace, but keeps
+                   any embedded whitespace. */
+                ptr = k->end_ptr-1;
+                while((ptr>=start) && isspace((int)*ptr))
+                  ptr--;
+                ptr++;
+
+                backup = *ptr; /* store the ending letter */
+                if(ptr != start) {
+                  *ptr = '\0';   /* zero terminate */
+                  conn->newurl = strdup(start); /* clone string */
+                  *ptr = backup; /* restore ending letter */
+                  if(!conn->newurl)
+                    return CURLE_OUT_OF_MEMORY;
+                }
+              }
+            }
+#endif   /* CURL_DISABLE_HTTP */
+
+            /*
+             * End of header-checks. Write them to the client.
+             */
+
+            writetype = CLIENTWRITE_HEADER;
+            if (data->set.include_header)
+              writetype |= CLIENTWRITE_BODY;
+
+            if(data->set.verbose)
+              Curl_debug(data, CURLINFO_HEADER_IN,
+                         k->p, k->hbuflen, conn->host.dispname);
+
+            result = Curl_client_write(data, writetype, k->p, k->hbuflen);
+            if(result)
+              return result;
+
+            data->info.header_size += k->hbuflen;
+            conn->headerbytecount += k->hbuflen;
+
+            /* reset hbufp pointer && hbuflen */
+            k->hbufp = data->state.headerbuff;
+            k->hbuflen = 0;
+          }
+          while (!stop_reading && *k->str); /* header line within buffer */
+
+          if(stop_reading)
+            /* We've stopped dealing with input, get out of the do-while loop */
+            break;
+
+          /* We might have reached the end of the header part here, but
+             there might be a non-header part left in the end of the read
+             buffer. */
+
+        }                       /* end if header mode */
+
+        /* This is not an 'else if' since it may be a rest from the header
+           parsing, where the beginning of the buffer is headers and the end
+           is non-headers. */
+        if (k->str && !k->header && (nread > 0)) {
+
+          if(0 == k->bodywrites) {
+            /* These checks are only made the first time we are about to
+               write a piece of the body */
+            if(conn->protocol&PROT_HTTP) {
+              /* HTTP-only checks */
+
+              if (conn->newurl) {
+                if(conn->bits.close) {
+                  /* Abort after the headers if "follow Location" is set
+                     and we're set to close anyway. */
+                  k->keepon &= ~KEEP_READ;
+                  FD_ZERO(&k->rkeepfd);
+                  *done = TRUE;
+                  return CURLE_OK;
+                }
+                /* We have a new url to load, but since we want to be able
+                   to re-use this connection properly, we read the full
+                   response in "ignore more" */
+                k->ignorebody = TRUE;
+                infof(data, "Ignoring the response-body\n");
+              }
+              if(data->set.timecondition && !conn->range) {
+                /* A time condition has been set AND no ranges have been
+                   requested. This seems to be what chapter 13.3.4 of
+                   RFC 2616 defines to be the correct action for a
+                   HTTP/1.1 client */
+                if((k->timeofdoc > 0) && (data->set.timevalue > 0)) {
+                  switch(data->set.timecondition) {
+                  case CURL_TIMECOND_IFMODSINCE:
+                  default:
+                    if(k->timeofdoc < data->set.timevalue) {
+                      infof(data,
+                            "The requested document is not new enough\n");
+                      *done = TRUE;
+                      return CURLE_OK;
+                    }
+                    break;
+                  case CURL_TIMECOND_IFUNMODSINCE:
+                    if(k->timeofdoc > data->set.timevalue) {
+                      infof(data,
+                            "The requested document is not old enough\n");
+                      *done = TRUE;
+                      return CURLE_OK;
+                    }
+                    break;
+                  } /* switch */
+                } /* two valid time strings */
+              } /* we have a time condition */
+
+            } /* this is HTTP */
+          } /* this is the first time we write a body part */
+          k->bodywrites++;
+
+          /* pass data to the debug function before it gets "dechunked" */
+          if(data->set.verbose) {
+            if(k->badheader) {
+              Curl_debug(data, CURLINFO_DATA_IN, data->state.headerbuff,
+                         k->hbuflen, conn->host.dispname);
+              if(k->badheader == HEADER_PARTHEADER)
+                Curl_debug(data, CURLINFO_DATA_IN, k->str, nread,
+                           conn->host.dispname);
+            }
+            else
+              Curl_debug(data, CURLINFO_DATA_IN, k->str, nread,
+                         conn->host.dispname);
+          }
+
+#ifndef CURL_DISABLE_HTTP
+          if(conn->bits.chunk) {
+            /*
+             * Bless me father for I have sinned. Here comes a chunked
+             * transfer flying and we need to decode this properly.  While
+             * the name says read, this function both reads and writes away
+             * the data. The returned 'nread' holds the number of actual
+             * data it wrote to the client.  */
+            CHUNKcode res =
+              Curl_httpchunk_read(conn, k->str, nread, &nread);
+
+            if(CHUNKE_OK < res) {
+              if(CHUNKE_WRITE_ERROR == res) {
+                failf(data, "Failed writing data");
+                return CURLE_WRITE_ERROR;
+              }
+              failf(data, "Received problem %d in the chunky parser", res);
+              return CURLE_RECV_ERROR;
+            }
+            else if(CHUNKE_STOP == res) {
+              /* we're done reading chunks! */
+              k->keepon &= ~KEEP_READ; /* read no more */
+              FD_ZERO(&k->rkeepfd);
+
+              /* There are now possibly N number of bytes at the end of the
+                 str buffer that weren't written to the client, but we don't
+                 care about them right now. */
+            }
+            /* If it returned OK, we just keep going */
+          }
+#endif   /* CURL_DISABLE_HTTP */
+
+          if((-1 != conn->maxdownload) &&
+             (k->bytecount + nread >= conn->maxdownload)) {
+            nread = (ssize_t) (conn->maxdownload - k->bytecount);
+            if(nread < 0 ) /* this should be unusual */
+              nread = 0;
+
+            k->keepon &= ~KEEP_READ; /* we're done reading */
+            FD_ZERO(&k->rkeepfd);
+          }
+
+          k->bytecount += nread;
+
+          Curl_pgrsSetDownloadCounter(data, k->bytecount);
+
+          if(!conn->bits.chunk && (nread || k->badheader)) {
+            /* If this is chunky transfer, it was already written */
+
+            if(k->badheader && !k->ignorebody) {
+              /* we parsed a piece of data wrongly assuming it was a header
+                 and now we output it as body instead */
+              result = Curl_client_write(data, CLIENTWRITE_BODY,
+                                         data->state.headerbuff,
+                                         k->hbuflen);
+            }
+            if(k->badheader < HEADER_ALLBAD) {
+              /* This switch handles various content encodings. If there's an
+                 error here, be sure to check over the almost identical code
+                 in http_chunks.c.
+                 Make sure that ALL_CONTENT_ENCODINGS contains all the
+                 encodings handled here. */
+#ifdef HAVE_LIBZ
+              switch (k->content_encoding) {
+              case IDENTITY:
+#endif
+                /* This is the default when the server sends no
+                   Content-Encoding header. See Curl_readwrite_init; the
+                   memset() call initializes k->content_encoding to zero. */
+                if(!k->ignorebody)
+                  result = Curl_client_write(data, CLIENTWRITE_BODY, k->str,
+                                             nread);
+#ifdef HAVE_LIBZ
+                break;
+
+              case DEFLATE:
+                /* Assume CLIENTWRITE_BODY; headers are not encoded. */
+                result = Curl_unencode_deflate_write(data, k, nread);
+                break;
+
+              case GZIP:
+                /* Assume CLIENTWRITE_BODY; headers are not encoded. */
+                result = Curl_unencode_gzip_write(data, k, nread);
+                break;
+
+              case COMPRESS:
+              default:
+                failf (data, "Unrecognized content encoding type. "
+                       "libcurl understands `identity', `deflate' and `gzip' "
+                       "content encodings.");
+                result = CURLE_BAD_CONTENT_ENCODING;
+                break;
+              }
+#endif
+            }
+            k->badheader = HEADER_NORMAL; /* taken care of now */
+
+            if(result)
+              return result;
+          }
+
+        } /* if (! header and data to read ) */
+
+      } while(!readdone);
+
+    } /* if( read from socket ) */
+
+    /* If we still have writing to do, we check if we have a writable
+       socket. Sometimes the writefdp is NULL, if no fd_set was done using
+       the multi interface and then we can do nothing but to attempt a
+       write to be sure. */
+    if((k->keepon & KEEP_WRITE) &&
+       (!writefdp || FD_ISSET(conn->writesockfd, writefdp)) ) {
+      /* write */
+
+      int i, si;
+      ssize_t bytes_written;
+      bool writedone=TRUE;
+
+      if ((k->bytecount == 0) && (k->writebytecount == 0))
+        Curl_pgrsTime(data, TIMER_STARTTRANSFER);
+
+      didwhat |= KEEP_WRITE;
+
+      /*
+       * We loop here to do the READ and SEND loop until we run out of
+       * data to send or until we get EWOULDBLOCK back
+       */
+      do {
+
+        /* only read more data if there's no upload data already
+           present in the upload buffer */
+        if(0 == conn->upload_present) {
+          /* init the "upload from here" pointer */
+          conn->upload_fromhere = k->uploadbuf;
+
+          if(!k->upload_done) {
+            /* HTTP pollution, this should be written nicer to become more
+               protocol agnostic. */
+            int fillcount;
+
+            if(k->wait100_after_headers &&
+               (conn->proto.http->sending == HTTPSEND_BODY)) {
+              /* If this call is to send body data, we must take some action:
+                 We have sent off the full HTTP 1.1 request, and we shall now
+                 go into the Expect: 100 state and await such a header */
+              k->wait100_after_headers = FALSE; /* headers sent */
+              k->write_after_100_header = TRUE; /* wait for the header */
+              FD_ZERO (&k->writefd);            /* clear it */
+              k->wkeepfd = k->writefd;          /* set the keeper variable */
+              k->keepon &= ~KEEP_WRITE;         /* disable writing */
+              k->start100 = Curl_tvnow();       /* timeout count starts now */
+              didwhat &= ~KEEP_WRITE;  /* we didn't write anything actually */
+              break;
+            }
+
+            result = Curl_fillreadbuffer(conn, BUFSIZE, &fillcount);
+            if(result)
+              return result;
+
+            nread = (ssize_t)fillcount;
+          }
+          else
+            nread = 0; /* we're done uploading/reading */
+
+          /* the signed int typecase of nread of for systems that has
+             unsigned size_t */
+          if (nread<=0) {
+            /* done */
+            k->keepon &= ~KEEP_WRITE; /* we're done writing */
+            FD_ZERO(&k->wkeepfd);
+            writedone = TRUE;
+            (void)writedone;
+            break;
+          }
+
+          /* store number of bytes available for upload */
+          conn->upload_present = nread;
+
+          /* convert LF to CRLF if so asked */
+          if (data->set.crlf) {
+              if(data->state.scratch == NULL)
+                data->state.scratch = malloc(2*BUFSIZE);
+              if(data->state.scratch == NULL) {
+                failf (data, "Failed to alloc scratch buffer!");
+                return CURLE_OUT_OF_MEMORY;
+              }
+            for(i = 0, si = 0; i < nread; i++, si++) {
+              if (conn->upload_fromhere[i] == 0x0a) {
+                data->state.scratch[si++] = 0x0d;
+                data->state.scratch[si] = 0x0a;
+              }
+              else
+                data->state.scratch[si] = conn->upload_fromhere[i];
+            }
+            if(si != nread) {
+              /* only perform the special operation if we really did replace
+                 anything */
+              nread = si;
+
+              /* upload from the new (replaced) buffer instead */
+              conn->upload_fromhere = data->state.scratch;
+
+              /* set the new amount too */
+              conn->upload_present = nread;
+            }
+          }
+        }
+        else {
+          /* We have a partial buffer left from a previous "round". Use
+             that instead of reading more data */
+        }
+
+        /* write to socket (send away data) */
+        result = Curl_write(conn,
+                            conn->writesockfd,     /* socket to send to */
+                            conn->upload_fromhere, /* buffer pointer */
+                            conn->upload_present,  /* buffer size */
+                            &bytes_written);       /* actually send away */
+        if(result)
+          return result;
+
+        if(data->set.verbose)
+          /* show the data before we change the pointer upload_fromhere */
+          Curl_debug(data, CURLINFO_DATA_OUT, conn->upload_fromhere,
+                     bytes_written, conn->host.dispname);
+
+        if(conn->upload_present != bytes_written) {
+          /* we only wrote a part of the buffer (if anything), deal with it! */
+
+          /* store the amount of bytes left in the buffer to write */
+          conn->upload_present -= bytes_written;
+
+          /* advance the pointer where to find the buffer when the next send
+             is to happen */
+          conn->upload_fromhere += bytes_written;
+
+          writedone = TRUE; /* we are done, stop the loop */
+        }
+        else {
+          /* we've uploaded that buffer now */
+          conn->upload_fromhere = k->uploadbuf;
+          conn->upload_present = 0; /* no more bytes left */
+
+          if(k->upload_done) {
+            /* switch off writing, we're done! */
+            k->keepon &= ~KEEP_WRITE; /* we're done writing */
+            FD_ZERO(&k->wkeepfd);
+            writedone = TRUE;
+          }
+        }
+
+        k->writebytecount += bytes_written;
+        Curl_pgrsSetUploadCounter(data, k->writebytecount);
+
+      } while(!writedone); /* loop until we're done writing! */
+
+    }
+
+  } while(0); /* just to break out from! */
+
+  k->now = Curl_tvnow();
+  if(didwhat) {
+    /* Update read/write counters */
+    if(conn->bytecountp)
+      *conn->bytecountp = k->bytecount; /* read count */
+    if(conn->writebytecountp)
+      *conn->writebytecountp = k->writebytecount; /* write count */
+  }
+  else {
+    /* no read no write, this is a timeout? */
+    if (k->write_after_100_header) {
+      /* This should allow some time for the header to arrive, but only a
+         very short time as otherwise it'll be too much wasted times too
+         often. */
+
+      /* Quoting RFC2616, section "8.2.3 Use of the 100 (Continue) Status":
+
+      Therefore, when a client sends this header field to an origin server
+      (possibly via a proxy) from which it has never seen a 100 (Continue)
+      status, the client SHOULD NOT wait for an indefinite period before
+      sending the request body.
+
+      */
+
+      long ms = Curl_tvdiff(k->now, k->start100);
+      if(ms > CURL_TIMEOUT_EXPECT_100) {
+        /* we've waited long enough, continue anyway */
+        k->write_after_100_header = FALSE;
+        FD_SET (conn->writesockfd, &k->writefd); /* write socket */
+        k->keepon |= KEEP_WRITE;
+        k->wkeepfd = k->writefd;
+      }
+    }
+  }
+
+  if(Curl_pgrsUpdate(conn))
+    result = CURLE_ABORTED_BY_CALLBACK;
+  else
+    result = Curl_speedcheck(data, k->now);
+  if (result)
+    return result;
+
+  if (data->set.timeout &&
+      ((Curl_tvdiff(k->now, k->start)/1000) >= data->set.timeout)) {
+    failf(data, "Operation timed out with %" FORMAT_OFF_T
+          " out of %" FORMAT_OFF_T " bytes received",
+          k->bytecount, conn->size);
+    return CURLE_OPERATION_TIMEOUTED;
+  }
+
+  if(!k->keepon) {
+    /*
+     * The transfer has been performed. Just make some general checks before
+     * returning.
+     */
+
+    if(!(conn->bits.no_body) && (conn->size != -1) &&
+       (k->bytecount != conn->size) &&
+       !conn->newurl) {
+      failf(data, "transfer closed with %" FORMAT_OFF_T
+            " bytes remaining to read",
+            conn->size - k->bytecount);
+      return CURLE_PARTIAL_FILE;
+    }
+    else if(conn->bits.chunk && conn->proto.http->chunk.datasize) {
+      failf(data, "transfer closed with at least %d bytes remaining",
+            conn->proto.http->chunk.datasize);
+      return CURLE_PARTIAL_FILE;
+    }
+    if(Curl_pgrsUpdate(conn))
+      return CURLE_ABORTED_BY_CALLBACK;
+  }
+
+  /* Now update the "done" boolean we return */
+  *done = !k->keepon;
+
+  return CURLE_OK;
+}
+
+
+/*
+ * Curl_readwrite_init() inits the readwrite session.
+ */
+
+CURLcode Curl_readwrite_init(struct connectdata *conn)
+{
+  struct SessionHandle *data;
+  struct Curl_transfer_keeper *k = &conn->keep;
+
+  /* NB: the content encoding software depends on this initialization of
+     Curl_transfer_keeper. */
+  memset(k, 0, sizeof(struct Curl_transfer_keeper));
+
+  k->start = Curl_tvnow(); /* start time */
+  k->now = k->start;   /* current time is now */
+  k->header = TRUE; /* assume header */
+  k->httpversion = -1; /* unknown at this point */
+
+  data = conn->data; /* there's the root struct */
+  k->buf = data->state.buffer;
+  k->uploadbuf = data->state.uploadbuffer;
+  k->maxfd = (conn->sockfd>conn->writesockfd?
+              conn->sockfd:conn->writesockfd)+1;
+  k->hbufp = data->state.headerbuff;
+  k->ignorebody=FALSE;
+
+  Curl_pgrsTime(data, TIMER_PRETRANSFER);
+  Curl_speedinit(data);
+
+  Curl_pgrsSetUploadCounter(data, 0);
+  Curl_pgrsSetDownloadCounter(data, 0);
+
+  if (!conn->bits.getheader) {
+    k->header = FALSE;
+    if(conn->size > 0)
+      Curl_pgrsSetDownloadSize(data, conn->size);
+  }
+  /* we want header and/or body, if neither then don't do this! */
+  if(conn->bits.getheader || !conn->bits.no_body) {
+
+    FD_ZERO (&k->readfd);               /* clear it */
+    if(conn->sockfd != CURL_SOCKET_BAD) {
+      FD_SET (conn->sockfd, &k->readfd); /* read socket */
+      k->keepon |= KEEP_READ;
+    }
+
+    FD_ZERO (&k->writefd);              /* clear it */
+    if(conn->writesockfd != CURL_SOCKET_BAD) {
+      /* HTTP 1.1 magic:
+
+         Even if we require a 100-return code before uploading data, we might
+         need to write data before that since the REQUEST may not have been
+         finished sent off just yet.
+
+         Thus, we must check if the request has been sent before we set the
+         state info where we wait for the 100-return code
+      */
+      if (data->set.expect100header &&
+          (conn->proto.http->sending == HTTPSEND_BODY)) {
+        /* wait with write until we either got 100-continue or a timeout */
+        k->write_after_100_header = TRUE;
+        k->start100 = k->start;
+      }
+      else {
+        if(data->set.expect100header)
+          /* when we've sent off the rest of the headers, we must await a
+             100-continue */
+          k->wait100_after_headers = TRUE;
+        FD_SET (conn->writesockfd, &k->writefd); /* write socket */
+        k->keepon |= KEEP_WRITE;
+      }
+    }
+
+    /* get these in backup variables to be able to restore them on each lap in
+       the select() loop */
+    k->rkeepfd = k->readfd;
+    k->wkeepfd = k->writefd;
+
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_single_fdset() gets called by the multi interface code when the app
+ * has requested to get the fd_sets for the current connection. This function
+ * will then be called once for every connection that the multi interface
+ * keeps track of. This function will only be called for connections that are
+ * in the proper state to have this information available.
+ */
+void Curl_single_fdset(struct connectdata *conn,
+                       fd_set *read_fd_set,
+                       fd_set *write_fd_set,
+                       fd_set *exc_fd_set,
+                       int *max_fd)
+{
+  *max_fd = -1; /* init */
+  if(conn->keep.keepon & KEEP_READ) {
+    FD_SET(conn->sockfd, read_fd_set);
+    *max_fd = conn->sockfd;
+    conn->keep.readfdp = read_fd_set; /* store the address of the set */
+  }
+  if(conn->keep.keepon & KEEP_WRITE) {
+    FD_SET(conn->writesockfd, write_fd_set);
+
+    /* since sockets are curl_socket_t nowadays, we typecast it to int here
+       to compare it nicely */
+    if((int)conn->writesockfd > *max_fd)
+      *max_fd = conn->writesockfd;
+    conn->keep.writefdp = write_fd_set; /* store the address of the set */
+  }
+  /* we don't use exceptions, only touch that one to prevent compiler
+     warnings! */
+  *exc_fd_set = *exc_fd_set;
+}
+
+
+/*
+ * Transfer()
+ *
+ * This function is what performs the actual transfer. It is capable of
+ * doing both ways simultaneously.
+ * The transfer must already have been setup by a call to Curl_Transfer().
+ *
+ * Note that headers are created in a preallocated buffer of a default size.
+ * That buffer can be enlarged on demand, but it is never shrunken again.
+ *
+ * Parts of this function was once written by the friendly Mark Butler
+ * <butlerm@xmission.com>.
+ */
+
+static CURLcode
+Transfer(struct connectdata *conn)
+{
+  CURLcode result;
+  struct Curl_transfer_keeper *k = &conn->keep;
+  bool done=FALSE;
+
+  if(!(conn->protocol & PROT_FILE))
+    /* Only do this if we are not transferring FILE:, since the file: treatment
+       is different*/
+    Curl_readwrite_init(conn);
+
+  if((conn->sockfd == CURL_SOCKET_BAD) &&
+     (conn->writesockfd == CURL_SOCKET_BAD))
+    /* nothing to read, nothing to write, we're already OK! */
+    return CURLE_OK;
+
+  /* we want header and/or body, if neither then don't do this! */
+  if(!conn->bits.getheader && conn->bits.no_body)
+    return CURLE_OK;
+
+  k->writefdp = &k->writefd; /* store the address of the set */
+  k->readfdp = &k->readfd;   /* store the address of the set */
+
+  while (!done) {
+    struct timeval interval;
+    k->readfd = k->rkeepfd;  /* set these every lap in the loop */
+    k->writefd = k->wkeepfd;
+    interval.tv_sec = 1;
+    interval.tv_usec = 0;
+
+    switch (select (k->maxfd, k->readfdp, k->writefdp, NULL, &interval)) {
+    case -1: /* select() error, stop reading */
+#ifdef EINTR
+      /* The EINTR is not serious, and it seems you might get this more
+         ofen when using the lib in a multi-threaded environment! */
+      if(errno == EINTR)
+        ;
+      else
+#endif
+        done = TRUE; /* no more read or write */
+      continue;
+    case 0:  /* timeout */
+    default: /* readable descriptors */
+      result = Curl_readwrite(conn, &done);
+      break;
+    }
+    if(result)
+      return result;
+
+    /* "done" signals to us if the transfer(s) are ready */
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_pretransfer() is called immediately before a transfer starts.
+ */
+CURLcode Curl_pretransfer(struct SessionHandle *data)
+{
+  if(!data->change.url)
+    /* we can't do anything wihout URL */
+    return CURLE_URL_MALFORMAT;
+
+#ifdef USE_SSLEAY
+  {
+    /* Init the SSL session ID cache here. We do it here since we want to do
+       it after the *_setopt() calls (that could change the size of the cache)
+       but before any transfer takes place. */
+    CURLcode res = Curl_SSL_InitSessions(data, data->set.ssl.numsessions);
+    if(res)
+      return res;
+  }
+#endif
+
+  data->set.followlocation=0; /* reset the location-follow counter */
+  data->state.this_is_a_follow = FALSE; /* reset this */
+  data->state.errorbuf = FALSE; /* no error has occurred */
+
+  data->state.authproblem = FALSE;
+  data->state.authhost.want = data->set.httpauth;
+  data->state.authproxy.want = data->set.proxyauth;
+
+#ifndef CURL_DISABLE_HTTP
+  /* If there was a list of cookie files to read and we haven't done it before,
+     do it now! */
+  if(data->change.cookielist) {
+    struct curl_slist *list = data->change.cookielist;
+    Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+    while(list) {
+      data->cookies = Curl_cookie_init(data,
+                                       list->data,
+                                       data->cookies,
+                                       data->set.cookiesession);
+      list = list->next;
+    }
+    Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+    curl_slist_free_all(data->change.cookielist); /* clean up list */
+    data->change.cookielist = NULL; /* don't do this again! */
+  }
+#endif   /* CURL_DISABLE_HTTP */
+
+
+ /* Allow data->set.use_port to set which port to use. This needs to be
+  * disabled for example when we follow Location: headers to URLs using
+  * different ports! */
+  data->state.allow_port = TRUE;
+
+#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
+  /*************************************************************
+   * Tell signal handler to ignore SIGPIPE
+   *************************************************************/
+  if(!data->set.no_signal)
+    data->state.prev_signal = signal(SIGPIPE, SIG_IGN);
+#endif
+
+  Curl_initinfo(data); /* reset session-specific information "variables" */
+  Curl_pgrsStartNow(data);
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_posttransfer() is called immediately after a transfer ends
+ */
+CURLcode Curl_posttransfer(struct SessionHandle *data)
+{
+#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
+  /* restore the signal handler for SIGPIPE before we get back */
+  if(!data->set.no_signal)
+    signal(SIGPIPE, data->state.prev_signal);
+#else
+  (void)data; /* unused parameter */
+#endif
+
+  return CURLE_OK;
+}
+
+/*
+ * strlen_url() returns the length of the given URL if the spaces within the
+ * URL were properly URL encoded.
+ */
+static int strlen_url(char *url)
+{
+  char *ptr;
+  int newlen=0;
+  bool left=TRUE; /* left side of the ? */
+
+  for(ptr=url; *ptr; ptr++) {
+    switch(*ptr) {
+    case '?':
+      left=FALSE;
+    default:
+      newlen++;
+      break;
+    case ' ':
+      if(left)
+        newlen+=3;
+      else
+        newlen++;
+      break;
+    }
+  }
+  return newlen;
+}
+
+/* strcpy_url() copies a url to a output buffer and URL-encodes the spaces in
+ * the source URL accordingly.
+ */
+static void strcpy_url(char *output, char *url)
+{
+  /* we must add this with whitespace-replacing */
+  bool left=TRUE;
+  char *iptr;
+  char *optr = output;
+  for(iptr = url;    /* read from here */
+      *iptr;         /* until zero byte */
+      iptr++) {
+    switch(*iptr) {
+    case '?':
+      left=FALSE;
+    default:
+      *optr++=*iptr;
+      break;
+    case ' ':
+      if(left) {
+        *optr++='%'; /* add a '%' */
+        *optr++='2'; /* add a '2' */
+        *optr++='0'; /* add a '0' */
+      }
+      else
+        *optr++='+'; /* add a '+' here */
+      break;
+    }
+  }
+  *optr=0; /* zero terminate output buffer */
+
+}
+
+/*
+ * Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string
+ * as given by the remote server and set up the new URL to request.
+ */
+CURLcode Curl_follow(struct SessionHandle *data,
+                     char *newurl) /* this 'newurl' is the Location: string,
+                                      and it must be malloc()ed before passed
+                                      here */
+{
+  /* Location: redirect */
+  char prot[16]; /* URL protocol string storage */
+  char letter;   /* used for a silly sscanf */
+  size_t newlen;
+  char *newest;
+
+  if (data->set.maxredirs &&
+      (data->set.followlocation >= data->set.maxredirs)) {
+    failf(data,"Maximum (%d) redirects followed", data->set.maxredirs);
+    return CURLE_TOO_MANY_REDIRECTS;
+  }
+
+  /* mark the next request as a followed location: */
+  data->state.this_is_a_follow = TRUE;
+
+  data->set.followlocation++; /* count location-followers */
+
+  if(data->set.http_auto_referer) {
+    /* We are asked to automatically set the previous URL as the
+       referer when we get the next URL. We pick the ->url field,
+       which may or may not be 100% correct */
+
+    if(data->change.referer_alloc)
+      /* If we already have an allocated referer, free this first */
+      free(data->change.referer);
+
+    data->change.referer = strdup(data->change.url);
+    data->change.referer_alloc = TRUE; /* yes, free this later */
+  }
+
+  if(2 != sscanf(newurl, "%15[^?&/:]://%c", prot, &letter)) {
+    /***
+     *DANG* this is an RFC 2068 violation. The URL is supposed
+     to be absolute and this doesn't seem to be that!
+     ***
+     Instead, we have to TRY to append this new path to the old URL
+     to the right of the host part. Oh crap, this is doomed to cause
+     problems in the future...
+    */
+    char *protsep;
+    char *pathsep;
+
+    char *useurl = newurl;
+    size_t urllen;
+
+    /* we must make our own copy of the URL to play with, as it may
+       point to read-only data */
+    char *url_clone=strdup(data->change.url);
+
+    if(!url_clone)
+      return CURLE_OUT_OF_MEMORY; /* skip out of this NOW */
+
+    /* protsep points to the start of the host name */
+    protsep=strstr(url_clone, "//");
+    if(!protsep)
+      protsep=url_clone;
+    else
+      protsep+=2; /* pass the slashes */
+
+    if('/' != newurl[0]) {
+      int level=0;
+
+      /* First we need to find out if there's a ?-letter in the URL,
+         and cut it and the right-side of that off */
+      pathsep = strrchr(protsep, '?');
+      if(pathsep)
+        *pathsep=0;
+
+      /* we have a relative path to append to the last slash if
+         there's one available */
+      pathsep = strrchr(protsep, '/');
+      if(pathsep)
+        *pathsep=0;
+
+      /* Check if there's any slash after the host name, and if so,
+         remember that position instead */
+      pathsep = strchr(protsep, '/');
+      if(pathsep)
+        protsep = pathsep+1;
+      else
+        protsep = NULL;
+
+      /* now deal with one "./" or any amount of "../" in the newurl
+         and act accordingly */
+
+      if((useurl[0] == '.') && (useurl[1] == '/'))
+        useurl+=2; /* just skip the "./" */
+
+      while((useurl[0] == '.') &&
+            (useurl[1] == '.') &&
+            (useurl[2] == '/')) {
+        level++;
+        useurl+=3; /* pass the "../" */
+      }
+
+      if(protsep) {
+        while(level--) {
+          /* cut off one more level from the right of the original URL */
+          pathsep = strrchr(protsep, '/');
+          if(pathsep)
+            *pathsep=0;
+          else {
+            *protsep=0;
+            break;
+          }
+        }
+      }
+    }
+    else {
+      /* We got a new absolute path for this server, cut off from the
+         first slash */
+      pathsep = strchr(protsep, '/');
+      if(pathsep)
+        *pathsep=0;
+      else {
+        /* There was no slash. Now, since we might be operating on a badly
+           formatted URL, such as "http://www.url.com?id=2380" which doesn't
+           use a slash separator as it is supposed to, we need to check for a
+           ?-letter as well! */
+        pathsep = strchr(protsep, '?');
+        if(pathsep)
+          *pathsep=0;
+      }
+    }
+
+    /* If the new part contains a space, this is a mighty stupid redirect
+       but we still make an effort to do "right". To the left of a '?'
+       letter we replace each space with %20 while it is replaced with '+'
+       on the right side of the '?' letter.
+    */
+    newlen = strlen_url(useurl);
+
+    urllen = strlen(url_clone);
+
+    newest=(char *)malloc( urllen + 1 + /* possible slash */
+                           newlen + 1 /* zero byte */);
+
+    if(!newest) {
+      free(url_clone); /* don't leak this */
+      return CURLE_OUT_OF_MEMORY; /* go out from this */
+    }
+
+    /* copy over the root url part */
+    memcpy(newest, url_clone, urllen);
+
+    /* check if we need to append a slash */
+    if(('/' == useurl[0]) || (protsep && !*protsep))
+      ;
+    else
+      newest[urllen++]='/';
+
+    /* then append the new piece on the right side */
+    strcpy_url(&newest[urllen], useurl);
+
+    free(newurl); /* newurl is the allocated pointer */
+    free(url_clone);
+    newurl = newest;
+  }
+  else {
+    /* This is an absolute URL, don't allow the custom port number */
+    data->state.allow_port = FALSE;
+
+    if(strchr(newurl, ' ')) {
+      /* This new URL contains at least one space, this is a mighty stupid
+         redirect but we still make an effort to do "right". */
+      newlen = strlen_url(newurl);
+
+      newest = malloc(newlen+1); /* get memory for this */
+      if(newest) {
+        strcpy_url(newest, newurl); /* create a space-free URL */
+
+        free(newurl); /* that was no good */
+        newurl = newest; /* use this instead now */
+      }
+    }
+
+  }
+
+  if(data->change.url_alloc)
+    free(data->change.url);
+  else
+    data->change.url_alloc = TRUE; /* the URL is allocated */
+
+  data->change.url = newurl;
+  newurl = NULL; /* don't free! */
+  (void)newurl;
+
+  infof(data, "Issue another request to this URL: '%s'\n", data->change.url);
+
+  /*
+   * We get here when the HTTP code is 300-399 (and 401). We need to perform
+   * differently based on exactly what return code there was.
+   *
+   * News from 7.10.6: we can also get here on a 401 or 407, in case we act on
+   * a HTTP (proxy-) authentication scheme other than Basic.
+   */
+  switch(data->info.httpcode) {
+    /* 401 - Act on a www-authentication, we keep on moving and do the
+       Authorization: XXXX header in the HTTP request code snippet */
+    /* 407 - Act on a proxy-authentication, we keep on moving and do the
+       Proxy-Authorization: XXXX header in the HTTP request code snippet */
+    /* 300 - Multiple Choices */
+    /* 306 - Not used */
+    /* 307 - Temporary Redirect */
+  default:  /* for all above (and the unknown ones) */
+    /* Some codes are explicitly mentioned since I've checked RFC2616 and they
+     * seem to be OK to POST to.
+     */
+    break;
+  case 301: /* Moved Permanently */
+    /* (quote from RFC2616, section 10.3.2):
+     *
+     * Note: When automatically redirecting a POST request after receiving a
+     * 301 status code, some existing HTTP/1.0 user agents will erroneously
+     * change it into a GET request.
+     *
+     * ----
+     *
+     * Warning: Because most of importants user agents do this obvious RFC2616
+     * violation, many webservers expect this misbehavior. So these servers
+     * often answers to a POST request with an error page.  To be sure that
+     * libcurl gets the page that most user agents would get, libcurl has to
+     * force GET:
+     */
+    if( data->set.httpreq == HTTPREQ_POST
+        || data->set.httpreq == HTTPREQ_POST_FORM) {
+      infof(data,
+            "Violate RFC 2616/10.3.2 and switch from POST to GET\n");
+      data->set.httpreq = HTTPREQ_GET;
+    }
+    break;
+  case 302: /* Found */
+    /* (From 10.3.3)
+
+    Note: RFC 1945 and RFC 2068 specify that the client is not allowed
+    to change the method on the redirected request.  However, most
+    existing user agent implementations treat 302 as if it were a 303
+    response, performing a GET on the Location field-value regardless
+    of the original request method. The status codes 303 and 307 have
+    been added for servers that wish to make unambiguously clear which
+    kind of reaction is expected of the client.
+
+    (From 10.3.4)
+
+    Note: Many pre-HTTP/1.1 user agents do not understand the 303
+    status. When interoperability with such clients is a concern, the
+    302 status code may be used instead, since most user agents react
+    to a 302 response as described here for 303.
+    */
+  case 303: /* See Other */
+    /* Disable both types of POSTs, since doing a second POST when
+     * following isn't what anyone would want! */
+    if(data->set.httpreq != HTTPREQ_GET) {
+      data->set.httpreq = HTTPREQ_GET; /* enforce GET request */
+      infof(data, "Disables POST, goes with %s\n",
+            data->set.opt_no_body?"HEAD":"GET");
+    }
+    break;
+  case 304: /* Not Modified */
+    /* 304 means we did a conditional request and it was "Not modified".
+     * We shouldn't get any Location: header in this response!
+     */
+    break;
+  case 305: /* Use Proxy */
+    /* (quote from RFC2616, section 10.3.6):
+     * "The requested resource MUST be accessed through the proxy given
+     * by the Location field. The Location field gives the URI of the
+     * proxy.  The recipient is expected to repeat this single request
+     * via the proxy. 305 responses MUST only be generated by origin
+     * servers."
+     */
+    break;
+  }
+  Curl_pgrsTime(data, TIMER_REDIRECT);
+  Curl_pgrsResetTimes(data);
+
+  return CURLE_OK;
+}
+
+static CURLcode
+Curl_connect_host(struct SessionHandle *data,
+                  struct connectdata **conn)
+{
+  CURLcode res;
+  int urlchanged;
+
+  do {
+    bool async;
+    Curl_pgrsTime(data, TIMER_STARTSINGLE);
+    data->change.url_changed = FALSE;
+    res = Curl_connect(data, conn, &async);
+
+    if((CURLE_OK == res) && async) {
+      /* Now, if async is TRUE here, we need to wait for the name
+         to resolve */
+      res = Curl_wait_for_resolv(*conn, NULL);
+      if(CURLE_OK == res)
+        /* Resolved, continue with the connection */
+        res = Curl_async_resolved(*conn);
+    }
+    if(res)
+      break;
+
+    /* If a callback (or something) has altered the URL we should use within
+       the Curl_connect(), we detect it here and act as if we are redirected
+       to the new URL */
+    urlchanged = data->change.url_changed;
+    if ((CURLE_OK == res) && urlchanged) {
+      res = Curl_done(conn, res);
+      if(CURLE_OK == res) {
+        char *gotourl = strdup(data->change.url);
+        res = Curl_follow(data, gotourl);
+        if(res)
+          free(gotourl);
+      }
+    }
+  } while (urlchanged && res == CURLE_OK);
+
+  return res;
+}
+
+
+
+/*
+ * Curl_perform() is the internal high-level function that gets called by the
+ * external curl_easy_perform() function. It inits, performs and cleans up a
+ * single file transfer.
+ */
+CURLcode Curl_perform(struct SessionHandle *data)
+{
+  CURLcode res;
+  CURLcode res2;
+  struct connectdata *conn=NULL;
+  char *newurl = NULL; /* possibly a new URL to follow to! */
+
+  data->state.used_interface = Curl_if_easy;
+
+  res = Curl_pretransfer(data);
+  if(res)
+    return res;
+
+  /*
+   * It is important that there is NO 'return' from this function at any other
+   * place than falling down to the end of the function! This is because we
+   * have cleanup stuff that must be done before we get back, and that is only
+   * performed after this do-while loop.
+   */
+
+  do {
+    res = Curl_connect_host(data, &conn);   /* primary connection */
+
+    if(res == CURLE_OK) {
+      if (data->set.source_host) /* 3rd party transfer */
+        res = Curl_pretransfersec(conn);
+      else
+        conn->sec_conn = NULL;
+    }
+
+    if(res == CURLE_OK) {
+
+      res = Curl_do(&conn);
+
+      /* for non 3rd party transfer only */
+      if(res == CURLE_OK && !data->set.source_host) {
+        res = Transfer(conn); /* now fetch that URL please */
+        if(res == CURLE_OK) {
+
+          if((conn->keep.bytecount+conn->headerbytecount == 0) &&
+             conn->bits.reuse) {
+            /* We got no data and we attempted to re-use a connection. This
+               might happen if the connection was left alive when we were done
+               using it before, but that was closed when we wanted to read
+               from it again. Bad luck. Retry the same request on a fresh
+               connect! */
+            infof(data, "Connection died, retrying a fresh connect\n");
+            newurl = strdup(conn->data->change.url);
+
+            conn->bits.close = TRUE; /* close this connection */
+            conn->bits.retry = TRUE; /* mark this as a connection we're about
+                                        to retry. Marking it this way should
+                                        prevent i.e HTTP transfers to return
+                                        error just because nothing has been
+                                        transfered! */
+          }
+          else
+            /*
+             * We must duplicate the new URL here as the connection data
+             * may be free()ed in the Curl_done() function.
+             */
+            newurl = conn->newurl?strdup(conn->newurl):NULL;
+        }
+        else {
+          /* The transfer phase returned error, we mark the connection to get
+           * closed to prevent being re-used. This is becasue we can't
+           * possibly know if the connection is in a good shape or not now. */
+          conn->bits.close = TRUE;
+
+          if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
+            /* if we failed anywhere, we must clean up the secondary socket if
+               it was used */
+            sclose(conn->sock[SECONDARYSOCKET]);
+            conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
+          }
+        }
+
+        /* Always run Curl_done(), even if some of the previous calls
+           failed, but return the previous (original) error code */
+        res2 = Curl_done(&conn, res);
+
+        if(CURLE_OK == res)
+          res = res2;
+      }
+      else
+        /* Curl_do() failed, clean up left-overs in the done-call */
+        res2 = Curl_done(&conn, res);
+
+      (void)res2;
+
+      /*
+       * Important: 'conn' cannot be used here, since it may have been closed
+       * in 'Curl_done' or other functions.
+       */
+
+      if((res == CURLE_OK) && newurl) {
+        res = Curl_follow(data, newurl);
+        if(CURLE_OK == res) {
+          newurl = NULL;
+          continue;
+        }
+      }
+    }
+    break; /* it only reaches here when this shouldn't loop */
+
+  } while(1); /* loop if Location: */
+
+  if(newurl)
+    free(newurl);
+
+  /* run post-transfer uncondionally, but don't clobber the return code if
+     we already have an error code recorder */
+  res2 = Curl_posttransfer(data);
+  if(!res && res2)
+    res = res2;
+
+  return res;
+}
+
+/*
+ * Curl_Transfer() is called to setup some basic properties for the upcoming
+ * transfer.
+ */
+CURLcode
+Curl_Transfer(struct connectdata *c_conn, /* connection data */
+              int sockindex,       /* socket index to read from or -1 */
+              curl_off_t size,     /* -1 if unknown at this point */
+              bool getheader,      /* TRUE if header parsing is wanted */
+              curl_off_t *bytecountp, /* return number of bytes read or NULL */
+              int writesockindex,  /* socket index to write to, it may very
+                                      well be the same we read from. -1
+                                      disables */
+              curl_off_t *writecountp /* return number of bytes written or
+                                       NULL */
+              )
+{
+  struct connectdata *conn = (struct connectdata *)c_conn;
+  if(!conn)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  curlassert((sockindex <= 1) && (sockindex >= -1));
+
+  /* now copy all input parameters */
+  conn->sockfd = sockindex==-1?
+    CURL_SOCKET_BAD:conn->sock[sockindex];
+  conn->size = size;
+  conn->bits.getheader = getheader;
+  conn->bytecountp = bytecountp;
+  conn->writesockfd = writesockindex==-1?
+    CURL_SOCKET_BAD:conn->sock[writesockindex];
+  conn->writebytecountp = writecountp;
+
+  return CURLE_OK;
+
+}
+
+/*
+ * Curl_pretransfersec() prepares the secondary connection (used for 3rd party
+ * FTP transfers).
+ */
+CURLcode Curl_pretransfersec(struct connectdata *conn)
+{
+  CURLcode status;
+  struct SessionHandle *data = conn->data;
+  struct connectdata *sec_conn = NULL;   /* secondary connection */
+
+  /* update data with source host options */
+  char *url = aprintf( "%s://%s/", conn->protostr, data->set.source_host);
+
+  if(!url)
+    return CURLE_OUT_OF_MEMORY;
+
+  if(data->change.url_alloc)
+    free(data->change.url);
+
+  data->change.url_alloc = TRUE;
+  data->change.url = url;
+  data->set.ftpport = data->set.source_port;
+  data->set.userpwd = data->set.source_userpwd;
+
+  /* secondary connection */
+  status = Curl_connect_host(data, &sec_conn);
+  if(CURLE_OK == status) {
+    sec_conn->data = data;
+    conn->sec_conn = sec_conn;
+  }
+
+  return status;
+}
diff --git a/Utilities/cmcurl/transfer.h b/Utilities/cmcurl/transfer.h
new file mode 100644
index 0000000..1b7eb82
--- /dev/null
+++ b/Utilities/cmcurl/transfer.h
@@ -0,0 +1,52 @@
+#ifndef __TRANSFER_H
+#define __TRANSFER_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+CURLcode Curl_perform(struct SessionHandle *data);
+CURLcode Curl_pretransfer(struct SessionHandle *data);
+CURLcode Curl_pretransfersec(struct connectdata *conn);
+CURLcode Curl_posttransfer(struct SessionHandle *data);
+CURLcode Curl_follow(struct SessionHandle *data, char *newurl);
+CURLcode Curl_readwrite(struct connectdata *conn, bool *done);
+void Curl_single_fdset(struct connectdata *conn,
+                       fd_set *read_fd_set,
+                       fd_set *write_fd_set,
+                       fd_set *exc_fd_set,
+                       int *max_fd);
+CURLcode Curl_readwrite_init(struct connectdata *conn);
+
+CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp);
+
+/* This sets up a forthcoming transfer */
+CURLcode
+Curl_Transfer (struct connectdata *data,
+               int sockindex,           /* socket index to read from or -1 */
+               curl_off_t size,         /* -1 if unknown at this point */
+               bool getheader,          /* TRUE if header parsing is wanted */
+               curl_off_t *bytecountp,  /* return number of bytes read */
+               int writesockindex,      /* socket index to write to, it may
+                                           very well be the same we read from.
+                                           -1 disables */
+               curl_off_t *writecountp /* return number of bytes written */
+);
+#endif
diff --git a/Utilities/cmcurl/url.c b/Utilities/cmcurl/url.c
new file mode 100644
index 0000000..b532e20
--- /dev/null
+++ b/Utilities/cmcurl/url.c
@@ -0,0 +1,3686 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/* -- WIN32 approved -- */
+
+#include "setup.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <errno.h>
+
+#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
+#include <time.h>
+#include <io.h>
+#else
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <netinet/in.h>
+#include <sys/time.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <netdb.h>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#include <sys/ioctl.h>
+#include <signal.h>
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifdef VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#ifndef HAVE_SELECT
+#error "We can't compile without select() support!"
+#endif
+#ifndef HAVE_SOCKET
+#error "We can't compile without socket() support!"
+#endif
+
+
+#endif
+
+#ifdef USE_LIBIDN
+#include <idna.h>
+#include <stringprep.h>
+#ifdef HAVE_IDN_FREE_H
+#include <idn-free.h>
+#else
+void idn_free (void *ptr); /* prototype from idn-free.h, not provided by
+                              libidn 0.4.5's make install! */
+#endif
+#ifndef HAVE_IDN_FREE
+/* if idn_free() was not found in this version of libidn, use plain free()
+   instead */
+#define idn_free(x) (free)(x)
+#endif
+#endif
+
+#ifdef HAVE_OPENSSL_ENGINE_H
+#include <openssl/engine.h>
+#endif
+#include "urldata.h"
+#include "netrc.h"
+
+#include "formdata.h"
+#include "base64.h"
+#include "ssluse.h"
+#include "hostip.h"
+#include "if2ip.h"
+#include "transfer.h"
+#include "sendf.h"
+#include "progress.h"
+#include "cookie.h"
+#include "strequal.h"
+#include "escape.h"
+#include "strtok.h"
+#include "share.h"
+#include "content_encoding.h"
+#include "http_digest.h"
+#include "http_negotiate.h"
+
+/* And now for the protocols */
+#include "ftp.h"
+#include "dict.h"
+#include "telnet.h"
+#include "http.h"
+#include "file.h"
+#include "ldap.h"
+#include "url.h"
+#include "connect.h"
+#include "inet_ntop.h"
+#include <ca-bundle.h>
+
+#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
+#include "inet_ntoa_r.h"
+#endif
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#ifdef HAVE_KRB4
+#include "security.h"
+#endif
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* Local static prototypes */
+static long ConnectionKillOne(struct SessionHandle *data);
+static bool ConnectionExists(struct SessionHandle *data,
+                             struct connectdata *needle,
+                             struct connectdata **usethis);
+static long ConnectionStore(struct SessionHandle *data,
+                            struct connectdata *conn);
+static bool safe_strequal(char* str1, char* str2);
+
+#ifndef USE_ARES
+/* not for Win32, unless it is cygwin
+   not for ares builds */
+#if !defined(WIN32) || defined(__CYGWIN32__)
+
+#ifndef RETSIGTYPE
+#define RETSIGTYPE void
+#endif
+#ifdef HAVE_SIGSETJMP
+extern sigjmp_buf curl_jmpenv;
+#endif
+static
+RETSIGTYPE alarmfunc(int sig)
+{
+  /* this is for "-ansi -Wall -pedantic" to stop complaining!   (rabe) */
+  (void)sig;
+#ifdef HAVE_SIGSETJMP
+  siglongjmp(curl_jmpenv, 1);
+#endif
+  return;
+}
+#endif
+#endif /* USE_ARES */
+
+void Curl_safefree(void *ptr)
+{
+  if(ptr)
+    free(ptr);
+}
+
+/*
+ * This is the internal function curl_easy_cleanup() calls. This should
+ * cleanup and free all resources associated with this sessionhandle.
+ *
+ * NOTE: if we ever add something that attempts to write to a socket or
+ * similar here, we must ignore SIGPIPE first. It is currently only done
+ * when curl_easy_perform() is invoked.
+ */
+
+CURLcode Curl_close(struct SessionHandle *data)
+{
+  /* Loop through all open connections and kill them one by one */
+  while(-1 != ConnectionKillOne(data));
+
+#ifdef USE_SSLEAY
+  /* Close down all open SSL info and sessions */
+  Curl_SSL_Close_All(data);
+#endif
+
+  if(data->change.cookielist) /* clean up list if any */
+    curl_slist_free_all(data->change.cookielist);
+
+  Curl_safefree(data->state.auth_host);
+  Curl_safefree(data->state.scratch);
+
+  if(data->change.proxy_alloc)
+    free(data->change.proxy);
+
+  if(data->change.referer_alloc)
+    free(data->change.referer);
+
+  if(data->change.url_alloc)
+    free(data->change.url);
+
+  Curl_safefree(data->state.headerbuff);
+
+#ifndef CURL_DISABLE_HTTP
+  Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+  if(data->set.cookiejar) {
+    /* we have a "destination" for all the cookies to get dumped to */
+    if(Curl_cookie_output(data->cookies, data->set.cookiejar))
+      infof(data, "WARNING: failed to save cookies in %s\n",
+            data->set.cookiejar);
+  }
+
+  if( !data->share || (data->cookies != data->share->cookies) ) {
+    Curl_cookie_cleanup(data->cookies);
+  }
+  Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+
+  Curl_digest_cleanup(data);
+#endif
+
+  /* free the connection cache */
+  free(data->state.connects);
+
+  Curl_safefree(data->info.contenttype);
+
+#ifdef USE_ARES
+  /* this destroys the channel and we cannot use it anymore after this */
+  ares_destroy(data->state.areschannel);
+#endif
+
+  /* No longer a dirty share, if it exists */
+  if (data->share)
+    data->share->dirty--;
+
+  free(data);
+  return CURLE_OK;
+}
+
+/**
+ * Curl_open()
+ *
+ * @param curl is a pointer to a sessionhandle pointer that gets set by this
+ * function.
+ * @return CURLcode
+ */
+
+CURLcode Curl_open(struct SessionHandle **curl)
+{
+  CURLcode res = CURLE_OK;
+  struct SessionHandle *data;
+  /* Very simple start-up: alloc the struct, init it with zeroes and return */
+  data = (struct SessionHandle *)calloc(1, sizeof(struct SessionHandle));
+  if(!data)
+    /* this is a very serious error */
+    return CURLE_OUT_OF_MEMORY;
+
+#ifdef USE_ARES
+  if(ARES_SUCCESS != ares_init(&data->state.areschannel)) {
+    free(data);
+    return CURLE_FAILED_INIT;
+  }
+  /* make sure that all other returns from this function should destroy the
+     ares channel before returning error! */
+#endif
+
+  /* We do some initial setup here, all those fields that can't be just 0 */
+
+  data->state.headerbuff=(char*)malloc(HEADERSIZE);
+  if(!data->state.headerbuff)
+    res = CURLE_OUT_OF_MEMORY;
+  else {
+    data->state.headersize=HEADERSIZE;
+
+    data->set.out = stdout; /* default output to stdout */
+    data->set.in  = stdin;  /* default input from stdin */
+    data->set.err  = stderr;  /* default stderr to stderr */
+
+    /* use fwrite as default function to store output */
+    data->set.fwrite = (curl_write_callback)fwrite;
+
+    /* use fread as default function to read input */
+    data->set.fread = (curl_read_callback)fread;
+
+    data->set.infilesize = -1; /* we don't know any size */
+
+    data->state.current_speed = -1; /* init to negative == impossible */
+
+    data->set.httpreq = HTTPREQ_GET; /* Default HTTP request */
+    data->set.ftp_use_epsv = TRUE;   /* FTP defaults to EPSV operations */
+    data->set.ftp_use_eprt = TRUE;   /* FTP defaults to EPRT operations */
+
+    data->set.dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
+
+    /* make libcurl quiet by default: */
+    data->set.hide_progress = TRUE;  /* CURLOPT_NOPROGRESS changes these */
+    data->progress.flags |= PGRS_HIDE;
+
+    /* Set the default size of the SSL session ID cache */
+    data->set.ssl.numsessions = 5;
+
+    data->set.proxyport = 1080;
+    data->set.proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
+    data->set.httpauth = CURLAUTH_BASIC;  /* defaults to basic */
+    data->set.proxyauth = CURLAUTH_BASIC; /* defaults to basic */
+
+    /* create an array with connection data struct pointers */
+    data->state.numconnects = 5; /* hard-coded right now */
+    data->state.connects = (struct connectdata **)
+      malloc(sizeof(struct connectdata *) * data->state.numconnects);
+
+    if(!data->state.connects)
+      res = CURLE_OUT_OF_MEMORY;
+    else
+      memset(data->state.connects, 0,
+             sizeof(struct connectdata *)*data->state.numconnects);
+
+    /*
+     * libcurl 7.10 introduced SSL verification *by default*! This needs to be
+     * switched off unless wanted.
+     */
+    data->set.ssl.verifypeer = TRUE;
+    data->set.ssl.verifyhost = 2;
+#ifdef CURL_CA_BUNDLE
+    /* This is our prefered CA cert bundle since install time */
+    data->set.ssl.CAfile = (char *)CURL_CA_BUNDLE;
+#endif
+  }
+
+  if(res) {
+#ifdef USE_ARES
+    ares_destroy(data->state.areschannel);
+#endif
+    if(data->state.headerbuff)
+      free(data->state.headerbuff);
+    free(data);
+    data = NULL;
+  }
+
+  *curl = data;
+  return CURLE_OK;
+}
+
+CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
+{
+  va_list param;
+  char *cookiefile;
+
+  va_start(param, option);
+
+  switch(option) {
+  case CURLOPT_DNS_CACHE_TIMEOUT:
+    data->set.dns_cache_timeout = va_arg(param, int);
+    break;
+  case CURLOPT_DNS_USE_GLOBAL_CACHE:
+    {
+      int use_cache = va_arg(param, int);
+      if (use_cache) {
+        Curl_global_host_cache_init();
+      }
+
+      data->set.global_dns_cache = use_cache;
+    }
+    break;
+  case CURLOPT_SSL_CIPHER_LIST:
+    /* set a list of cipher we want to use in the SSL connection */
+    data->set.ssl.cipher_list = va_arg(param, char *);
+    break;
+
+  case CURLOPT_RANDOM_FILE:
+    /*
+     * This is the path name to a file that contains random data to seed
+     * the random SSL stuff with. The file is only used for reading.
+     */
+    data->set.ssl.random_file = va_arg(param, char *);
+    break;
+  case CURLOPT_EGDSOCKET:
+    /*
+     * The Entropy Gathering Daemon socket pathname
+     */
+    data->set.ssl.egdsocket = va_arg(param, char *);
+    break;
+  case CURLOPT_MAXCONNECTS:
+    /*
+     * Set the absolute number of maximum simultaneous alive connection that
+     * libcurl is allowed to have.
+     */
+    {
+      long newconnects= va_arg(param, long);
+      struct connectdata **newptr;
+      long i;
+
+      if(newconnects < data->state.numconnects) {
+        /* Since this number is *decreased* from the existing number, we must
+           close the possibly open connections that live on the indexes that
+           are being removed! */
+        for(i=newconnects; i< data->state.numconnects; i++)
+          Curl_disconnect(data->state.connects[i]);
+      }
+      if(newconnects) {
+        newptr= (struct connectdata **)
+          realloc(data->state.connects,
+                  sizeof(struct connectdata *) * newconnects);
+        if(!newptr)
+          /* we closed a few connections in vain, but so what? */
+          return CURLE_OUT_OF_MEMORY;
+
+        /* nullify the newly added pointers */
+        for(i=data->state.numconnects; i<newconnects; i++) {
+          newptr[i] = NULL;
+        }
+
+        data->state.connects = newptr;
+        data->state.numconnects = newconnects;
+      }
+      else {
+        /* zero makes NO cache at all */
+        if(data->state.connects)
+          free(data->state.connects);
+        data->state.connects=NULL;
+        data->state.numconnects=0;
+      }
+    }
+    break;
+  case CURLOPT_FORBID_REUSE:
+    /*
+     * When this transfer is done, it must not be left to be reused by a
+     * subsequent transfer but shall be closed immediately.
+     */
+    data->set.reuse_forbid = va_arg(param, long)?TRUE:FALSE;
+    break;
+  case CURLOPT_FRESH_CONNECT:
+    /*
+     * This transfer shall not use a previously cached connection but
+     * should be made with a fresh new connect!
+     */
+    data->set.reuse_fresh = va_arg(param, long)?TRUE:FALSE;
+    break;
+  case CURLOPT_VERBOSE:
+    /*
+     * Verbose means infof() calls that give a lot of information about
+     * the connection and transfer procedures as well as internal choices.
+     */
+    data->set.verbose = va_arg(param, long)?TRUE:FALSE;
+    break;
+  case CURLOPT_HEADER:
+    /*
+     * Set to include the header in the general data output stream.
+     */
+    data->set.include_header = va_arg(param, long)?TRUE:FALSE;
+    break;
+  case CURLOPT_NOPROGRESS:
+    /*
+     * Shut off the internal supported progress meter
+     */
+    data->set.hide_progress = va_arg(param, long)?TRUE:FALSE;
+    if(data->set.hide_progress)
+      data->progress.flags |= PGRS_HIDE;
+    else
+      data->progress.flags &= ~PGRS_HIDE;
+    break;
+  case CURLOPT_NOBODY:
+    /*
+     * Do not include the body part in the output data stream.
+     */
+    data->set.opt_no_body = va_arg(param, long)?TRUE:FALSE;
+    if(data->set.opt_no_body)
+      /* in HTTP lingo, this means using the HEAD request */
+      data->set.httpreq = HTTPREQ_HEAD;
+    break;
+  case CURLOPT_FAILONERROR:
+    /*
+     * Don't output the >=300 error code HTML-page, but instead only
+     * return error.
+     */
+    data->set.http_fail_on_error = va_arg(param, long)?TRUE:FALSE;
+    break;
+  case CURLOPT_UPLOAD:
+  case CURLOPT_PUT:
+    /*
+     * We want to sent data to the remote host. If this is HTTP, that equals
+     * using the PUT request.
+     */
+    data->set.upload = va_arg(param, long)?TRUE:FALSE;
+    if(data->set.upload)
+      /* If this is HTTP, PUT is what's needed to "upload" */
+      data->set.httpreq = HTTPREQ_PUT;
+    break;
+  case CURLOPT_FILETIME:
+    /*
+     * Try to get the file time of the remote document. The time will
+     * later (possibly) become available using curl_easy_getinfo().
+     */
+    data->set.get_filetime = va_arg(param, long)?TRUE:FALSE;
+    break;
+  case CURLOPT_FTP_CREATE_MISSING_DIRS:
+    /*
+     * An FTP option that modifies an upload to create missing directories on
+     * the server.
+     */
+    data->set.ftp_create_missing_dirs = va_arg( param , long )?TRUE:FALSE;
+    break;
+  case CURLOPT_FTP_RESPONSE_TIMEOUT:
+    /*
+     * An FTP option that specifies how quickly an FTP response must be
+     * obtained before it is considered failure.
+     */
+    data->set.ftp_response_timeout = va_arg( param , long );
+    break;
+  case CURLOPT_FTPLISTONLY:
+    /*
+     * An FTP option that changes the command to one that asks for a list
+     * only, no file info details.
+     */
+    data->set.ftp_list_only = va_arg(param, long)?TRUE:FALSE;
+    break;
+  case CURLOPT_FTPAPPEND:
+    /*
+     * We want to upload and append to an existing (FTP) file.
+     */
+    data->set.ftp_append = va_arg(param, long)?TRUE:FALSE;
+    break;
+  case CURLOPT_NETRC:
+    /*
+     * Parse the $HOME/.netrc file
+     */
+    data->set.use_netrc = (enum CURL_NETRC_OPTION)va_arg(param, long);
+    break;
+  case CURLOPT_NETRC_FILE:
+    /*
+     * Use this file instead of the $HOME/.netrc file
+     */
+    data->set.netrc_file = va_arg(param, char *);
+    break;
+  case CURLOPT_TRANSFERTEXT:
+    /*
+     * This option was previously named 'FTPASCII'. Renamed to work with
+     * more protocols than merely FTP.
+     *
+     * Transfer using ASCII (instead of BINARY).
+     */
+    data->set.ftp_ascii = va_arg(param, long)?TRUE:FALSE;
+    break;
+  case CURLOPT_TIMECONDITION:
+    /*
+     * Set HTTP time condition. This must be one of the defines in the
+     * curl/curl.h header file.
+     */
+    data->set.timecondition = (curl_TimeCond)va_arg(param, long);
+    break;
+  case CURLOPT_TIMEVALUE:
+    /*
+     * This is the value to compare with the remote document with the
+     * method set with CURLOPT_TIMECONDITION
+     */
+    data->set.timevalue = (time_t)va_arg(param, long);
+    break;
+  case CURLOPT_SSLVERSION:
+    /*
+     * Set explicit SSL version to try to connect with, as some SSL
+     * implementations are lame.
+     */
+    data->set.ssl.version = va_arg(param, long);
+    break;
+
+#ifndef CURL_DISABLE_HTTP
+  case CURLOPT_AUTOREFERER:
+    /*
+     * Switch on automatic referer that gets set if curl follows locations.
+     */
+    data->set.http_auto_referer = va_arg(param, long)?1:0;
+    break;
+
+  case CURLOPT_ENCODING:
+    /*
+     * String to use at the value of Accept-Encoding header.
+     *
+     * If the encoding is set to "" we use an Accept-Encoding header that
+     * encompasses all the encodings we support.
+     * If the encoding is set to NULL we don't send an Accept-Encoding header
+     * and ignore an received Content-Encoding header.
+     *
+     */
+    data->set.encoding = va_arg(param, char *);
+    if(data->set.encoding && !*data->set.encoding)
+      data->set.encoding = (char*)ALL_CONTENT_ENCODINGS;
+    break;
+
+  case CURLOPT_FOLLOWLOCATION:
+    /*
+     * Follow Location: header hints on a HTTP-server.
+     */
+    data->set.http_follow_location = va_arg(param, long)?TRUE:FALSE;
+    break;
+
+  case CURLOPT_UNRESTRICTED_AUTH:
+    /*
+     * Send authentication (user+password) when following locations, even when
+     * hostname changed.
+     */
+    data->set.http_disable_hostname_check_before_authentication =
+      va_arg(param, long)?TRUE:FALSE;
+    break;
+
+  case CURLOPT_MAXREDIRS:
+    /*
+     * The maximum amount of hops you allow curl to follow Location:
+     * headers. This should mostly be used to detect never-ending loops.
+     */
+    data->set.maxredirs = va_arg(param, long);
+    break;
+
+  case CURLOPT_POST:
+    /* Does this option serve a purpose anymore? Yes it does, when
+       CURLOPT_POSTFIELDS isn't used and the POST data is read off the
+       callback! */
+    if(va_arg(param, long))
+      data->set.httpreq = HTTPREQ_POST;
+    break;
+
+  case CURLOPT_POSTFIELDS:
+    /*
+     * A string with POST data. Makes curl HTTP POST.
+     */
+    data->set.postfields = va_arg(param, char *);
+    if(data->set.postfields)
+      data->set.httpreq = HTTPREQ_POST;
+    break;
+
+  case CURLOPT_POSTFIELDSIZE:
+    /*
+     * The size of the POSTFIELD data to prevent libcurl to do strlen() to
+     * figure it out. Enables binary posts.
+     */
+    data->set.postfieldsize = va_arg(param, long);
+    break;
+
+  case CURLOPT_POSTFIELDSIZE_LARGE:
+    /*
+     * The size of the POSTFIELD data to prevent libcurl to do strlen() to
+     * figure it out. Enables binary posts.
+     */
+    data->set.postfieldsize = va_arg(param, curl_off_t);
+    break;
+
+  case CURLOPT_HTTPPOST:
+    /*
+     * Set to make us do HTTP POST
+     */
+    data->set.httppost = va_arg(param, struct curl_httppost *);
+    if(data->set.httppost)
+      data->set.httpreq = HTTPREQ_POST_FORM;
+    break;
+
+  case CURLOPT_REFERER:
+    /*
+     * String to set in the HTTP Referer: field.
+     */
+    if(data->change.referer_alloc) {
+      free(data->change.referer);
+      data->change.referer_alloc = FALSE;
+    }
+    data->set.set_referer = va_arg(param, char *);
+    data->change.referer = data->set.set_referer;
+    break;
+
+  case CURLOPT_USERAGENT:
+    /*
+     * String to use in the HTTP User-Agent field
+     */
+    data->set.useragent = va_arg(param, char *);
+    break;
+
+  case CURLOPT_HTTPHEADER:
+    /*
+     * Set a list with HTTP headers to use (or replace internals with)
+     */
+    data->set.headers = va_arg(param, struct curl_slist *);
+    break;
+
+  case CURLOPT_HTTP200ALIASES:
+    /*
+     * Set a list of aliases for HTTP 200 in response header
+     */
+    data->set.http200aliases = va_arg(param, struct curl_slist *);
+    break;
+
+  case CURLOPT_COOKIE:
+    /*
+     * Cookie string to send to the remote server in the request.
+     */
+    data->set.cookie = va_arg(param, char *);
+    break;
+
+  case CURLOPT_COOKIEFILE:
+    /*
+     * Set cookie file to read and parse. Can be used multiple times.
+     */
+    cookiefile = (char *)va_arg(param, void *);
+    if(cookiefile) {
+      struct curl_slist *cl;
+      /* append the cookie file name to the list of file names, and deal with
+         them later */
+      cl = curl_slist_append(data->change.cookielist, cookiefile);
+
+      if(!cl)
+        return CURLE_OUT_OF_MEMORY;
+
+      data->change.cookielist = cl;
+    }
+    break;
+
+  case CURLOPT_COOKIEJAR:
+    /*
+     * Set cookie file name to dump all cookies to when we're done.
+     */
+    data->set.cookiejar = (char *)va_arg(param, void *);
+
+    /*
+     * Activate the cookie parser. This may or may not already
+     * have been made.
+     */
+    data->cookies = Curl_cookie_init(data, NULL, data->cookies,
+                                     data->set.cookiesession);
+    break;
+
+  case CURLOPT_COOKIESESSION:
+    /*
+     * Set this option to TRUE to start a new "cookie session". It will
+     * prevent the forthcoming read-cookies-from-file actions to accept
+     * cookies that are marked as being session cookies, as they belong to a
+     * previous session.
+     *
+     * In the original Netscape cookie spec, "session cookies" are cookies
+     * with no expire date set. RFC2109 describes the same action if no
+     * 'Max-Age' is set and RFC2965 includes the RFC2109 description and adds
+     * a 'Discard' action that can enforce the discard even for cookies that
+     * have a Max-Age.
+     *
+     * We run mostly with the original cookie spec, as hardly anyone implements
+     * anything else.
+     */
+    data->set.cookiesession = (bool)va_arg(param, long);
+    break;
+
+  case CURLOPT_HTTPGET:
+    /*
+     * Set to force us do HTTP GET
+     */
+    if(va_arg(param, long)) {
+      data->set.httpreq = HTTPREQ_GET;
+      data->set.upload = FALSE; /* switch off upload */
+    }
+    break;
+
+  case CURLOPT_HTTP_VERSION:
+    /*
+     * This sets a requested HTTP version to be used. The value is one of
+     * the listed enums in curl/curl.h.
+     */
+    data->set.httpversion = va_arg(param, long);
+    break;
+
+  case CURLOPT_HTTPPROXYTUNNEL:
+    /*
+     * Tunnel operations through the proxy instead of normal proxy use
+     */
+    data->set.tunnel_thru_httpproxy = va_arg(param, long)?TRUE:FALSE;
+    break;
+
+  case CURLOPT_CUSTOMREQUEST:
+    /*
+     * Set a custom string to use as request
+     */
+    data->set.customrequest = va_arg(param, char *);
+
+    /* we don't set
+       data->set.httpreq = HTTPREQ_CUSTOM;
+       here, we continue as if we were using the already set type
+       and this just changes the actual request keyword */
+    break;
+
+  case CURLOPT_PROXY:
+    /*
+     * Set proxy server:port to use as HTTP proxy.
+     *
+     * If the proxy is set to "" we explicitly say that we don't want to use a
+     * proxy (even though there might be environment variables saying so).
+     *
+     * Setting it to NULL, means no proxy but allows the environment variables
+     * to decide for us.
+     */
+    if(data->change.proxy_alloc) {
+      /*
+       * The already set string is allocated, free that first
+       */
+      data->change.proxy_alloc=FALSE;;
+      free(data->change.proxy);
+    }
+    data->set.set_proxy = va_arg(param, char *);
+    data->change.proxy = data->set.set_proxy;
+    break;
+
+  case CURLOPT_PROXYPORT:
+    /*
+     * Explicitly set HTTP proxy port number.
+     */
+    data->set.proxyport = va_arg(param, long);
+    break;
+
+  case CURLOPT_HTTPAUTH:
+    /*
+     * Set HTTP Authentication type BITMASK.
+     */
+  {
+    long auth = va_arg(param, long);
+    /* switch off bits we can't support */
+#ifndef USE_SSLEAY
+    auth &= ~CURLAUTH_NTLM; /* no NTLM without SSL */
+#endif
+#ifndef HAVE_GSSAPI
+    auth &= ~CURLAUTH_GSSNEGOTIATE; /* no GSS-Negotiate without GSSAPI */
+#endif
+    if(!auth)
+      return CURLE_FAILED_INIT; /* no supported types left! */
+
+    data->set.httpauth = auth;
+  }
+  break;
+
+  case CURLOPT_PROXYAUTH:
+    /*
+     * Set HTTP Authentication type BITMASK.
+     */
+  {
+    long auth = va_arg(param, long);
+    /* switch off bits we can't support */
+#ifndef USE_SSLEAY
+    auth &= ~CURLAUTH_NTLM; /* no NTLM without SSL */
+#endif
+#ifndef HAVE_GSSAPI
+    auth &= ~CURLAUTH_GSSNEGOTIATE; /* no GSS-Negotiate without GSSAPI */
+#endif
+    if(!auth)
+      return CURLE_FAILED_INIT; /* no supported types left! */
+
+    data->set.proxyauth = auth;
+  }
+  break;
+#endif   /* CURL_DISABLE_HTTP */
+
+  case CURLOPT_WRITEHEADER:
+    /*
+     * Custom pointer to pass the header write callback function
+     */
+    data->set.writeheader = (void *)va_arg(param, void *);
+    break;
+  case CURLOPT_ERRORBUFFER:
+    /*
+     * Error buffer provided by the caller to get the human readable
+     * error string in.
+     */
+    data->set.errorbuffer = va_arg(param, char *);
+    break;
+  case CURLOPT_FILE:
+    /*
+     * FILE pointer to write to or include in the data write callback
+     */
+    data->set.out = va_arg(param, FILE *);
+    break;
+  case CURLOPT_FTPPORT:
+    /*
+     * Use FTP PORT, this also specifies which IP address to use
+     */
+    data->set.ftpport = va_arg(param, char *);
+    data->set.ftp_use_port = data->set.ftpport?1:0;
+    break;
+
+  case CURLOPT_FTP_USE_EPRT:
+    data->set.ftp_use_eprt = va_arg(param, long)?TRUE:FALSE;
+    break;
+
+  case CURLOPT_FTP_USE_EPSV:
+    data->set.ftp_use_epsv = va_arg(param, long)?TRUE:FALSE;
+    break;
+
+  case CURLOPT_INFILE:
+    /*
+     * FILE pointer to read the file to be uploaded from. Or possibly
+     * used as argument to the read callback.
+     */
+    data->set.in = va_arg(param, FILE *);
+    break;
+  case CURLOPT_INFILESIZE:
+    /*
+     * If known, this should inform curl about the file size of the
+     * to-be-uploaded file.
+     */
+    data->set.infilesize = va_arg(param, long);
+    break;
+  case CURLOPT_INFILESIZE_LARGE:
+    /*
+     * If known, this should inform curl about the file size of the
+     * to-be-uploaded file.
+     */
+    data->set.infilesize = va_arg(param, curl_off_t);
+    break;
+  case CURLOPT_LOW_SPEED_LIMIT:
+    /*
+     * The low speed limit that if transfers are below this for
+     * CURLOPT_LOW_SPEED_TIME, the transfer is aborted.
+     */
+    data->set.low_speed_limit=va_arg(param, long);
+    break;
+  case CURLOPT_LOW_SPEED_TIME:
+    /*
+     * The low speed time that if transfers are below the set
+     * CURLOPT_LOW_SPEED_LIMIT during this time, the transfer is aborted.
+     */
+    data->set.low_speed_time=va_arg(param, long);
+    break;
+  case CURLOPT_URL:
+    /*
+     * The URL to fetch.
+     */
+    if(data->change.url_alloc) {
+      /* the already set URL is allocated, free it first! */
+      free(data->change.url);
+      data->change.url_alloc=FALSE;
+    }
+    data->set.set_url = va_arg(param, char *);
+    data->change.url = data->set.set_url;
+    data->change.url_changed = TRUE;
+    break;
+  case CURLOPT_PORT:
+    /*
+     * The port number to use when getting the URL
+     */
+    data->set.use_port = va_arg(param, long);
+    break;
+  case CURLOPT_TIMEOUT:
+    /*
+     * The maximum time you allow curl to use for a single transfer
+     * operation.
+     */
+    data->set.timeout = va_arg(param, long);
+    break;
+  case CURLOPT_CONNECTTIMEOUT:
+    /*
+     * The maximum time you allow curl to use to connect.
+     */
+    data->set.connecttimeout = va_arg(param, long);
+    break;
+
+  case CURLOPT_USERPWD:
+    /*
+     * user:password to use in the operation
+     */
+    data->set.userpwd = va_arg(param, char *);
+    break;
+  case CURLOPT_POSTQUOTE:
+    /*
+     * List of RAW FTP commands to use after a transfer
+     */
+    data->set.postquote = va_arg(param, struct curl_slist *);
+    break;
+  case CURLOPT_PREQUOTE:
+    /*
+     * List of RAW FTP commands to use prior to RETR (Wesley Laxton)
+     */
+    data->set.prequote = va_arg(param, struct curl_slist *);
+    break;
+  case CURLOPT_QUOTE:
+    /*
+     * List of RAW FTP commands to use before a transfer
+     */
+    data->set.quote = va_arg(param, struct curl_slist *);
+    break;
+  case CURLOPT_PROGRESSFUNCTION:
+    /*
+     * Progress callback function
+     */
+    data->set.fprogress = va_arg(param, curl_progress_callback);
+    if(data->set.fprogress)
+      data->progress.callback = TRUE; /* no longer internal */
+    else
+      data->progress.callback = FALSE; /* NULL enforces internal */
+
+    break;
+  case CURLOPT_PROGRESSDATA:
+    /*
+     * Custom client data to pass to the progress callback
+     */
+    data->set.progress_client = va_arg(param, void *);
+    break;
+  case CURLOPT_PROXYUSERPWD:
+    /*
+     * user:password needed to use the proxy
+     */
+    data->set.proxyuserpwd = va_arg(param, char *);
+    break;
+  case CURLOPT_RANGE:
+    /*
+     * What range of the file you want to transfer
+     */
+    data->set.set_range = va_arg(param, char *);
+    break;
+  case CURLOPT_RESUME_FROM:
+    /*
+     * Resume transfer at the give file position
+     */
+    data->set.set_resume_from = va_arg(param, long);
+    break;
+  case CURLOPT_RESUME_FROM_LARGE:
+    /*
+     * Resume transfer at the give file position
+     */
+    data->set.set_resume_from = va_arg(param, curl_off_t);
+    break;
+  case CURLOPT_DEBUGFUNCTION:
+    /*
+     * stderr write callback.
+     */
+    data->set.fdebug = va_arg(param, curl_debug_callback);
+    /*
+     * if the callback provided is NULL, it'll use the default callback
+     */
+    break;
+  case CURLOPT_DEBUGDATA:
+    /*
+     * Set to a void * that should receive all error writes. This
+     * defaults to CURLOPT_STDERR for normal operations.
+     */
+    data->set.debugdata = va_arg(param, void *);
+    break;
+  case CURLOPT_STDERR:
+    /*
+     * Set to a FILE * that should receive all error writes. This
+     * defaults to stderr for normal operations.
+     */
+    data->set.err = va_arg(param, FILE *);
+    if(!data->set.err)
+      data->set.err = stderr;
+    break;
+  case CURLOPT_HEADERFUNCTION:
+    /*
+     * Set header write callback
+     */
+    data->set.fwrite_header = va_arg(param, curl_write_callback);
+    break;
+  case CURLOPT_WRITEFUNCTION:
+    /*
+     * Set data write callback
+     */
+    data->set.fwrite = va_arg(param, curl_write_callback);
+    if(!data->set.fwrite)
+      /* When set to NULL, reset to our internal default function */
+      data->set.fwrite = (curl_write_callback)fwrite;
+    break;
+  case CURLOPT_READFUNCTION:
+    /*
+     * Read data callback
+     */
+    data->set.fread = va_arg(param, curl_read_callback);
+    if(!data->set.fread)
+      /* When set to NULL, reset to our internal default function */
+      data->set.fread = (curl_read_callback)fread;
+    break;
+  case CURLOPT_SSLCERT:
+    /*
+     * String that holds file name of the SSL certificate to use
+     */
+    data->set.cert = va_arg(param, char *);
+    break;
+  case CURLOPT_SSLCERTTYPE:
+    /*
+     * String that holds file type of the SSL certificate to use
+     */
+    data->set.cert_type = va_arg(param, char *);
+    break;
+  case CURLOPT_SSLKEY:
+    /*
+     * String that holds file name of the SSL certificate to use
+     */
+    data->set.key = va_arg(param, char *);
+    break;
+  case CURLOPT_SSLKEYTYPE:
+    /*
+     * String that holds file type of the SSL certificate to use
+     */
+    data->set.key_type = va_arg(param, char *);
+    break;
+  case CURLOPT_SSLKEYPASSWD:
+    /*
+     * String that holds the SSL private key password.
+     */
+    data->set.key_passwd = va_arg(param, char *);
+    break;
+  case CURLOPT_SSLENGINE:
+    /*
+     * String that holds the SSL crypto engine.
+     */
+#ifdef HAVE_OPENSSL_ENGINE_H
+    {
+      const char *cpTemp = va_arg(param, char *);
+      ENGINE     *e;
+      if (cpTemp && cpTemp[0]) {
+        e = ENGINE_by_id(cpTemp);
+        if (e) {
+          if (data->engine) {
+            ENGINE_free(data->engine);
+          }
+          data->engine = e;
+        }
+        else {
+          failf(data, "SSL Engine '%s' not found", cpTemp);
+          return CURLE_SSL_ENGINE_NOTFOUND;
+        }
+      }
+    }
+    break;
+#else
+    return CURLE_SSL_ENGINE_NOTFOUND;
+#endif
+  case CURLOPT_SSLENGINE_DEFAULT:
+    /*
+     * flag to set engine as default.
+     */
+#ifdef HAVE_OPENSSL_ENGINE_H
+    if (data->engine) {
+      if (ENGINE_set_default(data->engine, ENGINE_METHOD_ALL) > 0) {
+#ifdef DEBUG
+        fprintf(stderr,"set default crypto engine\n");
+#endif
+      }
+      else {
+#ifdef DEBUG
+        failf(data, "set default crypto engine failed");
+#endif
+        return CURLE_SSL_ENGINE_SETFAILED;
+      }
+    }
+#endif
+    break;
+  case CURLOPT_CRLF:
+    /*
+     * Kludgy option to enable CRLF convertions. Subject for removal.
+     */
+    data->set.crlf = va_arg(param, long)?TRUE:FALSE;
+    break;
+  case CURLOPT_INTERFACE:
+    /*
+     * Set what interface to bind to when performing an operation and thus
+     * what from-IP your connection will use.
+     */
+    data->set.device = va_arg(param, char *);
+    break;
+  case CURLOPT_KRB4LEVEL:
+    /*
+     * A string that defines the krb4 security level.
+     */
+    data->set.krb4_level = va_arg(param, char *);
+    data->set.krb4=data->set.krb4_level?TRUE:FALSE;
+    break;
+  case CURLOPT_SSL_VERIFYPEER:
+    /*
+     * Enable peer SSL verifying.
+     */
+    data->set.ssl.verifypeer = va_arg(param, long);
+    break;
+  case CURLOPT_SSL_VERIFYHOST:
+    /*
+     * Enable verification of the CN contained in the peer certificate
+     */
+    data->set.ssl.verifyhost = va_arg(param, long);
+    break;
+  case CURLOPT_SSL_CTX_FUNCTION:
+    /*
+     * Set a SSL_CTX callback
+     */
+       data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
+    break;
+  case CURLOPT_SSL_CTX_DATA:
+    /*
+     * Set a SSL_CTX callback parameter pointer
+     */
+    data->set.ssl.fsslctxp = va_arg(param, void *);
+    break;
+  case CURLOPT_CAINFO:
+    /*
+     * Set CA info for SSL connection. Specify file name of the CA certificate
+     */
+    data->set.ssl.CAfile = va_arg(param, char *);
+    break;
+  case CURLOPT_CAPATH:
+    /*
+     * Set CA path info for SSL connection. Specify directory name of the CA
+     * certificates which have been prepared using openssl c_rehash utility.
+     */
+    /* This does not work on windows. */
+    data->set.ssl.CApath = va_arg(param, char *);
+    break;
+  case CURLOPT_TELNETOPTIONS:
+    /*
+     * Set a linked list of telnet options
+     */
+    data->set.telnet_options = va_arg(param, struct curl_slist *);
+    break;
+
+  case CURLOPT_BUFFERSIZE:
+    /*
+     * The application kindly asks for a differently sized receive buffer.
+     * If it seems reasonable, we'll use it.
+     */
+    data->set.buffer_size = va_arg(param, long);
+
+    if((data->set.buffer_size> (BUFSIZE -1 )) ||
+       (data->set.buffer_size < 1))
+      data->set.buffer_size = 0; /* huge internal default */
+
+    break;
+
+  case CURLOPT_NOSIGNAL:
+    /*
+     * The application asks not to set any signal() or alarm() handlers,
+     * even when using a timeout.
+     */
+    data->set.no_signal = va_arg(param, long) ? TRUE : FALSE;
+    break;
+
+  case CURLOPT_SHARE:
+    {
+      struct Curl_share *set;
+      set = va_arg(param, struct Curl_share *);
+
+      /* disconnect from old share, if any */
+      if(data->share) {
+        Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
+
+        if(data->share->hostcache == data->hostcache)
+          data->hostcache = NULL;
+
+        if(data->share->cookies == data->cookies)
+          data->cookies = NULL;
+
+        data->share->dirty--;
+
+        Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
+        data->share = NULL;
+      }
+
+      /* use new share if it set */
+      data->share = set;
+      if(data->share) {
+
+        Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
+
+        data->share->dirty++;
+
+        if(data->share->hostcache) {
+          /* use shared host cache, first free own one if any */
+          if(data->hostcache)
+            Curl_hash_destroy(data->hostcache);
+
+          data->hostcache = data->share->hostcache;
+        }
+#ifndef CURL_DISABLE_HTTP
+        if(data->share->cookies) {
+          /* use shared cookie list, first free own one if any */
+          if (data->cookies)
+            Curl_cookie_cleanup(data->cookies);
+          data->cookies = data->share->cookies;
+        }
+#endif   /* CURL_DISABLE_HTTP */
+        Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
+
+      }
+#ifndef CURL_DISABLE_HTTP
+      /* check cookie list is set */
+      if(!data->cookies)
+        data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE );
+#endif   /* CURL_DISABLE_HTTP */
+      /* check for host cache not needed,
+       * it will be done by curl_easy_perform */
+    }
+    break;
+
+  case CURLOPT_PROXYTYPE:
+    /*
+     * Set proxy type. HTTP/SOCKS4/SOCKS5
+     */
+    data->set.proxytype = (curl_proxytype)va_arg(param, long);
+    break;
+
+  case CURLOPT_PRIVATE:
+    /*
+     * Set private data pointer.
+     */
+    data->set.private = va_arg(param, char *);
+    break;
+
+  case CURLOPT_MAXFILESIZE:
+    /*
+     * Set the maximum size of a file to download.
+     */
+    data->set.max_filesize = va_arg(param, long);
+    break;
+
+  case CURLOPT_FTP_SSL:
+    /*
+     * Make FTP transfers attempt to use SSL/TLS.
+     */
+    data->set.ftp_ssl = (curl_ftpssl)va_arg(param, long);
+    break;
+
+  case CURLOPT_IPRESOLVE:
+    data->set.ip_version = va_arg(param, long);
+    break;
+
+  case CURLOPT_MAXFILESIZE_LARGE:
+    /*
+     * Set the maximum size of a file to download.
+     */
+    data->set.max_filesize = va_arg(param, curl_off_t);
+    break;
+
+  case CURLOPT_TCP_NODELAY:
+    /*
+     * Enable or disable TCP_NODELAY, which will disable/enable the Nagle
+     * algorithm
+     */
+    data->set.tcp_nodelay = (bool)va_arg(param, long);
+    break;
+
+  /*********** 3rd party transfer options ***********/
+  case CURLOPT_SOURCE_HOST:
+    /*
+     * Use SOURCE HOST
+     */
+    data->set.source_host = va_arg(param, char *);
+    data->set.printhost = (data->set.source_host != NULL);
+    break;
+
+  case CURLOPT_SOURCE_PORT:
+    /*
+     * Use SOURCE PORT
+     */
+    data->set.source_port = va_arg(param, char *);
+    break;
+
+  case CURLOPT_SOURCE_USERPWD:
+    /*
+     * Use SOURCE USER[:PASSWORD]
+     */
+    data->set.source_userpwd = va_arg(param, char *);
+    break;
+
+  case CURLOPT_SOURCE_PATH:
+    /*
+     * Use SOURCE PATH
+     */
+    data->set.source_path = va_arg(param, char *);
+    break;
+
+  case CURLOPT_PASV_HOST:
+    /*
+     * Indicates whether source or target host is passive
+     */
+    data->set.pasvHost = va_arg(param, long)?CURL_SOURCE_PASV:CURL_TARGET_PASV;
+    break;
+
+  case CURLOPT_SOURCE_PREQUOTE:
+    /*
+     * List of RAW FTP commands to use before a transfer on the source host
+     */
+    data->set.source_prequote = va_arg(param, struct curl_slist *);
+    break;
+
+  case CURLOPT_SOURCE_POSTQUOTE:
+    /*
+     * List of RAW FTP commands to use after a transfer on the source host
+     */
+    data->set.source_postquote = va_arg(param, struct curl_slist *);
+    break;
+
+  default:
+    /* unknown tag and its companion, just ignore: */
+    return CURLE_FAILED_INIT; /* correct this */
+  }
+  return CURLE_OK;
+}
+
+CURLcode Curl_disconnect(struct connectdata *conn)
+{
+  struct SessionHandle *data;
+  if(!conn)
+    return CURLE_OK; /* this is closed and fine already */
+
+  data = conn->data;
+
+  /*
+   * The range string is usually freed in curl_done(), but we might
+   * get here *instead* if we fail prematurely. Thus we need to be able
+   * to free this resource here as well.
+   */
+  if(conn->bits.rangestringalloc) {
+    free(conn->range);
+    conn->bits.rangestringalloc = FALSE;
+  }
+
+  if((conn->ntlm.state != NTLMSTATE_NONE) ||
+     (conn->proxyntlm.state != NTLMSTATE_NONE)) {
+    /* Authentication data is a mix of connection-related and sessionhandle-
+       related stuff. NTLM is connection-related so when we close the shop
+       we shall forget. */
+    data->state.authhost.done = FALSE;
+    data->state.authhost.picked =
+      data->state.authhost.want;
+
+    data->state.authproxy.done = FALSE;
+    data->state.authproxy.picked =
+      data->state.authhost.want;
+
+    data->state.authproblem = FALSE;
+  }
+
+  if(conn->curl_disconnect)
+    /* This is set if protocol-specific cleanups should be made */
+    conn->curl_disconnect(conn);
+
+  if(-1 != conn->connectindex) {
+    /* unlink ourselves! */
+    infof(data, "Closing connection #%ld\n", conn->connectindex);
+    data->state.connects[conn->connectindex] = NULL;
+  }
+
+  Curl_safefree(conn->proto.generic);
+  Curl_safefree(conn->newurl);
+  Curl_safefree(conn->pathbuffer); /* the URL path buffer */
+
+  Curl_safefree(conn->host.rawalloc); /* host name buffer */
+  Curl_safefree(conn->proxy.rawalloc); /* proxy name buffer */
+#ifdef USE_LIBIDN
+  if(conn->host.encalloc)
+    idn_free(conn->host.encalloc); /* encoded host name buffer, must be freed
+                                      with idn_free() since this was allocated
+                                      by libidn */
+  if(conn->proxy.encalloc)
+    idn_free(conn->proxy.encalloc); /* encoded proxy name buffer, must be
+                                       freed with idn_free() since this was
+                                       allocated by libidn */
+#endif
+  Curl_SSL_Close(conn);
+
+  /* close possibly still open sockets */
+  if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
+    sclose(conn->sock[SECONDARYSOCKET]);
+  if(CURL_SOCKET_BAD != conn->sock[FIRSTSOCKET])
+    sclose(conn->sock[FIRSTSOCKET]);
+
+  Curl_safefree(conn->user);
+  Curl_safefree(conn->passwd);
+  Curl_safefree(conn->proxyuser);
+  Curl_safefree(conn->proxypasswd);
+  Curl_safefree(conn->allocptr.proxyuserpwd);
+  Curl_safefree(conn->allocptr.uagent);
+  Curl_safefree(conn->allocptr.userpwd);
+  Curl_safefree(conn->allocptr.accept_encoding);
+  Curl_safefree(conn->allocptr.rangeline);
+  Curl_safefree(conn->allocptr.ref);
+  Curl_safefree(conn->allocptr.host);
+  Curl_safefree(conn->allocptr.cookiehost);
+
+#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \
+    defined(USE_THREADING_GETADDRINFO)
+  /* possible left-overs from the async name resolve */
+  Curl_safefree(conn->async.hostname);
+  Curl_safefree(conn->async.os_specific);
+#endif
+
+  Curl_free_ssl_config(&conn->ssl_config);
+
+  free(conn); /* free all the connection oriented data */
+
+  return CURLE_OK;
+}
+
+/*
+ * This function should return TRUE if the socket is to be assumed to
+ * be dead. Most commonly this happens when the server has closed the
+ * connection due to inactivity.
+ */
+static bool SocketIsDead(curl_socket_t sock)
+{
+  int sval;
+  bool ret_val = TRUE;
+  fd_set check_set;
+  struct timeval to;
+
+  FD_ZERO(&check_set);
+  FD_SET(sock, &check_set);
+
+  to.tv_sec = 0;
+  to.tv_usec = 0;
+
+  sval = select(sock + 1, &check_set, 0, 0, &to);
+  if(sval == 0)
+    /* timeout */
+    ret_val = FALSE;
+
+  return ret_val;
+}
+
+/*
+ * Given one filled in connection struct (named needle), this function should
+ * detect if there already is one that have all the significant details
+ * exactly the same and thus should be used instead.
+ */
+static bool
+ConnectionExists(struct SessionHandle *data,
+                 struct connectdata *needle,
+                 struct connectdata **usethis)
+{
+  long i;
+  struct connectdata *check;
+
+  for(i=0; i< data->state.numconnects; i++) {
+    bool match = FALSE;
+    /*
+     * Note that if we use a HTTP proxy, we check connections to that
+     * proxy and not to the actual remote server.
+     */
+    check = data->state.connects[i];
+    if(!check)
+      /* NULL pointer means not filled-in entry */
+      continue;
+
+    if((needle->protocol&PROT_SSL) != (check->protocol&PROT_SSL))
+      /* don't do mixed SSL and non-SSL connections */
+      continue;
+
+    if(!needle->bits.httpproxy || needle->protocol&PROT_SSL) {
+      /* The requested connection does not use a HTTP proxy or it
+         uses SSL. */
+
+      if(!(needle->protocol&PROT_SSL) && check->bits.httpproxy)
+        /* we don't do SSL but the cached connection has a proxy,
+           then don't match this */
+        continue;
+
+      if(strequal(needle->protostr, check->protostr) &&
+         strequal(needle->host.name, check->host.name) &&
+         (needle->remote_port == check->remote_port) ) {
+        if(needle->protocol & PROT_SSL) {
+          /* This is SSL, verify that we're using the same
+             ssl options as well */
+          if(!Curl_ssl_config_matches(&needle->ssl_config,
+                                      &check->ssl_config)) {
+            continue;
+          }
+        }
+        if((needle->protocol & PROT_FTP) ||
+           ((needle->protocol & PROT_HTTP) &&
+            (needle->data->state.authhost.want==CURLAUTH_NTLM))) {
+          /* This is FTP or HTTP+NTLM, verify that we're using the same name
+             and password as well */
+          if(!strequal(needle->user, check->user) ||
+             !strequal(needle->passwd, check->passwd)) {
+            /* one of them was different */
+            continue;
+          }
+        }
+        match = TRUE;
+      }
+    }
+    else { /* The requested needle connection is using a proxy,
+              is the checked one using the same? */
+      if(check->bits.httpproxy &&
+         strequal(needle->proxy.name, check->proxy.name) &&
+         needle->port == check->port) {
+        /* This is the same proxy connection, use it! */
+        match = TRUE;
+      }
+    }
+
+    if(match) {
+      bool dead = SocketIsDead(check->sock[FIRSTSOCKET]);
+      if(dead) {
+        /*
+         */
+        infof(data, "Connection %d seems to be dead!\n", i);
+        Curl_disconnect(check); /* disconnect resources */
+        data->state.connects[i]=NULL; /* nothing here */
+
+        /* There's no need to continue searching, because we only store
+           one connection for each unique set of identifiers */
+        return FALSE;
+      }
+
+      *usethis = check;
+      return TRUE; /* yes, we found one to use! */
+    }
+  }
+  return FALSE; /* no matching connecting exists */
+}
+
+/*
+ * This function frees/closes a connection in the connection cache. This
+ * should take the previously set policy into account when deciding which
+ * of the connections to kill.
+ */
+static long
+ConnectionKillOne(struct SessionHandle *data)
+{
+  long i;
+  struct connectdata *conn;
+  long highscore=-1;
+  long connindex=-1;
+  long score;
+  struct timeval now;
+
+  now = Curl_tvnow();
+
+  for(i=0; i< data->state.numconnects; i++) {
+    conn = data->state.connects[i];
+
+    if(!conn)
+      continue;
+
+    /*
+     * By using the set policy, we score each connection.
+     */
+    switch(data->set.closepolicy) {
+    case CURLCLOSEPOLICY_LEAST_RECENTLY_USED:
+    default:
+      /*
+       * Set higher score for the age passed since the connection
+       * was used.
+       */
+      score = Curl_tvdiff(now, conn->now);
+      break;
+    case CURLCLOSEPOLICY_OLDEST:
+      /*
+       * Set higher score for the age passed since the connection
+       * was created.
+       */
+      score = Curl_tvdiff(now, conn->created);
+      break;
+    }
+
+    if(score > highscore) {
+      highscore = score;
+      connindex = i;
+    }
+  }
+  if(connindex >= 0) {
+
+    /* the winner gets the honour of being disconnected */
+    (void) Curl_disconnect(data->state.connects[connindex]);
+
+    /* clean the array entry */
+    data->state.connects[connindex] = NULL;
+  }
+
+  return connindex; /* return the available index or -1 */
+}
+
+/*
+ * The given input connection struct pointer is to be stored. If the "cache"
+ * is already full, we must clean out the most suitable using the previously
+ * set policy.
+ *
+ * The given connection should be unique. That must've been checked prior to
+ * this call.
+ */
+static long
+ConnectionStore(struct SessionHandle *data,
+                struct connectdata *conn)
+{
+  long i;
+  for(i=0; i< data->state.numconnects; i++) {
+    if(!data->state.connects[i])
+      break;
+  }
+  if(i == data->state.numconnects) {
+    /* there was no room available, kill one */
+    i = ConnectionKillOne(data);
+    infof(data, "Connection (#%d) was killed to make room\n", i);
+  }
+
+  if(-1 != i) {
+    /* only do this if a true index was returned, if -1 was returned there
+       is no room in the cache for an unknown reason and we cannot store
+       this there. */
+    data->state.connects[i] = conn; /* fill in this */
+    conn->connectindex = i; /* make the child know where the pointer to this
+                               particular data is stored */
+  }
+  return i;
+}
+
+/*
+ * This function logs in to a SOCKS5 proxy and sends the specifies the final
+ * desitination server.
+ */
+static int handleSock5Proxy(const char *proxy_name,
+                            const char *proxy_password,
+                            struct connectdata *conn)
+{
+  /*
+    According to the RFC1928, section "6.  Replies". This is what a SOCK5
+    replies:
+
+        +----+-----+-------+------+----------+----------+
+        |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
+        +----+-----+-------+------+----------+----------+
+        | 1  |  1  | X'00' |  1   | Variable |    2     |
+        +----+-----+-------+------+----------+----------+
+
+    Where:
+
+    o  VER    protocol version: X'05'
+    o  REP    Reply field:
+    o  X'00' succeeded
+  */
+
+  unsigned char socksreq[600]; /* room for large user/pw (255 max each) */
+  ssize_t actualread;
+  ssize_t written;
+  int result;
+  CURLcode code;
+  int sock = conn->sock[FIRSTSOCKET];
+
+  Curl_nonblock(sock, FALSE);
+
+  socksreq[0] = 5; /* version */
+  socksreq[1] = (char)(proxy_name ? 2 : 1); /* number of methods (below) */
+  socksreq[2] = 0; /* no authentication */
+  socksreq[3] = 2; /* username/password */
+
+  code = Curl_write(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]),
+                      &written);
+  if ((code != CURLE_OK) || (written != (2 + (int)socksreq[1]))) {
+    failf(conn->data, "Unable to send initial SOCKS5 request.");
+    return 1;
+  }
+
+  result=Curl_read(conn, sock, (char *)socksreq, 2, &actualread);
+  if ((result != CURLE_OK) || (actualread != 2)) {
+    failf(conn->data, "Unable to receive initial SOCKS5 response.");
+    return 1;
+  }
+
+  if (socksreq[0] != 5) {
+    failf(conn->data, "Received invalid version in initial SOCKS5 response.");
+    return 1;
+  }
+  if (socksreq[1] == 0) {
+    /* Nothing to do, no authentication needed */
+    ;
+  }
+  else if (socksreq[1] == 2) {
+    /* Needs user name and password */
+    int userlen, pwlen, len;
+
+    userlen = (int)strlen(proxy_name);
+    pwlen = proxy_password?(int)strlen(proxy_password):0;
+
+    /*   username/password request looks like
+     * +----+------+----------+------+----------+
+     * |VER | ULEN |  UNAME   | PLEN |  PASSWD  |
+     * +----+------+----------+------+----------+
+     * | 1  |  1   | 1 to 255 |  1   | 1 to 255 |
+     * +----+------+----------+------+----------+
+     */
+    len = 0;
+    socksreq[len++] = 1;    /* username/pw subnegotiation version */
+    socksreq[len++] = (char) userlen;
+    memcpy(socksreq + len, proxy_name, (int) userlen);
+    len += userlen;
+    socksreq[len++] = (char) pwlen;
+    memcpy(socksreq + len, proxy_password, (int) pwlen);
+    len += pwlen;
+
+    code = Curl_write(conn, sock, (char *)socksreq, len, &written);
+    if ((code != CURLE_OK) || (len != written)) {
+      failf(conn->data, "Failed to send SOCKS5 sub-negotiation request.");
+      return 1;
+    }
+
+    result=Curl_read(conn, sock, (char *)socksreq, 2, &actualread);
+    if ((result != CURLE_OK) || (actualread != 2)) {
+      failf(conn->data, "Unable to receive SOCKS5 sub-negotiation response.");
+      return 1;
+    }
+
+    if ((socksreq[0] != 5) || /* version */
+        (socksreq[1] != 0)) { /* status */
+      failf(conn->data, "User was rejected by the SOCKS5 server (%d %d).",
+            socksreq[0], socksreq[1]);
+      return 1;
+    }
+
+    /* Everything is good so far, user was authenticated! */
+  }
+  else {
+    /* error */
+    if (socksreq[1] == 1) {
+      failf(conn->data,
+            "SOCKS5 GSSAPI per-message authentication is not supported.");
+      return 1;
+    }
+    else if (socksreq[1] == 255) {
+      if (proxy_name[0] == 0) {
+        failf(conn->data,
+              "No authentication method was acceptable. (It is quite likely"
+              " that the SOCKS5 server wanted a username/password, since none"
+              " was supplied to the server on this connection.)");
+      }
+      else {
+        failf(conn->data, "No authentication method was acceptable.");
+      }
+      return 1;
+    }
+    else {
+      failf(conn->data,
+            "Undocumented SOCKS5 mode attempted to be used by server.");
+      return 1;
+    }
+  }
+
+  /* Authentication is complete, now specify destination to the proxy */
+  socksreq[0] = 5; /* version (SOCKS5) */
+  socksreq[1] = 1; /* connect */
+  socksreq[2] = 0; /* must be zero */
+  socksreq[3] = 1; /* IPv4 = 1 */
+
+  {
+    struct Curl_dns_entry *dns;
+    Curl_addrinfo *hp=NULL;
+    int rc = Curl_resolv(conn, conn->host.name, (int)conn->remote_port, &dns);
+
+    if(rc == CURLRESOLV_ERROR)
+      return 1;
+
+    if(rc == CURLRESOLV_PENDING)
+      /* this requires that we're in "wait for resolve" state */
+      rc = Curl_wait_for_resolv(conn, &dns);
+    (void)rc;
+
+    /*
+     * We cannot use 'hostent' as a struct that Curl_resolv() returns.  It
+     * returns a Curl_addrinfo pointer that may not always look the same.
+     */
+    if(dns)
+      hp=dns->addr;
+    if (hp) {
+      char buf[64];
+      unsigned short ip[4];
+      Curl_printable_address(hp, buf, sizeof(buf));
+
+      if(4 == sscanf( buf, "%hu.%hu.%hu.%hu",
+                      &ip[0], &ip[1], &ip[2], &ip[3])) {
+        socksreq[4] = (unsigned char)ip[0];
+        socksreq[5] = (unsigned char)ip[1];
+        socksreq[6] = (unsigned char)ip[2];
+        socksreq[7] = (unsigned char)ip[3];
+      }
+      else
+        hp = NULL; /* fail! */
+
+      Curl_resolv_unlock(conn->data, dns); /* not used anymore from now on */
+    }
+    if(!hp) {
+      failf(conn->data, "Failed to resolve \"%s\" for SOCKS5 connect.",
+            conn->host.name);
+      return 1;
+    }
+  }
+
+  {
+    unsigned short s = htons(conn->remote_port);
+    memcpy(socksreq+8, &s, sizeof(unsigned short));
+  }
+
+  {
+    const int packetsize = 10;
+
+    code = Curl_write(conn, sock, (char *)socksreq, packetsize, &written);
+    if ((code != CURLE_OK) || (written != packetsize)) {
+      failf(conn->data, "Failed to send SOCKS5 connect request.");
+      return 1;
+    }
+
+    result = Curl_read(conn, sock, (char *)socksreq, packetsize, &actualread);
+    if ((result != CURLE_OK) || (actualread != packetsize)) {
+      failf(conn->data, "Failed to receive SOCKS5 connect request ack.");
+      return 1;
+    }
+
+    if (socksreq[0] != 5) { /* version */
+      failf(conn->data,
+            "SOCKS5 reply has wrong version, version should be 5.");
+      return 1;
+    }
+    if (socksreq[1] != 0) { /* Anything besides 0 is an error */
+        unsigned short sh;
+        memcpy(&sh, socksreq+8, sizeof(unsigned short));
+
+        failf(conn->data,
+              "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)",
+              (unsigned char)socksreq[4], (unsigned char)socksreq[5],
+              (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+              (unsigned int)ntohs(sh),
+              socksreq[1]);
+        return 1;
+    }
+  }
+
+  Curl_nonblock(sock, TRUE);
+  return 0; /* Proxy was successful! */
+}
+
+static CURLcode ConnectPlease(struct connectdata *conn,
+                              struct Curl_dns_entry *hostaddr,
+                              bool *connected)
+{
+  CURLcode result;
+  Curl_addrinfo *addr;
+  struct SessionHandle *data = conn->data;
+  char *hostname = data->change.proxy?conn->proxy.name:conn->host.name;
+
+  infof(data, "About to connect() to %s port %d\n",
+        hostname, conn->port);
+
+  /*************************************************************
+   * Connect to server/proxy
+   *************************************************************/
+  result= Curl_connecthost(conn,
+                           hostaddr,
+                           &conn->sock[FIRSTSOCKET],
+                           &addr,
+                           connected);
+  if(CURLE_OK == result) {
+    /* All is cool, then we store the current information */
+    conn->dns_entry = hostaddr;
+    conn->ip_addr = addr;
+
+    if (conn->data->set.proxytype == CURLPROXY_SOCKS5) {
+      return handleSock5Proxy(conn->proxyuser,
+                              conn->proxypasswd,
+                              conn) ?
+        CURLE_COULDNT_CONNECT : CURLE_OK;
+    }
+    else if (conn->data->set.proxytype == CURLPROXY_HTTP) {
+      /* do nothing here. handled later. */
+    }
+    else {
+      failf(conn->data, "unknown proxytype option given");
+      return CURLE_COULDNT_CONNECT;
+    }
+  }
+
+  return result;
+}
+
+/*
+ * verboseconnect() displays verbose information after a connect
+ */
+static void verboseconnect(struct connectdata *conn)
+{
+  struct SessionHandle *data = conn->data;
+  char addrbuf[256];
+
+  /* Get a printable version of the network address. */
+  Curl_printable_address(conn->ip_addr, addrbuf, sizeof(addrbuf));
+  infof(data, "Connected to %s (%s) port %d\n",
+        conn->bits.httpproxy ? conn->proxy.dispname : conn->host.dispname,
+        addrbuf[0] ? addrbuf : "??", conn->port);
+}
+
+/*
+ * We have discovered that the TCP connection has been successful, we can now
+ * proceed with some action.
+ *
+ * If we're using the multi interface, this host address pointer is most
+ * likely NULL at this point as we can't keep the resolved info around. This
+ * may call for some reworking, like a reference counter in the struct or
+ * something.
+ */
+CURLcode Curl_protocol_connect(struct connectdata *conn)
+{
+  struct SessionHandle *data = conn->data;
+  CURLcode result=CURLE_OK;
+
+  if(conn->bits.tcpconnect)
+    /* We already are connected, get back. This may happen when the connect
+       worked fine in the first call, like when we connect to a local server
+       or proxy. */
+    return CURLE_OK;
+
+  Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
+
+  if(data->set.verbose)
+    verboseconnect(conn);
+
+  if(conn->curl_connect) {
+    /* is there a protocol-specific connect() procedure? */
+
+    /* set start time here for timeout purposes in the
+     * connect procedure, it is later set again for the
+     * progress meter purpose */
+    conn->now = Curl_tvnow();
+
+    /* Call the protocol-specific connect function */
+    result = conn->curl_connect(conn);
+  }
+
+  return result; /* pass back status */
+}
+
+/*
+ * Helpers for IDNA convertions.
+ */
+#ifdef USE_LIBIDN
+static bool is_ASCII_name (const char *hostname)
+{
+  const unsigned char *ch = (const unsigned char*)hostname;
+
+  while (*ch) {
+    if (*ch++ & 0x80)
+      return FALSE;
+  }
+  return TRUE;
+}
+#endif
+
+static void fix_hostname(struct connectdata *conn, struct hostname *host)
+{
+  /* set the name we use to display the host name */
+  host->dispname = host->name;
+
+#ifdef USE_LIBIDN
+  /*************************************************************
+   * Check name for non-ASCII and convert hostname to ACE form.
+   *************************************************************/
+  if (!is_ASCII_name(host->name) &&
+      stringprep_check_version(LIBIDN_REQUIRED_VERSION)) {
+    char *ace_hostname = NULL;
+    struct SessionHandle *data = conn->data;
+    int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0);
+    infof (data, "Input domain encoded as `%s'\n",
+           stringprep_locale_charset ());
+    if (rc != IDNA_SUCCESS)
+      infof(data, "Failed to convert %s to ACE; IDNA error %d\n",
+            host->name, rc);
+    else {
+      host->encalloc = ace_hostname;
+      /* change the name pointer to point to the encoded hostname */
+      host->name = host->encalloc;
+    }
+  }
+#else
+  (void)conn; /* never used */
+#endif
+}
+
+
+/**
+ * CreateConnection() sets up a new connectdata struct, or re-uses an already
+ * existing one, and resolves host name.
+ *
+ * if this function returns CURLE_OK and *async is set to TRUE, the resolve
+ * response will be coming asynchronously. If *async is FALSE, the name is
+ * already resolved.
+ *
+ * @param data The sessionhandle pointer
+ * @param in_connect is set to the next connection data pointer
+ * @param addr is set to the new dns entry for this connection
+ * @param async is set TRUE/FALSE depending on the nature of this lookup
+ * @return CURLcode
+ * @see SetupConnection()
+ */
+
+static CURLcode CreateConnection(struct SessionHandle *data,
+                                 struct connectdata **in_connect,
+                                 struct Curl_dns_entry **addr,
+                                 bool *async)
+{
+  char *tmp;
+  CURLcode result=CURLE_OK;
+  struct connectdata *conn;
+  struct connectdata *conn_temp;
+  size_t urllen;
+  struct Curl_dns_entry *hostaddr;
+#if defined(HAVE_ALARM) && !defined(USE_ARES)
+  unsigned int prev_alarm=0;
+#endif
+  char endbracket;
+  char user[MAX_CURL_USER_LENGTH];
+  char passwd[MAX_CURL_PASSWORD_LENGTH];
+  int rc;
+  bool reuse;
+
+#ifndef USE_ARES
+#ifdef SIGALRM
+#ifdef HAVE_SIGACTION
+  struct sigaction keep_sigact;   /* store the old struct here */
+  bool keep_copysig=FALSE;        /* did copy it? */
+#else
+#ifdef HAVE_SIGNAL
+  void *keep_sigact;              /* store the old handler here */
+#endif /* HAVE_SIGNAL */
+#endif /* HAVE_SIGACTION */
+#endif /* SIGALRM */
+#endif /* USE_ARES */
+
+  *addr = NULL; /* nothing yet */
+  *async = FALSE;
+
+  /*************************************************************
+   * Check input data
+   *************************************************************/
+
+  if(!data->change.url)
+    return CURLE_URL_MALFORMAT;
+
+  /* First, split up the current URL in parts so that we can use the
+     parts for checking against the already present connections. In order
+     to not have to modify everything at once, we allocate a temporary
+     connection data struct and fill in for comparison purposes. */
+
+  conn = (struct connectdata *)malloc(sizeof(struct connectdata));
+  if(!conn) {
+    *in_connect = NULL; /* clear the pointer */
+    return CURLE_OUT_OF_MEMORY;
+  }
+  /* We must set the return variable as soon as possible, so that our
+     parent can cleanup any possible allocs we may have done before
+     any failure */
+  *in_connect = conn;
+
+  /* we have to init the struct */
+  memset(conn, 0, sizeof(struct connectdata));
+
+  /* and we setup a few fields in case we end up actually using this struct */
+  conn->data = data;           /* remember our daddy */
+  conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD;     /* no file descriptor */
+  conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
+  conn->connectindex = -1;    /* no index */
+  conn->bits.httpproxy = (data->change.proxy && *data->change.proxy &&
+                          (data->set.proxytype == CURLPROXY_HTTP))?
+    TRUE:FALSE; /* http proxy or not */
+
+  /* Default protocol-independent behavior doesn't support persistant
+     connections, so we set this to force-close. Protocols that support
+     this need to set this to FALSE in their "curl_do" functions. */
+  conn->bits.close = TRUE;
+
+  /* maxdownload must be -1 on init, as 0 is a valid value! */
+  conn->maxdownload = -1;  /* might have been used previously! */
+
+  /* Store creation time to help future close decision making */
+  conn->created = Curl_tvnow();
+
+  conn->bits.use_range = data->set.set_range?TRUE:FALSE; /* range status */
+  conn->range = data->set.set_range;              /* clone the range setting */
+  conn->resume_from = data->set.set_resume_from;   /* inherite resume_from */
+
+  /* Set the start time temporary to this creation time to allow easier
+     timeout checks before the transfer has started for real. The start time
+     is later set "for real" using Curl_pgrsStartNow(). */
+  conn->data->progress.start = conn->created;
+
+  conn->bits.user_passwd = data->set.userpwd?1:0;
+  conn->bits.proxy_user_passwd = data->set.proxyuserpwd?1:0;
+  conn->bits.no_body = data->set.opt_no_body;
+  conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
+
+  /* This initing continues below, see the comment "Continue connectdata
+   * initialization here" */
+
+  /***********************************************************
+   * We need to allocate memory to store the path in. We get the size of the
+   * full URL to be sure, and we need to make it at least 256 bytes since
+   * other parts of the code will rely on this fact
+   ***********************************************************/
+#define LEAST_PATH_ALLOC 256
+  urllen=strlen(data->change.url);
+  if(urllen < LEAST_PATH_ALLOC)
+    urllen=LEAST_PATH_ALLOC;
+
+  conn->pathbuffer=(char *)malloc(urllen);
+  if(NULL == conn->pathbuffer)
+    return CURLE_OUT_OF_MEMORY; /* really bad error */
+  conn->path = conn->pathbuffer;
+
+  conn->host.rawalloc=(char *)malloc(urllen);
+  if(NULL == conn->host.rawalloc)
+    return CURLE_OUT_OF_MEMORY;
+  conn->host.name = conn->host.rawalloc;
+
+  /*************************************************************
+   * Parse the URL.
+   *
+   * We need to parse the url even when using the proxy, because we will need
+   * the hostname and port in case we are trying to SSL connect through the
+   * proxy -- and we don't know if we will need to use SSL until we parse the
+   * url ...
+   ************************************************************/
+  if((2 == sscanf(data->change.url, "%15[^:]:%[^\n]",
+                  conn->protostr,
+                  conn->path)) && strequal(conn->protostr, "file")) {
+    if(conn->path[0] == '/' && conn->path[1] == '/') {
+      /* Allow omitted hostname (e.g. file:/<path>).  This is not strictly
+       * speaking a valid file: URL by RFC 1738, but treating file:/<path> as
+       * file://localhost/<path> is similar to how other schemes treat missing
+       * hostnames.  See RFC 1808. */
+
+      /* This cannot be done with strcpy() in a portable manner, since the
+         memory areas overlap! */
+      memmove(conn->path, conn->path + 2, strlen(conn->path + 2)+1);
+    }
+    /*
+     * we deal with file://<host>/<path> differently since it supports no
+     * hostname other than "localhost" and "127.0.0.1", which is unique among
+     * the URL protocols specified in RFC 1738
+     */
+    if(conn->path[0] != '/') {
+      /* the URL included a host name, we ignore host names in file:// URLs
+         as the standards don't define what to do with them */
+      char *ptr=strchr(conn->path, '/');
+      if(ptr) {
+        /* there was a slash present
+
+           RFC1738 (section 3.1, page 5) says:
+
+           The rest of the locator consists of data specific to the scheme,
+           and is known as the "url-path". It supplies the details of how the
+           specified resource can be accessed. Note that the "/" between the
+           host (or port) and the url-path is NOT part of the url-path.
+
+           As most agents use file://localhost/foo to get '/foo' although the
+           slash preceeding foo is a separator and not a slash for the path,
+           a URL as file://localhost//foo must be valid as well, to refer to
+           the same file with an absolute path.
+        */
+
+        if(ptr[1] && ('/' == ptr[1]))
+          /* if there was two slashes, we skip the first one as that is then
+             used truly as a separator */
+          ptr++;
+
+        /* This cannot be made with strcpy, as the memory chunks overlap! */
+        memmove(conn->path, ptr, strlen(ptr)+1);
+      }
+    }
+
+    strcpy(conn->protostr, "file"); /* store protocol string lowercase */
+  }
+  else {
+    /* Set default path */
+    strcpy(conn->path, "/");
+
+    /* We need to search for '/' OR '?' - whichever comes first after host
+     * name but before the path. We need to change that to handle things like
+     * http://example.com?param= (notice the missing '/'). Later we'll insert
+     * that missing slash at the beginning of the path.
+     */
+    if (2 > sscanf(data->change.url,
+                   "%15[^\n:]://%[^\n/?]%[^\n]",
+                   conn->protostr,
+                   conn->host.name, conn->path)) {
+
+      /*
+       * The URL was badly formatted, let's try the browser-style _without_
+       * protocol specified like 'http://'.
+       */
+      if((1 > sscanf(data->change.url, "%[^\n/?]%[^\n]",
+                     conn->host.name, conn->path)) ) {
+        /*
+         * We couldn't even get this format.
+         */
+        failf(data, "<url> malformed");
+        return CURLE_URL_MALFORMAT;
+      }
+
+      /*
+       * Since there was no protocol part specified, we guess what protocol it
+       * is based on the first letters of the server name.
+       */
+
+      /* Note: if you add a new protocol, please update the list in
+       * lib/version.c too! */
+
+      if(checkprefix("GOPHER", conn->host.name))
+        strcpy(conn->protostr, "gopher");
+#ifdef USE_SSLEAY
+      else if(checkprefix("HTTPS", conn->host.name))
+        strcpy(conn->protostr, "https");
+      else if(checkprefix("FTPS", conn->host.name))
+        strcpy(conn->protostr, "ftps");
+#endif /* USE_SSLEAY */
+      else if(checkprefix("FTP", conn->host.name))
+        strcpy(conn->protostr, "ftp");
+      else if(checkprefix("TELNET", conn->host.name))
+        strcpy(conn->protostr, "telnet");
+      else if (checkprefix("DICT", conn->host.name))
+        strcpy(conn->protostr, "DICT");
+      else if (checkprefix("LDAP", conn->host.name))
+        strcpy(conn->protostr, "LDAP");
+      else {
+        strcpy(conn->protostr, "http");
+      }
+
+      conn->protocol |= PROT_MISSING; /* not given in URL */
+    }
+  }
+
+  /* If the URL is malformatted (missing a '/' after hostname before path) we
+   * insert a slash here. The only letter except '/' we accept to start a path
+   * is '?'.
+   */
+  if(conn->path[0] == '?') {
+    /* We need this function to deal with overlapping memory areas. We know
+       that the memory area 'path' points to is 'urllen' bytes big and that
+       is bigger than the path. Use +1 to move the zero byte too. */
+    memmove(&conn->path[1], conn->path, strlen(conn->path)+1);
+    conn->path[0] = '/';
+  }
+
+  /*
+   * So if the URL was A://B/C,
+   *   conn->protostr is A
+   *   conn->host.name is B
+   *   conn->path is /C
+   */
+
+  /*************************************************************
+   * Take care of proxy authentication stuff
+   *************************************************************/
+  if(conn->bits.proxy_user_passwd) {
+    char proxyuser[MAX_CURL_USER_LENGTH]="";
+    char proxypasswd[MAX_CURL_PASSWORD_LENGTH]="";
+
+    sscanf(data->set.proxyuserpwd,
+           "%" MAX_CURL_USER_LENGTH_TXT "[^:]:"
+           "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]",
+           proxyuser, proxypasswd);
+
+    conn->proxyuser = strdup(proxyuser);
+    if(!conn->proxyuser)
+      return CURLE_OUT_OF_MEMORY;
+
+    conn->proxypasswd = strdup(proxypasswd);
+    if(!conn->proxypasswd)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  /*************************************************************
+   * Detect what (if any) proxy to use
+   *************************************************************/
+  if(!data->change.proxy) {
+    /* If proxy was not specified, we check for default proxy environment
+     * variables, to enable i.e Lynx compliance:
+     *
+     * http_proxy=http://some.server.dom:port/
+     * https_proxy=http://some.server.dom:port/
+     * ftp_proxy=http://some.server.dom:port/
+     * gopher_proxy=http://some.server.dom:port/
+     * no_proxy=domain1.dom,host.domain2.dom
+     *   (a comma-separated list of hosts which should
+     *   not be proxied, or an asterisk to override
+     *   all proxy variables)
+     * all_proxy=http://some.server.dom:port/
+     *   (seems to exist for the CERN www lib. Probably
+     *   the first to check for.)
+     *
+     * For compatibility, the all-uppercase versions of these variables are
+     * checked if the lowercase versions don't exist.
+     */
+    char *no_proxy;
+    char *no_proxy_tok_buf;
+    char *proxy=NULL;
+    char proxy_env[128];
+    (void)proxy;
+
+    no_proxy=curl_getenv("no_proxy");
+    if(!no_proxy)
+      no_proxy=curl_getenv("NO_PROXY");
+
+    if(!no_proxy || !strequal("*", no_proxy)) {
+      /* NO_PROXY wasn't specified or it wasn't just an asterisk */
+      char *nope;
+
+      nope=no_proxy?strtok_r(no_proxy, ", ", &no_proxy_tok_buf):NULL;
+      while(nope) {
+        size_t namelen;
+        char *endptr = strchr(conn->host.name, ':');
+        if(endptr)
+          namelen=endptr-conn->host.name;
+        else
+          namelen=strlen(conn->host.name);
+
+        if(strlen(nope) <= namelen) {
+          char *checkn=
+            conn->host.name + namelen - strlen(nope);
+          if(checkprefix(nope, checkn)) {
+            /* no proxy for this host! */
+            break;
+          }
+        }
+        nope=strtok_r(NULL, ", ", &no_proxy_tok_buf);
+      }
+      if(!nope) {
+        /* It was not listed as without proxy */
+        char *protop = conn->protostr;
+        char *envp = proxy_env;
+        char *prox;
+
+        /* Now, build <protocol>_proxy and check for such a one to use */
+        while(*protop)
+          *envp++ = tolower((int)*protop++);
+
+        /* append _proxy */
+        strcpy(envp, "_proxy");
+
+        /* read the protocol proxy: */
+        prox=curl_getenv(proxy_env);
+
+        /*
+         * We don't try the uppercase version of HTTP_PROXY because of
+         * security reasons:
+         *
+         * When curl is used in a webserver application
+         * environment (cgi or php), this environment variable can
+         * be controlled by the web server user by setting the
+         * http header 'Proxy:' to some value.
+         *
+         * This can cause 'internal' http/ftp requests to be
+         * arbitrarily redirected by any external attacker.
+         */
+        if(!prox && !strequal("http_proxy", proxy_env)) {
+          /* There was no lowercase variable, try the uppercase version: */
+          for(envp = proxy_env; *envp; envp++)
+            *envp = toupper((int)*envp);
+          prox=curl_getenv(proxy_env);
+        }
+
+        if(prox && *prox) { /* don't count "" strings */
+          proxy = prox; /* use this */
+        }
+        else {
+          proxy = curl_getenv("all_proxy"); /* default proxy to use */
+          if(!proxy)
+            proxy=curl_getenv("ALL_PROXY");
+        }
+
+        if(proxy && *proxy) {
+          /* we have a proxy here to set */
+          char *ptr;
+          char proxyuser[MAX_CURL_USER_LENGTH];
+          char proxypasswd[MAX_CURL_PASSWORD_LENGTH];
+
+          char *fineptr;
+
+          /* skip the possible protocol piece */
+          ptr=strstr(proxy, "://");
+          if(ptr)
+            ptr += 3;
+          else
+            ptr = proxy;
+
+          fineptr = ptr;
+
+          /* check for an @-letter */
+          ptr = strchr(ptr, '@');
+          if(ptr && (2 == sscanf(fineptr,
+                                 "%" MAX_CURL_USER_LENGTH_TXT"[^:]:"
+                                 "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]",
+                                 proxyuser, proxypasswd))) {
+            CURLcode res = CURLE_OK;
+
+            /* found user and password, rip them out */
+            Curl_safefree(conn->proxyuser);
+            conn->proxyuser = strdup(proxyuser);
+
+            if(!conn->proxyuser)
+              res = CURLE_OUT_OF_MEMORY;
+            else {
+              Curl_safefree(conn->proxypasswd);
+              conn->proxypasswd = strdup(proxypasswd);
+
+              if(!conn->proxypasswd)
+                res = CURLE_OUT_OF_MEMORY;
+            }
+
+            if(CURLE_OK == res) {
+              conn->bits.proxy_user_passwd = TRUE; /* enable it */
+              ptr = strdup(ptr+1); /* the right side of the @-letter */
+
+              if(ptr) {
+                free(proxy); /* free the former proxy string */
+                proxy = ptr; /* now use this instead */
+              }
+              else
+                res = CURLE_OUT_OF_MEMORY;
+            }
+
+            if(res) {
+              free(proxy); /* free the allocated proxy string */
+              return res;
+            }
+          }
+
+          data->change.proxy = proxy;
+          data->change.proxy_alloc=TRUE; /* this needs to be freed later */
+          conn->bits.httpproxy = TRUE;
+        }
+      } /* if (!nope) - it wasn't specified non-proxy */
+    } /* NO_PROXY wasn't specified or '*' */
+    if(no_proxy)
+      free(no_proxy);
+  } /* if not using proxy */
+
+  /*************************************************************
+   * No protocol part in URL was used, add it!
+   *************************************************************/
+  if(conn->protocol&PROT_MISSING) {
+    /* We're guessing prefixes here and if we're told to use a proxy or if
+       we're gonna follow a Location: later or... then we need the protocol
+       part added so that we have a valid URL. */
+    char *reurl;
+
+    reurl = aprintf("%s://%s", conn->protostr, data->change.url);
+
+    if(!reurl)
+      return CURLE_OUT_OF_MEMORY;
+
+    data->change.url = reurl;
+    data->change.url_alloc = TRUE; /* free this later */
+    conn->protocol &= ~PROT_MISSING; /* switch that one off again */
+  }
+
+#ifndef CURL_DISABLE_HTTP
+  /************************************************************
+   * RESUME on a HTTP page is a tricky business. First, let's just check that
+   * 'range' isn't used, then set the range parameter and leave the resume as
+   * it is to inform about this situation for later use. We will then
+   * "attempt" to resume, and if we're talking to a HTTP/1.1 (or later)
+   * server, we will get the document resumed. If we talk to a HTTP/1.0
+   * server, we just fail since we can't rewind the file writing from within
+   * this function.
+   ***********************************************************/
+  if(conn->resume_from) {
+    if(!conn->bits.use_range) {
+      /* if it already was in use, we just skip this */
+      conn->range = aprintf("%" FORMAT_OFF_T "-", conn->resume_from);
+      if(!conn->range)
+        return CURLE_OUT_OF_MEMORY;
+      conn->bits.rangestringalloc = TRUE; /* mark as allocated */
+      conn->bits.use_range = 1; /* switch on range usage */
+    }
+  }
+#endif
+  /*************************************************************
+   * Setup internals depending on protocol
+   *************************************************************/
+
+  if (strequal(conn->protostr, "HTTP")) {
+#ifndef CURL_DISABLE_HTTP
+    conn->port = (data->set.use_port && data->state.allow_port)?
+      data->set.use_port:PORT_HTTP;
+    conn->remote_port = PORT_HTTP;
+    conn->protocol |= PROT_HTTP;
+    conn->curl_do = Curl_http;
+    conn->curl_do_more = NULL;
+    conn->curl_done = Curl_http_done;
+    conn->curl_connect = Curl_http_connect;
+#else
+    failf(data, LIBCURL_NAME
+          " was built with HTTP disabled, http: not supported!");
+    return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+  }
+  else if (strequal(conn->protostr, "HTTPS")) {
+#if defined(USE_SSLEAY) && !defined(CURL_DISABLE_HTTP)
+
+    conn->port = (data->set.use_port && data->state.allow_port)?
+      data->set.use_port:PORT_HTTPS;
+    conn->remote_port = PORT_HTTPS;
+    conn->protocol |= PROT_HTTP|PROT_HTTPS|PROT_SSL;
+
+    conn->curl_do = Curl_http;
+    conn->curl_do_more = NULL;
+    conn->curl_done = Curl_http_done;
+    conn->curl_connect = Curl_http_connect;
+
+#else /* USE_SSLEAY */
+    failf(data, LIBCURL_NAME
+          " was built with SSL disabled, https: not supported!");
+    return CURLE_UNSUPPORTED_PROTOCOL;
+#endif /* !USE_SSLEAY */
+  }
+  else if (strequal(conn->protostr, "GOPHER")) {
+#ifndef CURL_DISABLE_GOPHER
+    conn->port = (data->set.use_port && data->state.allow_port)?
+      data->set.use_port:PORT_GOPHER;
+    conn->remote_port = PORT_GOPHER;
+    /* Skip /<item-type>/ in path if present */
+    if (isdigit((int)conn->path[1])) {
+      conn->path = strchr(&conn->path[1], '/');
+      if (conn->path == NULL)
+        conn->path = conn->pathbuffer;
+    }
+    conn->protocol |= PROT_GOPHER;
+    conn->curl_do = Curl_http;
+    conn->curl_do_more = NULL;
+    conn->curl_done = Curl_http_done;
+#else
+    failf(data, LIBCURL_NAME
+          " was built with GOPHER disabled, gopher: not supported!");
+#endif
+  }
+  else if(strequal(conn->protostr, "FTP") ||
+          strequal(conn->protostr, "FTPS")) {
+
+#ifndef CURL_DISABLE_FTP
+    char *type;
+    int port = PORT_FTP;
+
+    if(strequal(conn->protostr, "FTPS")) {
+#ifdef USE_SSLEAY
+      conn->protocol |= PROT_FTPS|PROT_SSL;
+      conn->ssl[SECONDARYSOCKET].use = TRUE; /* send data securely */
+      port = PORT_FTPS;
+#else
+      failf(data, LIBCURL_NAME
+            " was built with SSL disabled, ftps: not supported!");
+      return CURLE_UNSUPPORTED_PROTOCOL;
+#endif /* !USE_SSLEAY */
+    }
+
+    conn->port = (data->set.use_port && data->state.allow_port)?
+      data->set.use_port:port;
+    conn->remote_port = port;
+    conn->protocol |= PROT_FTP;
+
+    if(data->change.proxy &&
+       *data->change.proxy &&
+       !data->set.tunnel_thru_httpproxy) {
+      /* Unless we have asked to tunnel ftp operations through the proxy, we
+         switch and use HTTP operations only */
+      if(conn->protocol & PROT_FTPS) {
+        /* FTPS is a hacked protocol and does not work through your
+           ordinary http proxy! */
+        failf(data, "ftps does not work through http proxy!");
+        return CURLE_UNSUPPORTED_PROTOCOL;
+      }
+#ifndef CURL_DISABLE_HTTP
+      conn->curl_do = Curl_http;
+      conn->curl_done = Curl_http_done;
+#else
+      failf(data, "FTP over http proxy requires HTTP support built-in!");
+      return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+    }
+    else {
+      conn->curl_do = Curl_ftp;
+      conn->curl_do_more = Curl_ftp_nextconnect;
+      conn->curl_done = Curl_ftp_done;
+      conn->curl_connect = Curl_ftp_connect;
+      conn->curl_disconnect = Curl_ftp_disconnect;
+    }
+
+    conn->path++; /* don't include the initial slash */
+
+    /* FTP URLs support an extension like ";type=<typecode>" that
+     * we'll try to get now! */
+    type=strstr(conn->path, ";type=");
+    if(!type) {
+      type=strstr(conn->host.rawalloc, ";type=");
+    }
+    if(type) {
+      char command;
+      *type=0;                     /* it was in the middle of the hostname */
+      command = toupper((int)type[6]);
+      switch(command) {
+      case 'A': /* ASCII mode */
+        data->set.ftp_ascii = 1;
+        break;
+      case 'D': /* directory mode */
+        data->set.ftp_list_only = 1;
+        break;
+      case 'I': /* binary mode */
+      default:
+        /* switch off ASCII */
+        data->set.ftp_ascii = 0;
+        break;
+      }
+    }
+#else /* CURL_DISABLE_FTP */
+    failf(data, LIBCURL_NAME
+          " was built with FTP disabled, ftp/ftps: not supported!");
+    return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+  }
+  else if(strequal(conn->protostr, "TELNET")) {
+#ifndef CURL_DISABLE_TELNET
+    /* telnet testing factory */
+    conn->protocol |= PROT_TELNET;
+
+    conn->port = (data->set.use_port && data->state.allow_port)?
+      data->set.use_port: PORT_TELNET;
+    conn->remote_port = PORT_TELNET;
+    conn->curl_do = Curl_telnet;
+    conn->curl_done = Curl_telnet_done;
+#else
+    failf(data, LIBCURL_NAME
+          " was built with TELNET disabled!");
+#endif
+  }
+  else if (strequal(conn->protostr, "DICT")) {
+#ifndef CURL_DISABLE_DICT
+    conn->protocol |= PROT_DICT;
+    conn->port = (data->set.use_port && data->state.allow_port)?
+      data->set.use_port:PORT_DICT;
+    conn->remote_port = PORT_DICT;
+    conn->curl_do = Curl_dict;
+    conn->curl_done = NULL; /* no DICT-specific done */
+#else
+    failf(data, LIBCURL_NAME
+          " was built with DICT disabled!");
+#endif
+  }
+  else if (strequal(conn->protostr, "LDAP")) {
+#ifndef CURL_DISABLE_LDAP
+    conn->protocol |= PROT_LDAP;
+    conn->port = (data->set.use_port && data->state.allow_port)?
+      data->set.use_port:PORT_LDAP;
+    conn->remote_port = PORT_LDAP;
+    conn->curl_do = Curl_ldap;
+    conn->curl_done = NULL; /* no LDAP-specific done */
+#else
+    failf(data, LIBCURL_NAME
+          " was built with LDAP disabled!");
+#endif
+  }
+  else if (strequal(conn->protostr, "FILE")) {
+#ifndef CURL_DISABLE_FILE
+    conn->protocol |= PROT_FILE;
+
+    conn->curl_do = Curl_file;
+    conn->curl_done = Curl_file_done;
+
+    /* anyway, this is supposed to be the connect function so we better
+       at least check that the file is present here! */
+    result = Curl_file_connect(conn);
+
+    /* Setup a "faked" transfer that'll do nothing */
+    if(CURLE_OK == result) {
+      conn->bits.tcpconnect = TRUE; /* we are "connected */
+      result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */
+                             -1, NULL); /* no upload */
+    }
+
+    return result;
+#else
+    failf(data, LIBCURL_NAME
+          " was built with FILE disabled!");
+#endif
+  }
+  else {
+    /* We fell through all checks and thus we don't support the specified
+       protocol */
+    failf(data, "Unsupported protocol: %s", conn->protostr);
+    return CURLE_UNSUPPORTED_PROTOCOL;
+  }
+
+  /*************************************************************
+   * Figure out the remote port number
+   *
+   * No matter if we use a proxy or not, we have to figure out the remote
+   * port number of various reasons.
+   *
+   * To be able to detect port number flawlessly, we must not confuse them
+   * IPv6-specified addresses in the [0::1] style. (RFC2732)
+   *
+   * The conn->host.name is currently [user:passwd@]host[:port] where host
+   * could be a hostname, IPv4 address or IPv6 address.
+   *************************************************************/
+  if((1 == sscanf(conn->host.name, "[%*39[0-9a-fA-F:.]%c", &endbracket)) &&
+     (']' == endbracket)) {
+    /* this is a RFC2732-style specified IP-address */
+    conn->bits.ipv6_ip = TRUE;
+
+    conn->host.name++; /* pass the starting bracket */
+    tmp = strchr(conn->host.name, ']');
+    *tmp = 0; /* zero terminate */
+    tmp++; /* pass the ending bracket */
+    if(':' != *tmp)
+      tmp = NULL; /* no port number available */
+  }
+  else
+    tmp = strrchr(conn->host.name, ':');
+
+  if (tmp) {
+    char *rest;
+    unsigned long port;
+
+    port=strtoul(tmp+1, &rest, 10);  /* Port number must be decimal */
+
+    if (rest != (tmp+1) && *rest == '\0') {
+      /* The colon really did have only digits after it,
+       * so it is either a port number or a mistake */
+
+      if (port > 0xffff) {   /* Single unix standard says port numbers are
+                              * 16 bits long */
+        failf(data, "Port number too large: %lu", port);
+        return CURLE_URL_MALFORMAT;
+      }
+
+      *tmp = '\0'; /* cut off the name there */
+      conn->remote_port = (unsigned short)port;
+    }
+  }
+
+  if(data->change.proxy && *data->change.proxy) {
+    /* If this is supposed to use a proxy, we need to figure out the proxy
+       host name name, so that we can re-use an existing connection
+       that may exist registered to the same proxy host. */
+
+    char *prox_portno;
+    char *endofprot;
+
+    /* We need to make a duplicate of the proxy so that we can modify the
+       string safely. */
+    char *proxydup=strdup(data->change.proxy);
+
+    /* We use 'proxyptr' to point to the proxy name from now on... */
+    char *proxyptr=proxydup;
+
+    if(NULL == proxydup) {
+      failf(data, "memory shortage");
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    /* Daniel Dec 10, 1998:
+       We do the proxy host string parsing here. We want the host name and the
+       port name. Accept a protocol:// prefix, even though it should just be
+       ignored. */
+
+    /* 1. skip the protocol part if present */
+    endofprot=strstr(proxyptr, "://");
+    if(endofprot) {
+      proxyptr = endofprot+3;
+    }
+
+    /* allow user to specify proxy.server.com:1080 if desired */
+    prox_portno = strchr (proxyptr, ':');
+    if (prox_portno) {
+      *prox_portno = 0x0; /* cut off number from host name */
+      prox_portno ++;
+      /* now set the local port number */
+      conn->port = atoi(prox_portno);
+    }
+    else if(data->set.proxyport) {
+      /* None given in the proxy string, then get the default one if it is
+         given */
+      conn->port = data->set.proxyport;
+    }
+
+    /* now, clone the cleaned proxy host name */
+    conn->proxy.rawalloc = strdup(proxyptr);
+    conn->proxy.name = conn->proxy.rawalloc;
+
+    free(proxydup); /* free the duplicate pointer and not the modified */
+    if(!conn->proxy.rawalloc)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  /*************************************************************
+   * If the protcol is using SSL and HTTP proxy is used, we set
+   * the tunnel_proxy bit.
+   *************************************************************/
+  if((conn->protocol&PROT_SSL) && conn->bits.httpproxy)
+    conn->bits.tunnel_proxy = TRUE;
+
+  /*************************************************************
+   * Take care of user and password authentication stuff
+   *************************************************************/
+
+  /*
+   * Inputs: data->set.userpwd   (CURLOPT_USERPWD)
+   *         data->set.fpasswd   (CURLOPT_PASSWDFUNCTION)
+   *         data->set.use_netrc (CURLOPT_NETRC)
+   *         conn->host.name
+   *         netrc file
+   *         hard-coded defaults
+   *
+   * Outputs: (almost :- all currently undefined)
+   *          conn->bits.user_passwd  - non-zero if non-default passwords exist
+   *          conn->user              - non-zero length if defined
+   *          conn->passwd            -   ditto
+   *          conn->host.name          - remove user name and password
+   */
+
+  /* At this point, we're hoping all the other special cases have
+   * been taken care of, so conn->host.name is at most
+   *    [user[:password]]@]hostname
+   *
+   * We need somewhere to put the embedded details, so do that first.
+   */
+
+  user[0] =0;   /* to make everything well-defined */
+  passwd[0]=0;
+
+  if (conn->protocol & (PROT_FTP|PROT_HTTP)) {
+    /* This is a FTP or HTTP URL, we will now try to extract the possible
+     * user+password pair in a string like:
+     * ftp://user:password@ftp.my.site:8021/README */
+    char *ptr=strchr(conn->host.name, '@');
+    char *userpass = conn->host.name;
+    if(ptr != NULL) {
+      /* there's a user+password given here, to the left of the @ */
+
+      conn->host.name = ++ptr;
+
+      /* So the hostname is sane.  Only bother interpreting the
+       * results if we could care.  It could still be wasted
+       * work because it might be overtaken by the programmatically
+       * set user/passwd, but doing that first adds more cases here :-(
+       */
+
+      if (data->set.use_netrc != CURL_NETRC_REQUIRED) {
+        /* We could use the one in the URL */
+
+        conn->bits.user_passwd = 1; /* enable user+password */
+
+        if(*userpass != ':') {
+          /* the name is given, get user+password */
+          sscanf(userpass, "%127[^:@]:%127[^@]",
+                 user, passwd);
+        }
+        else
+          /* no name given, get the password only */
+          sscanf(userpass, ":%127[^@]", passwd);
+
+        if(user[0]) {
+          char *newname=curl_unescape(user, 0);
+          if(!newname)
+            return CURLE_OUT_OF_MEMORY;
+          if(strlen(newname) < sizeof(user))
+            strcpy(user, newname);
+
+          /* if the new name is longer than accepted, then just use
+             the unconverted name, it'll be wrong but what the heck */
+          free(newname);
+        }
+        if (passwd[0]) {
+          /* we have a password found in the URL, decode it! */
+          char *newpasswd=curl_unescape(passwd, 0);
+          if(!newpasswd)
+            return CURLE_OUT_OF_MEMORY;
+          if(strlen(newpasswd) < sizeof(passwd))
+            strcpy(passwd, newpasswd);
+
+          free(newpasswd);
+        }
+      }
+    }
+  }
+
+  /* Programmatically set password:
+   *   - always applies, if available
+   *   - takes precedence over the values we just set above
+   * so scribble it over the top.
+   * User-supplied passwords are assumed not to need unescaping.
+   *
+   * user_password is set in "inherite initial knowledge' above,
+   * so it doesn't have to be set in this block
+   */
+  if (data->set.userpwd != NULL) {
+    /* the name is given, get user+password */
+    sscanf(data->set.userpwd,
+           "%" MAX_CURL_USER_LENGTH_TXT "[^:]:"
+           "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]",
+           user, passwd);
+  }
+
+  if (data->set.use_netrc != CURL_NETRC_IGNORED) {
+    if(Curl_parsenetrc(conn->host.name,
+                       user, passwd,
+                       data->set.netrc_file)) {
+      infof(data, "Couldn't find host %s in the .netrc file, using defaults\n",
+            conn->host.name);
+    }
+    else
+      conn->bits.user_passwd = 1; /* enable user+password */
+  }
+
+  /* If our protocol needs a password and we have none, use the defaults */
+  if ( (conn->protocol & PROT_FTP) &&
+       !conn->bits.user_passwd) {
+
+    conn->user = strdup(CURL_DEFAULT_USER);
+    conn->passwd = strdup(CURL_DEFAULT_PASSWORD);
+    /* This is the default password, so DON'T set conn->bits.user_passwd */
+  }
+  else {
+    /* store user + password, zero-length if not set */
+    conn->user = strdup(user);
+    conn->passwd = strdup(passwd);
+  }
+  if(!conn->user || !conn->passwd)
+    return CURLE_OUT_OF_MEMORY;
+
+  /*************************************************************
+   * Check the current list of connections to see if we can
+   * re-use an already existing one or if we have to create a
+   * new one.
+   *************************************************************/
+
+  /* get a cloned copy of the SSL config situation stored in the
+     connection struct */
+  if(!Curl_clone_ssl_config(&data->set.ssl, &conn->ssl_config))
+    return CURLE_OUT_OF_MEMORY;
+
+  /* reuse_fresh is TRUE if we are told to use a new connection by force, but
+     we only acknowledge this option if this is not a re-used connection
+     already (which happens due to follow-location or during a HTTP
+     authentication phase). */
+  if(data->set.reuse_fresh && !data->state.this_is_a_follow)
+    reuse = FALSE;
+  else
+    reuse = ConnectionExists(data, conn, &conn_temp);
+
+  if(reuse) {
+    /*
+     * We already have a connection for this, we got the former connection
+     * in the conn_temp variable and thus we need to cleanup the one we
+     * just allocated before we can move along and use the previously
+     * existing one.
+     */
+    struct connectdata *old_conn = conn;
+
+    if(old_conn->proxy.rawalloc)
+      free(old_conn->proxy.rawalloc);
+
+    /* free the SSL config struct from this connection struct as this was
+       allocated in vain and is targeted for destruction */
+    Curl_free_ssl_config(&conn->ssl_config);
+
+    conn = conn_temp;        /* use this connection from now on */
+
+    /* get the user+password information from the old_conn struct since it may
+     * be new for this request even when we re-use an existing connection */
+    conn->bits.user_passwd = old_conn->bits.user_passwd;
+    conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd;
+
+    /* host can change, when doing keepalive with a proxy ! */
+    if (conn->bits.httpproxy) {
+      free(conn->host.rawalloc);
+      conn->host=old_conn->host;
+    }
+
+    /* get the newly set value, not the old one */
+    conn->bits.no_body = old_conn->bits.no_body;
+
+    if (!conn->bits.httpproxy)
+      free(old_conn->host.rawalloc); /* free the newly allocated name buffer */
+
+    free(conn->pathbuffer); /* free the newly allocated path pointer */
+    conn->pathbuffer = old_conn->pathbuffer; /* use the old one */
+    conn->path = old_conn->path;
+
+    /* re-use init */
+    conn->bits.reuse = TRUE; /* yes, we're re-using here */
+    conn->bits.chunk = FALSE; /* always assume not chunked unless told
+                                 otherwise */
+    conn->maxdownload = -1;  /* might have been used previously! */
+
+    Curl_safefree(old_conn->user);
+    Curl_safefree(old_conn->passwd);
+    Curl_safefree(old_conn->proxyuser);
+    Curl_safefree(old_conn->proxypasswd);
+
+    if(old_conn->bits.rangestringalloc)
+      free(old_conn->range);
+
+    free(old_conn);          /* we don't need this anymore */
+
+    /*
+     * If we're doing a resumed transfer, we need to setup our stuff
+     * properly.
+     */
+    conn->resume_from = data->set.set_resume_from;
+    if (conn->resume_from) {
+      if (conn->bits.rangestringalloc == TRUE)
+        free(conn->range);
+      conn->range = aprintf("%" FORMAT_OFF_T "-", conn->resume_from);
+      if(!conn->range)
+        return CURLE_OUT_OF_MEMORY;
+
+      /* tell ourselves to fetch this range */
+      conn->bits.use_range = TRUE;        /* enable range download */
+      conn->bits.rangestringalloc = TRUE; /* mark range string allocated */
+    }
+    else if (data->set.set_range) {
+      /* There is a range, but is not a resume, useful for random ftp access */
+      conn->range = strdup(data->set.set_range);
+      if(!conn->range)
+        return CURLE_OUT_OF_MEMORY;
+      conn->bits.rangestringalloc = TRUE; /* mark range string allocated */
+      conn->bits.use_range = TRUE;        /* enable range download */
+    }
+    else
+      conn->bits.use_range = FALSE; /* disable range download */
+
+    *in_connect = conn;      /* return this instead! */
+
+    infof(data, "Re-using existing connection! (#%ld) with host %s\n",
+          conn->connectindex,
+          conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
+  }
+  else {
+    /*
+     * This is a brand new connection, so let's store it in the connection
+     * cache of ours!
+     */
+    ConnectionStore(data, conn);
+  }
+
+  /* Continue connectdata initialization here.
+   *
+   * Inherit the proper values from the urldata struct AFTER we have arranged
+   * the persistant conncetion stuff */
+  conn->fread = data->set.fread;
+  conn->fread_in = data->set.in;
+
+  conn->bits.upload_chunky =
+    ((conn->protocol&PROT_HTTP) &&
+     data->set.upload &&
+     (data->set.infilesize == -1) &&
+     (data->set.httpversion != CURL_HTTP_VERSION_1_0))?
+    /* HTTP, upload, unknown file size and not HTTP 1.0 */
+    TRUE:
+  /* else, no chunky upload */
+  FALSE;
+
+#ifndef USE_ARES
+  /*************************************************************
+   * Set timeout if that is being used, and we're not using an asynchronous
+   * name resolve.
+   *************************************************************/
+  if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
+    /*************************************************************
+     * Set signal handler to catch SIGALRM
+     * Store the old value to be able to set it back later!
+     *************************************************************/
+
+#ifdef SIGALRM
+#ifdef HAVE_SIGACTION
+    struct sigaction sigact;
+    sigaction(SIGALRM, NULL, &sigact);
+    keep_sigact = sigact;
+    keep_copysig = TRUE; /* yes, we have a copy */
+    sigact.sa_handler = alarmfunc;
+#ifdef SA_RESTART
+    /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */
+    sigact.sa_flags &= ~SA_RESTART;
+#endif
+    /* now set the new struct */
+    sigaction(SIGALRM, &sigact, NULL);
+#else /* HAVE_SIGACTION */
+    /* no sigaction(), revert to the much lamer signal() */
+#ifdef HAVE_SIGNAL
+    keep_sigact = signal(SIGALRM, alarmfunc);
+#endif
+#endif /* HAVE_SIGACTION */
+
+    /* We set the timeout on the name resolving phase first, separately from
+     * the download/upload part to allow a maximum time on everything. This is
+     * a signal-based timeout, why it won't work and shouldn't be used in
+     * multi-threaded environments. */
+
+#ifdef HAVE_ALARM
+    /* alarm() makes a signal get sent when the timeout fires off, and that
+       will abort system calls */
+    prev_alarm = alarm(data->set.connecttimeout?
+                       data->set.connecttimeout:
+                       data->set.timeout);
+    /* We can expect the conn->created time to be "now", as that was just
+       recently set in the beginning of this function and nothing slow
+       has been done since then until now. */
+#endif
+#endif /* SIGALRM */
+  }
+#endif /* USE_ARES */
+
+  /*************************************************************
+   * Resolve the name of the server or proxy
+   *************************************************************/
+  if(conn->bits.reuse) {
+    /* re-used connection, no resolving is necessary */
+    hostaddr = NULL;
+    conn->dns_entry = NULL; /* we don't connect now so we don't have any fresh
+                               dns entry struct to point to */
+
+    if (conn->bits.httpproxy)
+      fix_hostname(conn, &conn->host);
+  }
+  else {
+    /* this is a fresh connect */
+
+    /* set a pointer to the hostname we display */
+    fix_hostname(conn, &conn->host);
+
+    if(!data->change.proxy || !*data->change.proxy) {
+      /* If not connecting via a proxy, extract the port from the URL, if it is
+       * there, thus overriding any defaults that might have been set above. */
+      conn->port =  conn->remote_port; /* it is the same port */
+
+      /* Resolve target host right on */
+      rc = Curl_resolv(conn, conn->host.name, (int)conn->port, &hostaddr);
+      if(rc == CURLRESOLV_PENDING)
+        *async = TRUE;
+
+      else if(!hostaddr) {
+        failf(data, "Couldn't resolve host '%s'", conn->host.dispname);
+        result =  CURLE_COULDNT_RESOLVE_HOST;
+        /* don't return yet, we need to clean up the timeout first */
+      }
+    }
+    else {
+      /* This is a proxy that hasn't been resolved yet. */
+
+      /* IDN-fix the proxy name */
+      fix_hostname(conn, &conn->proxy);
+
+      /* resolve proxy */
+      rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &hostaddr);
+
+      if(rc == CURLRESOLV_PENDING)
+        *async = TRUE;
+
+      else if(!hostaddr) {
+        failf(data, "Couldn't resolve proxy '%s'", conn->proxy.dispname);
+        result = CURLE_COULDNT_RESOLVE_PROXY;
+        /* don't return yet, we need to clean up the timeout first */
+      }
+    }
+  }
+  *addr = hostaddr;
+
+#if defined(HAVE_ALARM) && defined(SIGALRM) && !defined(USE_ARES)
+  if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
+#ifdef HAVE_SIGACTION
+    if(keep_copysig) {
+      /* we got a struct as it looked before, now put that one back nice
+         and clean */
+      sigaction(SIGALRM, &keep_sigact, NULL); /* put it back */
+    }
+#else
+#ifdef HAVE_SIGNAL
+    /* restore the previous SIGALRM handler */
+    signal(SIGALRM, keep_sigact);
+#endif
+#endif /* HAVE_SIGACTION */
+
+    /* switch back the alarm() to either zero or to what it was before minus
+       the time we spent until now! */
+    if(prev_alarm) {
+      /* there was an alarm() set before us, now put it back */
+      unsigned long elapsed_ms = Curl_tvdiff(Curl_tvnow(), conn->created);
+      unsigned long alarm_set;
+
+      /* the alarm period is counted in even number of seconds */
+      alarm_set = prev_alarm - elapsed_ms/1000;
+
+      if(!alarm_set ||
+         ((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) {
+        /* if the alarm time-left reached zero or turned "negative" (counted
+           with unsigned values), we should fire off a SIGALRM here, but we
+           won't, and zero would be to switch it off so we never set it to
+           less than 1! */
+        alarm(1);
+        result = CURLE_OPERATION_TIMEOUTED;
+        failf(data, "Previous alarm fired off!");
+      }
+      else
+        alarm((unsigned int)alarm_set);
+    }
+    else
+      alarm(0); /* just shut it off */
+  }
+#endif
+
+  return result;
+}
+
+/* SetupConnection() should be called after the name resolve initiated in
+ * CreateConnection() is all done.
+ */
+
+static CURLcode SetupConnection(struct connectdata *conn,
+                                struct Curl_dns_entry *hostaddr)
+{
+  struct SessionHandle *data = conn->data;
+  CURLcode result=CURLE_OK;
+
+  Curl_pgrsTime(data, TIMER_NAMELOOKUP);
+
+  if(conn->protocol & PROT_FILE)
+    /* There's nothing in this function to setup if we're only doing
+       a file:// transfer */
+    return result;
+
+  /*************************************************************
+   * Send user-agent to HTTP proxies even if the target protocol
+   * isn't HTTP.
+   *************************************************************/
+  if((conn->protocol&PROT_HTTP) ||
+     (data->change.proxy && *data->change.proxy)) {
+    if(data->set.useragent) {
+      Curl_safefree(conn->allocptr.uagent);
+      conn->allocptr.uagent =
+        aprintf("User-Agent: %s\015\012", data->set.useragent);
+      if(!conn->allocptr.uagent)
+        return CURLE_OUT_OF_MEMORY;
+    }
+  }
+
+  if(data->set.encoding) {
+    Curl_safefree(conn->allocptr.accept_encoding);
+    conn->allocptr.accept_encoding =
+      aprintf("Accept-Encoding: %s\015\012", data->set.encoding);
+    if(!conn->allocptr.accept_encoding)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  conn->bytecount = 0;
+  conn->headerbytecount = 0;
+
+  if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
+    bool connected;
+
+    /* Connect only if not already connected! */
+    result = ConnectPlease(conn, hostaddr, &connected);
+
+    if(connected) {
+      result = Curl_protocol_connect(conn);
+      if(CURLE_OK == result)
+        conn->bits.tcpconnect = TRUE;
+    }
+    else
+      conn->bits.tcpconnect = FALSE;
+
+
+    if(CURLE_OK != result)
+      return result;
+  }
+  else {
+    Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
+    conn->bits.tcpconnect = TRUE;
+    if(data->set.verbose)
+      verboseconnect(conn);
+  }
+
+  conn->now = Curl_tvnow(); /* time this *after* the connect is done, we
+                               set this here perhaps a second time */
+
+#ifdef __EMX__
+  /* 20000330 mgs
+   * the check is quite a hack...
+   * we're calling _fsetmode to fix the problem with fwrite converting newline
+   * characters (you get mangled text files, and corrupted binary files when
+   * you download to stdout and redirect it to a file). */
+
+  if ((data->set.out)->_handle == NULL) {
+    _fsetmode(stdout, "b");
+  }
+#endif
+
+  return CURLE_OK;
+}
+
+CURLcode Curl_connect(struct SessionHandle *data,
+                      struct connectdata **in_connect,
+                      bool *asyncp)
+{
+  CURLcode code;
+  struct Curl_dns_entry *dns;
+
+  *asyncp = FALSE; /* assume synchronous resolves by default */
+
+  /* call the stuff that needs to be called */
+  code = CreateConnection(data, in_connect, &dns, asyncp);
+
+  if(CURLE_OK == code) {
+    /* no error */
+    if(dns || !*asyncp)
+      /* If an address is available it means that we already have the name
+         resolved, OR it isn't async.
+         If so => continue connecting from here */
+      code = SetupConnection(*in_connect, dns);
+    /* else
+         response will be received and treated async wise */
+  }
+
+  if(CURLE_OK != code) {
+    /* We're not allowed to return failure with memory left allocated
+       in the connectdata struct, free those here */
+    if(*in_connect) {
+      Curl_disconnect(*in_connect); /* close the connection */
+      *in_connect = NULL;           /* return a NULL */
+    }
+  }
+
+  return code;
+}
+
+/* Call this function after Curl_connect() has returned async=TRUE and
+   then a successful name resolve has been received */
+CURLcode Curl_async_resolved(struct connectdata *conn)
+{
+#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \
+    defined(USE_THREADING_GETADDRINFO)
+  CURLcode code = SetupConnection(conn, conn->async.dns);
+
+  if(code)
+    /* We're not allowed to return failure with memory left allocated
+       in the connectdata struct, free those here */
+    Curl_disconnect(conn); /* close the connection */
+
+  return code;
+#else
+  (void)conn;
+  return CURLE_OK;
+#endif
+}
+
+
+CURLcode Curl_done(struct connectdata **connp,
+                   CURLcode status) /* an error if this is called after an
+                                       error was detected */
+{
+  CURLcode result;
+  struct connectdata *conn = *connp;
+  struct SessionHandle *data=conn->data;
+
+  /* cleanups done even if the connection is re-used */
+
+  if(conn->bits.rangestringalloc) {
+    free(conn->range);
+    conn->bits.rangestringalloc = FALSE;
+  }
+
+  /* Cleanup possible redirect junk */
+  if(conn->newurl) {
+    free(conn->newurl);
+    conn->newurl = NULL;
+  }
+
+  if(conn->dns_entry)
+    Curl_resolv_unlock(conn->data, conn->dns_entry); /* done with this */
+
+#if defined(CURLDEBUG) && defined(AGGRESIVE_TEST)
+  /* scan for DNS cache entries still marked as in use */
+  Curl_hash_apply(data->hostcache,
+                  NULL, Curl_scan_cache_used);
+#endif
+
+  Curl_hostcache_prune(data); /* kill old DNS cache entries */
+
+  /* this calls the protocol-specific function pointer previously set */
+  if(conn->curl_done)
+    result = conn->curl_done(conn, status);
+  else
+    result = CURLE_OK;
+
+  Curl_pgrsDone(conn); /* done with the operation */
+
+  /* if data->set.reuse_forbid is TRUE, it means the libcurl client has
+     forced us to close this no matter what we think.
+
+     if conn->bits.close is TRUE, it means that the connection should be
+     closed in spite of all our efforts to be nice, due to protocol
+     restrictions in our or the server's end */
+  if(data->set.reuse_forbid || conn->bits.close) {
+    CURLcode res2;
+    res2 = Curl_disconnect(conn); /* close the connection */
+
+    *connp = NULL; /* to make the caller of this function better detect that
+                      this was actually killed here */
+
+    /* If we had an error already, make sure we return that one. But
+       if we got a new error, return that. */
+    if(!result && res2)
+      result = res2;
+  }
+  else
+    infof(data, "Connection #%ld to host %s left intact\n",
+          conn->connectindex,
+          conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
+
+  return result;
+}
+
+CURLcode Curl_do(struct connectdata **connp)
+{
+  CURLcode result=CURLE_OK;
+  struct connectdata *conn = *connp;
+  struct SessionHandle *data=conn->data;
+
+  conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to use */
+
+  if(conn->curl_do) {
+    /* generic protocol-specific function pointer set in curl_connect() */
+    result = conn->curl_do(conn);
+
+    /* This was formerly done in transfer.c, but we better do it here */
+
+    if((CURLE_SEND_ERROR == result) && conn->bits.reuse) {
+      /* This was a re-use of a connection and we got a write error in the
+       * DO-phase. Then we DISCONNECT this connection and have another attempt
+       * to CONNECT and then DO again! The retry cannot possibly find another
+       * connection to re-use, since we only keep one possible connection for
+       * each.  */
+
+      infof(data, "Re-used connection seems dead, get a new one\n");
+
+      conn->bits.close = TRUE; /* enforce close of this connection */
+      result = Curl_done(&conn, result); /* we are so done with this */
+
+      /* conn may no longer be a good pointer */
+
+      if(CURLE_OK == result) {
+        bool async;
+        /* Now, redo the connect and get a new connection */
+        result = Curl_connect(data, connp, &async);
+        if(CURLE_OK == result) {
+          /* We have connected or sent away a name resolve query fine */
+
+          conn = *connp; /* setup conn to again point to something nice */
+          if(async) {
+            /* Now, if async is TRUE here, we need to wait for the name
+               to resolve */
+            result = Curl_wait_for_resolv(conn, NULL);
+            if(result)
+              return result;
+
+            /* Resolved, continue with the connection */
+            result = Curl_async_resolved(conn);
+            if(result)
+              return result;
+          }
+
+          /* ... finally back to actually retry the DO phase */
+          result = conn->curl_do(conn);
+        }
+      }
+    }
+  }
+  return result;
+}
+
+CURLcode Curl_do_more(struct connectdata *conn)
+{
+  CURLcode result=CURLE_OK;
+
+  if(conn->curl_do_more)
+    result = conn->curl_do_more(conn);
+
+  return result;
+}
+
+static bool safe_strequal(char* str1, char* str2)
+{
+  if(str1 && str2)
+    /* both pointers point to something then compare them */
+    return strequal(str1, str2);
+  else
+    /* if both pointers are NULL then treat them as equal */
+    return (!str1 && !str2);
+}
+
+bool
+Curl_ssl_config_matches(struct ssl_config_data* data,
+                        struct ssl_config_data* needle)
+{
+  if((data->version == needle->version) &&
+     (data->verifypeer == needle->verifypeer) &&
+     (data->verifyhost == needle->verifyhost) &&
+     safe_strequal(data->CApath, needle->CApath) &&
+     safe_strequal(data->CAfile, needle->CAfile) &&
+     safe_strequal(data->random_file, needle->random_file) &&
+     safe_strequal(data->egdsocket, needle->egdsocket) &&
+     safe_strequal(data->cipher_list, needle->cipher_list))
+    return TRUE;
+
+  return FALSE;
+}
+
+bool
+Curl_clone_ssl_config(struct ssl_config_data *source,
+                      struct ssl_config_data *dest)
+{
+  dest->verifyhost = source->verifyhost;
+  dest->verifypeer = source->verifypeer;
+  dest->version = source->version;
+
+  if(source->CAfile) {
+    dest->CAfile = strdup(source->CAfile);
+    if(!dest->CAfile)
+      return FALSE;
+  }
+
+  if(source->CApath) {
+    dest->CApath = strdup(source->CApath);
+    if(!dest->CApath)
+      return FALSE;
+  }
+
+  if(source->cipher_list) {
+    dest->cipher_list = strdup(source->cipher_list);
+    if(!dest->cipher_list)
+      return FALSE;
+  }
+
+  if(source->egdsocket) {
+    dest->egdsocket = strdup(source->egdsocket);
+    if(!dest->egdsocket)
+      return FALSE;
+  }
+
+  if(source->random_file) {
+    dest->random_file = strdup(source->random_file);
+    if(!dest->random_file)
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+void Curl_free_ssl_config(struct ssl_config_data* sslc)
+{
+  if(sslc->CAfile)
+    free(sslc->CAfile);
+
+  if(sslc->CApath)
+    free(sslc->CApath);
+
+  if(sslc->cipher_list)
+    free(sslc->cipher_list);
+
+  if(sslc->egdsocket)
+    free(sslc->egdsocket);
+
+  if(sslc->random_file)
+    free(sslc->random_file);
+}
+
diff --git a/Utilities/cmcurl/url.h b/Utilities/cmcurl/url.h
new file mode 100644
index 0000000..8fd4795
--- /dev/null
+++ b/Utilities/cmcurl/url.h
@@ -0,0 +1,47 @@
+#ifndef __URL_H
+#define __URL_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/*
+ * Prototypes for library-wide functions provided by url.c
+ */
+
+CURLcode Curl_open(struct SessionHandle **curl);
+CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...);
+CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */
+CURLcode Curl_connect(struct SessionHandle *, struct connectdata **,
+                      bool *async);
+CURLcode Curl_async_resolved(struct connectdata *conn);
+CURLcode Curl_do(struct connectdata **);
+CURLcode Curl_do_more(struct connectdata *);
+CURLcode Curl_done(struct connectdata **, CURLcode);
+CURLcode Curl_disconnect(struct connectdata *);
+CURLcode Curl_protocol_connect(struct connectdata *conn);
+bool Curl_ssl_config_matches(struct ssl_config_data* data,
+                             struct ssl_config_data* needle);
+bool Curl_clone_ssl_config(struct ssl_config_data* source,
+                           struct ssl_config_data* dest);
+void Curl_free_ssl_config(struct ssl_config_data* sslc);
+void Curl_safefree(void *ptr);
+#endif
diff --git a/Utilities/cmcurl/urldata.h b/Utilities/cmcurl/urldata.h
new file mode 100644
index 0000000..07aff9b
--- /dev/null
+++ b/Utilities/cmcurl/urldata.h
@@ -0,0 +1,962 @@
+#ifndef __URLDATA_H
+#define __URLDATA_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+/* This file is for lib internal stuff */
+
+#include "setup.h"
+
+#define PORT_FTP 21
+#define PORT_FTPS 990
+#define PORT_TELNET 23
+#define PORT_GOPHER 70
+#define PORT_HTTP 80
+#define PORT_HTTPS 443
+#define PORT_DICT 2628
+#define PORT_LDAP 389
+
+#define DICT_MATCH "/MATCH:"
+#define DICT_MATCH2 "/M:"
+#define DICT_MATCH3 "/FIND:"
+#define DICT_DEFINE "/DEFINE:"
+#define DICT_DEFINE2 "/D:"
+#define DICT_DEFINE3 "/LOOKUP:"
+
+#define CURL_DEFAULT_USER "anonymous"
+#define CURL_DEFAULT_PASSWORD "curl_by_daniel@haxx.se"
+
+#include "cookie.h"
+#include "formdata.h"
+
+#ifdef USE_SSLEAY
+/* SSLeay stuff usually in /usr/local/ssl/include */
+#ifdef USE_OPENSSL
+#include "openssl/rsa.h"
+#include "openssl/crypto.h"
+#include "openssl/x509.h"
+#include "openssl/pem.h"
+#include "openssl/ssl.h"
+#include "openssl/err.h"
+#ifdef HAVE_OPENSSL_ENGINE_H
+#include <openssl/engine.h>
+#endif
+#else
+#include "rsa.h"
+#include "crypto.h"
+#include "x509.h"
+#include "pem.h"
+#include "ssl.h"
+#include "err.h"
+#endif
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#include "timeval.h"
+
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>               /* for content-encoding */
+#endif
+
+#ifdef CURL_SPECIAL_ZLIB_H
+#include CURL_SPECIAL_ZLIB_H
+#endif
+
+#ifdef USE_ARES
+#include <ares.h>
+#endif
+
+#include <curl/curl.h>
+
+#include "http_chunks.h" /* for the structs and enum stuff */
+#include "hostip.h"
+#include "hash.h"
+
+#ifdef HAVE_GSSAPI
+#ifdef HAVE_GSSMIT
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_generic.h>
+#else
+#include <gssapi.h>
+#endif
+#endif
+
+/* Download buffer size, keep it fairly big for speed reasons */
+#define BUFSIZE CURL_MAX_WRITE_SIZE
+
+/* Initial size of the buffer to store headers in, it'll be enlarged in case
+   of need. */
+#define HEADERSIZE 256
+
+/* Just a convenience macro to get the larger value out of two given.
+   We prefix with CURL to prevent name collisions. */
+#define CURLMAX(x,y) ((x)>(y)?(x):(y))
+
+#ifdef HAVE_KRB4
+/* Types needed for krb4-ftp connections */
+struct krb4buffer {
+  void *data;
+  size_t size;
+  size_t index;
+  int eof_flag;
+};
+enum protection_level {
+    prot_clear,
+    prot_safe,
+    prot_confidential,
+    prot_private
+};
+#endif
+
+/* struct for data related to each SSL connection */
+struct ssl_connect_data {
+  bool use;        /* use ssl encrypted communications TRUE/FALSE */
+#ifdef USE_SSLEAY
+  /* these ones requires specific SSL-types */
+  SSL_CTX* ctx;
+  SSL*     handle;
+  X509*    server_cert;
+#endif /* USE_SSLEAY */
+};
+
+struct ssl_config_data {
+  long version;          /* what version the client wants to use */
+  long certverifyresult; /* result from the certificate verification */
+  long verifypeer;       /* set TRUE if this is desired */
+  long verifyhost;       /* 0: no verify
+                            1: check that CN exists
+                            2: CN must match hostname */
+  char *CApath;          /* DOES NOT WORK ON WINDOWS */
+  char *CAfile;          /* cerficate to verify peer against */
+  char *random_file;     /* path to file containing "random" data */
+  char *egdsocket;       /* path to file containing the EGD daemon socket */
+  char *cipher_list;     /* list of ciphers to use */
+  long numsessions;      /* SSL session id cache size */
+  curl_ssl_ctx_callback fsslctx;        /* function to initialize ssl ctx */
+  void *fsslctxp;       /*parameter for call back */
+};
+
+/* information stored about one single SSL session */
+struct curl_ssl_session {
+  char *name;       /* host name for which this ID was used */
+  void *sessionid;  /* as returned from the SSL layer */
+  long age;         /* just a number, the higher the more recent */
+  unsigned short remote_port; /* remote port to connect to */
+  struct ssl_config_data ssl_config; /* setup for this session */
+};
+
+/* Struct used for Digest challenge-response authentication */
+struct digestdata {
+  char *nonce;
+  char *cnonce;
+  char *realm;
+  int algo;
+  bool stale; /* set true for re-negotiation */
+  char *opaque;
+  char *qop;
+  char *algorithm;
+  int nc; /* nounce count */
+};
+
+typedef enum {
+  NTLMSTATE_NONE,
+  NTLMSTATE_TYPE1,
+  NTLMSTATE_TYPE2,
+  NTLMSTATE_TYPE3,
+  NTLMSTATE_LAST
+} curlntlm;
+
+/* for 3rd party transfers to decide which side that issues PASV */
+typedef enum {
+  CURL_TARGET_PASV,
+  CURL_SOURCE_PASV
+} curl_pasv_side;
+
+/* Struct used for NTLM challenge-response authentication */
+struct ntlmdata {
+  curlntlm state;
+  unsigned char nonce[8];
+};
+
+#ifdef HAVE_GSSAPI
+struct negotiatedata {
+  bool gss; /* Whether we're processing GSS-Negotiate or Negotiate */
+  const char* protocol; /* "GSS-Negotiate" or "Negotiate" */
+  OM_uint32 status;
+  gss_ctx_id_t context;
+  gss_name_t server_name;
+  gss_buffer_desc output_token;
+};
+#endif
+
+/****************************************************************************
+ * HTTP unique setup
+ ***************************************************************************/
+struct HTTP {
+  struct FormData *sendit;
+  curl_off_t postsize; /* off_t to handle large file sizes */
+  char *postdata;
+
+  const char *p_pragma;      /* Pragma: string */
+  const char *p_accept;      /* Accept: string */
+  curl_off_t readbytecount;
+  curl_off_t writebytecount;
+
+  /* For FORM posting */
+  struct Form form;
+  struct Curl_chunker chunk;
+
+  struct back {
+    curl_read_callback fread; /* backup storage for fread pointer */
+    void *fread_in;           /* backup storage for fread_in pointer */
+    char *postdata;
+    curl_off_t postsize;
+  } backup;
+
+  enum {
+    HTTPSEND_NADA,    /* init */
+    HTTPSEND_REQUEST, /* sending a request */
+    HTTPSEND_BODY,    /* sending body */
+    HTTPSEND_LAST     /* never use this */
+  } sending;
+
+  void *send_buffer; /* used if the request couldn't be sent in one chunk,
+                        points to an allocated send_buffer struct */
+};
+
+/****************************************************************************
+ * FTP unique setup
+ ***************************************************************************/
+struct FTP {
+  curl_off_t *bytecountp;
+  char *user;    /* user name string */
+  char *passwd;  /* password string */
+  char *urlpath; /* the originally given path part of the URL */
+  char **dirs;   /* realloc()ed array for path components */
+  int dirdepth;  /* number of entries used in the 'dirs' array */
+  int diralloc;  /* number of entries allocated for the 'dirs' array */
+  char *file;    /* decoded file */
+
+  char *entrypath; /* the PWD reply when we logged on */
+
+  char *cache;       /* data cache between getresponse()-calls */
+  curl_off_t cache_size; /* size of cache in bytes */
+  bool dont_check;  /* Set to TRUE to prevent the final (post-transfer)
+                       file size and 226/250 status check. It should still
+                       read the line, just ignore the result. */
+  bool no_transfer; /* nothing was transfered, (possibly because a resumed
+                       transfer already was complete) */
+  long response_time; /* When no timeout is given, this is the amount of
+                         seconds we await for an FTP response. Initialized
+                         in Curl_ftp_connect() */
+  bool ctl_valid;     /* Tells Curl_ftp_quit() whether or not to do
+                         anything. If the connection has timed out or
+                         been closed, this should be FALSE when it gets
+                         to Curl_ftp_quit() */
+};
+
+/****************************************************************************
+ * FILE unique setup
+ ***************************************************************************/
+struct FILEPROTO {
+  char *path; /* the path we operate on */
+  char *freepath; /* pointer to the allocated block we must free, this might
+                     differ from the 'path' pointer */
+  int fd;     /* open file descriptor to read from! */
+};
+
+/*
+ * Boolean values that concerns this connection.
+ */
+struct ConnectBits {
+  bool close; /* if set, we close the connection after this request */
+  bool reuse; /* if set, this is a re-used connection */
+  bool chunk; /* if set, this is a chunked transfer-encoding */
+  bool httpproxy;    /* if set, this transfer is done through a http proxy */
+  bool user_passwd;    /* do we use user+password for this connection? */
+  bool proxy_user_passwd; /* user+password for the proxy? */
+  bool ipv6_ip; /* we communicate with a remove site specified with pure IPv6
+                   IP address */
+  bool use_range;
+  bool rangestringalloc; /* the range string is malloc()'ed */
+
+  bool do_more; /* this is set TRUE if the ->curl_do_more() function is
+                   supposed to be called, after ->curl_do() */
+
+  bool upload_chunky; /* set TRUE if we are doing chunked transfer-encoding
+                         on upload */
+  bool getheader;     /* TRUE if header parsing is wanted */
+
+  bool forbidchunk;   /* used only to explicitly forbid chunk-upload for
+                         specific upload buffers. See readmoredata() in
+                         http.c for details. */
+  bool tcpconnect;    /* the tcp stream (or simimlar) is connected, this
+                         is set the first time on the first connect function
+                         call */
+  bool retry;         /* this connection is about to get closed and then
+                         re-attempted at another connection. */
+  bool no_body;       /* CURLOPT_NO_BODY (or similar) was set */
+  bool tunnel_proxy;  /* if CONNECT is used to "tunnel" through the proxy.
+                         This is implicit when SSL-protocols are used through
+                         proxies, but can also be enabled explicitly by
+                         apps */
+  bool authprobe;     /* set TRUE when this transfer is done to probe for auth
+                         types, as when asking for "any" type when speaking
+                         HTTP */
+};
+
+struct hostname {
+  char *rawalloc; /* allocated "raw" version of the name */
+  char *encalloc; /* allocated IDN-encoded version of the name */
+  char *name;     /* name to use internally, might be encoded, might be raw */
+  char *dispname; /* name to display, as 'name' might be encoded */
+};
+
+/*
+ * This struct is all the previously local variables from Curl_perform() moved
+ * to struct to allow the function to return and get re-invoked better without
+ * losing state.
+ */
+
+struct Curl_transfer_keeper {
+  curl_off_t bytecount;         /* total number of bytes read */
+  curl_off_t writebytecount;    /* number of bytes written */
+  struct timeval start;         /* transfer started at this time */
+  struct timeval now;           /* current time */
+  bool header;                  /* incoming data has HTTP header */
+  enum {
+    HEADER_NORMAL,              /* no bad header at all */
+    HEADER_PARTHEADER,          /* part of the chunk is a bad header, the rest
+                                   is normal data */
+    HEADER_ALLBAD               /* all was believed to be header */
+  } badheader;                  /* the header was deemed bad and will be
+                                   written as body */
+  int headerline;               /* counts header lines to better track the
+                                   first one */
+  char *hbufp;                  /* points at *end* of header line */
+  size_t hbuflen;
+  char *str;                    /* within buf */
+  char *str_start;              /* within buf */
+  char *end_ptr;                /* within buf */
+  char *p;                      /* within headerbuff */
+  bool content_range;           /* set TRUE if Content-Range: was found */
+  curl_off_t offset;            /* possible resume offset read from the
+                                   Content-Range: header */
+  int httpcode;                 /* error code from the 'HTTP/1.? XXX' line */
+  int httpversion;              /* the HTTP version*10 */
+  struct timeval start100;      /* time stamp to wait for the 100 code from */
+  bool write_after_100_header;  /* TRUE = we enable the write after we
+                                   received a 100-continue/timeout or
+                                   FALSE = directly */
+  bool wait100_after_headers;   /* TRUE = after the request-headers have been
+                                   sent off properly, we go into the wait100
+                                   state, FALSE = don't */
+  int content_encoding;         /* What content encoding. sec 3.5, RFC2616. */
+
+#define IDENTITY 0              /* No encoding */
+#define DEFLATE 1               /* zlib delfate [RFC 1950 & 1951] */
+#define GZIP 2                  /* gzip algorithm [RFC 1952] */
+#define COMPRESS 3              /* Not handled, added for completeness */
+
+#ifdef HAVE_LIBZ
+  bool zlib_init;               /* True if zlib already initialized;
+                                   undefined if Content-Encoding header. */
+  z_stream z;                   /* State structure for zlib. */
+#endif
+
+  time_t timeofdoc;
+  long bodywrites;
+
+  char *buf;
+  char *uploadbuf;
+  curl_socket_t maxfd;
+
+  /* pointers to the actual descriptors we check */
+  fd_set *readfdp;
+  fd_set *writefdp;
+
+  /* the file descriptors to play with */
+  fd_set readfd;
+  fd_set writefd;
+  fd_set rkeepfd;
+  fd_set wkeepfd;
+  int keepon;
+
+  bool upload_done; /* set to TRUE when doing chunked transfer-encoding upload
+                       and we're uploading the last chunk */
+
+  bool ignorebody;  /* we read a response-body but we ignore it! */
+};
+
+#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \
+    defined(USE_THREADING_GETADDRINFO)
+struct Curl_async {
+  char *hostname;
+  int port;
+  struct Curl_dns_entry *dns;
+  bool done;  /* set TRUE when the lookup is complete */
+  int status; /* if done is TRUE, this is the status from the callback */
+  void *os_specific;  /* 'struct thread_data' for Windows */
+};
+#endif
+
+#define FIRSTSOCKET     0
+#define SECONDARYSOCKET 1
+
+/*
+ * The connectdata struct contains all fields and variables that should be
+ * unique for an entire connection.
+ */
+struct connectdata {
+  /**** Fields set when inited and not modified again */
+  struct SessionHandle *data; /* link to the root CURL struct */
+  long connectindex; /* what index in the connects index this particular
+                       struct has */
+
+  long protocol; /* PROT_* flags concerning the protocol set */
+#define PROT_MISSING (1<<0)
+#define PROT_GOPHER  (1<<1)
+#define PROT_HTTP    (1<<2)
+#define PROT_HTTPS   (1<<3)
+#define PROT_FTP     (1<<4)
+#define PROT_TELNET  (1<<5)
+#define PROT_DICT    (1<<6)
+#define PROT_LDAP    (1<<7)
+#define PROT_FILE    (1<<8)
+#define PROT_FTPS    (1<<9)
+#define PROT_SSL     (1<<10) /* protocol requires SSL */
+
+  /* the particular host we use, in two different ways */
+  struct Curl_dns_entry *dns_entry;
+  Curl_addrinfo *ip_addr; /* the particular IP we connected to */
+
+  char protostr[16];  /* store the protocol string in this buffer */
+
+  struct hostname host;
+  struct hostname proxy;
+
+  char *pathbuffer;/* allocated buffer to store the URL's path part in */
+  char *path;      /* path to use, points to somewhere within the pathbuffer
+                      area */
+  long port;       /* which port to use locally */
+  unsigned short remote_port; /* what remote port to connect to,
+                                 not the proxy port! */
+  curl_off_t bytecount;
+  long headerbytecount;  /* only count received headers */
+  long deductheadercount; /* this amount of bytes doesn't count when we check
+                             if anything has been transfered at the end of
+                             a connection. We use this counter to make only
+                             a 100 reply (without a following second response
+                             code) result in a CURLE_GOT_NOTHING error code */
+
+  char *range; /* range, if used. See README for detailed specification on
+                  this syntax. */
+  curl_off_t resume_from; /* continue [ftp] transfer from here */
+
+  char *user;    /* user name string, allocated */
+  char *passwd;  /* password string, allocated */
+
+  char *proxyuser;    /* proxy user name string, allocated */
+  char *proxypasswd;  /* proxy password string, allocated */
+
+  struct timeval now;     /* "current" time */
+  struct timeval created; /* creation time */
+  curl_socket_t sock[2]; /* two sockets, the second is used for the data
+                            transfer when doing FTP */
+  curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch, 0
+                             means unlimited */
+
+  struct ssl_connect_data ssl[2]; /* this is for ssl-stuff */
+  struct ssl_config_data ssl_config;
+
+  struct ConnectBits bits;    /* various state-flags for this connection */
+
+  /* These two functions MUST be set by the curl_connect() function to be
+     be protocol dependent */
+  CURLcode (*curl_do)(struct connectdata *);
+  CURLcode (*curl_done)(struct connectdata *, CURLcode);
+
+  /* If the curl_do() function is better made in two halves, this
+   * curl_do_more() function will be called afterwards, if set. For example
+   * for doing the FTP stuff after the PASV/PORT command.
+   */
+  CURLcode (*curl_do_more)(struct connectdata *);
+
+  /* This function *MAY* be set to a protocol-dependent function that is run
+   * after the connect() and everything is done, as a step in the connection.
+   */
+  CURLcode (*curl_connect)(struct connectdata *);
+
+  /* This function *MAY* be set to a protocol-dependent function that is run
+   * by the curl_disconnect(), as a step in the disconnection.
+   */
+  CURLcode (*curl_disconnect)(struct connectdata *);
+
+  /* This function *MAY* be set to a protocol-dependent function that is run
+   * in the curl_close() function if protocol-specific cleanups are required.
+   */
+  CURLcode (*curl_close)(struct connectdata *);
+
+  /**** curl_get() phase fields */
+
+  /* READ stuff */
+  curl_socket_t sockfd;   /* socket to read from or CURL_SOCKET_BAD */
+  curl_off_t size;        /* -1 if unknown at this point */
+  curl_off_t *bytecountp; /* return number of bytes read or NULL */
+
+  /* WRITE stuff */
+  curl_socket_t writesockfd; /* socket to write to, it may very
+                                well be the same we read from.
+                                CURL_SOCKET_BAD disables */
+  curl_off_t *writebytecountp; /* return number of bytes written or NULL */
+
+  /** Dynamicly allocated strings, may need to be freed before this **/
+  /** struct is killed.                                             **/
+  struct dynamically_allocated_data {
+    char *proxyuserpwd; /* free later if not NULL! */
+    char *uagent; /* free later if not NULL! */
+    char *accept_encoding; /* free later if not NULL! */
+    char *userpwd; /* free later if not NULL! */
+    char *rangeline; /* free later if not NULL! */
+    char *ref; /* free later if not NULL! */
+    char *host; /* free later if not NULL */
+    char *cookiehost; /* free later if not NULL */
+  } allocptr;
+
+  char *newurl; /* This can only be set if a Location: was in the
+                   document headers */
+
+#ifdef HAVE_KRB4
+  enum protection_level command_prot;
+  enum protection_level data_prot;
+  enum protection_level request_data_prot;
+
+  size_t buffer_size;
+
+  struct krb4buffer in_buffer, out_buffer;
+  int sec_complete;
+  void *app_data;
+
+  struct Curl_sec_client_mech *mech;
+  struct sockaddr_in local_addr;
+
+#endif
+
+  /*************** Request - specific items ************/
+  /* previously this was in the urldata struct */
+  union {
+    struct HTTP *http;
+    struct HTTP *gopher; /* alias, just for the sake of being more readable */
+    struct HTTP *https;  /* alias, just for the sake of being more readable */
+    struct FTP *ftp;
+    struct FILEPROTO *file;
+    void *telnet;        /* private for telnet.c-eyes only */
+    void *generic;
+  } proto;
+
+  /* This struct is inited when needed */
+  struct Curl_transfer_keeper keep;
+
+  /* 'upload_present' is used to keep a byte counter of how much data there is
+     still left in the buffer, aimed for upload. */
+  ssize_t upload_present;
+
+   /* 'upload_fromhere' is used as a read-pointer when we uploaded parts of a
+      buffer, so the next read should read from where this pointer points to,
+      and the 'upload_present' contains the number of bytes available at this
+      position */
+  char *upload_fromhere;
+
+  curl_read_callback fread; /* function that reads the input */
+  void *fread_in;           /* pointer to pass to the fread() above */
+
+  struct ntlmdata ntlm;     /* NTLM differs from other authentication schemes
+                               because it authenticates connections, not
+                               single requests! */
+  struct ntlmdata proxyntlm; /* NTLM data for proxy */
+
+  char syserr_buf [256]; /* buffer for Curl_strerror() */
+
+#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \
+    defined(USE_THREADING_GETADDRINFO)
+  /* data used for the asynch name resolve callback */
+  struct Curl_async async;
+#endif
+  struct connectdata *sec_conn;   /* secondary connection for 3rd party
+                                     transfer */
+};
+
+/* The end of connectdata. */
+
+/*
+ * Struct to keep statistical and informational data.
+ */
+struct PureInfo {
+  int httpcode;  /* Recent HTTP or FTP response code */
+  int httpproxycode;
+  int httpversion;
+  long filetime; /* If requested, this is might get set. Set to -1 if the time
+                    was unretrievable. We cannot have this of type time_t,
+                    since time_t is unsigned on several platforms such as
+                    OpenVMS. */
+  long header_size;  /* size of read header(s) in bytes */
+  long request_size; /* the amount of bytes sent in the request(s) */
+
+  long proxyauthavail;
+  long httpauthavail;
+
+  char *contenttype; /* the content type of the object */
+};
+
+
+struct Progress {
+  long lastshow; /* time() of the last displayed progress meter or NULL to
+                    force redraw at next call */
+  curl_off_t size_dl; /* total expected size */
+  curl_off_t size_ul; /* total expected size */
+  curl_off_t downloaded; /* transfered so far */
+  curl_off_t uploaded; /* transfered so far */
+
+  curl_off_t current_speed; /* uses the currently fastest transfer */
+
+  bool callback;  /* set when progress callback is used */
+  int width; /* screen width at download start */
+  int flags; /* see progress.h */
+
+  double timespent;
+
+  curl_off_t dlspeed;
+  curl_off_t ulspeed;
+
+  double t_nslookup;
+  double t_connect;
+  double t_pretransfer;
+  double t_starttransfer;
+  double t_redirect;
+
+  struct timeval start;
+  struct timeval t_startsingle;
+#define CURR_TIME (5+1) /* 6 entries for 5 seconds */
+
+  curl_off_t speeder[ CURR_TIME ];
+  struct timeval speeder_time[ CURR_TIME ];
+  int speeder_c;
+};
+
+typedef enum {
+  HTTPREQ_NONE, /* first in list */
+  HTTPREQ_GET,
+  HTTPREQ_POST,
+  HTTPREQ_POST_FORM, /* we make a difference internally */
+  HTTPREQ_PUT,
+  HTTPREQ_HEAD,
+  HTTPREQ_CUSTOM,
+  HTTPREQ_LAST /* last in list */
+} Curl_HttpReq;
+
+/*
+ * Values that are generated, temporary or calculated internally for a
+ * "session handle" must be defined within the 'struct urlstate'.  This struct
+ * will be used within the SessionHandle struct. When the 'SessionHandle'
+ * struct is cloned, this data MUST NOT be copied.
+ *
+ * Remember that any "state" information goes globally for the curl handle.
+ * Session-data MUST be put in the connectdata struct and here.  */
+#define MAX_CURL_USER_LENGTH 256
+#define MAX_CURL_PASSWORD_LENGTH 256
+#define MAX_CURL_USER_LENGTH_TXT "255"
+#define MAX_CURL_PASSWORD_LENGTH_TXT "255"
+
+struct auth {
+  long want;  /* Bitmask set to the authentication methods wanted by the app
+                 (with CURLOPT_HTTPAUTH or CURLOPT_PROXYAUTH). */
+  long picked;
+  long avail; /* bitmask for what the server reports to support for this
+                 resource */
+  bool done;  /* TRUE when the auth phase is done and ready to do the *actual*
+                 request */
+};
+
+struct UrlState {
+  enum {
+    Curl_if_none,
+    Curl_if_easy,
+    Curl_if_multi
+  } used_interface;
+
+  /* buffers to store authentication data in, as parsed from input options */
+  struct timeval keeps_speed; /* for the progress meter really */
+
+  /* 'connects' will be an allocated array with pointers. If the pointer is
+     set, it holds an allocated connection. */
+  struct connectdata **connects;
+  long numconnects; /* size of the 'connects' array */
+
+  char *headerbuff; /* allocated buffer to store headers in */
+  size_t headersize;   /* size of the allocation */
+
+  char buffer[BUFSIZE+1]; /* download buffer */
+  char uploadbuffer[BUFSIZE+1]; /* upload buffer */
+  curl_off_t current_speed;  /* the ProgressShow() funcion sets this,
+                                bytes / second */
+  bool this_is_a_follow; /* this is a followed Location: request */
+
+  char *auth_host; /* if set, this should be the host name that we will
+                      sent authorization to, no else. Used to make Location:
+                      following not keep sending user+password... This is
+                      strdup() data.
+                    */
+
+  struct curl_ssl_session *session; /* array of 'numsessions' size */
+  long sessionage;                  /* number of the most recent session */
+
+  char *scratch; /* huge buffer[BUFSIZE*2] when doing upload CRLF replacing */
+  bool errorbuf; /* Set to TRUE if the error buffer is already filled in.
+                    This must be set to FALSE every time _easy_perform() is
+                    called. */
+
+#ifdef HAVE_SIGNAL
+  /* storage for the previous bag^H^H^HSIGPIPE signal handler :-) */
+  void (*prev_signal)(int sig);
+#endif
+  bool allow_port; /* Is set.use_port allowed to take effect or not. This
+                      is always set TRUE when curl_easy_perform() is called. */
+
+  struct digestdata digest;
+  struct digestdata proxydigest;
+
+#ifdef HAVE_GSSAPI
+  struct negotiatedata negotiate;
+#endif
+
+  struct auth authhost;
+  struct auth authproxy;
+
+  bool authproblem; /* TRUE if there's some problem authenticating */
+#ifdef USE_ARES
+  ares_channel areschannel; /* for name resolves */
+#endif
+};
+
+
+/*
+ * This 'DynamicStatic' struct defines dynamic states that actually change
+ * values in the 'UserDefined' area, which MUST be taken into consideration
+ * if the UserDefined struct is cloned or similar. You can probably just
+ * copy these, but each one indicate a special action on other data.
+ */
+
+struct DynamicStatic {
+  char *url;        /* work URL, copied from UserDefined */
+  bool url_alloc;   /* URL string is malloc()'ed */
+  bool url_changed; /* set on CURL_OPT_URL, used to detect if the URL was
+                       changed after the connect phase, as we allow callback
+                       to change it and if so, we reconnect to use the new
+                       URL instead */
+  char *proxy;      /* work proxy, copied from UserDefined */
+  bool proxy_alloc; /* http proxy string is malloc()'ed */
+  char *referer;    /* referer string */
+  bool referer_alloc; /* referer sting is malloc()ed */
+  struct curl_slist *cookielist; /* list of cookie files set by
+                                    curl_easy_setopt(COOKIEFILE) calls */
+};
+
+/*
+ * This 'UserDefined' struct must only contain data that is set once to go
+ * for many (perhaps) independent connections. Values that are generated or
+ * calculated internally for the "session handle" MUST be defined within the
+ * 'struct urlstate' instead. The only exceptions MUST note the changes in
+ * the 'DynamicStatic' struct.
+ */
+
+struct UserDefined {
+  FILE *err;         /* the stderr user data goes here */
+  void *debugdata;   /* the data that will be passed to fdebug */
+  char *errorbuffer; /* store failure messages in here */
+  char *proxyuserpwd;  /* Proxy <user:password>, if used */
+  long proxyport; /* If non-zero, use this port number by default. If the
+                     proxy string features a ":[port]" that one will override
+                     this. */
+  void *out;         /* the fetched file goes here */
+  void *in;          /* the uploaded file is read from here */
+  void *writeheader; /* write the header to this is non-NULL */
+  char *set_url;     /* what original URL to work on */
+  char *set_proxy;   /* proxy to use */
+  long use_port;     /* which port to use (when not using default) */
+  char *userpwd;     /* <user:password>, if used */
+  long httpauth;     /* what kind of HTTP authentication to use (bitmask) */
+  long proxyauth;    /* what kind of proxy authentication to use (bitmask) */
+  char *set_range;   /* range, if used. See README for detailed specification
+                        on this syntax. */
+  long followlocation; /* as in HTTP Location: */
+  long maxredirs;    /* maximum no. of http(s) redirects to follow */
+  char *set_referer; /* custom string */
+  bool free_referer; /* set TRUE if 'referer' points to a string we
+                        allocated */
+  char *useragent;   /* User-Agent string */
+  char *encoding;    /* Accept-Encoding string */
+  char *postfields;  /* if POST, set the fields' values here */
+  curl_off_t postfieldsize; /* if POST, this might have a size to use instead
+                               of strlen(), and then the data *may* be binary
+                               (contain zero bytes) */
+  char *ftpport;     /* port to send with the FTP PORT command */
+  char *device;      /* network interface to use */
+  curl_write_callback fwrite;        /* function that stores the output */
+  curl_write_callback fwrite_header; /* function that stores headers */
+  curl_read_callback fread;          /* function that reads the input */
+  curl_progress_callback fprogress;  /* function for progress information */
+  curl_debug_callback fdebug;      /* function that write informational data */
+  void *progress_client; /* pointer to pass to the progress callback */
+  long timeout;         /* in seconds, 0 means no timeout */
+  long connecttimeout;  /* in seconds, 0 means no timeout */
+  long ftp_response_timeout; /* in seconds, 0 means no timeout */
+  curl_off_t infilesize;      /* size of file to upload, -1 means unknown */
+  long low_speed_limit; /* bytes/second */
+  long low_speed_time;  /* number of seconds */
+  curl_off_t set_resume_from;  /* continue [ftp] transfer from here */
+  char *cookie;         /* HTTP cookie string to send */
+  struct curl_slist *headers; /* linked list of extra headers */
+  struct curl_httppost *httppost;  /* linked list of POST data */
+  char *cert;           /* certificate */
+  char *cert_type;      /* format for certificate (default: PEM) */
+  char *key;            /* private key */
+  char *key_type;       /* format for private key (default: PEM) */
+  char *key_passwd;     /* plain text private key password */
+  char *crypto_engine;  /* name of the crypto engine to use */
+  char *cookiejar;      /* dump all cookies to this file */
+  bool cookiesession;   /* new cookie session? */
+  bool crlf;            /* convert crlf on ftp upload(?) */
+  struct curl_slist *quote;     /* after connection is established */
+  struct curl_slist *postquote; /* after the transfer */
+  struct curl_slist *prequote; /* before the transfer, after type */
+  struct curl_slist *source_prequote;  /* in 3rd party transfer mode - before
+                                          the transfer on source host */
+  struct curl_slist *source_postquote; /* in 3rd party transfer mode - after
+                                          the transfer on source host */
+  struct curl_slist *telnet_options; /* linked list of telnet options */
+  curl_TimeCond timecondition; /* kind of time/date comparison */
+  time_t timevalue;       /* what time to compare with */
+  curl_closepolicy closepolicy; /* connection cache close concept */
+  Curl_HttpReq httpreq;   /* what kind of HTTP request (if any) is this */
+  char *customrequest;    /* HTTP/FTP request to use */
+  long httpversion; /* when non-zero, a specific HTTP version requested to
+                       be used in the library's request(s) */
+  char *auth_host; /* if set, this is the allocated string to the host name
+                    * to which to send the authorization data to, and no other
+                    * host (which location-following otherwise could lead to)
+                    */
+  char *krb4_level; /* what security level */
+  struct ssl_config_data ssl;  /* user defined SSL stuff */
+
+  curl_proxytype proxytype; /* what kind of proxy that is in use */
+
+  int dns_cache_timeout; /* DNS cache timeout */
+  long buffer_size;      /* size of receive buffer to use */
+
+  char *private; /* Private data */
+
+  struct curl_slist *http200aliases; /* linked list of aliases for http200 */
+
+  long ip_version;
+
+  curl_off_t max_filesize; /* Maximum file size to download */
+
+  char *source_host;     /* for 3rd party transfer */
+  char *source_port;     /* for 3rd party transfer */
+  char *source_userpwd;  /* for 3rd party transfer */
+  char *source_path;     /* for 3rd party transfer */
+  curl_pasv_side pasvHost; /* for 3rd party transfer indicates passive host */
+
+/* Here follows boolean settings that define how to behave during
+   this session. They are STATIC, set by libcurl users or at least initially
+   and they don't change during operations. */
+
+  bool printhost;       /* printing host name in debug info */
+  bool get_filetime;
+  bool tunnel_thru_httpproxy;
+  bool ftp_append;
+  bool ftp_ascii;
+  bool ftp_list_only;
+  bool ftp_create_missing_dirs;
+  bool ftp_use_port;
+  bool hide_progress;
+  bool http_fail_on_error;
+  bool http_follow_location;
+  bool http_disable_hostname_check_before_authentication;
+  bool include_header;   /* include received protocol headers in data output */
+  bool http_set_referer;
+  bool http_auto_referer; /* set "correct" referer when following location: */
+  bool opt_no_body;      /* as set with CURLOPT_NO_BODY */
+  bool set_port;
+  bool upload;
+  enum CURL_NETRC_OPTION
+       use_netrc;        /* defined in include/curl.h */
+  char *netrc_file;      /* if not NULL, use this instead of trying to find
+                            $HOME/.netrc */
+  bool verbose;
+  bool krb4;             /* kerberos4 connection requested */
+  bool reuse_forbid;     /* forbidden to be reused, close after use */
+  bool reuse_fresh;      /* do not re-use an existing connection  */
+  bool expect100header;  /* TRUE if we added Expect: 100-continue */
+  bool ftp_use_epsv;     /* if EPSV is to be attempted or not */
+  bool ftp_use_eprt;     /* if EPRT is to be attempted or not */
+  curl_ftpssl ftp_ssl;   /* if AUTH TLS is to be attempted etc */
+  bool no_signal;        /* do not use any signal/alarm handler */
+  bool global_dns_cache; /* subject for future removal */
+  bool tcp_nodelay;      /* whether to enable TCP_NODELAY or not */
+
+};
+
+/*
+ * In August 2001, this struct was redesigned and is since stricter than
+ * before. The 'connectdata' struct MUST have all the connection oriented
+ * stuff as we may now have several simultaneous connections and connection
+ * structs in memory.
+ *
+ * From now on, the 'SessionHandle' must only contain data that is set once to
+ * go for many (perhaps) independent connections. Values that are generated or
+ * calculated internally for the "session handle" must be defined within the
+ * 'struct urlstate' instead.  */
+
+struct SessionHandle {
+  curl_hash *hostcache;
+  struct Curl_share *share;    /* Share, handles global variable mutexing */
+  struct UserDefined set;      /* values set by the libcurl user */
+  struct DynamicStatic change; /* possibly modified userdefined data */
+
+  struct CookieInfo *cookies;  /* the cookies, read from files and servers */
+  struct Progress progress;    /* for all the progress meter data */
+  struct UrlState state;       /* struct for fields used for state info and
+                                  other dynamic purposes */
+  struct PureInfo info;        /* stats, reports and info data */
+#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
+  ENGINE*  engine;
+#endif /* USE_SSLEAY */
+};
+
+#define LIBCURL_NAME "libcurl"
+
+#endif
diff --git a/Utilities/cmcurl/version.c b/Utilities/cmcurl/version.c
new file mode 100644
index 0000000..4af298b
--- /dev/null
+++ b/Utilities/cmcurl/version.c
@@ -0,0 +1,261 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2004, 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
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * $Id$
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include <string.h>
+#include <stdio.h>
+
+#include <curl/curl.h>
+#include "urldata.h"
+
+#define _MPRINTF_REPLACE /* use the internal *printf() functions */
+#include <curl/mprintf.h>
+
+#ifdef USE_ARES
+#include <ares_version.h>
+#endif
+
+#ifdef USE_LIBIDN
+#include <stringprep.h>
+#endif
+
+#ifdef USE_SSLEAY
+static int getssl_version(char *ptr, size_t left, long *num)
+{
+
+#if (SSLEAY_VERSION_NUMBER >= 0x905000)
+  {
+    char sub[2];
+    unsigned long ssleay_value;
+    sub[1]='\0';
+    ssleay_value=SSLeay();
+    *num = (long)ssleay_value;
+    if(ssleay_value < 0x906000) {
+      ssleay_value=SSLEAY_VERSION_NUMBER;
+      sub[0]='\0';
+    }
+    else {
+      if(ssleay_value&0xff0) {
+        sub[0]=(char)((ssleay_value>>4)&0xff) + 'a' -1;
+      }
+      else
+        sub[0]='\0';
+    }
+
+    return snprintf(ptr, left, " OpenSSL/%lx.%lx.%lx%s",
+                    (ssleay_value>>28)&0xf,
+                    (ssleay_value>>20)&0xff,
+                    (ssleay_value>>12)&0xff,
+                    sub);
+  }
+
+#else
+  *num = SSLEAY_VERSION_NUMBER;
+#if (SSLEAY_VERSION_NUMBER >= 0x900000)
+  return snprintf(ptr, left, " OpenSSL/%lx.%lx.%lx",
+                  (SSLEAY_VERSION_NUMBER>>28)&0xff,
+                  (SSLEAY_VERSION_NUMBER>>20)&0xff,
+                  (SSLEAY_VERSION_NUMBER>>12)&0xf);
+#else
+  {
+    char sub[2];
+    sub[1]='\0';
+    if(SSLEAY_VERSION_NUMBER&0x0f) {
+      sub[0]=(SSLEAY_VERSION_NUMBER&0x0f) + 'a' -1;
+    }
+    else
+      sub[0]='\0';
+
+    return snprintf(ptr, left, " SSL/%x.%x.%x%s",
+                    (SSLEAY_VERSION_NUMBER>>12)&0xff,
+                    (SSLEAY_VERSION_NUMBER>>8)&0xf,
+                    (SSLEAY_VERSION_NUMBER>>4)&0xf, sub);
+  }
+#endif
+#endif
+}
+
+#endif
+
+char *curl_version(void)
+{
+  static char version[200];
+  char *ptr=version;
+  /* to prevent compier warnings, we only declare len if we have code
+     that uses it */
+#if defined(USE_SSLEAY) || defined(HAVE_LIBZ) || defined(USE_ARES) || \
+  defined(USE_LIBIDN)
+  int len;
+#endif
+  size_t left = sizeof(version);
+  strcpy(ptr, LIBCURL_NAME "/" LIBCURL_VERSION );
+  ptr=strchr(ptr, '\0');
+  left -= strlen(ptr);
+  (void)left;
+
+#ifdef USE_SSLEAY
+  {
+    long num;
+    len = getssl_version(ptr, left, &num);
+    left -= len;
+    ptr += len;
+  }
+#endif
+
+#ifdef HAVE_LIBZ
+  len = snprintf(ptr, left, " zlib/%s", zlibVersion());
+  left -= len;
+  ptr += len;
+#endif
+#ifdef USE_ARES
+  /* this function is only present in c-ares, not in the original ares */
+  len = snprintf(ptr, left, " c-ares/%s", ares_version(NULL));
+  left -= len;
+  ptr += len;
+#endif
+#ifdef USE_LIBIDN
+  if(stringprep_check_version(LIBIDN_REQUIRED_VERSION)) {
+    len = snprintf(ptr, left, " libidn/%s", stringprep_check_version(NULL));
+    left -= len;
+    ptr += len;
+  }
+#endif
+
+  return version;
+}
+
+/* data for curl_version_info */
+
+static const char *protocols[] = {
+#ifndef CURL_DISABLE_FTP
+  "ftp",
+#endif
+#ifndef CURL_DISABLE_GOPHER
+  "gopher",
+#endif
+#ifndef CURL_DISABLE_TELNET
+  "telnet",
+#endif
+#ifndef CURL_DISABLE_DICT
+  "dict",
+#endif
+#ifndef CURL_DISABLE_LDAP
+  "ldap",
+#endif
+#ifndef CURL_DISABLE_HTTP
+  "http",
+#endif
+#ifndef CURL_DISABLE_FILE
+  "file",
+#endif
+
+#ifdef USE_SSLEAY
+#ifndef CURL_DISABLE_HTTP
+  "https",
+#endif
+#ifndef CURL_DISABLE_FTP
+  "ftps",
+#endif
+#endif
+  NULL
+};
+
+static curl_version_info_data version_info = {
+  CURLVERSION_NOW,
+  LIBCURL_VERSION,
+  LIBCURL_VERSION_NUM,
+  OS, /* as found by configure or set by hand at build-time */
+  0 /* features is 0 by default */
+#ifdef ENABLE_IPV6
+  | CURL_VERSION_IPV6
+#endif
+#ifdef HAVE_KRB4
+  | CURL_VERSION_KERBEROS4
+#endif
+#ifdef USE_SSLEAY
+  | CURL_VERSION_SSL
+  | CURL_VERSION_NTLM /* since this requires OpenSSL */
+#endif
+#ifdef HAVE_LIBZ
+  | CURL_VERSION_LIBZ
+#endif
+#ifdef HAVE_GSSAPI
+  | CURL_VERSION_GSSNEGOTIATE
+#endif
+#ifdef CURLDEBUG
+  | CURL_VERSION_DEBUG
+#endif
+#ifdef USE_ARES
+  | CURL_VERSION_ASYNCHDNS
+#endif
+#ifdef HAVE_SPNEGO
+  | CURL_VERSION_SPNEGO
+#endif
+#if defined(ENABLE_64BIT) && (SIZEOF_CURL_OFF_T > 4)
+  | CURL_VERSION_LARGEFILE
+#endif
+  ,
+  NULL, /* ssl_version */
+  0,    /* ssl_version_num */
+  NULL, /* zlib_version */
+  protocols,
+  NULL, /* c-ares version */
+  0,    /* c-ares version numerical */
+  NULL, /* libidn version */
+};
+
+curl_version_info_data *curl_version_info(CURLversion stamp)
+{
+#ifdef USE_SSLEAY
+  static char ssl_buffer[80];
+  long num;
+  getssl_version(ssl_buffer, sizeof(ssl_buffer), &num);
+
+  version_info.ssl_version = ssl_buffer;
+  version_info.ssl_version_num = num;
+  /* SSL stuff is left zero if undefined */
+#endif
+
+#ifdef HAVE_LIBZ
+  version_info.libz_version = zlibVersion();
+  /* libz left NULL if non-existing */
+#endif
+#ifdef USE_ARES
+  {
+    int aresnum;
+    version_info.ares = ares_version(&aresnum);
+    version_info.ares_num = aresnum;
+  }
+#endif
+#ifdef USE_LIBIDN
+  /* This returns a version string if we use the given version or later,
+     otherwise it returns NULL */
+  version_info.libidn = stringprep_check_version(LIBIDN_REQUIRED_VERSION);
+  if(version_info.libidn)
+    version_info.features |= CURL_VERSION_IDN;
+#endif
+  (void)stamp; /* avoid compiler warnings, we don't use this */
+
+  return &version_info;
+}
-- 
cgit v0.12