Initial check in of curl.

Plan to:
- Fix warnings
- Add java support

Change-Id: Ia61d4d479aa61178f2883161491ab844301317e0
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..91d3baa
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,98 @@
+# Google Android makefile for curl and libcurl
+#
+# Place the curl source (including this makefile) into external/curl/ in the
+# Android source tree.  Then build them with 'make curl' or just 'make libcurl'
+# from the Android root. Tested with Android 1.5
+#
+# Note: you must first create a curl_config.h file by running configure in the
+# Android environment. The only way I've found to do this is tricky. Perform a
+# normal Android build with libcurl in the source tree, providing the target
+# "showcommands" to make. The build will eventually fail (because curl_config.h
+# doesn't exist yet), but the compiler commands used to build curl will be
+# shown. Now, from the external/curl/ directory, run curl's normal configure
+# command with flags that match what Android itself uses. This will mean
+# putting the compiler directory into the PATH, putting the -I, -isystem and
+# -D options into CPPFLAGS, putting the -m, -f, -O and -nostdlib options into
+# CFLAGS, and putting the -Wl, -L and -l options into LIBS, along with the path
+# to the files libgcc.a, crtbegin_dynamic.o, and ccrtend_android.o. Remember
+# that the paths must be absolute since you will not be running configure from
+# the same directory as the Android make.  The normal cross-compiler options
+# must also be set.
+#
+# The end result will be a configure command that looks something like this
+# (the environment variable A is set to the Android root path):
+#
+#  A=`realpath ../..` && \
+#  PATH="$A/prebuilt/linux-x86/toolchain/arm-eabi-X/bin:$PATH" \
+#  ./configure --host=arm-linux CC=arm-eabi-gcc \
+#  CPPFLAGS="-I $A/system/core/include ..." \
+#  CFLAGS="-fno-exceptions -Wno-multichar ..." \
+#  LIB="$A/prebuilt/linux-x86/toolchain/arm-eabi-X/lib/gcc/arm-eabi/X\
+#  /interwork/libgcc.a ..." \
+#
+# Dan Fandrich
+# September 2009
+
+LOCAL_PATH:= $(call my-dir)
+
+common_CFLAGS := -Wpointer-arith -Wwrite-strings -Wunused -Winline -Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wno-long-long -Wfloat-equal -Wno-multichar -Wsign-compare -Wno-format-nonliteral -Wendif-labels -Wstrict-prototypes -Wdeclaration-after-statement -Wno-system-headers -DHAVE_CONFIG_H
+
+#########################
+# Build the libcurl library
+
+include $(CLEAR_VARS)
+include $(LOCAL_PATH)/lib/Makefile.inc
+CURL_HEADERS := \
+	curlbuild.h \
+	curl.h \
+	curlrules.h \
+	curlver.h \
+	easy.h \
+	mprintf.h \
+	multi.h \
+	stdcheaders.h \
+	typecheck-gcc.h \
+	types.h
+
+LOCAL_SRC_FILES := $(addprefix lib/,$(CSOURCES))
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH)/include \
+    external/openssl/include \
+    external/zlib
+
+LOCAL_CFLAGS += $(common_CFLAGS)
+
+LOCAL_COPY_HEADERS_TO := libcurl/curl
+LOCAL_COPY_HEADERS := $(addprefix include/curl/,$(CURL_HEADERS))
+#LOCAL_SHARED_LIBRARIES := libz
+
+LOCAL_MODULE:= libcurl
+
+#include $(BUILD_STATIC_LIBRARY)
+
+
+#########################
+# Build the curl binary
+
+include $(CLEAR_VARS)
+include $(LOCAL_PATH)/src/Makefile.inc
+LOCAL_SRC_FILES := $(addprefix src/,$(CURL_SOURCES))
+
+LOCAL_MODULE := curl
+LOCAL_STATIC_LIBRARIES := libcurl
+LOCAL_SYSTEM_SHARED_LIBRARIES := libc
+
+LOCAL_C_INCLUDES := \
+    $(LOCAL_PATH)/include \
+    $(LOCAL_PATH)/lib \
+    external/openssl/include \
+    external/zlib
+
+LOCAL_SHARED_LIBRARIES := libz libssl libcrypto
+
+# This will also need to include $(CURLX_ONES) in order to correctly build
+# a dynamic library
+LOCAL_CFLAGS += $(common_CFLAGS)
+
+#include $(BUILD_EXECUTABLE)
+
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..163b299
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,21 @@
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright (c) 1996 - 2010, 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/README b/README
new file mode 100644
index 0000000..2ffacc3
--- /dev/null
+++ b/README
@@ -0,0 +1,49 @@
+                                  _   _ ____  _
+                              ___| | | |  _ \| |
+                             / __| | | | |_) | |
+                            | (__| |_| |  _ <| |___
+                             \___|\___/|_| \_\_____|
+
+README
+
+  Curl is a command line tool for transferring data specified with URL
+  syntax. Find out how to use curl by reading the curl.1 man page or the
+  MANUAL document. Find out how to install Curl by reading the INSTALL
+  document.
+
+  libcurl is the library curl is using to do its job. It is readily
+  available to be used by your software. Read the libcurl.3 man page to
+  learn how!
+
+  You find answers to the most frequent questions we get in the FAQ document.
+
+  Study the COPYING file for distribution terms and similar. If you distribute
+  curl binaries or other binaries that involve libcurl, you might enjoy the
+  LICENSE-MIXING document.
+
+CONTACT
+
+  If you have problems, questions, ideas or suggestions, please contact us
+  by posting to a suitable mailing list. See http://curl.haxx.se/mail/
+
+  All contributors to the project are listed in the THANKS document.
+
+WEB SITE
+
+  Visit the curl web site for the latest news and downloads:
+
+        http://curl.haxx.se/
+
+GIT
+
+  To download the very latest source off the GIT server do this:
+
+    git clone git://github.com/bagder/curl.git
+
+  (you'll get a directory named curl created, filled with the source code)
+
+NOTICE
+
+  Curl contains pieces of source code that is Copyright (c) 1998, 1999
+  Kungliga Tekniska Högskolan. This notice is included here to comply with the
+  distribution terms.
diff --git a/README.Android b/README.Android
new file mode 100644
index 0000000..00fbe45
--- /dev/null
+++ b/README.Android
@@ -0,0 +1,14 @@
+I have removed many files that are not needed to use curl, including docs and tests. If you want these, they can be downloaded from:
+http://curl.haxx.se/
+
+Uncomment the include $(BUILD_* lines from Android.mk depending on what you want to build.
+
+Run the following from the top dir:
+make libcurl curl
+adb remount
+adb push out/target/product/passion/system/bin/curl /system/bin/
+adb push /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ (if you are on goobuntu)
+
+any questions, mail me: kristianm@google.com
+
+This is not intended to go into an release.
diff --git a/include/README b/include/README
new file mode 100644
index 0000000..205f9f7
--- /dev/null
+++ b/include/README
@@ -0,0 +1,55 @@
+                                  _   _ ____  _
+                              ___| | | |  _ \| |
+                             / __| | | | |_) | |
+                            | (__| |_| |  _ <| |___
+                             \___|\___/|_| \_\_____|
+
+Include files for libcurl, external users.
+
+They're all placed in the curl subdirectory here for better fit in any kind
+of environment. You must include files from here using...
+
+        #include <curl/curl.h>
+
+... style and point the compiler's include path to the directory holding the
+curl subdirectory. It makes it more likely to survive future modifications.
+
+NOTE FOR LIBCURL HACKERS
+
+The following notes apply to libcurl version 7.19.0 and later.
+
+* The distributed curl/curlbuild.h file is only intended to be used on systems
+  which can not run the also distributed configure script.
+
+* The distributed curlbuild.h file is generated as a copy of curlbuild.h.dist
+  when the libcurl source code distribution archive file is originally created.
+
+* If you check out from git on a non-configure platform, you must run the
+  appropriate buildconf* script to set up curlbuild.h and other local files
+  before being able of compiling the library.
+
+* On systems capable of running the configure script, the configure process
+  will overwrite the distributed include/curl/curlbuild.h file with one that
+  is suitable and specific to the library being configured and built, which
+  is generated from the include/curl/curlbuild.h.in template file.
+
+* If you intend to distribute an already compiled libcurl library you _MUST_
+  also distribute along with it the generated curl/curlbuild.h which has been
+  used to compile it. Otherwise the library will be of no use for the users of
+  the library that you have built. It is _your_ responsability to provide this
+  file. No one at the cURL project can know how you have built the library.
+
+* File curl/curlbuild.h includes platform and configuration dependent info,
+  and must not be modified by anyone. Configure script generates it for you.
+
+* We cannot assume anything else but very basic compiler features being
+  present. While libcurl requires an ANSI C compiler to build, some of the
+  earlier ANSI compilers clearly can't deal with some preprocessor operators.
+
+* Newlines must remain unix-style for older compilers' sake.
+
+* Comments must be written in the old-style /* unnested C-fashion */
+
+To figure out how to do good and portable checks for features, operating
+systems or specific hardwarare, a very good resource is Bjorn Reese's
+collection at http://predef.sf.net/
diff --git a/include/curl/curl.h b/include/curl/curl.h
new file mode 100644
index 0000000..e635968
--- /dev/null
+++ b/include/curl/curl.h
@@ -0,0 +1,1996 @@
+#ifndef __CURL_CURL_H
+#define __CURL_CURL_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+/*
+ * If you have libcurl problems, all docs and details are found here:
+ *   http://curl.haxx.se/libcurl/
+ *
+ * curl-library mailing list subscription and unsubscription web interface:
+ *   http://cool.haxx.se/mailman/listinfo/curl-library/
+ */
+
+#include "curlver.h"         /* libcurl version defines   */
+#include "curlbuild.h"       /* libcurl build definitions */
+#include "curlrules.h"       /* libcurl rules enforcement */
+
+/*
+ * Define WIN32 when build target is Win32 API
+ */
+
+#if (defined(_WIN32) || defined(__WIN32__)) && \
+     !defined(WIN32) && !defined(__SYMBIAN32__)
+#define WIN32
+#endif
+
+#include <stdio.h>
+#include <limits.h>
+
+#if defined(__FreeBSD__) && (__FreeBSD__ >= 2)
+/* Needed for __FreeBSD_version symbol definition */
+#include <osreldate.h>
+#endif
+
+/* The include stuff here below is mainly for time_t! */
+#include <sys/types.h>
+#include <time.h>
+
+#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__GNUC__) && \
+  !defined(__CYGWIN__) || defined(__MINGW32__)
+#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H))
+/* The check above prevents the winsock2 inclusion if winsock.h already was
+   included, since they can't co-exist without problems */
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+#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(__NOVELL_LIBC__) || defined(__NetBSD__) || \
+    defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \
+    defined(ANDROID) || \
+   (defined(__FreeBSD_version) && (__FreeBSD_version < 800000))
+#include <sys/select.h>
+#endif
+
+#ifndef _WIN32_WCE
+#include <sys/socket.h>
+#endif
+#if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__)
+#include <sys/time.h>
+#endif
+#include <sys/types.h>
+#endif
+
+#ifdef __BEOS__
+#include <support/SupportDefs.h>
+#endif
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef void CURL;
+
+/*
+ * Decorate exportable functions for Win32 and Symbian OS DLL linking.
+ * This avoids using a .def file for building libcurl.dll.
+ */
+#if (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)) && \
+     !defined(CURL_STATICLIB)
+#if defined(BUILDING_LIBCURL)
+#define CURL_EXTERN  __declspec(dllexport)
+#else
+#define CURL_EXTERN  __declspec(dllimport)
+#endif
+#else
+
+#ifdef CURL_HIDDEN_SYMBOLS
+/*
+ * This definition is used to make external definitions visible in the
+ * shared library when symbols are hidden by default.  It makes no
+ * difference when compiling applications whether this is set or not,
+ * only when compiling the library.
+ */
+#define CURL_EXTERN CURL_EXTERN_SYMBOL
+#else
+#define CURL_EXTERN
+#endif
+#endif
+
+#ifndef curl_socket_typedef
+/* socket typedef */
+#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
+#define curl_socket_typedef
+#endif /* curl_socket_typedef */
+
+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 */
+#define HTTPPOST_CALLBACK (1<<6)    /* upload file contents by using the
+                                       regular read callback to get the data
+                                       and pass the given pointer as custom
+                                       pointer */
+
+  char *showfilename;               /* The file name to show. If not set, the
+                                       actual file name will be used (if this
+                                       is a file part) */
+  void *userp;                      /* custom pointer used for
+                                       HTTPPOST_CALLBACK posts */
+};
+
+typedef int (*curl_progress_callback)(void *clientp,
+                                      double dltotal,
+                                      double dlnow,
+                                      double ultotal,
+                                      double ulnow);
+
+#ifndef CURL_MAX_WRITE_SIZE
+  /* 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.
+     We do the ifndef check to allow this value to easier be changed at build
+     time for those who feel adventurous. The practical minimum is about
+     400 bytes since libcurl uses a buffer of this size as a scratch area
+     (unrelated to network send operations). */
+#define CURL_MAX_WRITE_SIZE 16384
+#endif
+
+#ifndef CURL_MAX_HTTP_HEADER
+/* The only reason to have a max limit for this is to avoid the risk of a bad
+   server feeding libcurl with a never-ending header that will cause reallocs
+   infinitely */
+#define CURL_MAX_HTTP_HEADER (100*1024)
+#endif
+
+
+/* This is a magic return code for the write callback that, when returned,
+   will signal libcurl to pause receiving on the current transfer. */
+#define CURL_WRITEFUNC_PAUSE 0x10000001
+typedef size_t (*curl_write_callback)(char *buffer,
+                                      size_t size,
+                                      size_t nitems,
+                                      void *outstream);
+
+/* These are the return codes for the seek callbacks */
+#define CURL_SEEKFUNC_OK       0
+#define CURL_SEEKFUNC_FAIL     1 /* fail the entire transfer */
+#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so
+                                    libcurl might try other means instead */
+typedef int (*curl_seek_callback)(void *instream,
+                                  curl_off_t offset,
+                                  int origin); /* 'whence' */
+
+/* This is a return code for the read callback that, when returned, will
+   signal libcurl to immediately abort the current transfer. */
+#define CURL_READFUNC_ABORT 0x10000000
+/* This is a return code for the read callback that, when returned, will
+   signal libcurl to pause sending data on the current transfer. */
+#define CURL_READFUNC_PAUSE 0x10000001
+
+typedef size_t (*curl_read_callback)(char *buffer,
+                                      size_t size,
+                                      size_t nitems,
+                                      void *instream);
+
+typedef enum  {
+  CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */
+  CURLSOCKTYPE_LAST   /* never use */
+} curlsocktype;
+
+typedef int (*curl_sockopt_callback)(void *clientp,
+                                     curl_socket_t curlfd,
+                                     curlsocktype purpose);
+
+struct curl_sockaddr {
+  int family;
+  int socktype;
+  int protocol;
+  unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it
+                           turned really ugly and painful on the systems that
+                           lack this type */
+  struct sockaddr addr;
+};
+
+typedef curl_socket_t
+(*curl_opensocket_callback)(void *clientp,
+                            curlsocktype purpose,
+                            struct curl_sockaddr *address);
+
+typedef enum {
+  CURLIOE_OK,            /* I/O operation successful */
+  CURLIOE_UNKNOWNCMD,    /* command was unknown to callback */
+  CURLIOE_FAILRESTART,   /* failed to restart the read */
+  CURLIOE_LAST           /* never use */
+} curlioerr;
+
+typedef enum  {
+  CURLIOCMD_NOP,         /* no operation */
+  CURLIOCMD_RESTARTREAD, /* restart the read stream from start */
+  CURLIOCMD_LAST         /* never use */
+} curliocmd;
+
+typedef curlioerr (*curl_ioctl_callback)(CURL *handle,
+                                         int cmd,
+                                         void *clientp);
+
+/*
+ * 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_OBSOLETE4,               /* 4 - NOT USED */
+  CURLE_COULDNT_RESOLVE_PROXY,   /* 5 */
+  CURLE_COULDNT_RESOLVE_HOST,    /* 6 */
+  CURLE_COULDNT_CONNECT,         /* 7 */
+  CURLE_FTP_WEIRD_SERVER_REPLY,  /* 8 */
+  CURLE_REMOTE_ACCESS_DENIED,    /* 9 a service was denied by the server
+                                    due to lack of access - when login fails
+                                    this is not returned. */
+  CURLE_OBSOLETE10,              /* 10 - NOT USED */
+  CURLE_FTP_WEIRD_PASS_REPLY,    /* 11 */
+  CURLE_OBSOLETE12,              /* 12 - NOT USED */
+  CURLE_FTP_WEIRD_PASV_REPLY,    /* 13 */
+  CURLE_FTP_WEIRD_227_FORMAT,    /* 14 */
+  CURLE_FTP_CANT_GET_HOST,       /* 15 */
+  CURLE_OBSOLETE16,              /* 16 - NOT USED */
+  CURLE_FTP_COULDNT_SET_TYPE,    /* 17 */
+  CURLE_PARTIAL_FILE,            /* 18 */
+  CURLE_FTP_COULDNT_RETR_FILE,   /* 19 */
+  CURLE_OBSOLETE20,              /* 20 - NOT USED */
+  CURLE_QUOTE_ERROR,             /* 21 - quote command failure */
+  CURLE_HTTP_RETURNED_ERROR,     /* 22 */
+  CURLE_WRITE_ERROR,             /* 23 */
+  CURLE_OBSOLETE24,              /* 24 - NOT USED */
+  CURLE_UPLOAD_FAILED,           /* 25 - failed upload "command" */
+  CURLE_READ_ERROR,              /* 26 - couldn't open/read from file */
+  CURLE_OUT_OF_MEMORY,           /* 27 */
+  /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error
+           instead of a memory allocation error if CURL_DOES_CONVERSIONS
+           is defined
+  */
+  CURLE_OPERATION_TIMEDOUT,      /* 28 - the timeout time was reached */
+  CURLE_OBSOLETE29,              /* 29 - NOT USED */
+  CURLE_FTP_PORT_FAILED,         /* 30 - FTP PORT operation failed */
+  CURLE_FTP_COULDNT_USE_REST,    /* 31 - the REST command failed */
+  CURLE_OBSOLETE32,              /* 32 - NOT USED */
+  CURLE_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_OBSOLETE40,              /* 40 - NOT USED */
+  CURLE_FUNCTION_NOT_FOUND,      /* 41 */
+  CURLE_ABORTED_BY_CALLBACK,     /* 42 */
+  CURLE_BAD_FUNCTION_ARGUMENT,   /* 43 */
+  CURLE_OBSOLETE44,              /* 44 - NOT USED */
+  CURLE_INTERFACE_FAILED,        /* 45 - CURLOPT_INTERFACE failed */
+  CURLE_OBSOLETE46,              /* 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_OBSOLETE50,              /* 50 - NOT USED */
+  CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint
+                                     wasn't verified fine */
+  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_OBSOLETE57,              /* 57 - NOT 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_USE_SSL_FAILED,          /* 64 - Requested FTP SSL level failed */
+  CURLE_SEND_FAIL_REWIND,        /* 65 - Sending the data requires a rewind
+                                    that failed */
+  CURLE_SSL_ENGINE_INITFAILED,   /* 66 - failed to initialise ENGINE */
+  CURLE_LOGIN_DENIED,            /* 67 - user, password or similar was not
+                                    accepted and we failed to login */
+  CURLE_TFTP_NOTFOUND,           /* 68 - file not found on server */
+  CURLE_TFTP_PERM,               /* 69 - permission problem on server */
+  CURLE_REMOTE_DISK_FULL,        /* 70 - out of disk space on server */
+  CURLE_TFTP_ILLEGAL,            /* 71 - Illegal TFTP operation */
+  CURLE_TFTP_UNKNOWNID,          /* 72 - Unknown transfer ID */
+  CURLE_REMOTE_FILE_EXISTS,      /* 73 - File already exists */
+  CURLE_TFTP_NOSUCHUSER,         /* 74 - No such user */
+  CURLE_CONV_FAILED,             /* 75 - conversion failed */
+  CURLE_CONV_REQD,               /* 76 - caller must register conversion
+                                    callbacks using curl_easy_setopt options
+                                    CURLOPT_CONV_FROM_NETWORK_FUNCTION,
+                                    CURLOPT_CONV_TO_NETWORK_FUNCTION, and
+                                    CURLOPT_CONV_FROM_UTF8_FUNCTION */
+  CURLE_SSL_CACERT_BADFILE,      /* 77 - could not load CACERT file, missing
+                                    or wrong format */
+  CURLE_REMOTE_FILE_NOT_FOUND,   /* 78 - remote file not found */
+  CURLE_SSH,                     /* 79 - error from the SSH layer, somewhat
+                                    generic so the error message will be of
+                                    interest when this has happened */
+
+  CURLE_SSL_SHUTDOWN_FAILED,     /* 80 - Failed to shut down the SSL
+                                    connection */
+  CURLE_AGAIN,                   /* 81 - socket is not ready for send/recv,
+                                    wait till it's ready and try again (Added
+                                    in 7.18.2) */
+  CURLE_SSL_CRL_BADFILE,         /* 82 - could not load CRL file, missing or
+                                    wrong format (Added in 7.19.0) */
+  CURLE_SSL_ISSUER_ERROR,        /* 83 - Issuer check failed.  (Added in
+                                    7.19.0) */
+  CURLE_FTP_PRET_FAILED,         /* 84 - a PRET command failed */
+  CURLE_RTSP_CSEQ_ERROR,         /* 85 - mismatch of RTSP CSeq numbers */
+  CURLE_RTSP_SESSION_ERROR,      /* 86 - mismatch of RTSP Session Identifiers */
+
+  CURL_LAST /* never use! */
+} CURLcode;
+
+#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
+                          the obsolete stuff removed! */
+
+/* Backwards compatibility with older names */
+
+/* The following were added in 7.17.1 */
+/* These are scheduled to disappear by 2009 */
+#define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION
+
+/* The following were added in 7.17.0 */
+/* These are scheduled to disappear by 2009 */
+#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* noone should be using this! */
+#define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46
+#define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44
+#define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10
+#define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16
+#define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32
+#define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29
+#define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12
+#define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20
+#define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40
+#define CURLE_MALFORMAT_USER CURLE_OBSOLETE24
+#define CURLE_SHARE_IN_USE CURLE_OBSOLETE57
+#define CURLE_URL_MALFORMAT_USER CURLE_OBSOLETE4
+
+#define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED
+#define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE
+#define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR
+#define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL
+#define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS
+#define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR
+#define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED
+
+/* The following were added earlier */
+
+#define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT
+
+#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR
+#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED
+#define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED
+
+#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE
+#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME
+
+/* 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
+
+#endif /*!CURL_NO_OLDIES*/
+
+/* This prototype applies to all conversion callbacks */
+typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length);
+
+typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl,    /* easy handle */
+                                          void *ssl_ctx, /* actually an
+                                                            OpenSSL SSL_CTX */
+                                          void *userptr);
+
+typedef enum {
+  CURLPROXY_HTTP = 0,   /* added in 7.10, new in 7.19.4 default is to use
+                           CONNECT HTTP/1.1 */
+  CURLPROXY_HTTP_1_0 = 1,   /* added in 7.19.4, force to use CONNECT
+                               HTTP/1.0  */
+  CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already
+                           in 7.10 */
+  CURLPROXY_SOCKS5 = 5, /* added in 7.10 */
+  CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */
+  CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the
+                                   host name rather than the IP address. added
+                                   in 7.18.0 */
+} curl_proxytype;  /* this enum was added in 7.10 */
+
+#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_DIGEST_IE    (1<<4)  /* Digest with IE flavour */
+#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE)  /* all fine types set */
+#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE))
+
+#define CURLSSH_AUTH_ANY       ~0     /* all types supported by the server */
+#define CURLSSH_AUTH_NONE      0      /* none allowed, silly but complete */
+#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */
+#define CURLSSH_AUTH_PASSWORD  (1<<1) /* password */
+#define CURLSSH_AUTH_HOST      (1<<2) /* host key files */
+#define CURLSSH_AUTH_KEYBOARD  (1<<3) /* keyboard interactive */
+#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY
+
+#define CURL_ERROR_SIZE 256
+
+struct curl_khkey {
+  const char *key; /* points to a zero-terminated string encoded with base64
+                      if len is zero, otherwise to the "raw" data */
+  size_t len;
+  enum type {
+    CURLKHTYPE_UNKNOWN,
+    CURLKHTYPE_RSA1,
+    CURLKHTYPE_RSA,
+    CURLKHTYPE_DSS
+  } keytype;
+};
+
+/* this is the set of return values expected from the curl_sshkeycallback
+   callback */
+enum curl_khstat {
+  CURLKHSTAT_FINE_ADD_TO_FILE,
+  CURLKHSTAT_FINE,
+  CURLKHSTAT_REJECT, /* reject the connection, return an error */
+  CURLKHSTAT_DEFER,  /* do not accept it, but we can't answer right now so
+                        this causes a CURLE_DEFER error but otherwise the
+                        connection will be left intact etc */
+  CURLKHSTAT_LAST    /* not for use, only a marker for last-in-list */
+};
+
+/* this is the set of status codes pass in to the callback */
+enum curl_khmatch {
+  CURLKHMATCH_OK,       /* match */
+  CURLKHMATCH_MISMATCH, /* host found, key mismatch! */
+  CURLKHMATCH_MISSING,  /* no matching host/key found */
+  CURLKHMATCH_LAST      /* not for use, only a marker for last-in-list */
+};
+
+typedef int
+  (*curl_sshkeycallback) (CURL *easy,     /* easy handle */
+                          const struct curl_khkey *knownkey, /* known */
+                          const struct curl_khkey *foundkey, /* found */
+                          enum curl_khmatch, /* libcurl's view on the keys */
+                          void *clientp); /* custom pointer passed from app */
+
+/* parameter for the CURLOPT_USE_SSL option */
+typedef enum {
+  CURLUSESSL_NONE,    /* do not attempt to use SSL */
+  CURLUSESSL_TRY,     /* try using SSL, proceed anyway otherwise */
+  CURLUSESSL_CONTROL, /* SSL for the control connection or fail */
+  CURLUSESSL_ALL,     /* SSL for all communication or fail */
+  CURLUSESSL_LAST     /* not an option, never use */
+} curl_usessl;
+
+#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
+                          the obsolete stuff removed! */
+
+/* Backwards compatibility with older names */
+/* These are scheduled to disappear by 2009 */
+
+#define CURLFTPSSL_NONE CURLUSESSL_NONE
+#define CURLFTPSSL_TRY CURLUSESSL_TRY
+#define CURLFTPSSL_CONTROL CURLUSESSL_CONTROL
+#define CURLFTPSSL_ALL CURLUSESSL_ALL
+#define CURLFTPSSL_LAST CURLUSESSL_LAST
+#define curl_ftpssl curl_usessl
+#endif /*!CURL_NO_OLDIES*/
+
+/* parameter for the CURLOPT_FTP_SSL_CCC option */
+typedef enum {
+  CURLFTPSSL_CCC_NONE,    /* do not send CCC */
+  CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */
+  CURLFTPSSL_CCC_ACTIVE,  /* Initiate the shutdown */
+  CURLFTPSSL_CCC_LAST     /* not an option, never use */
+} curl_ftpccc;
+
+/* parameter for the CURLOPT_FTPSSLAUTH option */
+typedef enum {
+  CURLFTPAUTH_DEFAULT, /* let libcurl decide */
+  CURLFTPAUTH_SSL,     /* use "AUTH SSL" */
+  CURLFTPAUTH_TLS,     /* use "AUTH TLS" */
+  CURLFTPAUTH_LAST /* not an option, never use */
+} curl_ftpauth;
+
+/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */
+typedef enum {
+  CURLFTP_CREATE_DIR_NONE,  /* do NOT create missing dirs! */
+  CURLFTP_CREATE_DIR,       /* (FTP/SFTP) if CWD fails, try MKD and then CWD
+                               again if MKD succeeded, for SFTP this does
+                               similar magic */
+  CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD
+                               again even if MKD failed! */
+  CURLFTP_CREATE_DIR_LAST   /* not an option, never use */
+} curl_ftpcreatedir;
+
+/* parameter for the CURLOPT_FTP_FILEMETHOD option */
+typedef enum {
+  CURLFTPMETHOD_DEFAULT,   /* let libcurl pick */
+  CURLFTPMETHOD_MULTICWD,  /* single CWD operation for each path part */
+  CURLFTPMETHOD_NOCWD,     /* no CWD at all */
+  CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */
+  CURLFTPMETHOD_LAST       /* not an option, never use */
+} curl_ftpmethod;
+
+/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */
+#define CURLPROTO_HTTP   (1<<0)
+#define CURLPROTO_HTTPS  (1<<1)
+#define CURLPROTO_FTP    (1<<2)
+#define CURLPROTO_FTPS   (1<<3)
+#define CURLPROTO_SCP    (1<<4)
+#define CURLPROTO_SFTP   (1<<5)
+#define CURLPROTO_TELNET (1<<6)
+#define CURLPROTO_LDAP   (1<<7)
+#define CURLPROTO_LDAPS  (1<<8)
+#define CURLPROTO_DICT   (1<<9)
+#define CURLPROTO_FILE   (1<<10)
+#define CURLPROTO_TFTP   (1<<11)
+#define CURLPROTO_IMAP   (1<<12)
+#define CURLPROTO_IMAPS  (1<<13)
+#define CURLPROTO_POP3   (1<<14)
+#define CURLPROTO_POP3S  (1<<15)
+#define CURLPROTO_SMTP   (1<<16)
+#define CURLPROTO_SMTPS  (1<<17)
+#define CURLPROTO_RTSP   (1<<18)
+#define CURLPROTO_ALL    (~0) /* enable everything */
+
+/* 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
+
+#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 successful. -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 static input fields. */
+  CINIT(POSTFIELDS, OBJECTPOINT, 15),
+
+  /* Set the referrer 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 curl_httppost */
+  CINIT(HTTPPOST, OBJECTPOINT, 24),
+
+  /* name of the file keeping your private SSL-certificate */
+  CINIT(SSLCERT, OBJECTPOINT, 25),
+
+  /* password for the SSL or SSH private key */
+  CINIT(KEYPASSWD, 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 specifically 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(DIRLISTONLY, LONG, 48),  /* return bare names when listing directories */
+
+  CINIT(APPEND, 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 referrer 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/5 security level, this also enables krb4/5 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(KRBLEVEL, 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),
+
+  /* Specifically 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 */
+  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, CURLPROXY_SOCKS4A 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 potentially send off the name
+     and password to whatever host the server decides. */
+  CINIT(UNRESTRICTED_AUTH, LONG, 105),
+
+  /* Specifically 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.
+     In 7.19.4 we introduced the convenience enums for this option using the
+     CURLFTP_CREATE_DIR prefix.
+  */
+  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),
+#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT
+
+  /* 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(USE_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),
+
+  /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+  /* 123 OBSOLETE. Gone in 7.16.0 */
+  /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+  /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+  /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+  /* 127 OBSOLETE. Gone in 7.16.0 */
+  /* 128 OBSOLETE. Gone in 7.16.0 */
+
+  /* When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option
+     can be used to change libcurl's default action which is to first try
+     "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK
+     response has been received.
+
+     Available parameters are:
+     CURLFTPAUTH_DEFAULT - let libcurl decide
+     CURLFTPAUTH_SSL     - try "AUTH SSL" first, then TLS
+     CURLFTPAUTH_TLS     - try "AUTH TLS" first, then SSL
+  */
+  CINIT(FTPSSLAUTH, LONG, 129),
+
+  CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130),
+  CINIT(IOCTLDATA, OBJECTPOINT, 131),
+
+  /* 132 OBSOLETE. Gone in 7.16.0 */
+  /* 133 OBSOLETE. Gone in 7.16.0 */
+
+  /* zero terminated string for pass on to the FTP server when asked for
+     "account" info */
+  CINIT(FTP_ACCOUNT, OBJECTPOINT, 134),
+
+  /* feed cookies into cookie engine */
+  CINIT(COOKIELIST, OBJECTPOINT, 135),
+
+  /* ignore Content-Length */
+  CINIT(IGNORE_CONTENT_LENGTH, LONG, 136),
+
+  /* Set to non-zero to skip the IP address received in a 227 PASV FTP server
+     response. Typically used for FTP-SSL purposes but is not restricted to
+     that. libcurl will then instead use the same IP address it used for the
+     control connection. */
+  CINIT(FTP_SKIP_PASV_IP, LONG, 137),
+
+  /* Select "file method" to use when doing FTP, see the curl_ftpmethod
+     above. */
+  CINIT(FTP_FILEMETHOD, LONG, 138),
+
+  /* Local port number to bind the socket to */
+  CINIT(LOCALPORT, LONG, 139),
+
+  /* Number of ports to try, including the first one set with LOCALPORT.
+     Thus, setting it to 1 will make no additional attempts but the first.
+  */
+  CINIT(LOCALPORTRANGE, LONG, 140),
+
+  /* no transfer, set up connection and let application use the socket by
+     extracting it with CURLINFO_LASTSOCKET */
+  CINIT(CONNECT_ONLY, LONG, 141),
+
+  /* Function that will be called to convert from the
+     network encoding (instead of using the iconv calls in libcurl) */
+  CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142),
+
+  /* Function that will be called to convert to the
+     network encoding (instead of using the iconv calls in libcurl) */
+  CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143),
+
+  /* Function that will be called to convert from UTF8
+     (instead of using the iconv calls in libcurl)
+     Note that this is used only for SSL certificate processing */
+  CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144),
+
+  /* if the connection proceeds too quickly then need to slow it down */
+  /* limit-rate: maximum number of bytes per second to send or receive */
+  CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145),
+  CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146),
+
+  /* Pointer to command string to send if USER/PASS fails. */
+  CINIT(FTP_ALTERNATIVE_TO_USER, OBJECTPOINT, 147),
+
+  /* callback function for setting socket options */
+  CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148),
+  CINIT(SOCKOPTDATA, OBJECTPOINT, 149),
+
+  /* set to 0 to disable session ID re-use for this transfer, default is
+     enabled (== 1) */
+  CINIT(SSL_SESSIONID_CACHE, LONG, 150),
+
+  /* allowed SSH authentication methods */
+  CINIT(SSH_AUTH_TYPES, LONG, 151),
+
+  /* Used by scp/sftp to do public/private key authentication */
+  CINIT(SSH_PUBLIC_KEYFILE, OBJECTPOINT, 152),
+  CINIT(SSH_PRIVATE_KEYFILE, OBJECTPOINT, 153),
+
+  /* Send CCC (Clear Command Channel) after authentication */
+  CINIT(FTP_SSL_CCC, LONG, 154),
+
+  /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */
+  CINIT(TIMEOUT_MS, LONG, 155),
+  CINIT(CONNECTTIMEOUT_MS, LONG, 156),
+
+  /* set to zero to disable the libcurl's decoding and thus pass the raw body
+     data to the application even when it is encoded/compressed */
+  CINIT(HTTP_TRANSFER_DECODING, LONG, 157),
+  CINIT(HTTP_CONTENT_DECODING, LONG, 158),
+
+  /* Permission used when creating new files and directories on the remote
+     server for protocols that support it, SFTP/SCP/FILE */
+  CINIT(NEW_FILE_PERMS, LONG, 159),
+  CINIT(NEW_DIRECTORY_PERMS, LONG, 160),
+
+  /* Set the behaviour of POST when redirecting. Values must be set to one
+     of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */
+  CINIT(POSTREDIR, LONG, 161),
+
+  /* used by scp/sftp to verify the host's public key */
+  CINIT(SSH_HOST_PUBLIC_KEY_MD5, OBJECTPOINT, 162),
+
+  /* Callback function for opening socket (instead of socket(2)). Optionally,
+     callback is able change the address or refuse to connect returning
+     CURL_SOCKET_BAD.  The callback should have type
+     curl_opensocket_callback */
+  CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163),
+  CINIT(OPENSOCKETDATA, OBJECTPOINT, 164),
+
+  /* POST volatile input fields. */
+  CINIT(COPYPOSTFIELDS, OBJECTPOINT, 165),
+
+  /* set transfer mode (;type=<a|i>) when doing FTP via an HTTP proxy */
+  CINIT(PROXY_TRANSFER_MODE, LONG, 166),
+
+  /* Callback function for seeking in the input stream */
+  CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167),
+  CINIT(SEEKDATA, OBJECTPOINT, 168),
+
+  /* CRL file */
+  CINIT(CRLFILE, OBJECTPOINT, 169),
+
+  /* Issuer certificate */
+  CINIT(ISSUERCERT, OBJECTPOINT, 170),
+
+  /* (IPv6) Address scope */
+  CINIT(ADDRESS_SCOPE, LONG, 171),
+
+  /* Collect certificate chain info and allow it to get retrievable with
+     CURLINFO_CERTINFO after the transfer is complete. (Unfortunately) only
+     working with OpenSSL-powered builds. */
+  CINIT(CERTINFO, LONG, 172),
+
+  /* "name" and "pwd" to use when fetching. */
+  CINIT(USERNAME, OBJECTPOINT, 173),
+  CINIT(PASSWORD, OBJECTPOINT, 174),
+
+    /* "name" and "pwd" to use with Proxy when fetching. */
+  CINIT(PROXYUSERNAME, OBJECTPOINT, 175),
+  CINIT(PROXYPASSWORD, OBJECTPOINT, 176),
+
+  /* Comma separated list of hostnames defining no-proxy zones. These should
+     match both hostnames directly, and hostnames within a domain. For
+     example, local.com will match local.com and www.local.com, but NOT
+     notlocal.com or www.notlocal.com. For compatibility with other
+     implementations of this, .local.com will be considered to be the same as
+     local.com. A single * is the only valid wildcard, and effectively
+     disables the use of proxy. */
+  CINIT(NOPROXY, OBJECTPOINT, 177),
+
+  /* block size for TFTP transfers */
+  CINIT(TFTP_BLKSIZE, LONG, 178),
+
+  /* Socks Service */
+  CINIT(SOCKS5_GSSAPI_SERVICE, OBJECTPOINT, 179),
+
+  /* Socks Service */
+  CINIT(SOCKS5_GSSAPI_NEC, LONG, 180),
+
+  /* set the bitmask for the protocols that are allowed to be used for the
+     transfer, which thus helps the app which takes URLs from users or other
+     external inputs and want to restrict what protocol(s) to deal
+     with. Defaults to CURLPROTO_ALL. */
+  CINIT(PROTOCOLS, LONG, 181),
+
+  /* set the bitmask for the protocols that libcurl is allowed to follow to,
+     as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs
+     to be set in both bitmasks to be allowed to get redirected to. Defaults
+     to all protocols except FILE and SCP. */
+  CINIT(REDIR_PROTOCOLS, LONG, 182),
+
+  /* set the SSH knownhost file name to use */
+  CINIT(SSH_KNOWNHOSTS, OBJECTPOINT, 183),
+
+  /* set the SSH host key callback, must point to a curl_sshkeycallback
+     function */
+  CINIT(SSH_KEYFUNCTION, FUNCTIONPOINT, 184),
+
+  /* set the SSH host key callback custom pointer */
+  CINIT(SSH_KEYDATA, OBJECTPOINT, 185),
+
+  /* set the SMTP mail originator */
+  CINIT(MAIL_FROM, OBJECTPOINT, 186),
+
+  /* set the SMTP mail receiver(s) */
+  CINIT(MAIL_RCPT, OBJECTPOINT, 187),
+
+  /* FTP: send PRET before PASV */
+  CINIT(FTP_USE_PRET, LONG, 188),
+
+  /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */
+  CINIT(RTSP_REQUEST, LONG, 189),
+
+  /* The RTSP session identifier */
+  CINIT(RTSP_SESSION_ID, OBJECTPOINT, 190),
+
+  /* The RTSP stream URI */
+  CINIT(RTSP_STREAM_URI, OBJECTPOINT, 191),
+
+  /* The Transport: header to use in RTSP requests */
+  CINIT(RTSP_TRANSPORT, OBJECTPOINT, 192),
+
+  /* Manually initialize the client RTSP CSeq for this handle */
+  CINIT(RTSP_CLIENT_CSEQ, LONG, 193),
+
+  /* Manually initialize the server RTSP CSeq for this handle */
+  CINIT(RTSP_SERVER_CSEQ, LONG, 194),
+
+  /* The stream to pass to INTERLEAVEFUNCTION. */
+  CINIT(INTERLEAVEDATA, OBJECTPOINT, 195),
+
+  /* Let the application define a custom write method for RTP data */
+  CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196),
+
+  CURLOPT_LASTENTRY /* the last unused */
+} CURLoption;
+
+#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
+                          the obsolete stuff removed! */
+
+/* Backwards compatibility with older names */
+/* These are scheduled to disappear by 2011 */
+
+/* This was added in version 7.19.1 */
+#define CURLOPT_POST301 CURLOPT_POSTREDIR
+
+/* These are scheduled to disappear by 2009 */
+
+/* The following were added in 7.17.0 */
+#define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD
+#define CURLOPT_FTPAPPEND CURLOPT_APPEND
+#define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY
+#define CURLOPT_FTP_SSL CURLOPT_USE_SSL
+
+/* The following were added earlier */
+
+#define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD
+#define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL
+
+#else
+/* This is set if CURL_NO_OLDIES is defined at compile-time */
+#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */
+#endif
+
+
+  /* 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
+#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER
+
+  /* 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 */
+};
+
+/*
+ * Public API enums for RTSP requests
+ */
+enum {
+    CURL_RTSPREQ_NONE, /* first in list */
+    CURL_RTSPREQ_OPTIONS,
+    CURL_RTSPREQ_DESCRIBE,
+    CURL_RTSPREQ_ANNOUNCE,
+    CURL_RTSPREQ_SETUP,
+    CURL_RTSPREQ_PLAY,
+    CURL_RTSPREQ_PAUSE,
+    CURL_RTSPREQ_TEARDOWN,
+    CURL_RTSPREQ_GET_PARAMETER,
+    CURL_RTSPREQ_SET_PARAMETER,
+    CURL_RTSPREQ_RECORD,
+    CURL_RTSPREQ_RECEIVE,
+    CURL_RTSPREQ_LAST /* last in list */
+};
+
+  /* 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 */
+};
+
+/* symbols to use with CURLOPT_POSTREDIR.
+   CURL_REDIR_POST_301 and CURL_REDIR_POST_302 can be bitwise ORed so that
+   CURL_REDIR_POST_301 | CURL_REDIR_POST_302 == CURL_REDIR_POST_ALL */
+
+#define CURL_REDIR_GET_ALL  0
+#define CURL_REDIR_POST_301 1
+#define CURL_REDIR_POST_302 2
+#define CURL_REDIR_POST_ALL (CURL_REDIR_POST_301|CURL_REDIR_POST_302)
+
+typedef enum {
+  CURL_TIMECOND_NONE,
+
+  CURL_TIMECOND_IFMODSINCE,
+  CURL_TIMECOND_IFUNMODSINCE,
+  CURL_TIMECOND_LASTMOD,
+
+  CURL_TIMECOND_LAST
+} curl_TimeCond;
+
+
+/* curl_strequal() and curl_strnequal() are subject for removal in a future
+   libcurl, see lib/README.curlx for details */
+CURL_EXTERN int (curl_strequal)(const char *s1, const char *s2);
+CURL_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),
+
+  CFINIT(STREAM),
+
+  CURLFORM_LASTENTRY /* the last unused */
+} 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 curl_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 advanced 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.
+ */
+CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost,
+                                      struct curl_httppost **last_post,
+                                      ...);
+
+/*
+ * callback function for curl_formget()
+ * The void *arg pointer will be the one passed as second argument to
+ *   curl_formget().
+ * The character buffer passed to it must not be freed.
+ * Should return the buffer length passed to it as the argument "len" on
+ *   success.
+ */
+typedef size_t (*curl_formget_callback)(void *arg, const char *buf, size_t len);
+
+/*
+ * NAME curl_formget()
+ *
+ * DESCRIPTION
+ *
+ * Serialize a curl_httppost struct built with curl_formadd().
+ * Accepts a void pointer as second argument which will be passed to
+ * the curl_formget_callback function.
+ * Returns 0 on success.
+ */
+CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg,
+                             curl_formget_callback append);
+/*
+ * NAME curl_formfree()
+ *
+ * DESCRIPTION
+ *
+ * Free a multipart formpost previously built with curl_formadd().
+ */
+CURL_EXTERN 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
+ */
+CURL_EXTERN char *curl_getenv(const char *variable);
+
+/*
+ * NAME curl_version()
+ *
+ * DESCRIPTION
+ *
+ * Returns a static ascii string of the libcurl version.
+ */
+CURL_EXTERN char *curl_version(void);
+
+/*
+ * NAME curl_easy_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.
+ */
+CURL_EXTERN char *curl_easy_escape(CURL *handle,
+                                   const char *string,
+                                   int length);
+
+/* the previous version: */
+CURL_EXTERN char *curl_escape(const char *string,
+                              int length);
+
+
+/*
+ * NAME curl_easy_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.
+ * Conversion Note: On non-ASCII platforms the ASCII %XX codes are
+ * converted into the host encoding.
+ */
+CURL_EXTERN char *curl_easy_unescape(CURL *handle,
+                                     const char *string,
+                                     int length,
+                                     int *outlength);
+
+/* the previous version */
+CURL_EXTERN 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
+ */
+CURL_EXTERN void curl_free(void *p);
+
+/*
+ * NAME curl_global_init()
+ *
+ * DESCRIPTION
+ *
+ * curl_global_init() should be invoked exactly once for each application that
+ * uses libcurl and before any call of other libcurl functions.
+ *
+ * This function is not thread-safe!
+ */
+CURL_EXTERN 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.
+ */
+CURL_EXTERN 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
+ */
+CURL_EXTERN 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.
+ */
+CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *,
+                                                 const char *);
+
+/*
+ * NAME curl_slist_free_all()
+ *
+ * DESCRIPTION
+ *
+ * free a previously built curl_slist.
+ */
+CURL_EXTERN 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 unused
+ * and should be set to NULL.
+ */
+CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused);
+
+/* info about the certificate chain, only for OpenSSL builds. Asked
+   for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */
+struct curl_certinfo {
+  int num_of_certs;             /* number of certificates with information */
+  struct curl_slist **certinfo; /* for each index in this array, there's a
+                                   linked list with textual information in the
+                                   format "name: value" */
+};
+
+#define CURLINFO_STRING   0x100000
+#define CURLINFO_LONG     0x200000
+#define CURLINFO_DOUBLE   0x300000
+#define CURLINFO_SLIST    0x400000
+#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,
+  CURLINFO_OS_ERRNO         = CURLINFO_LONG   + 25,
+  CURLINFO_NUM_CONNECTS     = CURLINFO_LONG   + 26,
+  CURLINFO_SSL_ENGINES      = CURLINFO_SLIST  + 27,
+  CURLINFO_COOKIELIST       = CURLINFO_SLIST  + 28,
+  CURLINFO_LASTSOCKET       = CURLINFO_LONG   + 29,
+  CURLINFO_FTP_ENTRY_PATH   = CURLINFO_STRING + 30,
+  CURLINFO_REDIRECT_URL     = CURLINFO_STRING + 31,
+  CURLINFO_PRIMARY_IP       = CURLINFO_STRING + 32,
+  CURLINFO_APPCONNECT_TIME  = CURLINFO_DOUBLE + 33,
+  CURLINFO_CERTINFO         = CURLINFO_SLIST  + 34,
+  CURLINFO_CONDITION_UNMET  = CURLINFO_LONG   + 35,
+  CURLINFO_RTSP_SESSION_ID  = CURLINFO_STRING + 36,
+  CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG   + 37,
+  CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG   + 38,
+  CURLINFO_RTSP_CSEQ_RECV   = CURLINFO_LONG   + 39,
+  /* Fill in new entries below here! */
+
+  CURLINFO_LASTONE          = 39
+} 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 internally 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 which 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;
+
+CURL_EXTERN CURLSH *curl_share_init(void);
+CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...);
+CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *);
+
+/****************************************************************************
+ * Structures for querying information about the curl library at runtime.
+ */
+
+typedef enum {
+  CURLVERSION_FIRST,
+  CURLVERSION_SECOND,
+  CURLVERSION_THIRD,
+  CURLVERSION_FOURTH,
+  CURLVERSION_LAST /* never actually use this */
+} CURLversion;
+
+/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by
+   basically 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 redefine the NOW to another enum
+   from above. */
+#define CURLVERSION_NOW CURLVERSION_FOURTH
+
+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 */
+  const char *ssl_version;  /* human readable string */
+  long ssl_version_num;     /* not used anymore, always 0 */
+  const char *libz_version; /* human readable string */
+  /* protocols is terminated by an entry with a NULL protoname */
+  const char * const *protocols;
+
+  /* The fields below this were added in CURLVERSION_SECOND */
+  const char *ares;
+  int ares_num;
+
+  /* This field was added in CURLVERSION_THIRD */
+  const char *libidn;
+
+  /* These field were added in CURLVERSION_FOURTH */
+
+  /* Same as '_libiconv_version' if built with HAVE_ICONV */
+  int iconv_ver_num;
+
+  const char *libssh_version; /* human readable string */
+
+} 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 */
+#define CURL_VERSION_SSPI      (1<<11) /* SSPI is supported */
+#define CURL_VERSION_CONV      (1<<12) /* character conversions supported */
+#define CURL_VERSION_CURLDEBUG (1<<13) /* debug memory tracking supported */
+
+/*
+ * NAME curl_version_info()
+ *
+ * DESCRIPTION
+ *
+ * This function returns a pointer to a static copy of the version info
+ * struct. See above.
+ */
+CURL_EXTERN 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.
+ */
+CURL_EXTERN 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.
+ */
+CURL_EXTERN const char *curl_share_strerror(CURLSHcode);
+
+/*
+ * NAME curl_easy_pause()
+ *
+ * DESCRIPTION
+ *
+ * The curl_easy_pause function pauses or unpauses transfers. Select the new
+ * state by setting the bitmask, use the convenience defines below.
+ *
+ */
+CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
+
+#define CURLPAUSE_RECV      (1<<0)
+#define CURLPAUSE_RECV_CONT (0)
+
+#define CURLPAUSE_SEND      (1<<2)
+#define CURLPAUSE_SEND_CONT (0)
+
+#define CURLPAUSE_ALL       (CURLPAUSE_RECV|CURLPAUSE_SEND)
+#define CURLPAUSE_CONT      (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT)
+
+#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"
+
+/* the typechecker doesn't work in C++ (yet) */
+#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \
+    ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \
+    !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK)
+#include "typecheck-gcc.h"
+#else
+#if defined(__STDC__) && (__STDC__ >= 1)
+/* This preprocessor magic that replaces a call with the exact same call is
+   only done to make sure application authors pass exactly three arguments
+   to these functions. */
+#define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param)
+#define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg)
+#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param)
+#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param)
+#endif /* __STDC__ >= 1 */
+#endif /* gcc >= 4.3 && !__cplusplus */
+
+#endif /* __CURL_CURL_H */
diff --git a/include/curl/curlbuild.h b/include/curl/curlbuild.h
new file mode 100644
index 0000000..951c10d
--- /dev/null
+++ b/include/curl/curlbuild.h
@@ -0,0 +1,191 @@
+/* include/curl/curlbuild.h.  Generated from curlbuild.h.in by configure.  */
+#ifndef __CURL_CURLBUILD_H
+#define __CURL_CURLBUILD_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/*               NOTES FOR CONFIGURE CAPABLE SYSTEMS                */
+/* ================================================================ */
+
+/*
+ * NOTE 1:
+ * -------
+ *
+ * Nothing in this file is intended to be modified or adjusted by the
+ * curl library user nor by the curl library builder.
+ *
+ * If you think that something actually needs to be changed, adjusted
+ * or fixed in this file, then, report it on the libcurl development
+ * mailing list: http://cool.haxx.se/mailman/listinfo/curl-library/
+ *
+ * This header file shall only export symbols which are 'curl' or 'CURL'
+ * prefixed, otherwise public name space would be polluted.
+ *
+ * NOTE 2:
+ * -------
+ *
+ * Right now you might be staring at file include/curl/curlbuild.h.in or
+ * at file include/curl/curlbuild.h, this is due to the following reason:
+ *
+ * On systems capable of running the configure script, the configure process
+ * will overwrite the distributed include/curl/curlbuild.h file with one that
+ * is suitable and specific to the library being configured and built, which
+ * is generated from the include/curl/curlbuild.h.in template file.
+ *
+ */
+
+/* ================================================================ */
+/*  DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE  */
+/* ================================================================ */
+
+#ifdef CURL_SIZEOF_LONG
+#  error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined
+#endif
+
+#ifdef CURL_TYPEOF_CURL_SOCKLEN_T
+#  error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined
+#endif
+
+#ifdef CURL_SIZEOF_CURL_SOCKLEN_T
+#  error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined
+#endif
+
+#ifdef CURL_TYPEOF_CURL_OFF_T
+#  error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_FORMAT_CURL_OFF_T
+#  error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_FORMAT_CURL_OFF_TU
+#  error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined
+#endif
+
+#ifdef CURL_FORMAT_OFF_T
+#  error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined
+#endif
+
+#ifdef CURL_SIZEOF_CURL_OFF_T
+#  error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_SUFFIX_CURL_OFF_T
+#  error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_SUFFIX_CURL_OFF_TU
+#  error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined
+#endif
+
+/* ================================================================ */
+/*  EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY  */
+/* ================================================================ */
+
+/* Configure process defines this to 1 when it finds out that system  */
+/* header file ws2tcpip.h must be included by the external interface. */
+/* #undef CURL_PULL_WS2TCPIP_H */
+#ifdef CURL_PULL_WS2TCPIP_H
+#  ifndef WIN32_LEAN_AND_MEAN
+#    define WIN32_LEAN_AND_MEAN
+#  endif
+#  include <windows.h>
+#  include <winsock2.h>
+#  include <ws2tcpip.h>
+#endif
+
+/* Configure process defines this to 1 when it finds out that system   */
+/* header file sys/types.h must be included by the external interface. */
+#define CURL_PULL_SYS_TYPES_H 1
+#ifdef CURL_PULL_SYS_TYPES_H
+#  include <sys/types.h>
+#endif
+
+/* Configure process defines this to 1 when it finds out that system */
+/* header file stdint.h must be included by the external interface.  */
+/* #undef CURL_PULL_STDINT_H */
+#ifdef CURL_PULL_STDINT_H
+#  include <stdint.h>
+#endif
+
+/* Configure process defines this to 1 when it finds out that system  */
+/* header file inttypes.h must be included by the external interface. */
+/* #undef CURL_PULL_INTTYPES_H */
+#ifdef CURL_PULL_INTTYPES_H
+#  include <inttypes.h>
+#endif
+
+/* Configure process defines this to 1 when it finds out that system    */
+/* header file sys/socket.h must be included by the external interface. */
+#define CURL_PULL_SYS_SOCKET_H 1
+#ifdef CURL_PULL_SYS_SOCKET_H
+#  include <sys/socket.h>
+#endif
+
+/* The size of `long', as computed by sizeof. */
+#define CURL_SIZEOF_LONG 4
+
+/* Integral data type used for curl_socklen_t. */
+#define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+
+/* The size of `curl_socklen_t', as computed by sizeof. */
+#define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+/* Data type definition of curl_socklen_t. */
+typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t;
+
+/* Signed integral data type used for curl_off_t. */
+#define CURL_TYPEOF_CURL_OFF_T long
+
+/* Data type definition of curl_off_t. */
+typedef CURL_TYPEOF_CURL_OFF_T curl_off_t;
+
+/* curl_off_t formatting string directive without "%" conversion specifier. */
+#define CURL_FORMAT_CURL_OFF_T "ld"
+
+/* unsigned curl_off_t formatting string without "%" conversion specifier. */
+#define CURL_FORMAT_CURL_OFF_TU "lu"
+
+/* curl_off_t formatting string directive with "%" conversion specifier. */
+#define CURL_FORMAT_OFF_T "%ld"
+
+/* The size of `curl_off_t', as computed by sizeof. */
+#define CURL_SIZEOF_CURL_OFF_T 4
+
+/* curl_off_t constant suffix. */
+#define CURL_SUFFIX_CURL_OFF_T L
+
+/* unsigned curl_off_t constant suffix. */
+#define CURL_SUFFIX_CURL_OFF_TU UL
+
+#endif /* __CURL_CURLBUILD_H */
diff --git a/include/curl/curlbuild.h.cmake b/include/curl/curlbuild.h.cmake
new file mode 100644
index 0000000..3aa772f
--- /dev/null
+++ b/include/curl/curlbuild.h.cmake
@@ -0,0 +1,180 @@
+#ifndef __CURL_CURLBUILD_H
+#define __CURL_CURLBUILD_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2008, 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.
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/*               NOTES FOR CONFIGURE CAPABLE SYSTEMS                */
+/* ================================================================ */
+
+/*
+ * NOTE 1:
+ * -------
+ *
+ * Nothing in this file is intended to be modified or adjusted by the
+ * curl library user nor by the curl library builder.
+ *
+ * If you think that something actually needs to be changed, adjusted
+ * or fixed in this file, then, report it on the libcurl development
+ * mailing list: http://cool.haxx.se/mailman/listinfo/curl-library/
+ *
+ * This header file shall only export symbols which are 'curl' or 'CURL'
+ * prefixed, otherwise public name space would be polluted.
+ *
+ * NOTE 2:
+ * -------
+ *
+ * Right now you might be staring at file include/curl/curlbuild.h.in or
+ * at file include/curl/curlbuild.h, this is due to the following reason:
+ *
+ * On systems capable of running the configure script, the configure process
+ * will overwrite the distributed include/curl/curlbuild.h file with one that
+ * is suitable and specific to the library being configured and built, which
+ * is generated from the include/curl/curlbuild.h.in template file.
+ *
+ */
+
+/* ================================================================ */
+/*  DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE  */
+/* ================================================================ */
+
+#ifdef CURL_SIZEOF_LONG
+#  error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined
+#endif
+
+#ifdef CURL_TYPEOF_CURL_SOCKLEN_T
+#  error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined
+#endif
+
+#ifdef CURL_SIZEOF_CURL_SOCKLEN_T
+#  error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined
+#endif
+#ifdef CURL_TYPEOF_CURL_OFF_T
+#  error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_FORMAT_CURL_OFF_T
+#  error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_FORMAT_CURL_OFF_TU
+#  error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined
+#endif
+
+#ifdef CURL_FORMAT_OFF_T
+#  error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined
+#endif
+
+#ifdef CURL_SIZEOF_CURL_OFF_T
+#  error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_SUFFIX_CURL_OFF_T
+#  error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_SUFFIX_CURL_OFF_TU
+#  error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined
+#endif
+
+/* ================================================================ */
+/*  EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY  */
+/* ================================================================ */
+
+/* Configure process defines this to 1 when it finds out that system   */
+/* header file sys/types.h must be included by the external interface. */
+#cmakedefine CURL_PULL_SYS_TYPES_H ${CURL_PULL_SYS_TYPES_H}
+#ifdef CURL_PULL_SYS_TYPES_H
+#  include <sys/types.h>
+#endif
+
+/* Configure process defines this to 1 when it finds out that system */
+/* header file stdint.h must be included by the external interface.  */
+#cmakedefine CURL_PULL_STDINT_H ${CURL_PULL_STDINT_H}
+#ifdef CURL_PULL_STDINT_H
+#  include <stdint.h>
+#endif
+
+/* Configure process defines this to 1 when it finds out that system  */
+/* header file inttypes.h must be included by the external interface. */
+#cmakedefine CURL_PULL_INTTYPES_H ${CURL_PULL_INTTYPES_H}
+#ifdef CURL_PULL_INTTYPES_H
+#  include <inttypes.h>
+#endif
+
+/* The size of `long', as computed by sizeof. */
+#cmakedefine CURL_SIZEOF_LONG ${CURL_SIZEOF_LONG}
+
+/* Integral data type used for curl_socklen_t. */
+#cmakedefine CURL_TYPEOF_CURL_SOCKLEN_T ${CURL_TYPEOF_CURL_SOCKLEN_T}
+
+/* on windows socklen_t is in here */
+#ifdef _WIN32
+#  include <winsock2.h>
+#  include <ws2tcpip.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#  include <sys/socket.h>
+#endif
+
+/* Data type definition of curl_socklen_t. */
+typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t;
+
+/* The size of `curl_socklen_t', as computed by sizeof. */
+#cmakedefine CURL_SIZEOF_CURL_SOCKLEN_T ${CURL_SIZEOF_CURL_SOCKLEN_T}
+
+/* Signed integral data type used for curl_off_t. */
+#cmakedefine CURL_TYPEOF_CURL_OFF_T ${CURL_TYPEOF_CURL_OFF_T}
+
+/* Data type definition of curl_off_t. */
+typedef CURL_TYPEOF_CURL_OFF_T curl_off_t;
+
+/* curl_off_t formatting string directive without "%" conversion specifier. */
+#cmakedefine CURL_FORMAT_CURL_OFF_T "${CURL_FORMAT_CURL_OFF_T}"
+
+/* unsigned curl_off_t formatting string without "%" conversion specifier. */
+#cmakedefine CURL_FORMAT_CURL_OFF_TU "${CURL_FORMAT_CURL_OFF_TU}"
+
+/* curl_off_t formatting string directive with "%" conversion specifier. */
+#cmakedefine CURL_FORMAT_OFF_T "${CURL_FORMAT_OFF_T}"
+
+/* The size of `curl_off_t', as computed by sizeof. */
+#cmakedefine CURL_SIZEOF_CURL_OFF_T ${CURL_SIZEOF_CURL_OFF_T}
+
+/* curl_off_t constant suffix. */
+#cmakedefine CURL_SUFFIX_CURL_OFF_T ${CURL_SUFFIX_CURL_OFF_T}
+
+/* unsigned curl_off_t constant suffix. */
+#cmakedefine CURL_SUFFIX_CURL_OFF_TU ${CURL_SUFFIX_CURL_OFF_TU}
+
+#endif /* __CURL_CURLBUILD_H */
diff --git a/include/curl/curlbuild.h.in b/include/curl/curlbuild.h.in
new file mode 100644
index 0000000..cb1de80
--- /dev/null
+++ b/include/curl/curlbuild.h.in
@@ -0,0 +1,190 @@
+#ifndef __CURL_CURLBUILD_H
+#define __CURL_CURLBUILD_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/*               NOTES FOR CONFIGURE CAPABLE SYSTEMS                */
+/* ================================================================ */
+
+/*
+ * NOTE 1:
+ * -------
+ *
+ * Nothing in this file is intended to be modified or adjusted by the
+ * curl library user nor by the curl library builder.
+ *
+ * If you think that something actually needs to be changed, adjusted
+ * or fixed in this file, then, report it on the libcurl development
+ * mailing list: http://cool.haxx.se/mailman/listinfo/curl-library/
+ *
+ * This header file shall only export symbols which are 'curl' or 'CURL'
+ * prefixed, otherwise public name space would be polluted.
+ *
+ * NOTE 2:
+ * -------
+ *
+ * Right now you might be staring at file include/curl/curlbuild.h.in or
+ * at file include/curl/curlbuild.h, this is due to the following reason:
+ *
+ * On systems capable of running the configure script, the configure process
+ * will overwrite the distributed include/curl/curlbuild.h file with one that
+ * is suitable and specific to the library being configured and built, which
+ * is generated from the include/curl/curlbuild.h.in template file.
+ *
+ */
+
+/* ================================================================ */
+/*  DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE  */
+/* ================================================================ */
+
+#ifdef CURL_SIZEOF_LONG
+#  error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined
+#endif
+
+#ifdef CURL_TYPEOF_CURL_SOCKLEN_T
+#  error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined
+#endif
+
+#ifdef CURL_SIZEOF_CURL_SOCKLEN_T
+#  error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined
+#endif
+
+#ifdef CURL_TYPEOF_CURL_OFF_T
+#  error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_FORMAT_CURL_OFF_T
+#  error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_FORMAT_CURL_OFF_TU
+#  error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined
+#endif
+
+#ifdef CURL_FORMAT_OFF_T
+#  error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined
+#endif
+
+#ifdef CURL_SIZEOF_CURL_OFF_T
+#  error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_SUFFIX_CURL_OFF_T
+#  error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_SUFFIX_CURL_OFF_TU
+#  error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h"
+   Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined
+#endif
+
+/* ================================================================ */
+/*  EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY  */
+/* ================================================================ */
+
+/* Configure process defines this to 1 when it finds out that system  */
+/* header file ws2tcpip.h must be included by the external interface. */
+#undef CURL_PULL_WS2TCPIP_H
+#ifdef CURL_PULL_WS2TCPIP_H
+#  ifndef WIN32_LEAN_AND_MEAN
+#    define WIN32_LEAN_AND_MEAN
+#  endif
+#  include <windows.h>
+#  include <winsock2.h>
+#  include <ws2tcpip.h>
+#endif
+
+/* Configure process defines this to 1 when it finds out that system   */
+/* header file sys/types.h must be included by the external interface. */
+#undef CURL_PULL_SYS_TYPES_H
+#ifdef CURL_PULL_SYS_TYPES_H
+#  include <sys/types.h>
+#endif
+
+/* Configure process defines this to 1 when it finds out that system */
+/* header file stdint.h must be included by the external interface.  */
+#undef CURL_PULL_STDINT_H
+#ifdef CURL_PULL_STDINT_H
+#  include <stdint.h>
+#endif
+
+/* Configure process defines this to 1 when it finds out that system  */
+/* header file inttypes.h must be included by the external interface. */
+#undef CURL_PULL_INTTYPES_H
+#ifdef CURL_PULL_INTTYPES_H
+#  include <inttypes.h>
+#endif
+
+/* Configure process defines this to 1 when it finds out that system    */
+/* header file sys/socket.h must be included by the external interface. */
+#undef CURL_PULL_SYS_SOCKET_H
+#ifdef CURL_PULL_SYS_SOCKET_H
+#  include <sys/socket.h>
+#endif
+
+/* The size of `long', as computed by sizeof. */
+#undef CURL_SIZEOF_LONG
+
+/* Integral data type used for curl_socklen_t. */
+#undef CURL_TYPEOF_CURL_SOCKLEN_T
+
+/* The size of `curl_socklen_t', as computed by sizeof. */
+#undef CURL_SIZEOF_CURL_SOCKLEN_T
+
+/* Data type definition of curl_socklen_t. */
+typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t;
+
+/* Signed integral data type used for curl_off_t. */
+#undef CURL_TYPEOF_CURL_OFF_T
+
+/* Data type definition of curl_off_t. */
+typedef CURL_TYPEOF_CURL_OFF_T curl_off_t;
+
+/* curl_off_t formatting string directive without "%" conversion specifier. */
+#undef CURL_FORMAT_CURL_OFF_T
+
+/* unsigned curl_off_t formatting string without "%" conversion specifier. */
+#undef CURL_FORMAT_CURL_OFF_TU
+
+/* curl_off_t formatting string directive with "%" conversion specifier. */
+#undef CURL_FORMAT_OFF_T
+
+/* The size of `curl_off_t', as computed by sizeof. */
+#undef CURL_SIZEOF_CURL_OFF_T
+
+/* curl_off_t constant suffix. */
+#undef CURL_SUFFIX_CURL_OFF_T
+
+/* unsigned curl_off_t constant suffix. */
+#undef CURL_SUFFIX_CURL_OFF_TU
+
+#endif /* __CURL_CURLBUILD_H */
diff --git a/include/curl/curlrules.h b/include/curl/curlrules.h
new file mode 100644
index 0000000..8aad1df
--- /dev/null
+++ b/include/curl/curlrules.h
@@ -0,0 +1,252 @@
+#ifndef __CURL_CURLRULES_H
+#define __CURL_CURLRULES_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/*                    COMPILE TIME SANITY CHECKS                    */
+/* ================================================================ */
+
+/*
+ * NOTE 1:
+ * -------
+ *
+ * All checks done in this file are intentionally placed in a public
+ * header file which is pulled by curl/curl.h when an application is
+ * being built using an already built libcurl library. Additionally
+ * this file is also included and used when building the library.
+ *
+ * If compilation fails on this file it is certainly sure that the
+ * problem is elsewhere. It could be a problem in the curlbuild.h
+ * header file, or simply that you are using different compilation
+ * settings than those used to build the library.
+ *
+ * Nothing in this file is intended to be modified or adjusted by the
+ * curl library user nor by the curl library builder.
+ *
+ * Do not deactivate any check, these are done to make sure that the
+ * library is properly built and used.
+ *
+ * You can find further help on the libcurl development mailing list:
+ * http://cool.haxx.se/mailman/listinfo/curl-library/
+ *
+ * NOTE 2
+ * ------
+ *
+ * Some of the following compile time checks are based on the fact
+ * that the dimension of a constant array can not be a negative one.
+ * In this way if the compile time verification fails, the compilation
+ * will fail issuing an error. The error description wording is compiler
+ * dependent but it will be quite similar to one of the following:
+ *
+ *   "negative subscript or subscript is too large"
+ *   "array must have at least one element"
+ *   "-1 is an illegal array size"
+ *   "size of array is negative"
+ *
+ * If you are building an application which tries to use an already
+ * built libcurl library and you are getting this kind of errors on
+ * this file, it is a clear indication that there is a mismatch between
+ * how the library was built and how you are trying to use it for your
+ * application. Your already compiled or binary library provider is the
+ * only one who can give you the details you need to properly use it.
+ */
+
+/*
+ * Verify that some macros are actually defined.
+ */
+
+#ifndef CURL_SIZEOF_LONG
+#  error "CURL_SIZEOF_LONG definition is missing!"
+   Error Compilation_aborted_CURL_SIZEOF_LONG_is_missing
+#endif
+
+#ifndef CURL_TYPEOF_CURL_SOCKLEN_T
+#  error "CURL_TYPEOF_CURL_SOCKLEN_T definition is missing!"
+   Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_is_missing
+#endif
+
+#ifndef CURL_SIZEOF_CURL_SOCKLEN_T
+#  error "CURL_SIZEOF_CURL_SOCKLEN_T definition is missing!"
+   Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_is_missing
+#endif
+
+#ifndef CURL_TYPEOF_CURL_OFF_T
+#  error "CURL_TYPEOF_CURL_OFF_T definition is missing!"
+   Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_is_missing
+#endif
+
+#ifndef CURL_FORMAT_CURL_OFF_T
+#  error "CURL_FORMAT_CURL_OFF_T definition is missing!"
+   Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_is_missing
+#endif
+
+#ifndef CURL_FORMAT_CURL_OFF_TU
+#  error "CURL_FORMAT_CURL_OFF_TU definition is missing!"
+   Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_is_missing
+#endif
+
+#ifndef CURL_FORMAT_OFF_T
+#  error "CURL_FORMAT_OFF_T definition is missing!"
+   Error Compilation_aborted_CURL_FORMAT_OFF_T_is_missing
+#endif
+
+#ifndef CURL_SIZEOF_CURL_OFF_T
+#  error "CURL_SIZEOF_CURL_OFF_T definition is missing!"
+   Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_is_missing
+#endif
+
+#ifndef CURL_SUFFIX_CURL_OFF_T
+#  error "CURL_SUFFIX_CURL_OFF_T definition is missing!"
+   Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_is_missing
+#endif
+
+#ifndef CURL_SUFFIX_CURL_OFF_TU
+#  error "CURL_SUFFIX_CURL_OFF_TU definition is missing!"
+   Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_is_missing
+#endif
+
+/*
+ * Macros private to this header file.
+ */
+
+#define CurlchkszEQ(t, s) sizeof(t) == s ? 1 : -1
+
+#define CurlchkszGE(t1, t2) sizeof(t1) >= sizeof(t2) ? 1 : -1
+
+/*
+ * Verify that the size previously defined and expected for long
+ * is the same as the one reported by sizeof() at compile time.
+ */
+
+typedef char
+  __curl_rule_01__
+    [CurlchkszEQ(long, CURL_SIZEOF_LONG)];
+
+/*
+ * Verify that the size previously defined and expected for
+ * curl_off_t is actually the the same as the one reported
+ * by sizeof() at compile time.
+ */
+
+typedef char
+  __curl_rule_02__
+    [CurlchkszEQ(curl_off_t, CURL_SIZEOF_CURL_OFF_T)];
+
+/*
+ * Verify at compile time that the size of curl_off_t as reported
+ * by sizeof() is greater or equal than the one reported for long
+ * for the current compilation.
+ */
+
+typedef char
+  __curl_rule_03__
+    [CurlchkszGE(curl_off_t, long)];
+
+/*
+ * Verify that the size previously defined and expected for
+ * curl_socklen_t is actually the the same as the one reported
+ * by sizeof() at compile time.
+ */
+
+typedef char
+  __curl_rule_04__
+    [CurlchkszEQ(curl_socklen_t, CURL_SIZEOF_CURL_SOCKLEN_T)];
+
+/*
+ * Verify at compile time that the size of curl_socklen_t as reported
+ * by sizeof() is greater or equal than the one reported for int for
+ * the current compilation.
+ */
+
+typedef char
+  __curl_rule_05__
+    [CurlchkszGE(curl_socklen_t, int)];
+
+/* ================================================================ */
+/*          EXTERNALLY AND INTERNALLY VISIBLE DEFINITIONS           */
+/* ================================================================ */
+
+/*
+ * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow
+ * these to be visible and exported by the external libcurl interface API,
+ * while also making them visible to the library internals, simply including
+ * setup.h, without actually needing to include curl.h internally.
+ * If some day this section would grow big enough, all this should be moved
+ * to its own header file.
+ */
+
+/*
+ * Figure out if we can use the ## preprocessor 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.
+ */
+
+#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \
+  defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \
+  defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \
+  defined(__ILEC400__)
+  /* 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
+
+/*
+ * Macros for minimum-width signed and unsigned curl_off_t integer constants.
+ */
+
+#ifdef CURL_ISOCPP
+#  define __CURL_OFF_T_C_HELPER2(Val,Suffix) Val ## Suffix
+#else
+#  define __CURL_OFF_T_C_HELPER2(Val,Suffix) Val/**/Suffix
+#endif
+#define __CURL_OFF_T_C_HELPER1(Val,Suffix) __CURL_OFF_T_C_HELPER2(Val,Suffix)
+#define CURL_OFF_T_C(Val)  __CURL_OFF_T_C_HELPER1(Val,CURL_SUFFIX_CURL_OFF_T)
+#define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HELPER1(Val,CURL_SUFFIX_CURL_OFF_TU)
+
+/*
+ * Get rid of macros private to this header file.
+ */
+
+#undef CurlchkszEQ
+#undef CurlchkszGE
+
+/*
+ * Get rid of macros not intended to exist beyond this point.
+ */
+
+#undef CURL_PULL_WS2TCPIP_H
+#undef CURL_PULL_SYS_TYPES_H
+#undef CURL_PULL_SYS_SOCKET_H
+#undef CURL_PULL_STDINT_H
+#undef CURL_PULL_INTTYPES_H
+
+#undef CURL_TYPEOF_CURL_SOCKLEN_T
+#undef CURL_TYPEOF_CURL_OFF_T
+
+#ifdef CURL_NO_OLDIES
+#undef CURL_FORMAT_OFF_T /* not required since 7.19.0 - obsoleted in 7.20.0 */
+#endif
+
+#endif /* __CURL_CURLRULES_H */
diff --git a/include/curl/curlver.h b/include/curl/curlver.h
new file mode 100644
index 0000000..35ca9a8
--- /dev/null
+++ b/include/curl/curlver.h
@@ -0,0 +1,69 @@
+#ifndef __CURL_CURLVER_H
+#define __CURL_CURLVER_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+/* 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 global package copyright */
+#define LIBCURL_COPYRIGHT "1996 - 2010 Daniel Stenberg, <daniel@haxx.se>."
+
+/* This is the version number of the libcurl package from which this header
+   file origins: */
+#define LIBCURL_VERSION "7.20.1"
+
+/* The numeric version number is also available "in parts" by using these
+   defines: */
+#define LIBCURL_VERSION_MAJOR 7
+#define LIBCURL_VERSION_MINOR 20
+#define LIBCURL_VERSION_PATCH 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 (using 8 bits each). 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 (24 bits) 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 0x071401
+
+/*
+ * This is the date and time when the full source package was created. The
+ * timestamp is not stored in git, as the timestamp is properly set in the
+ * tarballs by the maketgz script.
+ *
+ * The format of the date should follow this template:
+ *
+ * "Mon Feb 12 11:35:33 UTC 2007"
+ */
+#define LIBCURL_TIMESTAMP "Wed Apr 14 14:55:20 UTC 2010"
+
+#endif /* __CURL_CURLVER_H */
diff --git a/include/curl/easy.h b/include/curl/easy.h
new file mode 100644
index 0000000..1ddb4fe
--- /dev/null
+++ b/include/curl/easy.h
@@ -0,0 +1,102 @@
+#ifndef __CURL_EASY_H
+#define __CURL_EASY_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2008, 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.
+ *
+ ***************************************************************************/
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+CURL_EXTERN CURL *curl_easy_init(void);
+CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...);
+CURL_EXTERN CURLcode curl_easy_perform(CURL *curl);
+CURL_EXTERN 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.
+ */
+CURL_EXTERN 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_EXTERN 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.
+ */
+CURL_EXTERN void curl_easy_reset(CURL *curl);
+
+/*
+ * NAME curl_easy_recv()
+ *
+ * DESCRIPTION
+ *
+ * Receives data from the connected socket. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ */
+CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen,
+                                    size_t *n);
+
+/*
+ * NAME curl_easy_send()
+ *
+ * DESCRIPTION
+ *
+ * Sends data over the connected socket. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ */
+CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer,
+                                    size_t buflen, size_t *n);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/curl/mprintf.h b/include/curl/mprintf.h
new file mode 100644
index 0000000..de7dd2f
--- /dev/null
+++ b/include/curl/mprintf.h
@@ -0,0 +1,81 @@
+#ifndef __CURL_MPRINTF_H
+#define __CURL_MPRINTF_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * 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 <stdarg.h>
+#include <stdio.h> /* needed for FILE */
+
+#include "curl.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+CURL_EXTERN int curl_mprintf(const char *format, ...);
+CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...);
+CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...);
+CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength,
+                               const char *format, ...);
+CURL_EXTERN int curl_mvprintf(const char *format, va_list args);
+CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args);
+CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args);
+CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength,
+                                const char *format, va_list args);
+CURL_EXTERN char *curl_maprintf(const char *format, ...);
+CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args);
+
+#ifdef _MPRINTF_REPLACE
+# undef printf
+# undef fprintf
+# undef sprintf
+# undef vsprintf
+# undef snprintf
+# undef vprintf
+# undef vfprintf
+# undef vsnprintf
+# undef aprintf
+# undef vaprintf
+# define printf curl_mprintf
+# define fprintf curl_mfprintf
+#ifdef CURLDEBUG
+/* When built with CURLDEBUG we define away the sprintf() functions since we
+   don't want internal code to be using them */
+# define sprintf sprintf_was_used
+# define vsprintf vsprintf_was_used
+#else
+# define sprintf curl_msprintf
+# define vsprintf curl_mvsprintf
+#endif
+# define snprintf curl_msnprintf
+# define vprintf curl_mvprintf
+# define vfprintf curl_mvfprintf
+# define vsnprintf curl_mvsnprintf
+# define aprintf curl_maprintf
+# define vaprintf curl_mvaprintf
+#endif
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* __CURL_MPRINTF_H */
diff --git a/include/curl/multi.h b/include/curl/multi.h
new file mode 100644
index 0000000..f965666
--- /dev/null
+++ b/include/curl/multi.h
@@ -0,0 +1,345 @@
+#ifndef __CURL_MULTI_H
+#define __CURL_MULTI_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, 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.
+ *
+ ***************************************************************************/
+/*
+  This is an "external" header file. Don't give away any internals here!
+
+  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.
+
+*/
+
+/*
+ * This header file should not really need to include "curl.h" since curl.h
+ * itself includes this file and we expect user applications to do #include
+ * <curl/curl.h> without the need for especially including multi.h.
+ *
+ * For some reason we added this include here at one point, and rather than to
+ * break existing (wrongly written) libcurl applications, we leave it as-is
+ * but with this warning attached.
+ */
+#include "curl.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+typedef void CURLM;
+
+typedef enum {
+  CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or
+                                    curl_multi_socket*() 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_BAD_SOCKET,      /* the passed in socket argument did not match */
+  CURLM_UNKNOWN_OPTION,  /* curl_multi_setopt() with unsupported option */
+  CURLM_LAST
+} CURLMcode;
+
+/* just to make code nicer when using curl_multi_socket() you can now check
+   for CURLM_CALL_MULTI_SOCKET too in the same style it works for
+   curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */
+#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM
+
+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.
+ */
+CURL_EXTERN 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.
+ */
+CURL_EXTERN 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.
+  */
+CURL_EXTERN 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.
+  */
+CURL_EXTERN 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.
+  */
+CURL_EXTERN 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.
+  */
+CURL_EXTERN 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.
+ */
+CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle,
+                                          int *msgs_in_queue);
+
+/*
+ * Name:    curl_multi_strerror()
+ *
+ * Desc:    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.
+ *
+ * Returns: A pointer to a zero-terminated error message.
+ */
+CURL_EXTERN const char *curl_multi_strerror(CURLMcode);
+
+/*
+ * Name:    curl_multi_socket() and
+ *          curl_multi_socket_all()
+ *
+ * Desc:    An alternative version of curl_multi_perform() that allows the
+ *          application to pass in one of the file descriptors that have been
+ *          detected to have "action" on them and let libcurl perform.
+ *          See man page for details.
+ */
+#define CURL_POLL_NONE   0
+#define CURL_POLL_IN     1
+#define CURL_POLL_OUT    2
+#define CURL_POLL_INOUT  3
+#define CURL_POLL_REMOVE 4
+
+#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD
+
+#define CURL_CSELECT_IN   0x01
+#define CURL_CSELECT_OUT  0x02
+#define CURL_CSELECT_ERR  0x04
+
+typedef int (*curl_socket_callback)(CURL *easy,      /* easy handle */
+                                    curl_socket_t s, /* socket */
+                                    int what,        /* see above */
+                                    void *userp,     /* private callback
+                                                        pointer */
+                                    void *socketp);  /* private socket
+                                                        pointer */
+/*
+ * Name:    curl_multi_timer_callback
+ *
+ * Desc:    Called by libcurl whenever the library detects a change in the
+ *          maximum number of milliseconds the app is allowed to wait before
+ *          curl_multi_socket() or curl_multi_perform() must be called
+ *          (to allow libcurl's timed events to take place).
+ *
+ * Returns: The callback should return zero.
+ */
+typedef int (*curl_multi_timer_callback)(CURLM *multi,    /* multi handle */
+                                         long timeout_ms, /* see above */
+                                         void *userp);    /* private callback
+                                                             pointer */
+
+CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
+                                        int *running_handles);
+
+CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle,
+                                               curl_socket_t s,
+                                               int ev_bitmask,
+                                               int *running_handles);
+
+CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle,
+                                            int *running_handles);
+
+#ifndef CURL_ALLOW_OLD_MULTI_SOCKET
+/* This macro below was added in 7.16.3 to push users who recompile to use
+   the new curl_multi_socket_action() instead of the old curl_multi_socket()
+*/
+#define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z)
+#endif
+
+/*
+ * Name:    curl_multi_timeout()
+ *
+ * Desc:    Returns the maximum number of milliseconds the app is allowed to
+ *          wait before curl_multi_socket() or curl_multi_perform() must be
+ *          called (to allow libcurl's timed events to take place).
+ *
+ * Returns: CURLM error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle,
+                                         long *milliseconds);
+
+#undef CINIT /* re-using the same name as in curl.h */
+
+#ifdef CURL_ISOCPP
+#define CINIT(name,type,num) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + num
+#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) CURLMOPT_/**/name = type + number
+#endif
+
+typedef enum {
+  /* This is the socket callback function pointer */
+  CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1),
+
+  /* This is the argument passed to the socket callback */
+  CINIT(SOCKETDATA, OBJECTPOINT, 2),
+
+    /* set to 1 to enable pipelining for this multi handle */
+  CINIT(PIPELINING, LONG, 3),
+
+   /* This is the timer callback function pointer */
+  CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4),
+
+  /* This is the argument passed to the timer callback */
+  CINIT(TIMERDATA, OBJECTPOINT, 5),
+
+  /* maximum number of entries in the connection cache */
+  CINIT(MAXCONNECTS, LONG, 6),
+
+  CURLMOPT_LASTENTRY /* the last unused */
+} CURLMoption;
+
+
+/*
+ * Name:    curl_multi_setopt()
+ *
+ * Desc:    Sets options for the multi handle.
+ *
+ * Returns: CURLM error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle,
+                                        CURLMoption option, ...);
+
+
+/*
+ * Name:    curl_multi_assign()
+ *
+ * Desc:    This function sets an association in the multi handle between the
+ *          given socket and a private pointer of the application. This is
+ *          (only) useful for curl_multi_socket uses.
+ *
+ * Returns: CURLM error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle,
+                                        curl_socket_t sockfd, void *sockp);
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
+#endif
diff --git a/include/curl/stamp-h3 b/include/curl/stamp-h3
new file mode 100644
index 0000000..e4ea1b8
--- /dev/null
+++ b/include/curl/stamp-h3
@@ -0,0 +1 @@
+timestamp for include/curl/curlbuild.h
diff --git a/include/curl/stdcheaders.h b/include/curl/stdcheaders.h
new file mode 100644
index 0000000..ad82ef6
--- /dev/null
+++ b/include/curl/stdcheaders.h
@@ -0,0 +1,33 @@
+#ifndef __STDC_HEADERS_H
+#define __STDC_HEADERS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 <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 /* __STDC_HEADERS_H */
diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h
new file mode 100644
index 0000000..c4fad51
--- /dev/null
+++ b/include/curl/typecheck-gcc.h
@@ -0,0 +1,550 @@
+#ifndef __CURL_TYPECHECK_GCC_H
+#define __CURL_TYPECHECK_GCC_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+/* wraps curl_easy_setopt() with typechecking */
+
+/* To add a new kind of warning, add an
+ *   if(_curl_is_sometype_option(_curl_opt) && ! _curl_is_sometype(value))
+ *     _curl_easy_setopt_err_sometype();
+ * block and define _curl_is_sometype_option, _curl_is_sometype and
+ * _curl_easy_setopt_err_sometype below
+ *
+ * To add an option that uses the same type as an existing option, you'll just
+ * need to extend the appropriate _curl_*_option macro
+ */
+#define curl_easy_setopt(handle, option, value)                               \
+__extension__ ({                                                              \
+  __typeof__ (option) _curl_opt = option;                                     \
+  if (__builtin_constant_p(_curl_opt)) {                                      \
+    if (_curl_is_long_option(_curl_opt) && !_curl_is_long(value))             \
+      _curl_easy_setopt_err_long();                                           \
+    if (_curl_is_off_t_option(_curl_opt) && !_curl_is_off_t(value))           \
+      _curl_easy_setopt_err_curl_off_t();                                     \
+    if (_curl_is_string_option(_curl_opt) && !_curl_is_string(value))         \
+      _curl_easy_setopt_err_string();                                         \
+    if (_curl_is_write_cb_option(_curl_opt) && !_curl_is_write_cb(value))     \
+      _curl_easy_setopt_err_write_callback();                                 \
+    if ((_curl_opt) == CURLOPT_READFUNCTION && !_curl_is_read_cb(value))      \
+      _curl_easy_setopt_err_read_cb();                                        \
+    if ((_curl_opt) == CURLOPT_IOCTLFUNCTION && !_curl_is_ioctl_cb(value))    \
+      _curl_easy_setopt_err_ioctl_cb();                                       \
+    if ((_curl_opt) == CURLOPT_SOCKOPTFUNCTION && !_curl_is_sockopt_cb(value))\
+      _curl_easy_setopt_err_sockopt_cb();                                     \
+    if ((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION &&                          \
+            !_curl_is_opensocket_cb(value))                                   \
+      _curl_easy_setopt_err_opensocket_cb();                                  \
+    if ((_curl_opt) == CURLOPT_PROGRESSFUNCTION &&                            \
+            !_curl_is_progress_cb(value))                                     \
+      _curl_easy_setopt_err_progress_cb();                                    \
+    if ((_curl_opt) == CURLOPT_DEBUGFUNCTION && !_curl_is_debug_cb(value))    \
+      _curl_easy_setopt_err_debug_cb();                                       \
+    if ((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION &&                            \
+            !_curl_is_ssl_ctx_cb(value))                                      \
+      _curl_easy_setopt_err_ssl_ctx_cb();                                     \
+    if (_curl_is_conv_cb_option(_curl_opt) && !_curl_is_conv_cb(value))       \
+      _curl_easy_setopt_err_conv_cb();                                        \
+    if ((_curl_opt) == CURLOPT_SEEKFUNCTION && !_curl_is_seek_cb(value))      \
+      _curl_easy_setopt_err_seek_cb();                                        \
+    if (_curl_is_cb_data_option(_curl_opt) && !_curl_is_cb_data(value))       \
+      _curl_easy_setopt_err_cb_data();                                        \
+    if ((_curl_opt) == CURLOPT_ERRORBUFFER && !_curl_is_error_buffer(value))  \
+      _curl_easy_setopt_err_error_buffer();                                   \
+    if ((_curl_opt) == CURLOPT_STDERR && !_curl_is_FILE(value))               \
+      _curl_easy_setopt_err_FILE();                                           \
+    if (_curl_is_postfields_option(_curl_opt) && !_curl_is_postfields(value)) \
+      _curl_easy_setopt_err_postfields();                                     \
+    if ((_curl_opt) == CURLOPT_HTTPPOST &&                                    \
+            !_curl_is_arr((value), struct curl_httppost))                     \
+      _curl_easy_setopt_err_curl_httpost();                                   \
+    if (_curl_is_slist_option(_curl_opt) &&                                   \
+            !_curl_is_arr((value), struct curl_slist))                        \
+      _curl_easy_setopt_err_curl_slist();                                     \
+    if ((_curl_opt) == CURLOPT_SHARE && !_curl_is_ptr((value), CURLSH))       \
+      _curl_easy_setopt_err_CURLSH();                                         \
+  }                                                                           \
+  curl_easy_setopt(handle, _curl_opt, value);                                 \
+})
+
+/* wraps curl_easy_getinfo() with typechecking */
+/* FIXME: don't allow const pointers */
+#define curl_easy_getinfo(handle, info, arg)                                  \
+__extension__ ({                                                              \
+  __typeof__ (info) _curl_info = info;                                        \
+  if (__builtin_constant_p(_curl_info)) {                                     \
+    if (_curl_is_string_info(_curl_info) && !_curl_is_arr((arg), char *))     \
+      _curl_easy_getinfo_err_string();                                        \
+    if (_curl_is_long_info(_curl_info) && !_curl_is_arr((arg), long))         \
+      _curl_easy_getinfo_err_long();                                          \
+    if (_curl_is_double_info(_curl_info) && !_curl_is_arr((arg), double))     \
+      _curl_easy_getinfo_err_double();                                        \
+    if (_curl_is_slist_info(_curl_info) &&                                    \
+           !_curl_is_arr((arg), struct curl_slist *))                         \
+      _curl_easy_getinfo_err_curl_slist();                                    \
+  }                                                                           \
+  curl_easy_getinfo(handle, _curl_info, arg);                                 \
+})
+
+/* TODO: typechecking for curl_share_setopt() and curl_multi_setopt(),
+ * for now just make sure that the functions are called with three
+ * arguments
+ */
+#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param)
+#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param)
+
+
+/* the actual warnings, triggered by calling the _curl_easy_setopt_err*
+ * functions */
+
+/* To define a new warning, use _CURL_WARNING(identifier, "message") */
+#define _CURL_WARNING(id, message)                                            \
+  static void __attribute__((warning(message))) __attribute__((unused))       \
+  __attribute__((noinline)) id(void) { __asm__(""); }
+
+_CURL_WARNING(_curl_easy_setopt_err_long,
+  "curl_easy_setopt expects a long argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_curl_off_t,
+  "curl_easy_setopt expects a curl_off_t argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_string,
+  "curl_easy_setopt expects a string (char* or char[]) argument for this option"
+  )
+_CURL_WARNING(_curl_easy_setopt_err_write_callback,
+  "curl_easy_setopt expects a curl_write_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_read_cb,
+  "curl_easy_setopt expects a curl_read_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_ioctl_cb,
+  "curl_easy_setopt expects a curl_ioctl_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_sockopt_cb,
+  "curl_easy_setopt expects a curl_sockopt_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_opensocket_cb,
+  "curl_easy_setopt expects a curl_opensocket_callback argument for this option"
+  )
+_CURL_WARNING(_curl_easy_setopt_err_progress_cb,
+  "curl_easy_setopt expects a curl_progress_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_debug_cb,
+  "curl_easy_setopt expects a curl_debug_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_ssl_ctx_cb,
+  "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_conv_cb,
+  "curl_easy_setopt expects a curl_conv_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_seek_cb,
+  "curl_easy_setopt expects a curl_seek_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_cb_data,
+  "curl_easy_setopt expects a private data pointer as argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_error_buffer,
+  "curl_easy_setopt expects a char buffer of CURL_ERROR_SIZE as argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_FILE,
+  "curl_easy_setopt expects a FILE* argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_postfields,
+  "curl_easy_setopt expects a void* or char* argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_curl_httpost,
+  "curl_easy_setopt expects a struct curl_httppost* argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_curl_slist,
+  "curl_easy_setopt expects a struct curl_slist* argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_CURLSH,
+  "curl_easy_setopt expects a CURLSH* argument for this option")
+
+_CURL_WARNING(_curl_easy_getinfo_err_string,
+  "curl_easy_getinfo expects a pointer to char * for this info")
+_CURL_WARNING(_curl_easy_getinfo_err_long,
+  "curl_easy_getinfo expects a pointer to long for this info")
+_CURL_WARNING(_curl_easy_getinfo_err_double,
+  "curl_easy_getinfo expects a pointer to double for this info")
+_CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
+  "curl_easy_getinfo expects a pointer to struct curl_slist * for this info")
+
+/* groups of curl_easy_setops options that take the same type of argument */
+
+/* To add a new option to one of the groups, just add
+ *   (option) == CURLOPT_SOMETHING
+ * to the or-expression. If the option takes a long or curl_off_t, you don't
+ * have to do anything
+ */
+
+/* evaluates to true if option takes a long argument */
+#define _curl_is_long_option(option)                                          \
+  (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT)
+
+#define _curl_is_off_t_option(option)                                         \
+  ((option) > CURLOPTTYPE_OFF_T)
+
+/* evaluates to true if option takes a char* argument */
+#define _curl_is_string_option(option)                                        \
+  ((option) == CURLOPT_URL ||                                                 \
+   (option) == CURLOPT_PROXY ||                                               \
+   (option) == CURLOPT_INTERFACE ||                                           \
+   (option) == CURLOPT_NETRC_FILE ||                                          \
+   (option) == CURLOPT_USERPWD ||                                             \
+   (option) == CURLOPT_USERNAME ||                                            \
+   (option) == CURLOPT_PASSWORD ||                                            \
+   (option) == CURLOPT_PROXYUSERPWD ||                                        \
+   (option) == CURLOPT_PROXYUSERNAME ||                                       \
+   (option) == CURLOPT_PROXYPASSWORD ||                                       \
+   (option) == CURLOPT_NOPROXY ||                                             \
+   (option) == CURLOPT_ENCODING ||                                            \
+   (option) == CURLOPT_REFERER ||                                             \
+   (option) == CURLOPT_USERAGENT ||                                           \
+   (option) == CURLOPT_COOKIE ||                                              \
+   (option) == CURLOPT_COOKIEFILE ||                                          \
+   (option) == CURLOPT_COOKIEJAR ||                                           \
+   (option) == CURLOPT_COOKIELIST ||                                          \
+   (option) == CURLOPT_FTPPORT ||                                             \
+   (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER ||                             \
+   (option) == CURLOPT_FTP_ACCOUNT ||                                         \
+   (option) == CURLOPT_RANGE ||                                               \
+   (option) == CURLOPT_CUSTOMREQUEST ||                                       \
+   (option) == CURLOPT_SSLCERT ||                                             \
+   (option) == CURLOPT_SSLCERTTYPE ||                                         \
+   (option) == CURLOPT_SSLKEY ||                                              \
+   (option) == CURLOPT_SSLKEYTYPE ||                                          \
+   (option) == CURLOPT_KEYPASSWD ||                                           \
+   (option) == CURLOPT_SSLENGINE ||                                           \
+   (option) == CURLOPT_CAINFO ||                                              \
+   (option) == CURLOPT_CAPATH ||                                              \
+   (option) == CURLOPT_RANDOM_FILE ||                                         \
+   (option) == CURLOPT_EGDSOCKET ||                                           \
+   (option) == CURLOPT_SSL_CIPHER_LIST ||                                     \
+   (option) == CURLOPT_KRBLEVEL ||                                            \
+   (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 ||                             \
+   (option) == CURLOPT_SSH_PUBLIC_KEYFILE ||                                  \
+   (option) == CURLOPT_SSH_PRIVATE_KEYFILE ||                                 \
+   (option) == CURLOPT_CRLFILE ||                                             \
+   (option) == CURLOPT_ISSUERCERT ||                                          \
+   0)
+
+/* evaluates to true if option takes a curl_write_callback argument */
+#define _curl_is_write_cb_option(option)                                      \
+  ((option) == CURLOPT_HEADERFUNCTION ||                                      \
+   (option) == CURLOPT_WRITEFUNCTION)
+
+/* evaluates to true if option takes a curl_conv_callback argument */
+#define _curl_is_conv_cb_option(option)                                       \
+  ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION ||                            \
+   (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION ||                          \
+   (option) == CURLOPT_CONV_FROM_UTF8_FUNCTION)
+
+/* evaluates to true if option takes a data argument to pass to a callback */
+#define _curl_is_cb_data_option(option)                                       \
+  ((option) == CURLOPT_WRITEDATA ||                                           \
+   (option) == CURLOPT_READDATA ||                                            \
+   (option) == CURLOPT_IOCTLDATA ||                                           \
+   (option) == CURLOPT_SOCKOPTDATA ||                                         \
+   (option) == CURLOPT_OPENSOCKETDATA ||                                      \
+   (option) == CURLOPT_PROGRESSDATA ||                                        \
+   (option) == CURLOPT_WRITEHEADER ||                                         \
+   (option) == CURLOPT_DEBUGDATA ||                                           \
+   (option) == CURLOPT_SSL_CTX_DATA ||                                        \
+   (option) == CURLOPT_SEEKDATA ||                                            \
+   (option) == CURLOPT_PRIVATE ||                                             \
+   0)
+
+/* evaluates to true if option takes a POST data argument (void* or char*) */
+#define _curl_is_postfields_option(option)                                    \
+  ((option) == CURLOPT_POSTFIELDS ||                                          \
+   (option) == CURLOPT_COPYPOSTFIELDS ||                                      \
+   0)
+
+/* evaluates to true if option takes a struct curl_slist * argument */
+#define _curl_is_slist_option(option)                                         \
+  ((option) == CURLOPT_HTTPHEADER ||                                          \
+   (option) == CURLOPT_HTTP200ALIASES ||                                      \
+   (option) == CURLOPT_QUOTE ||                                               \
+   (option) == CURLOPT_POSTQUOTE ||                                           \
+   (option) == CURLOPT_PREQUOTE ||                                            \
+   (option) == CURLOPT_TELNETOPTIONS ||                                       \
+   0)
+
+/* groups of curl_easy_getinfo infos that take the same type of argument */
+
+/* evaluates to true if info expects a pointer to char * argument */
+#define _curl_is_string_info(info)                                            \
+  (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG)
+
+/* evaluates to true if info expects a pointer to long argument */
+#define _curl_is_long_info(info)                                              \
+  (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE)
+
+/* evaluates to true if info expects a pointer to double argument */
+#define _curl_is_double_info(info)                                            \
+  (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST)
+
+/* true if info expects a pointer to struct curl_slist * argument */
+#define _curl_is_slist_info(info)                                             \
+  (CURLINFO_SLIST < (info))
+
+
+/* typecheck helpers -- check whether given expression has requested type*/
+
+/* For pointers, you can use the _curl_is_ptr/_curl_is_arr macros,
+ * otherwise define a new macro. Search for __builtin_types_compatible_p
+ * in the GCC manual.
+ * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is
+ * the actual expression passed to the curl_easy_setopt macro. This
+ * means that you can only apply the sizeof and __typeof__ operators, no
+ * == or whatsoever.
+ */
+
+/* XXX: should evaluate to true iff expr is a pointer */
+#define _curl_is_any_ptr(expr)                                                \
+  (sizeof(expr) == sizeof(void*))
+
+/* evaluates to true if expr is NULL */
+/* XXX: must not evaluate expr, so this check is not accurate */
+#define _curl_is_NULL(expr)                                                   \
+  (__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL)))
+
+/* evaluates to true if expr is type*, const type* or NULL */
+#define _curl_is_ptr(expr, type)                                              \
+  (_curl_is_NULL(expr) ||                                                     \
+   __builtin_types_compatible_p(__typeof__(expr), type *) ||                  \
+   __builtin_types_compatible_p(__typeof__(expr), const type *))
+
+/* evaluates to true if expr is one of type[], type*, NULL or const type* */
+#define _curl_is_arr(expr, type)                                              \
+  (_curl_is_ptr((expr), type) ||                                              \
+   __builtin_types_compatible_p(__typeof__(expr), type []))
+
+/* evaluates to true if expr is a string */
+#define _curl_is_string(expr)                                                 \
+  (_curl_is_arr((expr), char) ||                                              \
+   _curl_is_arr((expr), signed char) ||                                       \
+   _curl_is_arr((expr), unsigned char))
+
+/* evaluates to true if expr is a long (no matter the signedness)
+ * XXX: for now, int is also accepted (and therefore short and char, which
+ * are promoted to int when passed to a variadic function) */
+#define _curl_is_long(expr)                                                   \
+  (__builtin_types_compatible_p(__typeof__(expr), long) ||                    \
+   __builtin_types_compatible_p(__typeof__(expr), signed long) ||             \
+   __builtin_types_compatible_p(__typeof__(expr), unsigned long) ||           \
+   __builtin_types_compatible_p(__typeof__(expr), int) ||                     \
+   __builtin_types_compatible_p(__typeof__(expr), signed int) ||              \
+   __builtin_types_compatible_p(__typeof__(expr), unsigned int) ||            \
+   __builtin_types_compatible_p(__typeof__(expr), short) ||                   \
+   __builtin_types_compatible_p(__typeof__(expr), signed short) ||            \
+   __builtin_types_compatible_p(__typeof__(expr), unsigned short) ||          \
+   __builtin_types_compatible_p(__typeof__(expr), char) ||                    \
+   __builtin_types_compatible_p(__typeof__(expr), signed char) ||             \
+   __builtin_types_compatible_p(__typeof__(expr), unsigned char))
+
+/* evaluates to true if expr is of type curl_off_t */
+#define _curl_is_off_t(expr)                                                  \
+  (__builtin_types_compatible_p(__typeof__(expr), curl_off_t))
+
+/* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */
+/* XXX: also check size of an char[] array? */
+#define _curl_is_error_buffer(expr)                                           \
+  (__builtin_types_compatible_p(__typeof__(expr), char *) ||                  \
+   __builtin_types_compatible_p(__typeof__(expr), char[]))
+
+/* evaluates to true if expr is of type (const) void* or (const) FILE* */
+#if 0
+#define _curl_is_cb_data(expr)                                                \
+  (_curl_is_ptr((expr), void) ||                                              \
+   _curl_is_ptr((expr), FILE))
+#else /* be less strict */
+#define _curl_is_cb_data(expr)                                                \
+  _curl_is_any_ptr(expr)
+#endif
+
+/* evaluates to true if expr is of type FILE* */
+#define _curl_is_FILE(expr)                                                   \
+  (__builtin_types_compatible_p(__typeof__(expr), FILE *))
+
+/* evaluates to true if expr can be passed as POST data (void* or char*) */
+#define _curl_is_postfields(expr)                                             \
+  (_curl_is_ptr((expr), void) ||                                              \
+   _curl_is_arr((expr), char))
+
+/* FIXME: the whole callback checking is messy...
+ * The idea is to tolerate char vs. void and const vs. not const
+ * pointers in arguments at least
+ */
+/* helper: __builtin_types_compatible_p distinguishes between functions and
+ * function pointers, hide it */
+#define _curl_callback_compatible(func, type)                                 \
+  (__builtin_types_compatible_p(__typeof__(func), type) ||                    \
+   __builtin_types_compatible_p(__typeof__(func), type*))
+
+/* evaluates to true if expr is of type curl_read_callback or "similar" */
+#define _curl_is_read_cb(expr)                                          \
+  (_curl_is_NULL(expr) ||                                                     \
+   __builtin_types_compatible_p(__typeof__(expr), __typeof__(fread)) ||       \
+   __builtin_types_compatible_p(__typeof__(expr), curl_read_callback) ||      \
+   _curl_callback_compatible((expr), _curl_read_callback1) ||                 \
+   _curl_callback_compatible((expr), _curl_read_callback2) ||                 \
+   _curl_callback_compatible((expr), _curl_read_callback3) ||                 \
+   _curl_callback_compatible((expr), _curl_read_callback4) ||                 \
+   _curl_callback_compatible((expr), _curl_read_callback5) ||                 \
+   _curl_callback_compatible((expr), _curl_read_callback6))
+typedef size_t (_curl_read_callback1)(char *, size_t, size_t, void*);
+typedef size_t (_curl_read_callback2)(char *, size_t, size_t, const void*);
+typedef size_t (_curl_read_callback3)(char *, size_t, size_t, FILE*);
+typedef size_t (_curl_read_callback4)(void *, size_t, size_t, void*);
+typedef size_t (_curl_read_callback5)(void *, size_t, size_t, const void*);
+typedef size_t (_curl_read_callback6)(void *, size_t, size_t, FILE*);
+
+/* evaluates to true if expr is of type curl_write_callback or "similar" */
+#define _curl_is_write_cb(expr)                                               \
+  (_curl_is_read_cb(expr) ||                                            \
+   __builtin_types_compatible_p(__typeof__(expr), __typeof__(fwrite)) ||      \
+   __builtin_types_compatible_p(__typeof__(expr), curl_write_callback) ||     \
+   _curl_callback_compatible((expr), _curl_write_callback1) ||                \
+   _curl_callback_compatible((expr), _curl_write_callback2) ||                \
+   _curl_callback_compatible((expr), _curl_write_callback3) ||                \
+   _curl_callback_compatible((expr), _curl_write_callback4) ||                \
+   _curl_callback_compatible((expr), _curl_write_callback5) ||                \
+   _curl_callback_compatible((expr), _curl_write_callback6))
+typedef size_t (_curl_write_callback1)(const char *, size_t, size_t, void*);
+typedef size_t (_curl_write_callback2)(const char *, size_t, size_t,
+                                       const void*);
+typedef size_t (_curl_write_callback3)(const char *, size_t, size_t, FILE*);
+typedef size_t (_curl_write_callback4)(const void *, size_t, size_t, void*);
+typedef size_t (_curl_write_callback5)(const void *, size_t, size_t,
+                                       const void*);
+typedef size_t (_curl_write_callback6)(const void *, size_t, size_t, FILE*);
+
+/* evaluates to true if expr is of type curl_ioctl_callback or "similar" */
+#define _curl_is_ioctl_cb(expr)                                         \
+  (_curl_is_NULL(expr) ||                                                     \
+   __builtin_types_compatible_p(__typeof__(expr), curl_ioctl_callback) ||     \
+   _curl_callback_compatible((expr), _curl_ioctl_callback1) ||                \
+   _curl_callback_compatible((expr), _curl_ioctl_callback2) ||                \
+   _curl_callback_compatible((expr), _curl_ioctl_callback3) ||                \
+   _curl_callback_compatible((expr), _curl_ioctl_callback4))
+typedef curlioerr (_curl_ioctl_callback1)(CURL *, int, void*);
+typedef curlioerr (_curl_ioctl_callback2)(CURL *, int, const void*);
+typedef curlioerr (_curl_ioctl_callback3)(CURL *, curliocmd, void*);
+typedef curlioerr (_curl_ioctl_callback4)(CURL *, curliocmd, const void*);
+
+/* evaluates to true if expr is of type curl_sockopt_callback or "similar" */
+#define _curl_is_sockopt_cb(expr)                                       \
+  (_curl_is_NULL(expr) ||                                                     \
+   __builtin_types_compatible_p(__typeof__(expr), curl_sockopt_callback) ||   \
+   _curl_callback_compatible((expr), _curl_sockopt_callback1) ||              \
+   _curl_callback_compatible((expr), _curl_sockopt_callback2))
+typedef int (_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype);
+typedef int (_curl_sockopt_callback2)(const void *, curl_socket_t,
+                                      curlsocktype);
+
+/* evaluates to true if expr is of type curl_opensocket_callback or "similar" */
+#define _curl_is_opensocket_cb(expr)                                    \
+  (_curl_is_NULL(expr) ||                                                     \
+   __builtin_types_compatible_p(__typeof__(expr), curl_opensocket_callback) ||\
+   _curl_callback_compatible((expr), _curl_opensocket_callback1) ||           \
+   _curl_callback_compatible((expr), _curl_opensocket_callback2) ||           \
+   _curl_callback_compatible((expr), _curl_opensocket_callback3) ||           \
+   _curl_callback_compatible((expr), _curl_opensocket_callback4))
+typedef curl_socket_t (_curl_opensocket_callback1)
+  (void *, curlsocktype, struct curl_sockaddr *);
+typedef curl_socket_t (_curl_opensocket_callback2)
+  (void *, curlsocktype, const struct curl_sockaddr *);
+typedef curl_socket_t (_curl_opensocket_callback3)
+  (const void *, curlsocktype, struct curl_sockaddr *);
+typedef curl_socket_t (_curl_opensocket_callback4)
+  (const void *, curlsocktype, const struct curl_sockaddr *);
+
+/* evaluates to true if expr is of type curl_progress_callback or "similar" */
+#define _curl_is_progress_cb(expr)                                      \
+  (_curl_is_NULL(expr) ||                                                     \
+   __builtin_types_compatible_p(__typeof__(expr), curl_progress_callback) ||  \
+   _curl_callback_compatible((expr), _curl_progress_callback1) ||             \
+   _curl_callback_compatible((expr), _curl_progress_callback2))
+typedef int (_curl_progress_callback1)(void *,
+    double, double, double, double);
+typedef int (_curl_progress_callback2)(const void *,
+    double, double, double, double);
+
+/* evaluates to true if expr is of type curl_debug_callback or "similar" */
+#define _curl_is_debug_cb(expr)                                         \
+  (_curl_is_NULL(expr) ||                                                     \
+   __builtin_types_compatible_p(__typeof__(expr), curl_debug_callback) ||     \
+   _curl_callback_compatible((expr), _curl_debug_callback1) ||                \
+   _curl_callback_compatible((expr), _curl_debug_callback2) ||                \
+   _curl_callback_compatible((expr), _curl_debug_callback3) ||                \
+   _curl_callback_compatible((expr), _curl_debug_callback4))
+typedef int (_curl_debug_callback1) (CURL *,
+    curl_infotype, char *, size_t, void *);
+typedef int (_curl_debug_callback2) (CURL *,
+    curl_infotype, char *, size_t, const void *);
+typedef int (_curl_debug_callback3) (CURL *,
+    curl_infotype, const char *, size_t, void *);
+typedef int (_curl_debug_callback4) (CURL *,
+    curl_infotype, const char *, size_t, const void *);
+
+/* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */
+/* this is getting even messier... */
+#define _curl_is_ssl_ctx_cb(expr)                                       \
+  (_curl_is_NULL(expr) ||                                                     \
+   __builtin_types_compatible_p(__typeof__(expr), curl_ssl_ctx_callback) ||   \
+   _curl_callback_compatible((expr), _curl_ssl_ctx_callback1) ||              \
+   _curl_callback_compatible((expr), _curl_ssl_ctx_callback2) ||              \
+   _curl_callback_compatible((expr), _curl_ssl_ctx_callback3) ||              \
+   _curl_callback_compatible((expr), _curl_ssl_ctx_callback4) ||              \
+   _curl_callback_compatible((expr), _curl_ssl_ctx_callback5) ||              \
+   _curl_callback_compatible((expr), _curl_ssl_ctx_callback6) ||              \
+   _curl_callback_compatible((expr), _curl_ssl_ctx_callback7) ||              \
+   _curl_callback_compatible((expr), _curl_ssl_ctx_callback8))
+typedef CURLcode (_curl_ssl_ctx_callback1)(CURL *, void *, void *);
+typedef CURLcode (_curl_ssl_ctx_callback2)(CURL *, void *, const void *);
+typedef CURLcode (_curl_ssl_ctx_callback3)(CURL *, const void *, void *);
+typedef CURLcode (_curl_ssl_ctx_callback4)(CURL *, const void *, const void *);
+#ifdef HEADER_SSL_H
+/* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX
+ * this will of course break if we're included before OpenSSL headers...
+ */
+typedef CURLcode (_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *);
+typedef CURLcode (_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *);
+typedef CURLcode (_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *);
+typedef CURLcode (_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX, const void *);
+#else
+typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5;
+typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6;
+typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7;
+typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8;
+#endif
+
+/* evaluates to true if expr is of type curl_conv_callback or "similar" */
+#define _curl_is_conv_cb(expr)                                          \
+  (_curl_is_NULL(expr) ||                                                     \
+   __builtin_types_compatible_p(__typeof__(expr), curl_conv_callback) ||      \
+   _curl_callback_compatible((expr), _curl_conv_callback1) ||                 \
+   _curl_callback_compatible((expr), _curl_conv_callback2) ||                 \
+   _curl_callback_compatible((expr), _curl_conv_callback3) ||                 \
+   _curl_callback_compatible((expr), _curl_conv_callback4))
+typedef CURLcode (*_curl_conv_callback1)(char *, size_t length);
+typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length);
+typedef CURLcode (*_curl_conv_callback3)(void *, size_t length);
+typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length);
+
+/* evaluates to true if expr is of type curl_seek_callback or "similar" */
+#define _curl_is_seek_cb(expr)                                          \
+  (_curl_is_NULL(expr) ||                                                     \
+   __builtin_types_compatible_p(__typeof__(expr), curl_seek_callback) ||      \
+   _curl_callback_compatible((expr), _curl_seek_callback1) ||                 \
+   _curl_callback_compatible((expr), _curl_seek_callback2))
+typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int);
+typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int);
+
+
+#endif /* __CURL_TYPECHECK_GCC_H */
diff --git a/include/curl/types.h b/include/curl/types.h
new file mode 100644
index 0000000..d37d6ae
--- /dev/null
+++ b/include/curl/types.h
@@ -0,0 +1 @@
+/* not used */
diff --git a/lib/Makefile.inc b/lib/Makefile.inc
new file mode 100644
index 0000000..9803c8c
--- /dev/null
+++ b/lib/Makefile.inc
@@ -0,0 +1,28 @@
+# ./lib/Makefile.inc
+
+CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c	\
+  cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c	\
+  ldap.c ssluse.c version.c getenv.c escape.c mprintf.c telnet.c	\
+  netrc.c getinfo.c transfer.c strequal.c easy.c security.c krb4.c	\
+  krb5.c memdebug.c http_chunks.c strtok.c connect.c llist.c hash.c	\
+  multi.c content_encoding.c share.c http_digest.c md5.c curl_rand.c	\
+  http_negotiate.c http_ntlm.c inet_pton.c strtoofft.c strerror.c	\
+  hostares.c hostasyn.c hostip4.c hostip6.c hostsyn.c hostthre.c	\
+  inet_ntop.c parsedate.c select.c gtls.c sslgen.c tftp.c splay.c	\
+  strdup.c socks.c ssh.c nss.c qssl.c rawstr.c curl_addrinfo.c          \
+  socks_gssapi.c socks_sspi.c curl_sspi.c slist.c nonblock.c		\
+  curl_memrchr.c imap.c pop3.c smtp.c pingpong.c rtsp.c curl_threads.c	\
+  warnless.c
+
+HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h	\
+  progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h	\
+  if2ip.h speedcheck.h urldata.h curl_ldap.h ssluse.h escape.h telnet.h	\
+  getinfo.h strequal.h krb4.h memdebug.h http_chunks.h curl_rand.h	\
+  strtok.h connect.h llist.h hash.h content_encoding.h share.h		\
+  curl_md5.h http_digest.h http_negotiate.h http_ntlm.h inet_pton.h	\
+  strtoofft.h strerror.h inet_ntop.h curlx.h curl_memory.h setup.h	\
+  transfer.h select.h easyif.h multiif.h parsedate.h sslgen.h gtls.h	\
+  tftp.h sockaddr.h splay.h strdup.h setup_once.h socks.h ssh.h nssg.h	\
+  curl_base64.h rawstr.h curl_addrinfo.h curl_sspi.h slist.h nonblock.h	\
+  curl_memrchr.h imap.h pop3.h smtp.h pingpong.h rtsp.h curl_threads.h	\
+  warnless.h
diff --git a/lib/README.ares b/lib/README.ares
new file mode 100644
index 0000000..d3ee24b
--- /dev/null
+++ b/lib/README.ares
@@ -0,0 +1,69 @@
+                                  _   _ ____  _
+                              ___| | | |  _ \| |
+                             / __| | | | |_) | |
+                            | (__| |_| |  _ <| |___
+                             \___|\___/|_| \_\_____|
+
+          How To Build libcurl to Use c-ares For Asynch Name Resolves
+          ===========================================================
+
+c-ares:
+  http://c-ares.haxx.se/
+
+NOTE
+  The latest libcurl version requires c-ares 1.4.0 or later.
+
+  Once upon the time libcurl built fine with the "original" ares. That is no
+  longer true. You need to use c-ares.
+
+Build c-ares
+============
+
+1. unpack the c-ares archive
+2. cd c-ares-dir
+3. ./configure
+4. make
+5. make install
+
+Build libcurl to use c-ares in the curl source tree
+===================================================
+
+1. name or symlink the c-ares source directory 'ares' in the curl source
+   directory
+2. ./configure --enable-ares
+
+  Optionally, you can point out the c-ares install tree root with the the
+  --enable-ares option.
+
+3. make
+
+Build libcurl to use an installed c-ares
+========================================
+
+1. ./configure --enable-ares=/path/to/ares/install
+2. make
+
+c-ares on win32
+===============
+(description brought by Dominick Meglio)
+
+First I compiled c-ares. I changed the default C runtime library to be the
+single-threaded rather than the multi-threaded (this seems to be required to
+prevent linking errors later on). Then I simply build the areslib project (the
+other projects adig/ahost seem to fail under MSVC).
+
+Next was libcurl. I opened lib/config-win32.h and I added a:
+ #define USE_ARES 1
+
+Next thing I did was I added the path for the ares includes to the include
+path, and the libares.lib to the libraries.
+
+Lastly, I also changed libcurl to be single-threaded rather than
+multi-threaded, again this was to prevent some duplicate symbol errors. I'm
+not sure why I needed to change everything to single-threaded, but when I
+didn't I got redefinition errors for several CRT functions (malloc, stricmp,
+etc.)
+
+I would have modified the MSVC++ project files, but I only have VC.NET and it
+uses a different format than VC6.0 so I didn't want to go and change
+everything and remove VC6.0 support from libcurl.
diff --git a/lib/README.curl_off_t b/lib/README.curl_off_t
new file mode 100644
index 0000000..923b277
--- /dev/null
+++ b/lib/README.curl_off_t
@@ -0,0 +1,68 @@
+
+   curl_off_t explained
+   ====================
+
+curl_off_t is a data type provided by the external libcurl include headers. It
+is the type meant to be used for the curl_easy_setopt() options that end with
+LARGE. The type is 64bit large on most modern platforms.
+
+Transition from < 7.19.0 to >= 7.19.0
+-------------------------------------
+
+Applications that used libcurl before 7.19.0 that are rebuilt with a libcurl
+that is 7.19.0 or later may or may not have to worry about anything of
+this. We have made a significant effort to make the transition really seamless
+and transparent.
+
+You have have to take notice if you are in one of the following situations:
+
+o Your app is using or will after the transition use a libcurl that is built
+  with LFS (large file support) disabled even though your system otherwise
+  supports it.
+
+o Your app is using or will after the transition use a libcurl that doesn't
+  support LFS at all, but your system and compiler support 64bit data types.
+
+In both these cases, the curl_off_t type will now (after the transition) be
+64bit where it previously was 32bit. This will cause a binary incompatibility
+that you MAY need to deal with.
+
+Benefits
+--------
+
+This new way has several benefits:
+
+o Platforms without LFS support can still use libcurl to do >32 bit file
+  transfers and range operations etc as long as they have >32 bit data-types
+  supported.
+
+o Applications will no longer easily build with the curl_off_t size
+  mismatched, which has been a very frequent (and annoying) problem with
+  libcurl <= 7.18.2
+
+Historically
+------------
+
+Previously, before 7.19.0, the curl_off_t type would be rather strongly
+connected to the size of the system off_t type, where currently curl_off_t is
+independent of that.
+
+The strong connection to off_t made it troublesome for application authors
+since when they did mistakes, they could get curl_off_t type of different
+sizes in the app vs libcurl, and that caused strange effects that were hard to
+track and detect by users of libcurl.
+
+SONAME
+------
+
+We opted to not bump the soname for the library unconditionally, simply
+because soname bumping is causing a lot of grief and moaning all over the
+community so we try to keep that at minimum. Also, our selected design path
+should be 100% backwards compatible for the vast majority of all libcurl
+users.
+
+Enforce SONAME bump
+-------------------
+
+If configure doesn't detect your case where a bump is necessary, re-run it
+with the --enable-soname-bump command line option!
diff --git a/lib/README.curlx b/lib/README.curlx
new file mode 100644
index 0000000..5375b0d
--- /dev/null
+++ b/lib/README.curlx
@@ -0,0 +1,61 @@
+                                  _   _ ____  _
+                              ___| | | |  _ \| |
+                             / __| | | | |_) | |
+                            | (__| |_| |  _ <| |___
+                             \___|\___/|_| \_\_____|
+
+                     Source Code Functions Apps Might Use
+                     ====================================
+
+The libcurl source code offers a few functions by source only. They are not
+part of the official libcurl API, but the source files might be useful for
+others so apps can optionally compile/build with these sources to gain
+additional functions.
+
+We provide them through a single header file for easy access for apps:
+"curlx.h"
+
+ curlx_strtoofft()
+
+   A macro that converts a string containing a number to a curl_off_t number.
+   This might use the curlx_strtoll() function which is provided as source
+   code in strtoofft.c. Note that the function is only provided if no
+   strtoll() (or equivalent) function exist on your platform. If curl_off_t
+   is only a 32 bit number on your platform, this macro uses strtol().
+
+ curlx_tvnow()
+
+   returns a struct timeval for the current time.
+
+ curlx_tvdiff()
+
+   returns the difference between two timeval structs, in number of
+   milliseconds.
+
+ curlx_tvdiff_secs()
+
+   returns the same as curlx_tvdiff but with full usec resolution (as a
+   double)
+
+FUTURE
+======
+
+ Several functions will be removed from the public curl_ name space in a
+ future libcurl release. They will then only become available as curlx_
+ functions instead. To make the transition easier, we already today provide
+ these functions with the curlx_ prefix to allow sources to get built properly
+ with the new function names. The functions this concerns are:
+
+      curlx_getenv
+      curlx_strequal
+      curlx_strnequal
+      curlx_mvsnprintf
+      curlx_msnprintf
+      curlx_maprintf
+      curlx_mvaprintf
+      curlx_msprintf
+      curlx_mprintf
+      curlx_mfprintf
+      curlx_mvsprintf
+      curlx_mvprintf
+      curlx_mvfprintf
diff --git a/lib/README.encoding b/lib/README.encoding
new file mode 100644
index 0000000..0d31b36
--- /dev/null
+++ b/lib/README.encoding
@@ -0,0 +1,60 @@
+
+                    Content Encoding Support for libcurl
+
+* About content encodings:
+
+HTTP/1.1 [RFC 2616] specifies that a client may request that a server encode
+its response. This is usually used to compress a response using one of a set
+of commonly available compression techniques. These schemes are `deflate' (the
+zlib algorithm), `gzip' and `compress' [sec 3.5, RFC 2616]. A client requests
+that the sever perform an encoding by including an Accept-Encoding header in
+the request document. The value of the header should be one of the recognized
+tokens `deflate', ... (there's a way to register new schemes/tokens, see sec
+3.5 of the spec). A server MAY honor the client's encoding request. When a
+response is encoded, the server includes a Content-Encoding header in the
+response. The value of the Content-Encoding header indicates which scheme was
+used to encode the data.
+
+A client may tell a server that it can understand several different encoding
+schemes. In this case the server may choose any one of those and use it to
+encode the response (indicating which one using the Content-Encoding header).
+It's also possible for a client to attach priorities to different schemes so
+that the server knows which it prefers. See sec 14.3 of RFC 2616 for more
+information on the Accept-Encoding header.
+
+* Current support for content encoding:
+
+Support for the 'deflate' and 'gzip' content encoding are supported by
+libcurl. Both regular and chunked transfers should work fine.  The library
+zlib is required for this feature. 'deflate' support was added by James
+Gallagher, and support for the 'gzip' encoding was added by Dan Fandrich.
+
+* The libcurl interface:
+
+To cause libcurl to request a content encoding use:
+
+    curl_easy_setopt(curl, CURLOPT_ENCODING, <string>)
+
+where <string> is the intended value of the Accept-Encoding header.
+
+Currently, libcurl only understands how to process responses that use the
+"deflate" or "gzip" Content-Encoding, so the only values for CURLOPT_ENCODING
+that will work (besides "identity," which does nothing) are "deflate" and
+"gzip" If a response is encoded using the "compress" or methods, libcurl will
+return an error indicating that the response could not be decoded.  If
+<string> is NULL no Accept-Encoding header is generated.  If <string> is a
+zero-length string, then an Accept-Encoding header containing all supported
+encodings will be generated.
+
+The CURLOPT_ENCODING must be set to any non-NULL value for content to be
+automatically decoded.  If it is not set and the server still sends encoded
+content (despite not having been asked), the data is returned in its raw form
+and the Content-Encoding type is not checked.
+
+* The curl interface:
+
+Use the --compressed option with curl to cause it to ask servers to compress
+responses using any format supported by curl.
+
+James Gallagher <jgallagher@gso.uri.edu>
+Dan Fandrich <dan@coneharvesters.com>
diff --git a/lib/README.hostip b/lib/README.hostip
new file mode 100644
index 0000000..9723b93
--- /dev/null
+++ b/lib/README.hostip
@@ -0,0 +1,35 @@
+ 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 asynch 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 single united header file for all this. It defines the
+ CURLRES_* defines based on the config*.h and setup.h defines.
diff --git a/lib/README.httpauth b/lib/README.httpauth
new file mode 100644
index 0000000..9605045
--- /dev/null
+++ b/lib/README.httpauth
@@ -0,0 +1,74 @@
+
+1. PUT/POST without a known auth to use (possibly no auth required):
+
+   (When explicitly set to use a multi-pass auth when doing a POST/PUT,
+   libcurl should immediately go the Content-Length: 0 bytes route to avoid
+   the first send all data phase, step 2. If told to use a single-pass auth,
+   goto step 3.)
+
+   Issue the proper PUT/POST request immediately, with the correct
+   Content-Length and Expect: headers.
+
+   If a 100 response is received or the wait for one times out, start sending
+   the request-body.
+
+   If a 401 (or 407 when talking through a proxy) is received, then:
+
+   If we have "more than just a little" data left to send, close the
+   connection. Exactly what "more than just a little" means will have to be
+   determined. Possibly the current transfer speed should be taken into
+   account as well.
+
+   NOTE: if the size of the POST data is less than MAX_INITIAL_POST_SIZE (when
+   CURLOPT_POSTFIELDS is used), libcurl will send everything in one single
+   write() (all request-headers and request-body) and thus it will
+   unconditionally send the full post data here.
+
+2. PUT/POST with multi-pass auth but not yet completely negotiated:
+
+   Send a PUT/POST request, we know that it will be rejected and thus we claim
+   Content-Length zero to avoid having to send the request-body. (This seems
+   to be what IE does.)
+
+3. PUT/POST as the last step in the auth negotiation, that is when we have
+   what we believe is a completed negotiation:
+
+   Send a full and proper PUT/POST request (again) with the proper
+   Content-Length and a following request-body.
+
+   NOTE: this may very well be the second (or even third) time the whole or at
+   least parts of the request body is sent to the server. Since the data may
+   be provided to libcurl with a callback, we need a way to tell the app that
+   the upload is to be restarted so that the callback will provide data from
+   the start again.  This requires an API method/mechanism that libcurl
+   doesn't have today. See below.
+
+Data Rewind
+
+   It will be troublesome for some apps to deal with a rewind like this in all
+   circumstances. I'm thinking for example when using 'curl' to upload data
+   from stdin. If libcurl ends up having to rewind the reading for a request
+   to succeed, of course a lack of this callback or if it returns failure, will
+   cause the request to fail completely.
+
+   The new callback is set with CURLOPT_IOCTLFUNCTION (in an attempt to add a
+   more generic function that might be used for other IO-related controls in
+   the future):
+
+     curlioerr curl_ioctl(CURL *handle, curliocmd cmd, void *clientp);
+
+   And in the case where the read is to be rewinded, it would be called with a
+   cmd named CURLIOCMD_RESTARTREAD. The callback would then return CURLIOE_OK,
+   if things are fine, or CURLIOE_FAILRESTART if not.
+
+Backwards Compatibility
+
+   The approach used until now, that issues a HEAD on the given URL to trigger
+   the auth negotiation could still be supported and encouraged, but it would
+   be up to the app to first fetch a URL with GET/HEAD to negotiate on, since
+   then a following PUT/POST wouldn't need to negotiate authentication and
+   thus avoid double-sending data.
+
+   Optionally, we keep the current approach if some option is set
+   (CURLOPT_HEADBEFOREAUTH or similar), since it seems to work fairly well for
+   POST on most servers.
diff --git a/lib/README.memoryleak b/lib/README.memoryleak
new file mode 100644
index 0000000..1661777
--- /dev/null
+++ b/lib/README.memoryleak
@@ -0,0 +1,55 @@
+                                  _   _ ____  _
+                              ___| | | |  _ \| |
+                             / __| | | | |_) | |
+                            | (__| |_| |  _ <| |___
+                             \___|\___/|_| \_\_____|
+
+             How To Track Down Suspected Memory Leaks in libcurl
+             ===================================================
+
+Single-threaded
+
+  Please note that this memory leak system is not adjusted to work in more
+  than one thread. If you want/need to use it in a multi-threaded app. Please
+  adjust accordingly.
+
+
+Build
+
+  Rebuild libcurl with -DCURLDEBUG (usually, rerunning configure with
+  --enable-debug fixes this). 'make clean' first, then 'make' so that all
+  files actually are rebuilt properly. It will also make sense to build
+  libcurl with the debug option (usually -g to the compiler) so that debugging
+  it will be easier if you actually do find a leak in the library.
+
+  This will create a library that has memory debugging enabled.
+
+Modify Your Application
+
+  Add a line in your application code:
+
+       curl_memdebug("dump");
+
+  This will make the malloc debug system output a full trace of all resource
+  using functions to the given file name. Make sure you rebuild your program
+  and that you link with the same libcurl you built for this purpose as
+  described above.
+
+Run Your Application
+
+  Run your program as usual. Watch the specified memory trace file grow.
+
+  Make your program exit and use the proper libcurl cleanup functions etc. So
+  that all non-leaks are returned/freed properly.
+
+Analyze the Flow
+
+  Use the tests/memanalyze.pl perl script to analyze the dump file:
+
+    tests/memanalyze.pl dump
+
+  This now outputs a report on what resources that were allocated but never
+  freed etc. This report is very fine for posting to the list!
+
+  If this doesn't produce any output, no leak was detected in libcurl. Then
+  the leak is mostly likely to be in your code.
diff --git a/lib/README.multi_socket b/lib/README.multi_socket
new file mode 100644
index 0000000..d91e1d9
--- /dev/null
+++ b/lib/README.multi_socket
@@ -0,0 +1,53 @@
+Implementation of the curl_multi_socket API
+
+  The main ideas of the new API are simply:
+
+   1 - The application can use whatever event system it likes as it gets info
+       from libcurl about what file descriptors libcurl waits for what action
+       on. (The previous API returns fd_sets which is very select()-centric).
+
+   2 - When the application discovers action on a single socket, it calls
+       libcurl and informs that there was action on this particular socket and
+       libcurl can then act on that socket/transfer only and not care about
+       any other transfers. (The previous API always had to scan through all
+       the existing transfers.)
+
+  The idea is that curl_multi_socket_action() calls a given callback with
+  information about what socket to wait for what action on, and the callback
+  only gets called if the status of that socket has changed.
+
+  We also added a timer callback that makes libcurl call the application when
+  the timeout value changes, and you set that with curl_multi_setopt() and the
+  CURLMOPT_TIMERFUNCTION option. To get this to work, Internally, there's an
+  added a struct to each easy handle in which we store an "expire time" (if
+  any). The structs are then "splay sorted" so that we can add and remove
+  times from the linked list and yet somewhat swiftly figure out both how long
+  time there is until the next nearest timer expires and which timer (handle)
+  we should take care of now. Of course, the upside of all this is that we get
+  a curl_multi_timeout() that should also work with old-style applications
+  that use curl_multi_perform().
+
+  We created an internal "socket to easy handles" hash table that given
+  a socket (file descriptor) return the easy handle that waits for action on
+  that socket.  This hash is made using the already existing hash code
+  (previously only used for the DNS cache).
+
+  To make libcurl able to report plain sockets in the socket callback, we had
+  to re-organize the internals of the curl_multi_fdset() etc so that the
+  conversion from sockets to fd_sets for that function is only done in the
+  last step before the data is returned. I also had to extend c-ares to get a
+  function that can return plain sockets, as that library too returned only
+  fd_sets and that is no longer good enough. The changes done to c-ares are
+  available in c-ares 1.3.1 and later.
+
+  We have done a test runs with up to 9000 connections (with a single active
+  one). The curl_multi_socket_action() invoke then takes less than 10
+  microseconds in average (using the read-only-1-byte-at-a-time hack).  We are
+  now below the 60 microseconds "per socket action" goal (the extra 50 is the
+  time libevent needs).
+
+Documentation
+
+    http://curl.haxx.se/libcurl/c/curl_multi_socket_action.html
+    http://curl.haxx.se/libcurl/c/curl_multi_timeout.html
+    http://curl.haxx.se/libcurl/c/curl_multi_setopt.html
diff --git a/lib/README.pingpong b/lib/README.pingpong
new file mode 100644
index 0000000..69ba9aa
--- /dev/null
+++ b/lib/README.pingpong
@@ -0,0 +1,30 @@
+Date: December 5, 2009
+
+Pingpong
+========
+
+ Pingpong is just my (Daniel's) jestful collective name on the protocols that
+ share a very similar kind of back-and-forth procedure with command and
+ responses to and from the server. FTP was previously the only protocol in
+ that family that libcurl supported, but when POP3, IMAP and SMTP joined the
+ team I moved some of the internals into a separate pingpong module to be
+ easier to get used by all these protocols to reduce code duplication and ease
+ code re-use between these protocols.
+
+FTP
+
+ In 7.20.0 we converted code to use the new pingpong code from previously
+ having been all "native" FTP code.
+
+POP3
+
+ There's no support in the documented URL format to specify the exact mail to
+ get, but we support that as the path specified in the URL.
+
+IMAP
+
+SMTP
+
+ There's no official URL syntax defined for SMTP, but we use only the generic
+ one and we provide two additional libcurl options to specify receivers and
+ sender of the actual mail.
diff --git a/lib/README.pipelining b/lib/README.pipelining
new file mode 100644
index 0000000..c7b4622
--- /dev/null
+++ b/lib/README.pipelining
@@ -0,0 +1,51 @@
+HTTP Pipelining with libcurl
+============================
+
+Background
+
+Since pipelining implies that one or more requests are sent to a server before
+the previous response(s) have been received, we only support it for multi
+interface use.
+
+Considerations
+
+When using the multi interface, you create one easy handle for each transfer.
+Bascially any number of handles can be created, added and used with the multi
+interface - simultaneously. It is an interface designed to allow many
+simultaneous transfers while still using a single thread. Pipelining does not
+change any of these details.
+
+API
+
+We've added a new option to curl_multi_setopt() called CURLMOPT_PIPELINING
+that enables "attempted pipelining" and then all easy handles used on that
+handle will attempt to use an existing pipeline.
+
+Details
+
+- A pipeline is only created if a previous connection exists to the same IP
+  address that the new request is being made to use.
+
+- Pipelines are only supported for HTTP(S) as no other currently supported
+  protocol has features resemembling this, but we still name this feature
+  plain 'pipelining' to possibly one day support it for other protocols as
+  well.
+
+- HTTP Pipelining is for GET and HEAD requests only.
+
+- When a pipeline is in use, we must take precautions so that when used easy
+  handles (i.e those who still wait for a response) are removed from the multi
+  handle, we must deal with the outstanding response nicely.
+
+- Explicitly asking for pipelining handle X and handle Y won't be supported.
+  It isn't easy for an app to do this association. The lib should probably
+  still resolve the second one properly to make sure that they actually _can_
+  be considered for pipelining. Also, asking for explicit pipelining on handle
+  X may be tricky when handle X get a closed connection.
+
+- We need options to control max pipeline length, and probably how to behave
+  if we reach that limit. As was discussed on the list, it can probably be
+  made very complicated, so perhaps we can think of a way to pass all
+  variables involved to a callback and let the application decide how to act
+  in specific situations. Either way, these fancy options are only interesting
+  to work on when everything is working and we have working apps to test with.
diff --git a/lib/amigaos.c b/lib/amigaos.c
new file mode 100644
index 0000000..2055126
--- /dev/null
+++ b/lib/amigaos.c
@@ -0,0 +1,80 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+#ifdef __AMIGA__ /* Any AmigaOS flavour */
+
+#include "amigaos.h"
+#include <amitcp/socketbasetags.h>
+
+struct Library *SocketBase = NULL;
+extern int errno, h_errno;
+
+#ifdef __libnix__
+#include <stabs.h>
+void __request(const char *msg);
+#else
+# define __request( msg )       Printf( msg "\n\a")
+#endif
+
+void amiga_cleanup()
+{
+  if(SocketBase) {
+    CloseLibrary(SocketBase);
+    SocketBase = NULL;
+  }
+}
+
+BOOL amiga_init()
+{
+  if(!SocketBase)
+    SocketBase = OpenLibrary("bsdsocket.library", 4);
+
+  if(!SocketBase) {
+    __request("No TCP/IP Stack running!");
+    return FALSE;
+  }
+
+  if(SocketBaseTags(SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (ULONG) &errno,
+                    SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG) "cURL",
+                    TAG_DONE)) {
+    __request("SocketBaseTags ERROR");
+    return FALSE;
+  }
+
+#ifndef __libnix__
+  atexit(amiga_cleanup);
+#endif
+
+  return TRUE;
+}
+
+#ifdef __libnix__
+ADD2EXIT(amiga_cleanup,-50);
+#endif
+
+#else /* __AMIGA__ */
+
+#ifdef __POCC__
+#  pragma warn(disable:2024)  /* Disable warning #2024: Empty input file */
+#endif
+
+#endif /* __AMIGA__ */
diff --git a/lib/amigaos.h b/lib/amigaos.h
new file mode 100644
index 0000000..d6ff064
--- /dev/null
+++ b/lib/amigaos.h
@@ -0,0 +1,57 @@
+#ifndef LIBCURL_AMIGAOS_H
+#define LIBCURL_AMIGAOS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, 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.
+ *
+ ***************************************************************************/
+
+#ifdef __AMIGA__ /* Any AmigaOS flavour */
+
+#ifndef __ixemul__
+
+#include <exec/types.h>
+#include <exec/execbase.h>
+
+#include <proto/exec.h>
+#include <proto/dos.h>
+
+#include <sys/socket.h>
+
+#include "config-amigaos.h"
+
+#ifndef select
+# define select(args...) WaitSelect( args, NULL)
+#endif
+#ifndef ioctl
+# define ioctl(a,b,c,d)  IoctlSocket( (LONG)a, (ULONG)b, (char*)c)
+#endif
+#define _AMIGASF        1
+
+extern void amiga_cleanup();
+extern BOOL amiga_init();
+
+#else /* __ixemul__ */
+
+#warning compiling with ixemul...
+
+#endif /* __ixemul__ */
+#endif /* __AMIGA__ */
+#endif /* LIBCURL_AMIGAOS_H */
+
diff --git a/lib/arpa_telnet.h b/lib/arpa_telnet.h
new file mode 100644
index 0000000..ddb14f6
--- /dev/null
+++ b/lib/arpa_telnet.h
@@ -0,0 +1,102 @@
+#ifndef HEADER_CURL_ARPA_TELNET_H
+#define HEADER_CURL_ARPA_TELNET_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+#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 * const 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 * const 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 /* CURL_DISABLE_TELNET */
+
+#endif /* HEADER_CURL_ARPA_TELNET_H */
diff --git a/lib/base64.c b/lib/base64.c
new file mode 100644
index 0000000..edccf54
--- /dev/null
+++ b/lib/base64.c
@@ -0,0 +1,247 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+/* 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 "urldata.h" /* for the SessionHandle definition */
+#include "easyif.h"  /* for Curl_convert_... prototypes */
+#include "warnless.h"
+#include "curl_base64.h"
+#include "curl_memory.h"
+
+/* include memdebug.h last */
+#include "memdebug.h"
+
+/* ---- Base64 Encoding/Decoding Table --- */
+static const char table64[]=
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static void decodeQuantum(unsigned char *dest, const char *src)
+{
+  const char *s, *p;
+  unsigned long i, v, x = 0;
+
+  for(i = 0, s = src; i < 4; i++, s++) {
+    v = 0;
+    p = table64;
+    while(*p && (*p != *s)) {
+      v++;
+      p++;
+    }
+    if(*p == *s)
+      x = (x << 6) + v;
+    else if(*s == '=')
+      x = (x << 6);
+  }
+
+  dest[2] = curlx_ultouc(x);
+  x >>= 8;
+  dest[1] = curlx_ultouc(x);
+  x >>= 8;
+  dest[0] = curlx_ultouc(x);
+}
+
+/*
+ * Curl_base64_decode()
+ *
+ * Given a base64 string at src, decode it and return an allocated memory in
+ * the *outptr. Returns the length of the decoded data.
+ */
+size_t Curl_base64_decode(const char *src, unsigned char **outptr)
+{
+  size_t length = 0;
+  size_t equalsTerm = 0;
+  size_t i;
+  size_t numQuantums;
+  unsigned char lastQuantum[3];
+  size_t rawlen = 0;
+  unsigned char *newstr;
+
+  *outptr = NULL;
+
+  while((src[length] != '=') && src[length])
+    length++;
+  /* A maximum of two = padding characters is allowed */
+  if(src[length] == '=') {
+    equalsTerm++;
+    if(src[length+equalsTerm] == '=')
+      equalsTerm++;
+  }
+  numQuantums = (length + equalsTerm) / 4;
+
+  /* Don't allocate a buffer if the decoded length is 0 */
+  if(numQuantums == 0)
+    return 0;
+
+  rawlen = (numQuantums * 3) - equalsTerm;
+
+  /* The buffer must be large enough to make room for the last quantum
+  (which may be partially thrown out) and the zero terminator. */
+  newstr = malloc(rawlen+4);
+  if(!newstr)
+    return 0;
+
+  *outptr = newstr;
+
+  /* Decode all but the last quantum (which may not decode to a
+  multiple of 3 bytes) */
+  for(i = 0; i < numQuantums - 1; i++) {
+    decodeQuantum(newstr, src);
+    newstr += 3; src += 4;
+  }
+
+  /* This final decode may actually read slightly past the end of the buffer
+  if the input string is missing pad bytes.  This will almost always be
+  harmless. */
+  decodeQuantum(lastQuantum, src);
+  for(i = 0; i < 3 - equalsTerm; i++)
+    newstr[i] = lastQuantum[i];
+
+  newstr[i] = '\0'; /* zero terminate */
+  return rawlen;
+}
+
+/*
+ * 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, 0 is returned.
+ *
+ */
+size_t Curl_base64_encode(struct SessionHandle *data,
+                          const char *inputbuff, size_t insize,
+                          char **outptr)
+{
+  unsigned char ibuf[3];
+  unsigned char obuf[4];
+  int i;
+  int inputparts;
+  char *output;
+  char *base64data;
+#ifdef CURL_DOES_CONVERSIONS
+  char *convbuf = NULL;
+#endif
+
+  const char *indata = inputbuff;
+
+  *outptr = NULL; /* set to NULL in case of failure before we reach the end */
+
+  if(0 == insize)
+    insize = strlen(indata);
+
+  base64data = output = malloc(insize*4/3+4);
+  if(NULL == output)
+    return 0;
+
+#ifdef CURL_DOES_CONVERSIONS
+  /*
+   * The base64 data needs to be created using the network encoding
+   * not the host encoding.  And we can't change the actual input
+   * so we copy it to a buffer, translate it, and use that instead.
+   */
+  if(data) {
+    convbuf = malloc(insize);
+    if(!convbuf) {
+      free(output);
+      return 0;
+    }
+    memcpy(convbuf, indata, insize);
+    if(CURLE_OK != Curl_convert_to_network(data, convbuf, insize)) {
+      free(convbuf);
+      free(output);
+      return 0;
+    }
+    indata = convbuf; /* switch to the converted buffer */
+  }
+#else
+  (void)data;
+#endif
+
+  while(insize > 0) {
+    for (i = inputparts = 0; i < 3; i++) {
+      if(insize > 0) {
+        inputparts++;
+        ibuf[i] = (unsigned char) *indata;
+        indata++;
+        insize--;
+      }
+      else
+        ibuf[i] = 0;
+    }
+
+    obuf[0] = (unsigned char)  ((ibuf[0] & 0xFC) >> 2);
+    obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \
+                               ((ibuf[1] & 0xF0) >> 4));
+    obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \
+                               ((ibuf[2] & 0xC0) >> 6));
+    obuf[3] = (unsigned char)   (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 */
+
+#ifdef CURL_DOES_CONVERSIONS
+  if(data)
+    free(convbuf);
+#endif
+  return strlen(base64data); /* return the length of the new data */
+}
+/* ---- End of Base64 Encoding ---- */
diff --git a/lib/connect.c b/lib/connect.c
new file mode 100644
index 0000000..eb6df71
--- /dev/null
+++ b/lib/connect.c
@@ -0,0 +1,1019 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.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_SYS_UN_H
+#include <sys/un.h> /* for sockaddr_un */
+#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_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
+#include <sys/filio.h>
+#endif
+#ifdef NETWARE
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "urldata.h"
+#include "sendf.h"
+#include "if2ip.h"
+#include "strerror.h"
+#include "connect.h"
+#include "curl_memory.h"
+#include "select.h"
+#include "url.h" /* for Curl_safefree() */
+#include "multiif.h"
+#include "sockaddr.h" /* required for Curl_sockaddr_storage */
+#include "inet_ntop.h"
+#include "inet_pton.h"
+#include "sslgen.h" /* for Curl_ssl_check_cxn() */
+#include "progress.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifdef __SYMBIAN32__
+/* This isn't actually supported under Symbian OS */
+#undef SO_NOSIGPIPE
+#endif
+
+struct Curl_sockaddr_ex {
+  int family;
+  int socktype;
+  int protocol;
+  unsigned int addrlen;
+  union {
+    struct sockaddr addr;
+    struct Curl_sockaddr_storage buff;
+  } _sa_ex_u;
+};
+#define sa_addr _sa_ex_u.addr
+
+static bool verifyconnect(curl_socket_t sockfd, int *error);
+
+static curl_socket_t
+singleipconnect(struct connectdata *conn,
+                const Curl_addrinfo *ai, /* start connecting to this */
+                long timeout_ms,
+                bool *connected);
+
+/*
+ * Curl_timeleft() returns the amount of milliseconds left allowed for the
+ * transfer/connection. If the value is negative, the timeout time has already
+ * elapsed.
+ *
+ * If 'nowp' is non-NULL, it points to the current time.
+ * 'duringconnect' is FALSE if not during a connect, as then of course the
+ * connect timeout is not taken into account!
+ */
+long Curl_timeleft(struct connectdata *conn,
+                   struct timeval *nowp,
+                   bool duringconnect)
+{
+  struct SessionHandle *data = conn->data;
+  int timeout_set = 0;
+  long timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
+  struct timeval now;
+
+  /* if a timeout is set, use the most restrictive one */
+
+  if(data->set.timeout > 0)
+    timeout_set |= 1;
+  if(duringconnect && (data->set.connecttimeout > 0))
+    timeout_set |= 2;
+
+  switch (timeout_set) {
+  case 1:
+    timeout_ms = data->set.timeout;
+    break;
+  case 2:
+    timeout_ms = data->set.connecttimeout;
+    break;
+  case 3:
+    if(data->set.timeout < data->set.connecttimeout)
+      timeout_ms = data->set.timeout;
+    else
+      timeout_ms = data->set.connecttimeout;
+    break;
+  default:
+    /* use the default */
+    if(!duringconnect)
+      /* if we're not during connect, there's no default timeout so if we're
+         at zero we better just return zero and not make it a negative number
+         by the math below */
+      return 0;
+    break;
+  }
+
+  if(!nowp) {
+    now = Curl_tvnow();
+    nowp = &now;
+  }
+
+  /* substract elapsed time */
+  timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle);
+
+  return timeout_ms;
+}
+
+/*
+ * 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(struct connectdata *conn,
+                curl_socket_t sockfd, /* socket */
+                long timeout_msec)
+{
+  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. */
+  (void)verifyconnect(sockfd, NULL);
+#endif
+
+  for(;;) {
+
+    /* now select() until we get connect or timeout */
+    rc = Curl_socket_ready(CURL_SOCKET_BAD, sockfd, (int)(timeout_msec>1000?
+                                                          1000:timeout_msec));
+
+    if(Curl_pgrsUpdate(conn))
+      return CURLE_ABORTED_BY_CALLBACK;
+
+    if(-1 == rc)
+      /* error, no connect here, try next */
+      return WAITCONN_SELECT_ERROR;
+
+    else if(0 == rc) {
+      /* timeout */
+      timeout_msec -= 1000;
+      if(timeout_msec <= 0)
+        return WAITCONN_TIMEOUT;
+
+      continue;
+    }
+
+    if(rc & CURL_CSELECT_ERR)
+      /* error condition caught */
+      return WAITCONN_FDSET_ERROR;
+
+    break;
+  }
+  return WAITCONN_CONNECTED;
+}
+
+static CURLcode bindlocal(struct connectdata *conn,
+                          curl_socket_t sockfd, int af)
+{
+  struct SessionHandle *data = conn->data;
+
+  struct Curl_sockaddr_storage sa;
+  struct sockaddr *sock = (struct sockaddr *)&sa;  /* bind to this address */
+  curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
+  struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
+#ifdef ENABLE_IPV6
+  struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
+#endif
+
+  struct Curl_dns_entry *h=NULL;
+  unsigned short port = data->set.localport; /* use this port number, 0 for
+                                                "random" */
+  /* how many port numbers to try to bind to, increasing one at a time */
+  int portnum = data->set.localportrange;
+  const char *dev = data->set.str[STRING_DEVICE];
+  int error;
+  char myhost[256] = "";
+  int done = 0; /* -1 for error, 1 for address found */
+
+  /*************************************************************
+   * Select device to bind socket to
+   *************************************************************/
+  if ( !dev && !port )
+    /* no local kind of binding was requested */
+    return CURLE_OK;
+
+  memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
+
+  if(dev && (strlen(dev)<255) ) {
+
+    /* interface */
+    if(Curl_if2ip(af, dev, myhost, sizeof(myhost))) {
+      /*
+       * We now have the numerical IP address in the 'myhost' buffer
+       */
+      infof(data, "Local Interface %s is ip %s using address family %i\n",
+            dev, myhost, af);
+      done = 1;
+
+#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.
+       *
+       *
+       * Only bind to the interface when specified as interface, not just as a
+       * hostname or ip address.
+       */
+      if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
+                    dev, (curl_socklen_t)strlen(dev)+1) != 0) {
+        error = SOCKERRNO;
+        infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;"
+              " will do regular bind\n",
+              dev, error, Curl_strerror(conn, error));
+        /* This is typically "errno 1, error: Operation not permitted" if
+           you're not running as root or another suitable privileged user */
+      }
+#endif
+    }
+    else {
+      /*
+       * This was not an interface, resolve the name as a host name
+       * or IP number
+       *
+       * Temporarily force name resolution to use only the address type
+       * of the connection. The resolve functions should really be changed
+       * to take a type parameter instead.
+       */
+      long ipver = data->set.ip_version;
+      int rc;
+
+      if (af == AF_INET)
+        data->set.ip_version = CURL_IPRESOLVE_V4;
+#ifdef ENABLE_IPV6
+      else if (af == AF_INET6)
+        data->set.ip_version = CURL_IPRESOLVE_V6;
+#endif
+
+      rc = Curl_resolv(conn, dev, 0, &h);
+      if(rc == CURLRESOLV_PENDING)
+        (void)Curl_wait_for_resolv(conn, &h);
+      data->set.ip_version = ipver;
+
+      if(h) {
+        /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
+        Curl_printable_address(h->addr, myhost, sizeof(myhost));
+        infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
+              dev, af, myhost, h->addr->ai_family);
+        Curl_resolv_unlock(data, h);
+        done = 1;
+      }
+      else {
+        /*
+         * provided dev was no interface (or interfaces are not supported
+         * e.g. solaris) no ip address and no domain we fail here
+         */
+        done = -1;
+      }
+    }
+
+    if(done > 0) {
+#ifdef ENABLE_IPV6
+      /* ipv6 address */
+      if((af == AF_INET6) &&
+         (Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0)) {
+        si6->sin6_family = AF_INET6;
+        si6->sin6_port = htons(port);
+        sizeof_sa = sizeof(struct sockaddr_in6);
+      }
+      else
+#endif
+      /* ipv4 address */
+      if((af == AF_INET) &&
+         (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
+        si4->sin_family = AF_INET;
+        si4->sin_port = htons(port);
+        sizeof_sa = sizeof(struct sockaddr_in);
+      }
+    }
+
+    if(done < 1) {
+      failf(data, "Couldn't bind to '%s'", dev);
+      return CURLE_INTERFACE_FAILED;
+    }
+  }
+  else {
+    /* no device was given, prepare sa to match af's needs */
+#ifdef ENABLE_IPV6
+    if ( af == AF_INET6 ) {
+      si6->sin6_family = AF_INET6;
+      si6->sin6_port = htons(port);
+      sizeof_sa = sizeof(struct sockaddr_in6);
+    }
+    else
+#endif
+    if ( af == AF_INET ) {
+      si4->sin_family = AF_INET;
+      si4->sin_port = htons(port);
+      sizeof_sa = sizeof(struct sockaddr_in);
+    }
+  }
+
+  for(;;) {
+    if( bind(sockfd, sock, sizeof_sa) >= 0) {
+    /* we succeeded to bind */
+      struct Curl_sockaddr_storage add;
+      curl_socklen_t size = sizeof(add);
+      memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
+      if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
+        data->state.os_errno = error = SOCKERRNO;
+        failf(data, "getsockname() failed with errno %d: %s",
+              error, Curl_strerror(conn, error));
+        return CURLE_INTERFACE_FAILED;
+      }
+      infof(data, "Local port: %hu\n", port);
+      conn->bits.bound = TRUE;
+      return CURLE_OK;
+    }
+
+    if(--portnum > 0) {
+      infof(data, "Bind to local port %hu failed, trying next\n", port);
+      port++; /* try next port */
+      /* We re-use/clobber the port variable here below */
+      if(sock->sa_family == AF_INET)
+        si4->sin_port = ntohs(port);
+#ifdef ENABLE_IPV6
+      else
+        si6->sin6_port = ntohs(port);
+#endif
+    }
+    else
+      break;
+  }
+
+  data->state.os_errno = error = SOCKERRNO;
+  failf(data, "bind failed with errno %d: %s",
+        error, Curl_strerror(conn, error));
+
+  return CURLE_INTERFACE_FAILED;
+}
+
+/*
+ * verifyconnect() returns TRUE if the connect really has happened.
+ */
+static bool verifyconnect(curl_socket_t sockfd, int *error)
+{
+  bool rc = TRUE;
+#ifdef SO_ERROR
+  int err = 0;
+  curl_socklen_t errSize = sizeof(err);
+
+#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."
+   */
+
+#ifdef _WIN32_WCE
+  Sleep(0);
+#else
+  SleepEx(0, FALSE);
+#endif
+
+#endif
+
+  if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
+    err = SOCKERRNO;
+#ifdef _WIN32_WCE
+  /* Old WinCE versions don't support SO_ERROR */
+  if(WSAENOPROTOOPT == err) {
+    SET_SOCKERRNO(0);
+    err = 0;
+  }
+#endif
+#ifdef __minix
+  /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
+  if(EBADIOCTL == err) {
+    SET_SOCKERRNO(0);
+    err = 0;
+  }
+#endif
+  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 = SOCKERRNO;
+#endif
+  return rc;
+}
+
+/* Used within the multi interface. Try next IP address, return TRUE if no
+   more address exists or error */
+static bool trynextip(struct connectdata *conn,
+                      int sockindex,
+                      bool *connected)
+{
+  curl_socket_t sockfd;
+  Curl_addrinfo *ai;
+
+  /* first close the failed socket */
+  sclose(conn->sock[sockindex]);
+  conn->sock[sockindex] = CURL_SOCKET_BAD;
+  *connected = FALSE;
+
+  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;
+
+  DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
+
+  *connected = FALSE; /* a very negative world view is best */
+
+  if(conn->bits.tcpconnect) {
+    /* we are connected already! */
+    long allow_total = 0;
+
+    /* subtract the most strict timeout of the ones */
+    if(data->set.timeout)
+      allow_total = data->set.timeout;
+
+    Curl_expire(data, allow_total);
+    *connected = TRUE;
+    return CURLE_OK;
+  }
+
+  /* figure out how long time we have left to connect */
+  allow = Curl_timeleft(conn, NULL, TRUE);
+
+  if(allow < 0) {
+    /* time-out, bail out, go home */
+    failf(data, "Connection time-out");
+    return CURLE_OPERATION_TIMEDOUT;
+  }
+
+  Curl_expire(data, allow);
+
+  /* check for connect without timeout as we want to return immediately */
+  rc = waitconnect(conn, sockfd, 0);
+
+  if(WAITCONN_CONNECTED == rc) {
+    int error;
+    if(verifyconnect(sockfd, &error)) {
+      /* we are connected, awesome! */
+      conn->bits.tcpconnect = TRUE;
+      *connected = TRUE;
+      return CURLE_OK;
+    }
+    /* nope, not connected for real */
+    data->state.os_errno = error;
+    infof(data, "Connection failed\n");
+    if(trynextip(conn, sockindex, connected)) {
+      failf(data, "Failed connect to %s:%ld; %s",
+            conn->host.name, conn->port, Curl_strerror(conn, error));
+      code = CURLE_COULDNT_CONNECT;
+    }
+  }
+  else if(WAITCONN_TIMEOUT != rc) {
+    int error = 0;
+
+    /* nope, not connected  */
+    if(WAITCONN_FDSET_ERROR == rc) {
+      (void)verifyconnect(sockfd, &error);
+      data->state.os_errno = error;
+      infof(data, "%s\n",Curl_strerror(conn,error));
+    }
+    else
+      infof(data, "Connection failed\n");
+
+    if(trynextip(conn, sockindex, connected)) {
+      error = SOCKERRNO;
+      data->state.os_errno = error;
+      failf(data, "Failed connect to %s:%ld; %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;
+  curl_socklen_t onoff = (curl_socklen_t) data->set.tcp_nodelay;
+  int proto = IPPROTO_TCP;
+
+#if 0
+  /* The use of getprotobyname() is disabled since it isn't thread-safe on
+     numerous systems. On these getprotobyname_r() should be used instead, but
+     that exists in at least one 4 arg version and one 5 arg version, and
+     since the proto number rarely changes anyway we now just use the hard
+     coded number. The "proper" fix would need a configure check for the
+     correct function much in the same style the gethostbyname_r versions are
+     detected. */
+  struct protoent *pe = getprotobyname("tcp");
+  if(pe)
+    proto = pe->p_proto;
+#endif
+
+  if(setsockopt(sockfd, proto, TCP_NODELAY, (void *)&onoff,
+                sizeof(onoff)) < 0)
+    infof(data, "Could not set TCP_NODELAY: %s\n",
+          Curl_strerror(conn, SOCKERRNO));
+  else
+    infof(data,"TCP_NODELAY set\n");
+#else
+  (void)conn;
+  (void)sockfd;
+#endif
+}
+
+#ifdef SO_NOSIGPIPE
+/* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
+   sending data to a dead peer (instead of relying on the 4th argument to send
+   being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
+   systems? */
+static void nosigpipe(struct connectdata *conn,
+                      curl_socket_t sockfd)
+{
+  struct SessionHandle *data= conn->data;
+  int onoff = 1;
+  if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
+                sizeof(onoff)) < 0)
+    infof(data, "Could not set SO_NOSIGPIPE: %s\n",
+          Curl_strerror(conn, SOCKERRNO));
+}
+#else
+#define nosigpipe(x,y)
+#endif
+
+#ifdef WIN32
+/* When you run a program that uses the Windows Sockets API, you may
+   experience slow performance when you copy data to a TCP server.
+
+   http://support.microsoft.com/kb/823764
+
+   Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
+   Buffer Size
+
+*/
+void Curl_sndbufset(curl_socket_t sockfd)
+{
+  int val = CURL_MAX_WRITE_SIZE + 32;
+  int curval = 0;
+  int curlen = sizeof(curval);
+
+  if (getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
+    if (curval > val)
+      return;
+
+  setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
+}
+#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,
+                const Curl_addrinfo *ai,
+                long timeout_ms,
+                bool *connected)
+{
+  struct Curl_sockaddr_ex addr;
+  char addr_buf[128];
+  int rc;
+  int error;
+  bool isconnected;
+  struct SessionHandle *data = conn->data;
+  curl_socket_t sockfd;
+  CURLcode res;
+  const void *iptoprint;
+  struct sockaddr_in * const sa4 = (void *)&addr.sa_addr;
+#ifdef ENABLE_IPV6
+  struct sockaddr_in6 * const sa6 = (void *)&addr.sa_addr;
+#endif
+
+  /*
+   * The Curl_sockaddr_ex structure is basically libcurl's external API
+   * curl_sockaddr structure with enough space available to directly hold
+   * any protocol-specific address structures. The variable declared here
+   * will be used to pass / receive data to/from the fopensocket callback
+   * if this has been set, before that, it is initialized from parameters.
+   */
+
+  addr.family = ai->ai_family;
+  addr.socktype = conn->socktype;
+  addr.protocol = ai->ai_protocol;
+  addr.addrlen = ai->ai_addrlen;
+
+  if(addr.addrlen > sizeof(struct Curl_sockaddr_storage))
+     addr.addrlen = sizeof(struct Curl_sockaddr_storage);
+  memcpy(&addr.sa_addr, ai->ai_addr, addr.addrlen);
+
+  *connected = FALSE; /* default is not connected */
+
+  if(data->set.fopensocket)
+   /*
+    * If the opensocket callback is set, all the destination address
+    * information is passed to the callback. Depending on this information the
+    * callback may opt to abort the connection, this is indicated returning
+    * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
+    * the callback returns a valid socket the destination address information
+    * might have been changed and this 'new' address will actually be used
+    * here to connect.
+    */
+    sockfd = data->set.fopensocket(data->set.opensocket_client,
+                                   CURLSOCKTYPE_IPCXN,
+                                   (struct curl_sockaddr *)&addr);
+  else
+    /* opensocket callback not set, so simply create the socket now */
+    sockfd = socket(addr.family, addr.socktype, addr.protocol);
+
+  if(sockfd == CURL_SOCKET_BAD)
+    /* no socket, no connection */
+    return CURL_SOCKET_BAD;
+
+#if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
+  if (conn->scope && (addr.family == AF_INET6))
+    sa6->sin6_scope_id = conn->scope;
+#endif
+
+  /* FIXME: do we have Curl_printable_address-like with struct sockaddr* as
+     argument? */
+#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
+  if(addr.family == AF_UNIX) {
+    infof(data, "  Trying %s... ",
+          ((const struct sockaddr_un*)(&addr.sa_addr))->sun_path);
+    snprintf(data->info.ip, MAX_IPADR_LEN, "%s",
+             ((const struct sockaddr_un*)(&addr.sa_addr))->sun_path);
+    strcpy(conn->ip_addr_str, data->info.ip);
+  }
+  else
+#endif
+  {
+#ifdef ENABLE_IPV6
+    if(addr.family == AF_INET6) {
+      iptoprint = &sa6->sin6_addr;
+      conn->bits.ipv6 = TRUE;
+    }
+    else
+#endif
+    {
+      iptoprint = &sa4->sin_addr;
+    }
+
+    if(Curl_inet_ntop(addr.family, iptoprint, addr_buf,
+                      sizeof(addr_buf)) != NULL) {
+      infof(data, "  Trying %s... ", addr_buf);
+      snprintf(data->info.ip, MAX_IPADR_LEN, "%s", addr_buf);
+      strcpy(conn->ip_addr_str, data->info.ip);
+    }
+  }
+
+  if(data->set.tcp_nodelay)
+    tcpnodelay(conn, sockfd);
+
+  nosigpipe(conn, sockfd);
+
+  Curl_sndbufset(sockfd);
+
+  if(data->set.fsockopt) {
+    /* activate callback for setting socket options */
+    error = data->set.fsockopt(data->set.sockopt_client,
+                               sockfd,
+                               CURLSOCKTYPE_IPCXN);
+    if(error) {
+      sclose(sockfd); /* close the socket and bail out */
+      return CURL_SOCKET_BAD;
+    }
+  }
+
+  /* possibly bind the local end to an IP, interface or port */
+  res = bindlocal(conn, sockfd, addr.family);
+  if(res) {
+    sclose(sockfd); /* close socket and bail out */
+    return CURL_SOCKET_BAD;
+  }
+
+  /* set socket non-blocking */
+  curlx_nonblock(sockfd, TRUE);
+
+  /* Connect TCP sockets, bind UDP */
+  if(conn->socktype == SOCK_STREAM)
+    rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
+  else
+    rc = 0;
+
+  if(-1 == rc) {
+    error = SOCKERRNO;
+
+    switch (error) {
+    case EINPROGRESS:
+    case EWOULDBLOCK:
+#if defined(EAGAIN)
+#if (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
+#endif
+      rc = waitconnect(conn, 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));
+      data->state.os_errno = 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;
+  }
+
+  isconnected = verifyconnect(sockfd, &error);
+
+  if(!rc && isconnected) {
+    /* 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 {
+    data->state.os_errno = error;
+    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 */
+                          const struct Curl_dns_entry *remotehost,
+                          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;
+  long timeout_per_addr;
+
+  DEBUGASSERT(sockconn);
+  *connected = FALSE; /* default to not connected */
+
+  /* get the timeout left */
+  timeout_ms = Curl_timeleft(conn, &before, TRUE);
+
+  if(timeout_ms < 0) {
+    /* a precaution, no need to continue if time already is up */
+    failf(data, "Connection time-out");
+    return CURLE_OPERATION_TIMEDOUT;
+  }
+  Curl_expire(data, timeout_ms);
+
+  /* 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 = 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_TIMEDOUT;
+    }
+    before = after;
+  }  /* end of connect-to-each-address loop */
+
+  *sockconn = sockfd;    /* the socket descriptor we've connected */
+
+  if(sockfd == CURL_SOCKET_BAD) {
+    /* no good connect was made */
+    failf(data, "couldn't connect to host");
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  /* leave the socket in non-blocking mode */
+
+  /* store the address we use */
+  if(addr)
+    *addr = curr_addr;
+
+  data->info.numconnects++; /* to track the number of connections made */
+
+  return CURLE_OK;
+}
+
+/*
+ * Used to extract socket and connectdata struct for the most recent
+ * transfer on the given SessionHandle.
+ *
+ * The socket 'long' will be -1 in case of failure!
+ */
+CURLcode Curl_getconnectinfo(struct SessionHandle *data,
+                             long *param_longp,
+                             struct connectdata **connp)
+{
+  if((data->state.lastconnect != -1) &&
+     (data->state.connc->connects[data->state.lastconnect] != NULL)) {
+    struct connectdata *c =
+      data->state.connc->connects[data->state.lastconnect];
+    if(connp)
+      /* only store this if the caller cares for it */
+      *connp = c;
+    *param_longp = c->sock[FIRSTSOCKET];
+    /* we have a socket connected, let's determine if the server shut down */
+    /* determine if ssl */
+    if(c->ssl[FIRSTSOCKET].use) {
+      /* use the SSL context */
+      if(!Curl_ssl_check_cxn(c))
+        *param_longp = -1;   /* FIN received */
+    }
+/* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
+#ifdef MSG_PEEK
+    else {
+      /* use the socket */
+      char buf;
+      if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
+              (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
+        *param_longp = -1;   /* FIN received */
+      }
+    }
+#endif
+  }
+  else
+    *param_longp = -1;
+
+  return CURLE_OK;
+}
diff --git a/lib/connect.h b/lib/connect.h
new file mode 100644
index 0000000..36ea4f6
--- /dev/null
+++ b/lib/connect.h
@@ -0,0 +1,71 @@
+#ifndef __CONNECT_H
+#define __CONNECT_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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 "nonblock.h" /* for curlx_nonblock(), formerly Curl_nonblock() */
+
+CURLcode Curl_is_connected(struct connectdata *conn,
+                           int sockindex,
+                           bool *connected);
+
+CURLcode Curl_connecthost(struct connectdata *conn,
+                          const 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? */
+
+/* generic function that returns how much time there's left to run, according
+   to the timeouts set */
+long Curl_timeleft(struct connectdata *conn,
+                   struct timeval *nowp,
+                   bool duringconnect);
+
+#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
+
+/*
+ * Used to extract socket and connectdata struct for the most recent
+ * transfer on the given SessionHandle.
+ *
+ * The socket 'long' will be -1 in case of failure!
+ */
+CURLcode Curl_getconnectinfo(struct SessionHandle *data,
+                             long *param_longp,
+                             struct connectdata **connp);
+
+#ifdef WIN32
+/* When you run a program that uses the Windows Sockets API, you may
+   experience slow performance when you copy data to a TCP server.
+
+   http://support.microsoft.com/kb/823764
+
+   Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
+   Buffer Size
+
+*/
+void Curl_sndbufset(curl_socket_t sockfd);
+#else
+#define Curl_sndbufset(y)
+#endif
+
+#endif
diff --git a/lib/content_encoding.c b/lib/content_encoding.c
new file mode 100644
index 0000000..69aa7bc
--- /dev/null
+++ b/lib/content_encoding.c
@@ -0,0 +1,426 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+#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"
+
+/* Comment this out if zlib is always going to be at least ver. 1.2.0.4
+   (doing so will reduce code size slightly). */
+#define OLD_ZLIB_SUPPORT 1
+
+#define DSIZ CURL_MAX_WRITE_SIZE /* 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 connectdata *conn, z_stream *z)
+{
+  struct SessionHandle *data = conn->data;
+  if(z->msg)
+    failf (data, "Error while processing content unencoding: %s",
+           z->msg);
+  else
+    failf (data, "Error while processing content unencoding: "
+           "Unknown failure within decompression software.");
+
+  return CURLE_BAD_CONTENT_ENCODING;
+}
+
+static CURLcode
+exit_zlib(z_stream *z, zlibInitState *zlib_init, CURLcode result)
+{
+  inflateEnd(z);
+  *zlib_init = ZLIB_UNINIT;
+  return result;
+}
+
+static CURLcode
+inflate_stream(struct connectdata *conn,
+               struct SingleRequest *k)
+{
+  int allow_restart = 1;
+  z_stream *z = &k->z;          /* zlib state structure */
+  uInt nread = z->avail_in;
+  Bytef *orig_in = z->next_in;
+  int status;                   /* zlib status */
+  CURLcode result = CURLE_OK;   /* Curl_client_write status */
+  char *decomp;                 /* Put the decompressed data here. */
+
+  /* Dynamically allocate a buffer for decompression because it's uncommonly
+     large to hold on the stack */
+  decomp = malloc(DSIZ);
+  if(decomp == NULL) {
+    return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
+  }
+
+  /* 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;
+    z->avail_out = DSIZ;
+
+    status = inflate(z, Z_SYNC_FLUSH);
+    if(status == Z_OK || status == Z_STREAM_END) {
+      allow_restart = 0;
+      if(DSIZ - z->avail_out) {
+        result = Curl_client_write(conn, CLIENTWRITE_BODY, decomp,
+                                   DSIZ - z->avail_out);
+        /* if !CURLE_OK, clean up, return */
+        if(result) {
+          free(decomp);
+          return exit_zlib(z, &k->zlib_init, result);
+        }
+      }
+
+      /* Done? clean up, return */
+      if(status == Z_STREAM_END) {
+        free(decomp);
+        if(inflateEnd(z) == Z_OK)
+          return exit_zlib(z, &k->zlib_init, result);
+        else
+          return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+      }
+
+      /* Done with these bytes, exit */
+      if(status == Z_OK && z->avail_in == 0) {
+        free(decomp);
+        return result;
+      }
+    }
+    else if(allow_restart && status == Z_DATA_ERROR) {
+      /* some servers seem to not generate zlib headers, so this is an attempt
+         to fix and continue anyway */
+
+      (void) inflateEnd(z);     /* don't care about the return code */
+      if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
+        free(decomp);
+        return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+      }
+      z->next_in = orig_in;
+      z->avail_in = nread;
+      allow_restart = 0;
+      continue;
+    }
+    else {                      /* Error; exit loop, handle below */
+      free(decomp);
+      return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+    }
+  }
+  /* Will never get here */
+}
+
+CURLcode
+Curl_unencode_deflate_write(struct connectdata *conn,
+                            struct SingleRequest *k,
+                            ssize_t nread)
+{
+  z_stream *z = &k->z;          /* zlib state structure */
+
+  /* Initialize zlib? */
+  if(k->zlib_init == ZLIB_UNINIT) {
+    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(conn, z);
+    k->zlib_init = ZLIB_INIT;
+  }
+
+  /* Set the compressed input when this function is called */
+  z->next_in = (Bytef *)k->str;
+  z->avail_in = (uInt)nread;
+
+  /* Now uncompress the data */
+  return inflate_stream(conn, k);
+}
+
+#ifdef OLD_ZLIB_SUPPORT
+/* 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);
+    data += (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;
+}
+#endif
+
+CURLcode
+Curl_unencode_gzip_write(struct connectdata *conn,
+                         struct SingleRequest *k,
+                         ssize_t nread)
+{
+  z_stream *z = &k->z;          /* zlib state structure */
+
+  /* Initialize zlib? */
+  if(k->zlib_init == ZLIB_UNINIT) {
+    z->zalloc = (alloc_func)Z_NULL;
+    z->zfree = (free_func)Z_NULL;
+    z->opaque = 0;
+    z->next_in = NULL;
+    z->avail_in = 0;
+
+    if(strcmp(zlibVersion(), "1.2.0.4") >= 0) {
+      /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */
+      if(inflateInit2(z, MAX_WBITS+32) != Z_OK) {
+        return process_zlib_error(conn, z);
+      }
+      k->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
+    }
+    else {
+      /* we must parse the gzip header ourselves */
+      if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
+        return process_zlib_error(conn, z);
+      }
+      k->zlib_init = ZLIB_INIT;   /* Initial call state */
+    }
+  }
+
+  if(k->zlib_init == ZLIB_INIT_GZIP) {
+    /* Let zlib handle the gzip decompression entirely */
+    z->next_in = (Bytef *)k->str;
+    z->avail_in = (uInt)nread;
+    /* Now uncompress the data */
+    return inflate_stream(conn, k);
+  }
+
+#ifndef OLD_ZLIB_SUPPORT
+  /* Support for old zlib versions is compiled away and we are running with
+     an old version, so return an error. */
+  return exit_zlib(z, &k->zlib_init, CURLE_FUNCTION_NOT_FOUND);
+
+#else
+  /* 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.
+   *
+   * This is only required with zlib versions < 1.2.0.4 as newer versions
+   * can handle the gzip header themselves.
+   */
+
+  switch (k->zlib_init) {
+  /* Skip over gzip header? */
+  case ZLIB_INIT:
+  {
+    /* 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 = ZLIB_GZIP_INFLATING; /* 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 = ZLIB_GZIP_HEADER;   /* 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(conn, z));
+    }
+
+  }
+  break;
+
+  case ZLIB_GZIP_HEADER:
+  {
+    /* Need more gzip header data state */
+    ssize_t hlen;
+    unsigned char *oldblock = z->next_in;
+
+    z->avail_in += (uInt)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 = ZLIB_GZIP_INFLATING;   /* 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(conn, z));
+    }
+
+  }
+  break;
+
+  case ZLIB_GZIP_INFLATING:
+  default:
+    /* Inflating stream state */
+    z->next_in = (Bytef *)k->str;
+    z->avail_in = (uInt)nread;
+    break;
+  }
+
+  if(z->avail_in == 0) {
+    /* We don't have any data to inflate; wait until next time */
+    return CURLE_OK;
+  }
+
+  /* We've parsed the header, now uncompress the data */
+  return inflate_stream(conn, k);
+#endif
+}
+
+void Curl_unencode_cleanup(struct connectdata *conn)
+{
+  struct SessionHandle *data = conn->data;
+  struct SingleRequest *k = &data->req;
+  z_stream *z = &k->z;
+  if(k->zlib_init != ZLIB_UNINIT)
+    (void) exit_zlib(z, &k->zlib_init, CURLE_OK);
+}
+
+#endif /* HAVE_LIBZ */
diff --git a/lib/content_encoding.h b/lib/content_encoding.h
new file mode 100644
index 0000000..3aff9d3
--- /dev/null
+++ b/lib/content_encoding.h
@@ -0,0 +1,48 @@
+#ifndef __CURL_CONTENT_ENCODING_H
+#define __CURL_CONTENT_ENCODING_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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"
+
+/*
+ * Comma-separated list all supported Content-Encodings ('identity' is implied)
+ */
+#ifdef HAVE_LIBZ
+#define ALL_CONTENT_ENCODINGS "deflate, gzip"
+/* force a cleanup */
+void Curl_unencode_cleanup(struct connectdata *conn);
+#else
+#define ALL_CONTENT_ENCODINGS "identity"
+#define Curl_unencode_cleanup(x)
+#endif
+
+CURLcode Curl_unencode_deflate_write(struct connectdata *conn,
+                                     struct SingleRequest *req,
+                                     ssize_t nread);
+
+CURLcode
+Curl_unencode_gzip_write(struct connectdata *conn,
+                         struct SingleRequest *k,
+                         ssize_t nread);
+
+
+#endif
diff --git a/lib/cookie.c b/lib/cookie.c
new file mode 100644
index 0000000..21617ad
--- /dev/null
+++ b/lib/cookie.c
@@ -0,0 +1,1135 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+/***
+
+
+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"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+
+#include <stdlib.h>
+#include <string.h>
+
+#define _MPRINTF_REPLACE /* without this on windows OS we get undefined reference to snprintf */
+#include <curl/mprintf.h>
+
+#include "urldata.h"
+#include "cookie.h"
+#include "strequal.h"
+#include "strtok.h"
+#include "sendf.h"
+#include "curl_memory.h"
+#include "share.h"
+#include "strtoofft.h"
+#include "rawstr.h"
+#include "curl_memrchr.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+
+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);
+  if(co->maxage)
+    free(co->maxage);
+  if(co->version)
+    free(co->version);
+
+  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)Curl_raw_equal(little, bigone+biglen-littlelen);
+}
+
+/*
+ * Load cookies from all given cookie files (CURLOPT_COOKIEFILE).
+ */
+void Curl_cookie_loadfiles(struct SessionHandle *data)
+{
+  struct curl_slist *list = data->change.cookielist;
+  if(list) {
+    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! */
+  }
+}
+
+/*
+ * strstore() makes a strdup() on the 'newstr' and if '*str' is non-NULL
+ * that will be freed before the allocated string is stored there.
+ *
+ * It is meant to easily replace strdup()
+ */
+static void strstore(char **str, const char *newstr)
+{
+  if(*str)
+    free(*str);
+  *str = strdup(newstr);
+}
+
+
+/****************************************************************************
+ *
+ * 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 */
+                const char *domain, /* default domain */
+                const char *path)   /* full path used when this cookie is set,
+                                       used to get default path for the cookie
+                                       unless set */
+{
+  struct Cookie *clist;
+  char name[MAX_NAME];
+  struct Cookie *co;
+  struct Cookie *lastc=NULL;
+  time_t now = time(NULL);
+  bool replace_old = FALSE;
+  bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
+
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+  (void)data;
+#endif
+
+  /* First, alloc and init a new struct for it */
+  co = calloc(1, sizeof(struct Cookie));
+  if(!co)
+    return NULL; /* bail out if we're this low on memory */
+
+  if(httpheader) {
+    /* This line was read off a HTTP-header */
+    const char *ptr;
+    const char *sep;
+    const char *semiptr;
+    char *what;
+
+    what = malloc(MAX_COOKIE_LINE);
+    if(!what) {
+      free(co);
+      return NULL;
+    }
+
+    semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
+
+    while(*lineptr && ISBLANK(*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. We use strstore() below to properly
+             deal with received cookie headers that have the same string
+             property set more than once, and then we use the last one. */
+
+          const char *whatptr;
+
+          /* Strip off trailing whitespace from the 'what' */
+          size_t len=strlen(what);
+          while(len && ISBLANK(what[len-1])) {
+            what[len-1]=0;
+            len--;
+          }
+
+          /* Skip leading whitespace from the 'what' */
+          whatptr=what;
+          while(*whatptr && ISBLANK(*whatptr)) {
+            whatptr++;
+          }
+
+          if(Curl_raw_equal("path", name)) {
+            strstore(&co->path, whatptr);
+            if(!co->path) {
+              badcookie = TRUE; /* out of memory bad */
+              break;
+            }
+          }
+          else if(Curl_raw_equal("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++;
+                strstore(&co->domain, 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(Curl_raw_equal("version", name)) {
+            strstore(&co->version, whatptr);
+            if(!co->version) {
+              badcookie = TRUE;
+              break;
+            }
+          }
+          else if(Curl_raw_equal("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.
+
+             */
+            strstore(&co->maxage, whatptr);
+            if(!co->maxage) {
+              badcookie = TRUE;
+              break;
+            }
+            co->expires =
+              atoi((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0]) +
+              (long)now;
+          }
+          else if(Curl_raw_equal("expires", name)) {
+            strstore(&co->expirestr, whatptr);
+            if(!co->expirestr) {
+              badcookie = TRUE;
+              break;
+            }
+            /* Note that if the date couldn't get parsed for whatever reason,
+               the cookie will be treated as a session cookie */
+            co->expires = curl_getdate(what, &now);
+
+            /* Session cookies have expires set to 0 so if we get that back
+               from the date parser let's add a second to make it a
+               non-session cookie */
+            if (co->expires == 0)
+              co->expires = 1;
+            else if( co->expires < 0 )
+                co->expires = 0;
+          }
+          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(Curl_raw_equal("secure", what)) {
+            co->secure = TRUE;
+          }
+          else if (Curl_raw_equal("httponly", what)) {
+            co->httponly = 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 && ISBLANK(*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.
+         Note that the passed-in path to this function MAY have a '?' and
+         following part that MUST not be stored as part of the path. */
+      char *queryp = strchr(path, '?');
+
+      /* queryp is where the interesting part of the path ends, so now we
+         want to the find the last */
+      char *endslash;
+      if(!queryp)
+        endslash = strrchr(path, '/');
+      else
+        endslash = memrchr(path, '/', (size_t)(queryp - path));
+      if(endslash) {
+        size_t pathlen = (size_t)(endslash-path+1); /* include 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 *ptr;
+    char *firstptr;
+    char *tok_buf=NULL;
+    int fields;
+
+    /* IE introduced HTTP-only cookies to prevent XSS attacks. Cookies
+       marked with httpOnly after the domain name are not accessible
+       from javascripts, but since curl does not operate at javascript
+       level, we include them anyway. In Firefox's cookie files, these
+       lines are preceeded with #HttpOnly_ and then everything is
+       as usual, so we skip 10 characters of the line..
+    */
+    if (strncmp(lineptr, "#HttpOnly_", 10) == 0) {
+      lineptr += 10;
+      co->httponly = TRUE;
+    }
+
+    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)Curl_raw_equal(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)Curl_raw_equal(ptr, "TRUE");
+        break;
+      case 4:
+        co->expires = curlx_strtoofft(ptr, NULL, 10);
+        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(Curl_raw_equal(clist->name, co->name)) {
+      /* the names are identical */
+
+      if(clist->domain && co->domain) {
+        if(Curl_raw_equal(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(Curl_raw_equal(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 */
+        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 %" FORMAT_OFF_T "\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,
+                                    const 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 = 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 if(file && !*file) {
+    /* points to a "" string */
+    fp = NULL;
+  }
+  else
+    fp = file?fopen(file, "r"):NULL;
+
+  c->newsession = newsession; /* new session? */
+
+  if(fp) {
+    char *lineptr;
+    bool headerline;
+
+    char *line = 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 && ISBLANK(*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;
+}
+
+/* sort this so that the longest path gets before the shorter path */
+static int cookie_sort(const void *p1, const void *p2)
+{
+  struct Cookie *c1 = *(struct Cookie **)p1;
+  struct Cookie *c2 = *(struct Cookie **)p2;
+
+  size_t l1 = c1->path?strlen(c1->path):0;
+  size_t l2 = c2->path?strlen(c2->path):0;
+
+  return (l2 > l1) ? 1 : (l2 < l1) ? -1 : 0 ;
+}
+
+/*****************************************************************************
+ *
+ * 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,
+                                   const char *host, const char *path,
+                                   bool secure)
+{
+  struct Cookie *newco;
+  struct Cookie *co;
+  time_t now = time(NULL);
+  struct Cookie *mainco=NULL;
+  size_t matches = 0;
+
+  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 || (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 && Curl_raw_equal(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 ||
+           /* not using checkprefix() because matching should be
+              case-sensitive */
+           !strncmp(co->path, path, strlen(co->path)) ) {
+
+          /* and now, we know this is a match and we should create an
+             entry for the return-linked-list */
+
+          newco = 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;
+
+            matches++;
+          }
+          else {
+            fail:
+            /* failure, clear up the allocated chain and return NULL */
+            while(mainco) {
+              co = mainco->next;
+              free(mainco);
+              mainco = co;
+            }
+
+            return NULL;
+          }
+        }
+      }
+    }
+    co = co->next;
+  }
+
+  if(matches) {
+    /* Now we need to make sure that if there is a name appearing more than
+       once, the longest specified path version comes first. To make this
+       the swiftest way, we just sort them all based on path length. */
+    struct Cookie **array;
+    size_t i;
+
+    /* alloc an array and store all cookie pointers */
+    array = (struct Cookie **)malloc(sizeof(struct Cookie *) * matches);
+    if(!array)
+      goto fail;
+
+    co = mainco;
+
+    for(i=0; co; co = co->next)
+      array[i++] = co;
+
+    /* now sort the cookie pointers in path lenth order */
+    qsort(array, matches, sizeof(struct Cookie *), cookie_sort);
+
+    /* remake the linked list order according to the new order */
+
+    mainco = array[0]; /* start here */
+    for(i=0; i<matches-1; i++)
+      array[i]->next = array[i+1];
+    array[matches-1]->next = NULL; /* terminate the list */
+
+    free(array); /* remove the temporary data again */
+  }
+
+  return mainco; /* return the new list */
+}
+
+/*****************************************************************************
+ *
+ * Curl_cookie_clearall()
+ *
+ * Clear all existing cookies and reset the counter.
+ *
+ ****************************************************************************/
+void Curl_cookie_clearall(struct CookieInfo *cookies)
+{
+  if(cookies) {
+    Curl_cookie_freelist(cookies->cookies, TRUE);
+    cookies->cookies = NULL;
+    cookies->numcookies = 0;
+  }
+}
+
+/*****************************************************************************
+ *
+ * Curl_cookie_freelist()
+ *
+ * Free a list of cookies previously returned by Curl_cookie_getlist();
+ *
+ * The 'cookiestoo' argument tells this function whether to just free the
+ * list or actually also free all cookies within the list as well.
+ *
+ ****************************************************************************/
+
+void Curl_cookie_freelist(struct Cookie *co, bool cookiestoo)
+{
+  struct Cookie *next;
+  if(co) {
+    while(co) {
+      next = co->next;
+      if(cookiestoo)
+        freecookie(co);
+      else
+        free(co); /* we only free the struct since the "members" are all just
+                     pointed out in the main cookie list! */
+      co = next;
+    }
+  }
+}
+
+
+/*****************************************************************************
+ *
+ * Curl_cookie_clearsess()
+ *
+ * Free all session cookies in the cookies list.
+ *
+ ****************************************************************************/
+void Curl_cookie_clearsess(struct CookieInfo *cookies)
+{
+  struct Cookie *first, *curr, *next, *prev = NULL;
+
+  if(!cookies || !cookies->cookies)
+    return;
+
+  first = curr = prev = cookies->cookies;
+
+  for(; curr; curr = next) {
+    next = curr->next;
+    if(!curr->expires) {
+      if(first == curr)
+        first = next;
+
+      if(prev == curr)
+        prev = next;
+      else
+        prev->next = next;
+
+      freecookie(curr);
+      cookies->numcookies--;
+    }
+    else
+      prev = curr;
+  }
+
+  cookies->cookies = first;
+}
+
+
+/*****************************************************************************
+ *
+ * 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 */
+  }
+}
+
+/* get_netscape_format()
+ *
+ * Formats a string for Netscape output file, w/o a newline at the end.
+ *
+ * Function returns a char * to a formatted line. Has to be free()d
+*/
+static char *get_netscape_format(const struct Cookie *co)
+{
+  return aprintf(
+    "%s"     /* httponly preamble */
+    "%s%s\t" /* domain */
+    "%s\t"   /* tailmatch */
+    "%s\t"   /* path */
+    "%s\t"   /* secure */
+    "%" FORMAT_OFF_T "\t"   /* expires */
+    "%s\t"   /* name */
+    "%s",    /* value */
+    co->httponly?"#HttpOnly_":"",
+    /* 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",
+    co->expires,
+    co->name,
+    co->value?co->value:"");
+}
+
+/*
+ * 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, const 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) {
+    char *format_ptr;
+
+    fputs("# Netscape HTTP Cookie File\n"
+          "# http://curl.haxx.se/rfc/cookie_spec.html\n"
+          "# This file was generated by libcurl! Edit at your own risk.\n\n",
+          out);
+    co = c->cookies;
+
+    while(co) {
+      format_ptr = get_netscape_format(co);
+      if(format_ptr == NULL) {
+        fprintf(out, "#\n# Fatal libcurl error\n");
+        if(!use_stdout)
+          fclose(out);
+        return 1;
+      }
+      fprintf(out, "%s\n", format_ptr);
+      free(format_ptr);
+      co=co->next;
+    }
+  }
+
+  if(!use_stdout)
+    fclose(out);
+
+  return 0;
+}
+
+struct curl_slist *Curl_cookie_list(struct SessionHandle *data)
+{
+  struct curl_slist *list = NULL;
+  struct curl_slist *beg;
+  struct Cookie *c;
+  char *line;
+
+  if((data->cookies == NULL) ||
+      (data->cookies->numcookies == 0))
+    return NULL;
+
+  c = data->cookies->cookies;
+
+  beg = list;
+  while(c) {
+    /* fill the list with _all_ the cookies we know */
+    line = get_netscape_format(c);
+    if(line == NULL) {
+      curl_slist_free_all(beg);
+      return NULL;
+    }
+    list = curl_slist_append(list, line);
+    free(line);
+    if(list == NULL) {
+      curl_slist_free_all(beg);
+      return NULL;
+    }
+    else if(beg == NULL) {
+      beg = list;
+    }
+    c = c->next;
+  }
+
+  return list;
+}
+
+#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */
diff --git a/lib/cookie.h b/lib/cookie.h
new file mode 100644
index 0000000..e8c005f
--- /dev/null
+++ b/lib/cookie.h
@@ -0,0 +1,108 @@
+#ifndef __COOKIE_H
+#define __COOKIE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2008, 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 <stdio.h>
+#if defined(WIN32)
+#include <time.h>
+#else
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#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> */
+  curl_off_t 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 */
+  bool httponly;     /* true if the httponly directive is present */
+};
+
+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 *lineptr,
+                               const char *domain, const char *path);
+
+struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
+                                    const char *, struct CookieInfo *, bool);
+struct Cookie *Curl_cookie_getlist(struct CookieInfo *, const char *,
+                                   const char *, bool);
+void Curl_cookie_freelist(struct Cookie *cookies, bool cookiestoo);
+void Curl_cookie_clearall(struct CookieInfo *cookies);
+void Curl_cookie_clearsess(struct CookieInfo *cookies);
+void Curl_cookie_cleanup(struct CookieInfo *);
+int Curl_cookie_output(struct CookieInfo *, const char *);
+
+#if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_COOKIES)
+#define Curl_cookie_list(x) NULL
+#define Curl_cookie_loadfiles(x) do { } while (0)
+#else
+struct curl_slist *Curl_cookie_list(struct SessionHandle *data);
+void Curl_cookie_loadfiles(struct SessionHandle *data);
+#endif
+
+#endif
diff --git a/lib/curl_addrinfo.c b/lib/curl_addrinfo.c
new file mode 100644
index 0000000..c38a1ed
--- /dev/null
+++ b/lib/curl_addrinfo.c
@@ -0,0 +1,482 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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>
+
+#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 __VMS
+#  include <in.h>
+#  include <inet.h>
+#  include <stdlib.h>
+#endif
+
+#if defined(NETWARE) && defined(__NOVELL_LIBC__)
+#  undef  in_addr_t
+#  define in_addr_t unsigned long
+#endif
+
+#include "curl_addrinfo.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+
+/*
+ * Curl_freeaddrinfo()
+ *
+ * This is used to free a linked list of Curl_addrinfo structs along
+ * with all its associated allocated storage. This function should be
+ * called once for each successful call to Curl_getaddrinfo_ex() or to
+ * any function call which actually allocates a Curl_addrinfo struct.
+ */
+
+#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
+    defined(__OPTIMIZE__) && defined(__unix__) &&  defined(__i386__)
+  /* workaround icc 9.1 optimizer issue */
+# define vqualifier volatile
+#else
+# define vqualifier
+#endif
+
+void
+Curl_freeaddrinfo(Curl_addrinfo *cahead)
+{
+  Curl_addrinfo *vqualifier canext;
+  Curl_addrinfo *ca;
+
+  for(ca = cahead; ca != NULL; ca = canext) {
+
+    if(ca->ai_addr)
+      free(ca->ai_addr);
+
+    if(ca->ai_canonname)
+      free(ca->ai_canonname);
+
+    canext = ca->ai_next;
+
+    free(ca);
+  }
+}
+
+
+#ifdef HAVE_GETADDRINFO
+/*
+ * Curl_getaddrinfo_ex()
+ *
+ * This is a wrapper function around system's getaddrinfo(), with
+ * the only difference that instead of returning a linked list of
+ * addrinfo structs this one returns a linked list of Curl_addrinfo
+ * ones. The memory allocated by this function *MUST* be free'd with
+ * Curl_freeaddrinfo().  For each successful call to this function
+ * there must be an associated call later to Curl_freeaddrinfo().
+ *
+ * There should be no single call to system's getaddrinfo() in the
+ * whole library, any such call should be 'routed' through this one.
+ */
+
+int
+Curl_getaddrinfo_ex(const char *nodename,
+                    const char *servname,
+                    const struct addrinfo *hints,
+                    Curl_addrinfo **result)
+{
+  const struct addrinfo *ainext;
+  const struct addrinfo *ai;
+  struct addrinfo *aihead;
+  Curl_addrinfo *cafirst = NULL;
+  Curl_addrinfo *calast = NULL;
+  Curl_addrinfo *ca;
+  int error;
+
+  *result = NULL; /* assume failure */
+
+  error = getaddrinfo(nodename, servname, hints, &aihead);
+  if(error)
+    return error;
+
+  for(ai = aihead; ai != NULL; ai = ainext) {
+
+    if((ca = malloc(sizeof(Curl_addrinfo))) == NULL) {
+      error = EAI_MEMORY;
+      break;
+    }
+
+    /* copy each structure member individually, member ordering, */
+    /* size, or padding might be different for each structure.   */
+
+    ca->ai_flags     = ai->ai_flags;
+    ca->ai_family    = ai->ai_family;
+    ca->ai_socktype  = ai->ai_socktype;
+    ca->ai_protocol  = ai->ai_protocol;
+    ca->ai_addrlen   = 0;
+    ca->ai_addr      = NULL;
+    ca->ai_canonname = NULL;
+    ca->ai_next      = NULL;
+
+    if((ai->ai_addrlen > 0) && (ai->ai_addr != NULL)) {
+      ca->ai_addrlen  = ai->ai_addrlen;
+      if((ca->ai_addr = malloc(ca->ai_addrlen)) == NULL) {
+        error = EAI_MEMORY;
+        free(ca);
+        break;
+      }
+      memcpy(ca->ai_addr, ai->ai_addr, ca->ai_addrlen);
+    }
+
+    if(ai->ai_canonname != NULL) {
+      if((ca->ai_canonname = strdup(ai->ai_canonname)) == NULL) {
+        error = EAI_MEMORY;
+        if(ca->ai_addr)
+          free(ca->ai_addr);
+        free(ca);
+        break;
+      }
+    }
+
+    /* if the return list is empty, this becomes the first element */
+    if(!cafirst)
+      cafirst = ca;
+
+    /* add this element last in the return list */
+    if(calast)
+      calast->ai_next = ca;
+    calast = ca;
+
+    /* fetch next element fom the addrinfo list */
+    ainext = ai->ai_next;
+  }
+
+  /* destroy the addrinfo list */
+  if(aihead)
+    freeaddrinfo(aihead);
+
+  /* if we failed, also destroy the Curl_addrinfo list */
+  if(error) {
+    Curl_freeaddrinfo(cafirst);
+    cafirst = NULL;
+  }
+
+  *result = cafirst;
+
+  /* This is not a CURLcode */
+  return error;
+}
+#endif /* HAVE_GETADDRINFO */
+
+
+/*
+ * Curl_he2ai()
+ *
+ * This function returns a pointer to the first element of a newly allocated
+ * Curl_addrinfo struct linked list filled with the data of a given hostent.
+ * Curl_addrinfo is meant to work like the addrinfo struct does for a IPv6
+ * stack, but usable also for IPv4, all hosts and environments.
+ *
+ * The memory allocated by this function *MUST* be free'd later on calling
+ * Curl_freeaddrinfo().  For each successful call to this function there
+ * must be an associated call later to Curl_freeaddrinfo().
+ *
+ *   Curl_addrinfo defined in "lib/curl_addrinfo.h"
+ *
+ *     struct Curl_addrinfo {
+ *       int                   ai_flags;
+ *       int                   ai_family;
+ *       int                   ai_socktype;
+ *       int                   ai_protocol;
+ *       curl_socklen_t        ai_addrlen;   * Follow rfc3493 struct addrinfo *
+ *       char                 *ai_canonname;
+ *       struct sockaddr      *ai_addr;
+ *       struct Curl_addrinfo *ai_next;
+ *     };
+ *     typedef struct Curl_addrinfo Curl_addrinfo;
+ *
+ *   hostent defined in <netdb.h>
+ *
+ *     struct hostent {
+ *       char    *h_name;
+ *       char    **h_aliases;
+ *       int     h_addrtype;
+ *       int     h_length;
+ *       char    **h_addr_list;
+ *     };
+ *
+ *   for backward compatibility:
+ *
+ *     #define h_addr  h_addr_list[0]
+ */
+
+Curl_addrinfo *
+Curl_he2ai(const struct hostent *he, int port)
+{
+  Curl_addrinfo *ai;
+  Curl_addrinfo *prevai = NULL;
+  Curl_addrinfo *firstai = NULL;
+  struct sockaddr_in *addr;
+#ifdef ENABLE_IPV6
+  struct sockaddr_in6 *addr6;
+#endif
+  CURLcode result = CURLE_OK;
+  int i;
+  char *curr;
+
+  if(!he)
+    /* no input == no output! */
+    return NULL;
+
+  DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL));
+
+  for(i=0; (curr = he->h_addr_list[i]) != NULL; i++) {
+
+    size_t ss_size;
+#ifdef ENABLE_IPV6
+    if (he->h_addrtype == AF_INET6)
+      ss_size = sizeof (struct sockaddr_in6);
+    else
+#endif
+      ss_size = sizeof (struct sockaddr_in);
+
+    if((ai = calloc(1, sizeof(Curl_addrinfo))) == NULL) {
+      result = CURLE_OUT_OF_MEMORY;
+      break;
+    }
+    if((ai->ai_canonname = strdup(he->h_name)) == NULL) {
+      result = CURLE_OUT_OF_MEMORY;
+      free(ai);
+      break;
+    }
+    if((ai->ai_addr = calloc(1, ss_size)) == NULL) {
+      result = CURLE_OUT_OF_MEMORY;
+      free(ai->ai_canonname);
+      free(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 = he->h_addrtype;
+
+    /* we return all names as STREAM, so when using this address for TFTP
+       the type must be ignored and conn->socktype be used instead! */
+    ai->ai_socktype = SOCK_STREAM;
+
+    ai->ai_addrlen = (curl_socklen_t)ss_size;
+
+    /* leave the rest of the struct filled with zero */
+
+    switch (ai->ai_family) {
+    case AF_INET:
+      addr = (void *)ai->ai_addr; /* storage area for this info */
+
+      memcpy(&addr->sin_addr, curr, sizeof(struct in_addr));
+      addr->sin_family = (unsigned short)(he->h_addrtype);
+      addr->sin_port = htons((unsigned short)port);
+      break;
+
+#ifdef ENABLE_IPV6
+    case AF_INET6:
+      addr6 = (void *)ai->ai_addr; /* storage area for this info */
+
+      memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr));
+      addr6->sin6_family = (unsigned short)(he->h_addrtype);
+      addr6->sin6_port = htons((unsigned short)port);
+      break;
+#endif
+    }
+
+    prevai = ai;
+  }
+
+  if(result != CURLE_OK) {
+    Curl_freeaddrinfo(firstai);
+    firstai = NULL;
+  }
+
+  return firstai;
+}
+
+
+struct namebuff {
+  struct hostent hostentry;
+  union {
+    struct in_addr  ina4;
+#ifdef ENABLE_IPV6
+    struct in6_addr ina6;
+#endif
+  } addrentry;
+  char *h_addr_list[2];
+};
+
+
+/*
+ * Curl_ip2addr()
+ *
+ * This function takes an internet address, in binary form, as input parameter
+ * along with its address family and the string version of the address, and it
+ * returns a Curl_addrinfo chain filled in correctly with information for the
+ * given address/host
+ */
+
+Curl_addrinfo *
+Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
+{
+  Curl_addrinfo *ai;
+
+#if defined(__VMS) && \
+    defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
+#pragma pointer_size save
+#pragma pointer_size short
+#pragma message disable PTRMISMATCH
+#endif
+
+  struct hostent  *h;
+  struct namebuff *buf;
+  char  *addrentry;
+  char  *hoststr;
+  size_t addrsize;
+
+  DEBUGASSERT(inaddr && hostname);
+
+  buf = malloc(sizeof(struct namebuff));
+  if(!buf)
+    return NULL;
+
+  hoststr = strdup(hostname);
+  if(!hoststr) {
+    free(buf);
+    return NULL;
+  }
+
+  switch(af) {
+  case AF_INET:
+    addrsize = sizeof(struct in_addr);
+    addrentry = (void *)&buf->addrentry.ina4;
+    memcpy(addrentry, inaddr, sizeof(struct in_addr));
+    break;
+#ifdef ENABLE_IPV6
+  case AF_INET6:
+    addrsize = sizeof(struct in6_addr);
+    addrentry = (void *)&buf->addrentry.ina6;
+    memcpy(addrentry, inaddr, sizeof(struct in6_addr));
+    break;
+#endif
+  default:
+    free(hoststr);
+    free(buf);
+    return NULL;
+  }
+
+  h = &buf->hostentry;
+  h->h_name = hoststr;
+  h->h_aliases = NULL;
+  h->h_addrtype = (short)af;
+  h->h_length = (short)addrsize;
+  h->h_addr_list = &buf->h_addr_list[0];
+  h->h_addr_list[0] = addrentry;
+  h->h_addr_list[1] = NULL; /* terminate list of entries */
+
+#if defined(__VMS) && \
+    defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
+#pragma pointer_size restore
+#pragma message enable PTRMISMATCH
+#endif
+
+  ai = Curl_he2ai(h, port);
+
+  free(hoststr);
+  free(buf);
+
+  return ai;
+}
+
+
+#if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO)
+/*
+ * curl_dofreeaddrinfo()
+ *
+ * This is 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
+ */
+
+void
+curl_dofreeaddrinfo(struct addrinfo *freethis,
+                    int line, const char *source)
+{
+  (freeaddrinfo)(freethis);
+  curl_memlog("ADDR %s:%d freeaddrinfo(%p)\n",
+              source, line, (void *)freethis);
+}
+#endif /* defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) */
+
+
+#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO)
+/*
+ * curl_dogetaddrinfo()
+ *
+ * This is 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(const char *hostname,
+                   const char *service,
+                   const struct addrinfo *hints,
+                   struct addrinfo **result,
+                   int line, const char *source)
+{
+  int res=(getaddrinfo)(hostname, service, hints, result);
+  if(0 == res)
+    /* success */
+    curl_memlog("ADDR %s:%d getaddrinfo() = %p\n",
+                source, line, (void *)*result);
+  else
+    curl_memlog("ADDR %s:%d getaddrinfo() failed\n",
+                source, line);
+  return res;
+}
+#endif /* defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) */
+
diff --git a/lib/curl_addrinfo.h b/lib/curl_addrinfo.h
new file mode 100644
index 0000000..63159cc
--- /dev/null
+++ b/lib/curl_addrinfo.h
@@ -0,0 +1,98 @@
+#ifndef HEADER_CURL_ADDRINFO_H
+#define HEADER_CURL_ADDRINFO_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+#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 __VMS
+#  include <in.h>
+#  include <inet.h>
+#  include <stdlib.h>
+#endif
+
+
+/*
+ * Curl_addrinfo is our internal struct definition that we use to allow
+ * consistent internal handling of this data. We use this even when the
+ * system provides an addrinfo structure definition. And we use this for
+ * all sorts of IPv4 and IPV6 builds.
+ */
+
+struct Curl_addrinfo {
+  int                   ai_flags;
+  int                   ai_family;
+  int                   ai_socktype;
+  int                   ai_protocol;
+  curl_socklen_t        ai_addrlen;   /* Follow rfc3493 struct addrinfo */
+  char                 *ai_canonname;
+  struct sockaddr      *ai_addr;
+  struct Curl_addrinfo *ai_next;
+};
+typedef struct Curl_addrinfo Curl_addrinfo;
+
+void
+Curl_freeaddrinfo(Curl_addrinfo *cahead);
+
+#ifdef HAVE_GETADDRINFO
+int
+Curl_getaddrinfo_ex(const char *nodename,
+                    const char *servname,
+                    const struct addrinfo *hints,
+                    Curl_addrinfo **result);
+#endif
+
+Curl_addrinfo *
+Curl_he2ai(const struct hostent *he, int port);
+
+Curl_addrinfo *
+Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port);
+
+#if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO)
+void
+curl_dofreeaddrinfo(struct addrinfo *freethis,
+                    int line, const char *source);
+#endif
+
+#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO)
+int
+curl_dogetaddrinfo(const char *hostname,
+                   const char *service,
+                   const struct addrinfo *hints,
+                   struct addrinfo **result,
+                   int line, const char *source);
+#endif
+
+#endif /* HEADER_CURL_ADDRINFO_H */
diff --git a/lib/curl_base64.h b/lib/curl_base64.h
new file mode 100644
index 0000000..2498a0a
--- /dev/null
+++ b/lib/curl_base64.h
@@ -0,0 +1,31 @@
+#ifndef HEADER_CURL_BASE64_H
+#define HEADER_CURL_BASE64_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+size_t Curl_base64_encode(struct SessionHandle *data,
+                          const char *inputbuff, size_t insize,
+                          char **outptr);
+
+size_t Curl_base64_decode(const char *src, unsigned char **outptr);
+
+#endif /* HEADER_CURL_BASE64_H */
diff --git a/lib/curl_config.h b/lib/curl_config.h
new file mode 100644
index 0000000..0a0e626
--- /dev/null
+++ b/lib/curl_config.h
@@ -0,0 +1,986 @@
+/* lib/curl_config.h.  Generated from curl_config.h.in by configure.  */
+/* lib/curl_config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* when building libcurl itself */
+/* #undef BUILDING_LIBCURL */
+
+/* Location of default ca bundle */
+#define CURL_CA_BUNDLE "/etc/ssl/certs/ca-certificates.crt"
+
+/* Location of default ca path */
+/* #undef CURL_CA_PATH */
+
+/* to disable cookies support */
+/* #undef CURL_DISABLE_COOKIES */
+
+/* to disable cryptographic authentication */
+/* #undef CURL_DISABLE_CRYPTO_AUTH */
+
+/* to disable DICT */
+/* #undef CURL_DISABLE_DICT */
+
+/* to disable FILE */
+/* #undef CURL_DISABLE_FILE */
+
+/* to disable FTP */
+/* #undef CURL_DISABLE_FTP */
+
+/* to disable HTTP */
+/* #undef CURL_DISABLE_HTTP */
+
+/* to disable IMAP */
+/* #undef CURL_DISABLE_IMAP */
+
+/* to disable LDAP */
+#define CURL_DISABLE_LDAP 1
+
+/* to disable LDAPS */
+#define CURL_DISABLE_LDAPS 1
+
+/* to disable POP3 */
+/* #undef CURL_DISABLE_POP3 */
+
+/* to disable proxies */
+/* #undef CURL_DISABLE_PROXY */
+
+/* to disable RTSP */
+/* #undef CURL_DISABLE_RTSP */
+
+/* to disable SMTP */
+/* #undef CURL_DISABLE_SMTP */
+
+/* to disable TELNET */
+/* #undef CURL_DISABLE_TELNET */
+
+/* to disable TFTP */
+/* #undef CURL_DISABLE_TFTP */
+
+/* to disable verbose strings */
+/* #undef CURL_DISABLE_VERBOSE_STRINGS */
+
+/* to make a symbol visible */
+/* #undef CURL_EXTERN_SYMBOL */
+
+/* to enable hidden symbols */
+/* #undef CURL_HIDDEN_SYMBOLS */
+
+/* W$ LDAP with non-W$ compiler */
+/* #undef CURL_LDAP_HYBRID */
+
+/* Use W$ LDAP implementation */
+/* #undef CURL_LDAP_WIN */
+
+/* when not building a shared library */
+/* #undef CURL_STATICLIB */
+
+/* your Entropy Gathering Daemon socket pathname */
+/* #undef EGD_SOCKET */
+
+/* Define if you want to enable IPv6 support */
+#define ENABLE_IPV6 1
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 socklen_t
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 unsigned int
+
+/* Specifies the number of arguments to getservbyport_r */
+#define GETSERVBYPORT_R_ARGS 6
+
+/* Specifies the size of the buffer to pass to getservbyport_r */
+#define GETSERVBYPORT_R_BUFSIZE 4096
+
+/* Define to 1 if you have the alarm function. */
+#define HAVE_ALARM 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 <arpa/tftp.h> header file. */
+#define HAVE_ARPA_TFTP_H 1
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the basename function. */
+#define HAVE_BASENAME 1
+
+/* Define to 1 if bool is an available type. */
+#define HAVE_BOOL_T 1
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+#define HAVE_CLOCK_GETTIME_MONOTONIC 1
+
+/* Define to 1 if you have the closesocket function. */
+/* #undef HAVE_CLOSESOCKET */
+
+/* Define to 1 if you have the CloseSocket camel case function. */
+/* #undef HAVE_CLOSESOCKET_CAMEL */
+
+/* Define to 1 if you have the connect function. */
+#define HAVE_CONNECT 1
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+#define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1
+
+/* 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 */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `ENGINE_cleanup' function. */
+//#define HAVE_ENGINE_CLEANUP 1
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+//#define HAVE_ENGINE_LOAD_BUILTIN_ENGINES 1
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <err.h> header file. */
+/* #undef HAVE_ERR_H */
+
+/* Define to 1 if you have the fcntl function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#define HAVE_FCNTL_O_NONBLOCK 1
+
+/* Define to 1 if you have the fdopen function. */
+#define HAVE_FDOPEN 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#define HAVE_FREEADDRINFO 1
+
+/* Define to 1 if you have the freeifaddrs function. */
+// not in bionic
+//#define HAVE_FREEIFADDRS 1
+
+/* Define to 1 if you have the ftruncate function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if the getaddrinfo function is threadsafe. */
+#define HAVE_GETADDRINFO_THREADSAFE 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
+
+/* gethostbyaddr_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYADDR_R_5 */
+
+/* gethostbyaddr_r() takes 7 args */
+/* #undef HAVE_GETHOSTBYADDR_R_7 */
+
+/* gethostbyaddr_r() takes 8 args */
+#define HAVE_GETHOSTBYADDR_R_8 1
+
+/* Define to 1 if you have the gethostbyname function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the gethostbyname_r function. */
+#define HAVE_GETHOSTBYNAME_R 1
+
+/* gethostbyname_r() takes 3 args */
+/* #undef HAVE_GETHOSTBYNAME_R_3 */
+
+/* gethostbyname_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYNAME_R_5 */
+
+/* gethostbyname_r() takes 6 args */
+#define HAVE_GETHOSTBYNAME_R_6 1
+
+/* Define to 1 if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have a working getifaddrs function. */
+// not in bionic
+//#define HAVE_GETIFADDRS 1
+
+/* Define to 1 if you have the getnameinfo function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getpass_r' function. */
+/* #undef HAVE_GETPASS_R */
+
+/* Define to 1 if you have the `getppid' function. */
+#define HAVE_GETPPID 1
+
+/* Define to 1 if you have the `getprotobyname' function. */
+#define HAVE_GETPROTOBYNAME 1
+
+/* Define to 1 if you have the `getpwuid' function. */
+#define HAVE_GETPWUID 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+#define HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the getservbyport_r function. */
+#define HAVE_GETSERVBYPORT_R 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+/* #undef HAVE_GLIBC_STRERROR_R */
+
+/* Define to 1 if you have a working gmtime_r function. */
+#define HAVE_GMTIME_R 1
+
+/* if you have the gssapi libraries */
+/* #undef HAVE_GSSAPI */
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */
+
+/* if you have the GNU gssapi libraries */
+/* #undef HAVE_GSSGNU */
+
+/* if you have the Heimdal gssapi libraries */
+/* #undef HAVE_GSSHEIMDAL */
+
+/* if you have the MIT gssapi libraries */
+/* #undef HAVE_GSSMIT */
+
+/* Define to 1 if you have the `idna_strerror' function. */
+/* #undef HAVE_IDNA_STRERROR */
+
+/* Define to 1 if you have the `idn_free' function. */
+/* #undef HAVE_IDN_FREE */
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+/* #undef HAVE_IDN_FREE_H */
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+// not in bionic
+// #define HAVE_IFADDRS_H 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_r function. */
+/* #undef HAVE_INET_NTOA_R */
+
+/* inet_ntoa_r() takes 2 args */
+/* #undef HAVE_INET_NTOA_R_2 */
+
+/* inet_ntoa_r() takes 3 args */
+/* #undef HAVE_INET_NTOA_R_3 */
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#define HAVE_INET_PTON 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the ioctl function. */
+// Defined by AndroidConfig.h that is automticaly included in builds
+#undef HAVE_IOCTL
+#define HAVE_IOCTL 1
+
+/* Define to 1 if you have the ioctlsocket function. */
+/* #undef HAVE_IOCTLSOCKET */
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+/* #undef HAVE_IOCTLSOCKET_CAMEL */
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+   */
+/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+/* #undef HAVE_IOCTLSOCKET_FIONBIO */
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+#define HAVE_IOCTL_FIONBIO 1
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+#define HAVE_IOCTL_SIOCGIFADDR 1
+
+/* Define to 1 if you have the <io.h> header file. */
+/* #undef HAVE_IO_H */
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+/* #undef HAVE_KRB4 */
+
+/* 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 lber.h header file. */
+/* #undef HAVE_LBER_H */
+
+/* Define to 1 if you have the ldapssl.h header file. */
+/* #undef HAVE_LDAPSSL_H */
+
+/* Define to 1 if you have the ldap.h header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Use LDAPS implementation */
+/* #undef HAVE_LDAP_SSL */
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+/* #undef HAVE_LDAP_SSL_H */
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+/* #undef HAVE_LDAP_URL_PARSE */
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#define HAVE_LIBGEN_H 1
+
+/* Define to 1 if you have the `idn' library (-lidn). */
+/* #undef HAVE_LIBIDN */
+
+/* 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 `ssh2' library (-lssh2). */
+/* #undef HAVE_LIBSSH2 */
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+/* #undef HAVE_LIBSSH2_H */
+
+/* Define to 1 if you have the `libssh2_version' function. */
+/* #undef HAVE_LIBSSH2_VERSION */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+#define HAVE_LIBSSL 1
+
+/* if zlib is available */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* if your compiler supports LL */
+#define HAVE_LL 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have a working localtime_r function. */
+#define HAVE_LOCALTIME_R 1
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#define HAVE_LONGLONG 1
+
+/* Define to 1 if you have the malloc.h header file. */
+// Defined by AndroidConfig.h that is automticaly included in builds
+#undef HAVE_MALLOC_H
+#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 memrchr function or macro. */
+/* #undef HAVE_MEMRCHR */
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+#define HAVE_MSG_NOSIGNAL 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/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#define HAVE_NETINET_TCP_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if NI_WITHSCOPEID exists and works. */
+/* #undef HAVE_NI_WITHSCOPEID */
+
+/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE
+   */
+/* #undef HAVE_OLD_GSSMIT */
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+#define HAVE_OPENSSL_CRYPTO_H 1
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+//#define HAVE_OPENSSL_ENGINE_H 1
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+#define HAVE_OPENSSL_ERR_H 1
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+#define HAVE_OPENSSL_PEM_H 1
+
+/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
+#define HAVE_OPENSSL_PKCS12_H 1
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+#define HAVE_OPENSSL_RSA_H 1
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+#define HAVE_OPENSSL_SSL_H 1
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+#define HAVE_OPENSSL_X509_H 1
+
+/* 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 `pipe' function. */
+#define HAVE_PIPE 1
+
+/* if you have the function PK11_CreateGenericObject */
+/* #undef HAVE_PK11_CREATEGENERICOBJECT */
+
+/* Define to 1 if you have a working poll function. */
+#define HAVE_POLL 1
+
+/* If you have a fine poll */
+#define HAVE_POLL_FINE 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+#define HAVE_POSIX_STRERROR_R 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. */
+#define HAVE_RAND_EGD 1
+
+/* Define to 1 if you have the `RAND_screen' function. */
+/* #undef HAVE_RAND_SCREEN */
+
+/* Define to 1 if you have the `RAND_status' function. */
+#define HAVE_RAND_STATUS 1
+
+/* Define to 1 if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to 1 if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* 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 send function. */
+#define HAVE_SEND 1
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#define HAVE_SETJMP_H 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `setmode' function. */
+/* #undef HAVE_SETMODE */
+
+/* Define to 1 if you have the `setrlimit' function. */
+#define HAVE_SETRLIMIT 1
+
+/* Define to 1 if you have the setsockopt function. */
+#define HAVE_SETSOCKOPT 1
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */
+
+/* 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 siginterrupt function. */
+#define HAVE_SIGINTERRUPT 1
+
+/* Define to 1 if you have the signal function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+#define HAVE_SIGSETJMP 1
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define to 1 if you have the socket function. */
+#define HAVE_SOCKET 1
+
+/* Define to 1 if you have the <socket.h> header file. */
+/* #undef HAVE_SOCKET_H */
+
+/* Define this if you have the SPNEGO library fbopenssl */
+/* #undef HAVE_SPNEGO */
+
+/* Define to 1 if you have the `SSL_get_shutdown' function. */
+#define HAVE_SSL_GET_SHUTDOWN 1
+
+/* Define to 1 if you have the <ssl.h> header file. */
+/* #undef HAVE_SSL_H */
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#define HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* 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 strcasestr function. */
+/* #undef HAVE_STRCASESTR */
+
+/* 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 strerror_r function. */
+#define HAVE_STRERROR_R 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 strncasecmp function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define to 1 if you have the strncmpi function. */
+/* #undef HAVE_STRNCMPI */
+
+/* Define to 1 if you have the strnicmp function. */
+/* #undef HAVE_STRNICMP */
+
+/* Define to 1 if you have the <stropts.h> header file. */
+// not in bionic
+//#define HAVE_STROPTS_H 1
+
+/* 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 strtoll function. */
+#define HAVE_STRTOLL 1
+
+/* if struct sockaddr_storage is defined */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if you have the timeval struct. */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+/* #undef HAVE_SYS_FILIO_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 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/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_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/uio.h> header file. */
+// Defined by AndroidConfig.h that is automticaly included in builds
+#undef HAVE_SYS_UIO_H
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_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 <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define to 1 if you have the <termio.h> header file. */
+// Defined by AndroidConfig.h that is automticaly included in builds
+#undef HAVE_TERMIO_H
+#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 <tld.h> header file. */
+/* #undef HAVE_TLD_H */
+
+/* Define to 1 if you have the `tld_strerror' function. */
+/* #undef HAVE_TLD_STRERROR */
+
+/* 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 compiler supports C99 variadic macro style. */
+#define HAVE_VARIADIC_MACROS_C99 1
+
+/* Define to 1 if compiler supports old gcc variadic macro style. */
+#define HAVE_VARIADIC_MACROS_GCC 1
+
+/* Define to 1 if you have the winber.h header file. */
+/* #undef HAVE_WINBER_H */
+
+/* Define to 1 if you have the windows.h header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the winldap.h header file. */
+/* #undef HAVE_WINLDAP_H */
+
+/* Define to 1 if you have the winsock2.h header file. */
+/* #undef HAVE_WINSOCK2_H */
+
+/* Define to 1 if you have the winsock.h header file. */
+/* #undef HAVE_WINSOCK_H */
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#define HAVE_WRITABLE_ARGV 1
+
+/* Define to 1 if you have the writev function. */
+#define HAVE_WRITEV 1
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
+/* Define to 1 if you have the <x509.h> header file. */
+/* #undef HAVE_X509_H */
+
+/* if you have the zlib.h header file */
+#define HAVE_ZLIB_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if you are building a native Windows target. */
+/* #undef NATIVE_WINDOWS */
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+/* #undef NEED_LBER_H */
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+/* #undef NEED_MALLOC_H */
+
+/* Define to 1 if you need the memory.h header file even with stdlib.h */
+/* #undef NEED_MEMORY_H */
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+/* #undef NEED_REENTRANT */
+
+/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */
+/* #undef NEED_THREAD_SAFE */
+
+/* cpu-machine-OS */
+#define OS "arm-unknown-eabi"
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "curl"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "curl -"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "curl"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "-"
+
+/* a suitable file to read random data from */
+#define RANDOM_FILE "/dev/urandom"
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 int
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 void
+
+/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */
+#define RECVFROM_TYPE_ARG2_IS_VOID 1
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG5_IS_VOID */
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 socklen_t
+
+/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG6_IS_VOID */
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV ssize_t
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV ssize_t
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to the type qualifier of arg 5 for select. */
+#define SELECT_QUAL_ARG5 
+
+/* Define to the type of arg 1 for select. */
+#define SELECT_TYPE_ARG1 int
+
+/* Define to the type of args 2, 3 and 4 for select. */
+#define SELECT_TYPE_ARG234 fd_set *
+
+/* Define to the type of arg 5 for select. */
+#define SELECT_TYPE_ARG5 struct timeval *
+
+/* Define to the function return type for select. */
+#define SELECT_TYPE_RETV int
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV ssize_t
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* The size of `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 8
+
+/* The size of `time_t', as computed by sizeof. */
+#define SIZEOF_TIME_T 8
+
+/* The size of `void*', as computed by sizeof. */
+#define SIZEOF_VOIDP 8
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to the type of arg 3 for strerror_r. */
+#define STRERROR_R_TYPE_ARG3 size_t
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define to enable c-ares support */
+/* #undef USE_ARES */
+
+/* Define to disable non-blocking sockets. */
+/* #undef USE_BLOCKING_SOCKETS */
+
+/* if GnuTLS is enabled */
+/* #undef USE_GNUTLS */
+
+/* if libSSH2 is in use */
+/* #undef USE_LIBSSH2 */
+
+/* If you want to build curl with the built-in manual */
+#define USE_MANUAL 1
+
+/* if NSS is enabled */
+/* #undef USE_NSS */
+
+/* if OpenSSL is in use */
+#define USE_OPENSSL 1
+
+/* if SSL is enabled */
+#define USE_SSLEAY 1
+
+/* Define to 1 if you are building a Windows target without large file
+   support. */
+/* #undef USE_WIN32_LARGE_FILES */
+
+/* to enable SSPI support */
+/* #undef USE_WINDOWS_SSPI */
+
+/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
+/* #undef USE_YASSLEMUL */
+
+/* Version number of package */
+#define VERSION "7.20.1"
+
+/* Define to avoid automatic inclusion of winsock.h */
+/* #undef WIN32_LEAN_AND_MEAN */
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+/* #  undef _ALL_SOURCE */
+#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. */
+/* #undef _LARGE_FILES */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+/* #undef in_addr_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* the signed version of size_t */
+/* #undef ssize_t */
diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake
new file mode 100644
index 0000000..fd6b32a
--- /dev/null
+++ b/lib/curl_config.h.cmake
@@ -0,0 +1,953 @@
+/* lib/curl_config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Define to 1 if you have the $func function. */
+#cmakedefine AS_TR_CPP ${AS_TR_CPP}
+
+/* when building libcurl itself */
+#cmakedefine BUILDING_LIBCURL ${BUILDING_LIBCURL}
+
+/* Location of default ca bundle */
+#cmakedefine CURL_CA_BUNDLE ${CURL_CA_BUNDLE}
+
+/* Location of default ca path */
+#cmakedefine CURL_CA_PATH ${CURL_CA_PATH}
+
+/* to disable cookies support */
+#cmakedefine CURL_DISABLE_COOKIES ${CURL_DISABLE_COOKIES}
+
+/* to disable cryptographic authentication */
+#cmakedefine CURL_DISABLE_CRYPTO_AUTH ${CURL_DISABLE_CRYPTO_AUTH}
+
+/* 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 HTTP */
+#cmakedefine CURL_DISABLE_HTTP ${CURL_DISABLE_HTTP}
+
+/* to disable LDAP */
+#cmakedefine CURL_DISABLE_LDAP ${CURL_DISABLE_LDAP}
+
+/* to disable LDAPS */
+#cmakedefine CURL_DISABLE_LDAPS ${CURL_DISABLE_LDAPS}
+
+/* to disable proxies */
+#cmakedefine CURL_DISABLE_PROXY ${CURL_DISABLE_PROXY}
+
+/* to disable TELNET */
+#cmakedefine CURL_DISABLE_TELNET ${CURL_DISABLE_TELNET}
+
+/* to disable TFTP */
+#cmakedefine CURL_DISABLE_TFTP ${CURL_DISABLE_TFTP}
+
+/* to disable verbose strings */
+#cmakedefine CURL_DISABLE_VERBOSE_STRINGS ${CURL_DISABLE_VERBOSE_STRINGS}
+
+/* to make a symbol visible */
+#cmakedefine CURL_EXTERN_SYMBOL ${CURL_EXTERN_SYMBOL}
+/* Ensure using CURL_EXTERN_SYMBOL is possible */
+#ifndef CURL_EXTERN_SYMBOL
+#define CURL_EXTERN_SYMBOL
+#endif
+
+/* to enable hidden symbols */
+#cmakedefine CURL_HIDDEN_SYMBOLS ${CURL_HIDDEN_SYMBOLS}
+
+/* W$ LDAP with non-W$ compiler */
+#cmakedefine CURL_LDAP_HYBRID ${CURL_LDAP_HYBRID}
+
+/* Use W$ LDAP implementation */
+#cmakedefine CURL_LDAP_WIN ${CURL_LDAP_WIN}
+
+/* when not building a shared library */
+#cmakedefine CURL_STATICLIB ${CURL_STATICLIB}
+
+/* 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 the type qualifier of arg 1 for getnameinfo. */
+#cmakedefine GETNAMEINFO_QUAL_ARG1 ${GETNAMEINFO_QUAL_ARG1}
+
+/* Define to the type of arg 1 for getnameinfo. */
+#cmakedefine GETNAMEINFO_TYPE_ARG1 ${GETNAMEINFO_TYPE_ARG1}
+
+/* Define to the type of arg 2 for getnameinfo. */
+#cmakedefine GETNAMEINFO_TYPE_ARG2 ${GETNAMEINFO_TYPE_ARG2}
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#cmakedefine GETNAMEINFO_TYPE_ARG46 ${GETNAMEINFO_TYPE_ARG46}
+
+/* Define to the type of arg 7 for getnameinfo. */
+#cmakedefine GETNAMEINFO_TYPE_ARG7 ${GETNAMEINFO_TYPE_ARG7}
+
+/* Specifies the number of arguments to getservbyport_r */
+#cmakedefine GETSERVBYPORT_R_ARGS ${GETSERVBYPORT_R_ARGS}
+
+/* Specifies the size of the buffer to pass to getservbyport_r */
+#cmakedefine GETSERVBYPORT_R_BUFSIZE ${GETSERVBYPORT_R_BUFSIZE}
+
+/* Define to 1 if you have the alarm function. */
+#cmakedefine HAVE_ALARM ${HAVE_ALARM}
+
+/* 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 <arpa/tftp.h> header file. */
+#cmakedefine HAVE_ARPA_TFTP_H ${HAVE_ARPA_TFTP_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 `basename' function. */
+#cmakedefine HAVE_BASENAME ${HAVE_BASENAME}
+
+/* Define to 1 if bool is an available type. */
+#cmakedefine HAVE_BOOL_T ${HAVE_BOOL_T}
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+#cmakedefine HAVE_CLOCK_GETTIME_MONOTONIC ${HAVE_CLOCK_GETTIME_MONOTONIC}
+
+/* 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}
+
+/* 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 `ENGINE_load_builtin_engines' function. */
+#cmakedefine HAVE_ENGINE_LOAD_BUILTIN_ENGINES ${HAVE_ENGINE_LOAD_BUILTIN_ENGINES}
+
+/* Define to 1 if you have the <errno.h> header file. */
+#cmakedefine HAVE_ERRNO_H ${HAVE_ERRNO_H}
+
+/* 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 function. */
+#cmakedefine HAVE_FCNTL ${HAVE_FCNTL}
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#cmakedefine HAVE_FCNTL_H ${HAVE_FCNTL_H}
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#cmakedefine HAVE_FCNTL_O_NONBLOCK ${HAVE_FCNTL_O_NONBLOCK}
+
+/* Define to 1 if you have the fdopen function. */
+#cmakedefine HAVE_FDOPEN ${HAVE_FDOPEN}
+
+/* Define to 1 if you have the `fork' function. */
+#cmakedefine HAVE_FORK ${HAVE_FORK}
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#cmakedefine HAVE_FREEADDRINFO ${HAVE_FREEADDRINFO}
+
+/* Define to 1 if you have the freeifaddrs function. */
+#cmakedefine HAVE_FREEIFADDRS ${HAVE_FREEIFADDRS}
+
+/* Define to 1 if you have the ftruncate function. */
+#cmakedefine HAVE_FTRUNCATE ${HAVE_FTRUNCATE}
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#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}
+
+/* Define to 1 if you have the gethostbyaddr_r function. */
+#cmakedefine HAVE_GETHOSTBYADDR_R ${HAVE_GETHOSTBYADDR_R}
+
+/* gethostbyaddr_r() takes 5 args */
+#cmakedefine HAVE_GETHOSTBYADDR_R_5 ${HAVE_GETHOSTBYADDR_R_5}
+
+/* gethostbyaddr_r() takes 7 args */
+#cmakedefine HAVE_GETHOSTBYADDR_R_7 ${HAVE_GETHOSTBYADDR_R_7}
+
+/* gethostbyaddr_r() takes 8 args */
+#cmakedefine HAVE_GETHOSTBYADDR_R_8 ${HAVE_GETHOSTBYADDR_R_8}
+
+/* Define to 1 if you have the gethostbyname function. */
+#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 gethostname function. */
+#cmakedefine HAVE_GETHOSTNAME ${HAVE_GETHOSTNAME}
+
+/* Define to 1 if you have a working getifaddrs function. */
+#cmakedefine HAVE_GETIFADDRS ${HAVE_GETIFADDRS}
+
+/* Define to 1 if you have the getnameinfo function. */
+#cmakedefine HAVE_GETNAMEINFO ${HAVE_GETNAMEINFO}
+
+/* Define to 1 if you have the `getpass_r' function. */
+#cmakedefine HAVE_GETPASS_R ${HAVE_GETPASS_R}
+
+/* Define to 1 if you have the `getppid' function. */
+#cmakedefine HAVE_GETPPID ${HAVE_GETPPID}
+
+/* Define to 1 if you have the `getprotobyname' function. */
+#cmakedefine HAVE_GETPROTOBYNAME ${HAVE_GETPROTOBYNAME}
+
+/* Define to 1 if you have the `getpwuid' function. */
+#cmakedefine HAVE_GETPWUID ${HAVE_GETPWUID}
+
+/* Define to 1 if you have the `getrlimit' function. */
+#cmakedefine HAVE_GETRLIMIT ${HAVE_GETRLIMIT}
+
+/* Define to 1 if you have the getservbyport_r function. */
+#cmakedefine HAVE_GETSERVBYPORT_R ${HAVE_GETSERVBYPORT_R}
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#cmakedefine HAVE_GETTIMEOFDAY ${HAVE_GETTIMEOFDAY}
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+#cmakedefine HAVE_GLIBC_STRERROR_R ${HAVE_GLIBC_STRERROR_R}
+
+/* Define to 1 if you have a working gmtime_r function. */
+#cmakedefine HAVE_GMTIME_R ${HAVE_GMTIME_R}
+
+/* if you have the gssapi libraries */
+#cmakedefine HAVE_GSSAPI ${HAVE_GSSAPI}
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+#cmakedefine HAVE_GSSAPI_GSSAPI_GENERIC_H ${HAVE_GSSAPI_GSSAPI_GENERIC_H}
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+#cmakedefine HAVE_GSSAPI_GSSAPI_H ${HAVE_GSSAPI_GSSAPI_H}
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+#cmakedefine HAVE_GSSAPI_GSSAPI_KRB5_H ${HAVE_GSSAPI_GSSAPI_KRB5_H}
+
+/* if you have the GNU gssapi libraries */
+#cmakedefine HAVE_GSSGNU ${HAVE_GSSGNU}
+
+/* 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 `idna_strerror' function. */
+#cmakedefine HAVE_IDNA_STRERROR ${HAVE_IDNA_STRERROR}
+
+/* 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 <ifaddrs.h> header file. */
+#cmakedefine HAVE_IFADDRS_H ${HAVE_IFADDRS_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_r function. */
+#cmakedefine HAVE_INET_NTOA_R ${HAVE_INET_NTOA_R}
+
+/* inet_ntoa_r() takes 2 args */
+#cmakedefine HAVE_INET_NTOA_R_2 ${HAVE_INET_NTOA_R_2}
+
+/* inet_ntoa_r() takes 3 args */
+#cmakedefine HAVE_INET_NTOA_R_3 ${HAVE_INET_NTOA_R_3}
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#cmakedefine HAVE_INET_NTOP ${HAVE_INET_NTOP}
+
+/* Define to 1 if you have a IPv6 capable working 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}
+
+/* Define to 1 if you have the ioctl function. */
+#cmakedefine HAVE_IOCTL ${HAVE_IOCTL}
+
+/* Define to 1 if you have the ioctlsocket function. */
+#cmakedefine HAVE_IOCTLSOCKET ${HAVE_IOCTLSOCKET}
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+#cmakedefine HAVE_IOCTLSOCKET_CAMEL ${HAVE_IOCTLSOCKET_CAMEL}
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+   */
+#cmakedefine HAVE_IOCTLSOCKET_CAMEL_FIONBIO ${HAVE_IOCTLSOCKET_CAMEL_FIONBIO}
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+#cmakedefine HAVE_IOCTLSOCKET_FIONBIO ${HAVE_IOCTLSOCKET_FIONBIO}
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+#cmakedefine HAVE_IOCTL_FIONBIO ${HAVE_IOCTL_FIONBIO}
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+#cmakedefine HAVE_IOCTL_SIOCGIFADDR ${HAVE_IOCTL_SIOCGIFADDR}
+
+/* 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 lber.h header file. */
+#cmakedefine HAVE_LBER_H ${HAVE_LBER_H}
+
+/* Define to 1 if you have the ldapssl.h header file. */
+#cmakedefine HAVE_LDAPSSL_H ${HAVE_LDAPSSL_H}
+
+/* Define to 1 if you have the ldap.h header file. */
+#cmakedefine HAVE_LDAP_H ${HAVE_LDAP_H}
+
+/* Use LDAPS implementation */
+#cmakedefine HAVE_LDAP_SSL ${HAVE_LDAP_SSL}
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+#cmakedefine HAVE_LDAP_SSL_H ${HAVE_LDAP_SSL_H}
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+#cmakedefine HAVE_LDAP_URL_PARSE ${HAVE_LDAP_URL_PARSE}
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#cmakedefine HAVE_LIBGEN_H ${HAVE_LIBGEN_H}
+
+/* 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 `ssh2' library (-lssh2). */
+#cmakedefine HAVE_LIBSSH2 ${HAVE_LIBSSH2}
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+#cmakedefine HAVE_LIBSSH2_H ${HAVE_LIBSSH2_H}
+
+/* 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}
+
+/* if your compiler supports LL */
+#cmakedefine HAVE_LL ${HAVE_LL}
+
+/* Define to 1 if you have the <locale.h> header file. */
+#cmakedefine HAVE_LOCALE_H ${HAVE_LOCALE_H}
+
+/* Define to 1 if you have a working localtime_r function. */
+#cmakedefine HAVE_LOCALTIME_R ${HAVE_LOCALTIME_R}
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#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 MSG_NOSIGNAL flag. */
+#cmakedefine HAVE_MSG_NOSIGNAL ${HAVE_MSG_NOSIGNAL}
+
+/* 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 to 1 if NI_WITHSCOPEID exists and works. */
+#cmakedefine HAVE_NI_WITHSCOPEID ${HAVE_NI_WITHSCOPEID}
+
+/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE
+   */
+#cmakedefine HAVE_OLD_GSSMIT ${HAVE_OLD_GSSMIT}
+
+/* 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/pkcs12.h> header file. */
+#cmakedefine HAVE_OPENSSL_PKCS12_H ${HAVE_OPENSSL_PKCS12_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}
+
+/* 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 `pipe' function. */
+#cmakedefine HAVE_PIPE ${HAVE_PIPE}
+
+/* if you have the function PK11_CreateGenericObject */
+#cmakedefine HAVE_PK11_CREATEGENERICOBJECT ${HAVE_PK11_CREATEGENERICOBJECT}
+
+/* Define to 1 if you have a working poll function. */
+#cmakedefine HAVE_POLL ${HAVE_POLL}
+
+/* If you have a fine poll */
+#cmakedefine HAVE_POLL_FINE ${HAVE_POLL_FINE}
+
+/* Define to 1 if you have the <poll.h> header file. */
+#cmakedefine HAVE_POLL_H ${HAVE_POLL_H}
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+#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 recv function. */
+#cmakedefine HAVE_RECV ${HAVE_RECV}
+
+/* Define to 1 if you have the recvfrom function. */
+#cmakedefine HAVE_RECVFROM ${HAVE_RECVFROM}
+
+/* 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 send function. */
+#cmakedefine HAVE_SEND ${HAVE_SEND}
+
+/* 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 `setlocale' function. */
+#cmakedefine HAVE_SETLOCALE ${HAVE_SETLOCALE}
+
+/* Define to 1 if you have the `setmode' function. */
+#cmakedefine HAVE_SETMODE ${HAVE_SETMODE}
+
+/* Define to 1 if you have the `setrlimit' function. */
+#cmakedefine HAVE_SETRLIMIT ${HAVE_SETRLIMIT}
+
+/* Define to 1 if you have the setsockopt function. */
+#cmakedefine HAVE_SETSOCKOPT ${HAVE_SETSOCKOPT}
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+#cmakedefine HAVE_SETSOCKOPT_SO_NONBLOCK ${HAVE_SETSOCKOPT_SO_NONBLOCK}
+
+/* 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}
+
+/* Define to 1 if you have the <signal.h> header file. */
+#cmakedefine HAVE_SIGNAL_H ${HAVE_SIGNAL_H}
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+#cmakedefine HAVE_SIGSETJMP ${HAVE_SIGSETJMP}
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#cmakedefine HAVE_SIG_ATOMIC_T ${HAVE_SIG_ATOMIC_T}
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+#cmakedefine HAVE_SIG_ATOMIC_T_VOLATILE ${HAVE_SIG_ATOMIC_T_VOLATILE}
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+#cmakedefine HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID ${HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID}
+
+/* Define to 1 if you have the `socket' function. */
+#cmakedefine HAVE_SOCKET ${HAVE_SOCKET}
+
+/* Define this if you have the SPNEGO library fbopenssl */
+#cmakedefine HAVE_SPNEGO ${HAVE_SPNEGO}
+
+/* Define to 1 if you have the `SSL_get_shutdown' function. */
+#cmakedefine HAVE_SSL_GET_SHUTDOWN ${HAVE_SSL_GET_SHUTDOWN}
+
+/* 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 <stdbool.h> header file. */
+#cmakedefine HAVE_STDBOOL_H ${HAVE_STDBOOL_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 <stdio.h> header file. */
+#cmakedefine HAVE_STDIO_H ${HAVE_STDIO_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 strcasestr function. */
+#cmakedefine HAVE_STRCASESTR ${HAVE_STRCASESTR}
+
+/* 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 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 strncasecmp function. */
+#cmakedefine HAVE_STRNCASECMP ${HAVE_STRNCASECMP}
+
+/* Define to 1 if you have the strncmpi function. */
+#cmakedefine HAVE_STRNCMPI ${HAVE_STRNCMPI}
+
+/* Define to 1 if you have the strnicmp function. */
+#cmakedefine HAVE_STRNICMP ${HAVE_STRNICMP}
+
+/* Define to 1 if you have the <stropts.h> header file. */
+#cmakedefine HAVE_STROPTS_H ${HAVE_STROPTS_H}
+
+/* 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}
+
+/* if struct sockaddr_storage is defined */
+#cmakedefine HAVE_STRUCT_SOCKADDR_STORAGE ${HAVE_STRUCT_SOCKADDR_STORAGE}
+
+/* Define to 1 if you have the timeval struct. */
+#cmakedefine HAVE_STRUCT_TIMEVAL ${HAVE_STRUCT_TIMEVAL}
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#cmakedefine HAVE_SYS_FILIO_H ${HAVE_SYS_FILIO_H}
+
+/* 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/resource.h> header file. */
+#cmakedefine HAVE_SYS_RESOURCE_H ${HAVE_SYS_RESOURCE_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/uio.h> header file. */
+#cmakedefine HAVE_SYS_UIO_H ${HAVE_SYS_UIO_H}
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#cmakedefine HAVE_SYS_UN_H ${HAVE_SYS_UN_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 <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 <tld.h> header file. */
+#cmakedefine HAVE_TLD_H ${HAVE_TLD_H}
+
+/* Define to 1 if you have the `tld_strerror' function. */
+#cmakedefine HAVE_TLD_STRERROR ${HAVE_TLD_STRERROR}
+
+/* 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 compiler supports C99 variadic macro style. */
+#cmakedefine HAVE_VARIADIC_MACROS_C99 ${HAVE_VARIADIC_MACROS_C99}
+
+/* Define to 1 if compiler supports old gcc variadic macro style. */
+#cmakedefine HAVE_VARIADIC_MACROS_GCC ${HAVE_VARIADIC_MACROS_GCC}
+
+/* Define to 1 if you have the winber.h header file. */
+#cmakedefine HAVE_WINBER_H ${HAVE_WINBER_H}
+
+/* Define to 1 if you have the windows.h header file. */
+#cmakedefine HAVE_WINDOWS_H ${HAVE_WINDOWS_H}
+
+/* Define to 1 if you have the winldap.h header file. */
+#cmakedefine HAVE_WINLDAP_H ${HAVE_WINLDAP_H}
+
+/* Define to 1 if you have the winsock2.h header file. */
+#cmakedefine HAVE_WINSOCK2_H ${HAVE_WINSOCK2_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 writev function. */
+#cmakedefine HAVE_WRITEV ${HAVE_WRITEV}
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+#cmakedefine HAVE_WS2TCPIP_H ${HAVE_WS2TCPIP_H}
+
+/* Define to 1 if you have the <x509.h> header file. */
+#cmakedefine HAVE_X509_H ${HAVE_X509_H}
+
+/* Define if you have the <process.h> header file. */
+#cmakedefine HAVE_PROCESS_H ${HAVE_PROCESS_H}
+
+/* if you have the zlib.h header file */
+#cmakedefine HAVE_ZLIB_H ${HAVE_ZLIB_H}
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#cmakedefine LT_OBJDIR ${LT_OBJDIR}
+
+/* Define to 1 if you are building a native Windows target. */
+#cmakedefine NATIVE_WINDOWS ${NATIVE_WINDOWS}
+
+/* If you lack a fine basename() prototype */
+#cmakedefine NEED_BASENAME_PROTO ${NEED_BASENAME_PROTO}
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+#cmakedefine NEED_LBER_H ${NEED_LBER_H}
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+#cmakedefine NEED_MALLOC_H ${NEED_MALLOC_H}
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+#cmakedefine NEED_REENTRANT ${NEED_REENTRANT}
+
+/* cpu-machine-OS */
+#cmakedefine OS ${OS}
+
+/* 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 to the type of arg 1 for recvfrom. */
+#cmakedefine RECVFROM_TYPE_ARG1 ${RECVFROM_TYPE_ARG1}
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#cmakedefine RECVFROM_TYPE_ARG2 ${RECVFROM_TYPE_ARG2}
+
+/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */
+#cmakedefine RECVFROM_TYPE_ARG2_IS_VOID ${RECVFROM_TYPE_ARG2_IS_VOID}
+
+/* Define to the type of arg 3 for recvfrom. */
+#cmakedefine RECVFROM_TYPE_ARG3 ${RECVFROM_TYPE_ARG3}
+
+/* Define to the type of arg 4 for recvfrom. */
+#cmakedefine RECVFROM_TYPE_ARG4 ${RECVFROM_TYPE_ARG4}
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#cmakedefine RECVFROM_TYPE_ARG5 ${RECVFROM_TYPE_ARG5}
+
+/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */
+#cmakedefine RECVFROM_TYPE_ARG5_IS_VOID ${RECVFROM_TYPE_ARG5_IS_VOID}
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#cmakedefine RECVFROM_TYPE_ARG6 ${RECVFROM_TYPE_ARG6}
+
+/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */
+#cmakedefine RECVFROM_TYPE_ARG6_IS_VOID ${RECVFROM_TYPE_ARG6_IS_VOID}
+
+/* Define to the function return type for recvfrom. */
+#cmakedefine RECVFROM_TYPE_RETV ${RECVFROM_TYPE_RETV}
+
+/* Define to the type of arg 1 for recv. */
+#cmakedefine RECV_TYPE_ARG1 ${RECV_TYPE_ARG1}
+
+/* Define to the type of arg 2 for recv. */
+#cmakedefine RECV_TYPE_ARG2 ${RECV_TYPE_ARG2}
+
+/* Define to the type of arg 3 for recv. */
+#cmakedefine RECV_TYPE_ARG3 ${RECV_TYPE_ARG3}
+
+/* Define to the type of arg 4 for recv. */
+#cmakedefine RECV_TYPE_ARG4 ${RECV_TYPE_ARG4}
+
+/* Define to the function return type for recv. */
+#cmakedefine RECV_TYPE_RETV ${RECV_TYPE_RETV}
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#cmakedefine RETSIGTYPE ${RETSIGTYPE}
+
+/* Define to the type qualifier of arg 5 for select. */
+#cmakedefine SELECT_QUAL_ARG5 ${SELECT_QUAL_ARG5}
+
+/* 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}
+
+/* Define to the function return type for select. */
+#cmakedefine SELECT_TYPE_RETV ${SELECT_TYPE_RETV}
+
+/* Define to the type qualifier of arg 2 for send. */
+#cmakedefine SEND_QUAL_ARG2 ${SEND_QUAL_ARG2}
+
+/* Define to the type of arg 1 for send. */
+#cmakedefine SEND_TYPE_ARG1 ${SEND_TYPE_ARG1}
+
+/* Define to the type of arg 2 for send. */
+#cmakedefine SEND_TYPE_ARG2 ${SEND_TYPE_ARG2}
+
+/* Define to the type of arg 3 for send. */
+#cmakedefine SEND_TYPE_ARG3 ${SEND_TYPE_ARG3}
+
+/* Define to the type of arg 4 for send. */
+#cmakedefine SEND_TYPE_ARG4 ${SEND_TYPE_ARG4}
+
+/* Define to the function return type for send. */
+#cmakedefine SEND_TYPE_RETV ${SEND_TYPE_RETV}
+
+/* The size of `int', as computed by sizeof. */
+#cmakedefine SIZEOF_INT ${SIZEOF_INT}
+
+/* The size of `short', as computed by sizeof. */
+#cmakedefine SIZEOF_SHORT ${SIZEOF_SHORT}
+
+/* The size of `long', as computed by sizeof. */
+#cmakedefine SIZEOF_LONG ${SIZEOF_LONG}
+
+/* The size of `off_t', as computed by sizeof. */
+#cmakedefine SIZEOF_OFF_T ${SIZEOF_OFF_T}
+
+/* The size of `size_t', as computed by sizeof. */
+#cmakedefine SIZEOF_SIZE_T ${SIZEOF_SIZE_T}
+
+/* The size of `time_t', as computed by sizeof. */
+#cmakedefine SIZEOF_TIME_T ${SIZEOF_TIME_T}
+
+/* The size of `void*', as computed by sizeof. */
+#cmakedefine SIZEOF_VOIDP ${SIZEOF_VOIDP}
+
+/* Define to 1 if you have the ANSI C header files. */
+#cmakedefine STDC_HEADERS ${STDC_HEADERS}
+
+/* Define to the type of arg 3 for strerror_r. */
+#cmakedefine STRERROR_R_TYPE_ARG3 ${STRERROR_R_TYPE_ARG3}
+
+/* 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 c-ares support */
+#cmakedefine USE_ARES ${USE_ARES}
+
+/* Define to disable non-blocking sockets. */
+#cmakedefine USE_BLOCKING_SOCKETS ${USE_BLOCKING_SOCKETS}
+
+/* if GnuTLS is enabled */
+#cmakedefine USE_GNUTLS ${USE_GNUTLS}
+
+/* if libSSH2 is in use */
+#cmakedefine USE_LIBSSH2 ${USE_LIBSSH2}
+
+/* If you want to build curl with the built-in manual */
+#cmakedefine USE_MANUAL ${USE_MANUAL}
+
+/* if NSS is enabled */
+#cmakedefine USE_NSS ${USE_NSS}
+
+/* if OpenSSL is in use */
+#cmakedefine USE_OPENSSL ${USE_OPENSSL}
+
+/* if SSL is enabled */
+#cmakedefine USE_SSLEAY ${USE_SSLEAY}
+
+/* Define to 1 if you are building a Windows target without large file
+   support. */
+#cmakedefine USE_WIN32_LARGE_FILES ${USE_WIN32_LARGE_FILES}
+
+/* to enable SSPI support */
+#cmakedefine USE_WINDOWS_SSPI ${USE_WINDOWS_SSPI}
+
+/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
+#cmakedefine USE_YASSLEMUL ${USE_YASSLEMUL}
+
+/* Version number of package */
+#cmakedefine VERSION ${VERSION}
+
+/* Define to avoid automatic inclusion of winsock.h */
+#cmakedefine WIN32_LEAN_AND_MEAN ${WIN32_LEAN_AND_MEAN}
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+#  undef _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 this if you need it to compile thread-safe code */
+#cmakedefine _THREAD_SAFE ${_THREAD_SAFE}
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#cmakedefine const ${const}
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+#cmakedefine in_addr_t ${in_addr_t}
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#cmakedefine size_t ${size_t}
+
+/* the signed version of size_t */
+#cmakedefine ssize_t ${ssize_t}
diff --git a/lib/curl_config.h.in b/lib/curl_config.h.in
new file mode 100644
index 0000000..846fb27
--- /dev/null
+++ b/lib/curl_config.h.in
@@ -0,0 +1,973 @@
+/* lib/curl_config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* when building libcurl itself */
+#undef BUILDING_LIBCURL
+
+/* Location of default ca bundle */
+#undef CURL_CA_BUNDLE
+
+/* Location of default ca path */
+#undef CURL_CA_PATH
+
+/* to disable cookies support */
+#undef CURL_DISABLE_COOKIES
+
+/* to disable cryptographic authentication */
+#undef CURL_DISABLE_CRYPTO_AUTH
+
+/* to disable DICT */
+#undef CURL_DISABLE_DICT
+
+/* to disable FILE */
+#undef CURL_DISABLE_FILE
+
+/* to disable FTP */
+#undef CURL_DISABLE_FTP
+
+/* to disable HTTP */
+#undef CURL_DISABLE_HTTP
+
+/* to disable IMAP */
+#undef CURL_DISABLE_IMAP
+
+/* to disable LDAP */
+#undef CURL_DISABLE_LDAP
+
+/* to disable LDAPS */
+#undef CURL_DISABLE_LDAPS
+
+/* to disable POP3 */
+#undef CURL_DISABLE_POP3
+
+/* to disable proxies */
+#undef CURL_DISABLE_PROXY
+
+/* to disable RTSP */
+#undef CURL_DISABLE_RTSP
+
+/* to disable SMTP */
+#undef CURL_DISABLE_SMTP
+
+/* to disable TELNET */
+#undef CURL_DISABLE_TELNET
+
+/* to disable TFTP */
+#undef CURL_DISABLE_TFTP
+
+/* to disable verbose strings */
+#undef CURL_DISABLE_VERBOSE_STRINGS
+
+/* to make a symbol visible */
+#undef CURL_EXTERN_SYMBOL
+
+/* to enable hidden symbols */
+#undef CURL_HIDDEN_SYMBOLS
+
+/* W$ LDAP with non-W$ compiler */
+#undef CURL_LDAP_HYBRID
+
+/* Use W$ LDAP implementation */
+#undef CURL_LDAP_WIN
+
+/* when not building a shared library */
+#undef CURL_STATICLIB
+
+/* your Entropy Gathering Daemon socket pathname */
+#undef EGD_SOCKET
+
+/* Define if you want to enable IPv6 support */
+#undef ENABLE_IPV6
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#undef GETNAMEINFO_QUAL_ARG1
+
+/* Define to the type of arg 1 for getnameinfo. */
+#undef GETNAMEINFO_TYPE_ARG1
+
+/* Define to the type of arg 2 for getnameinfo. */
+#undef GETNAMEINFO_TYPE_ARG2
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#undef GETNAMEINFO_TYPE_ARG46
+
+/* Define to the type of arg 7 for getnameinfo. */
+#undef GETNAMEINFO_TYPE_ARG7
+
+/* Specifies the number of arguments to getservbyport_r */
+#undef GETSERVBYPORT_R_ARGS
+
+/* Specifies the size of the buffer to pass to getservbyport_r */
+#undef GETSERVBYPORT_R_BUFSIZE
+
+/* Define to 1 if you have the alarm function. */
+#undef HAVE_ALARM
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#undef HAVE_ALLOCA_H
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Define to 1 if you have the <arpa/tftp.h> header file. */
+#undef HAVE_ARPA_TFTP_H
+
+/* Define to 1 if you have the <assert.h> header file. */
+#undef HAVE_ASSERT_H
+
+/* Define to 1 if you have the basename function. */
+#undef HAVE_BASENAME
+
+/* Define to 1 if bool is an available type. */
+#undef HAVE_BOOL_T
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+#undef HAVE_CLOCK_GETTIME_MONOTONIC
+
+/* Define to 1 if you have the closesocket function. */
+#undef HAVE_CLOSESOCKET
+
+/* Define to 1 if you have the CloseSocket camel case function. */
+#undef HAVE_CLOSESOCKET_CAMEL
+
+/* Define to 1 if you have the connect function. */
+#undef HAVE_CONNECT
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+#undef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA
+
+/* 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
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the `ENGINE_cleanup' function. */
+#undef HAVE_ENGINE_CLEANUP
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+#undef HAVE_ENGINE_LOAD_BUILTIN_ENGINES
+
+/* Define to 1 if you have the <errno.h> header file. */
+#undef HAVE_ERRNO_H
+
+/* Define to 1 if you have the <err.h> header file. */
+#undef HAVE_ERR_H
+
+/* Define to 1 if you have the fcntl function. */
+#undef HAVE_FCNTL
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#undef HAVE_FCNTL_O_NONBLOCK
+
+/* Define to 1 if you have the fdopen function. */
+#undef HAVE_FDOPEN
+
+/* Define to 1 if you have the `fork' function. */
+#undef HAVE_FORK
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#undef HAVE_FREEADDRINFO
+
+/* Define to 1 if you have the freeifaddrs function. */
+#undef HAVE_FREEIFADDRS
+
+/* Define to 1 if you have the ftruncate function. */
+#undef HAVE_FTRUNCATE
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if the getaddrinfo function is threadsafe. */
+#undef HAVE_GETADDRINFO_THREADSAFE
+
+/* Define to 1 if you have the `geteuid' function. */
+#undef HAVE_GETEUID
+
+/* Define to 1 if you have the gethostbyaddr function. */
+#undef HAVE_GETHOSTBYADDR
+
+/* Define to 1 if you have the gethostbyaddr_r function. */
+#undef HAVE_GETHOSTBYADDR_R
+
+/* gethostbyaddr_r() takes 5 args */
+#undef HAVE_GETHOSTBYADDR_R_5
+
+/* gethostbyaddr_r() takes 7 args */
+#undef HAVE_GETHOSTBYADDR_R_7
+
+/* gethostbyaddr_r() takes 8 args */
+#undef HAVE_GETHOSTBYADDR_R_8
+
+/* Define to 1 if you have the gethostbyname function. */
+#undef HAVE_GETHOSTBYNAME
+
+/* Define to 1 if you have the gethostbyname_r function. */
+#undef HAVE_GETHOSTBYNAME_R
+
+/* gethostbyname_r() takes 3 args */
+#undef HAVE_GETHOSTBYNAME_R_3
+
+/* gethostbyname_r() takes 5 args */
+#undef HAVE_GETHOSTBYNAME_R_5
+
+/* gethostbyname_r() takes 6 args */
+#undef HAVE_GETHOSTBYNAME_R_6
+
+/* Define to 1 if you have the gethostname function. */
+#undef HAVE_GETHOSTNAME
+
+/* Define to 1 if you have a working getifaddrs function. */
+#undef HAVE_GETIFADDRS
+
+/* Define to 1 if you have the getnameinfo function. */
+#undef HAVE_GETNAMEINFO
+
+/* Define to 1 if you have the `getpass_r' function. */
+#undef HAVE_GETPASS_R
+
+/* Define to 1 if you have the `getppid' function. */
+#undef HAVE_GETPPID
+
+/* Define to 1 if you have the `getprotobyname' function. */
+#undef HAVE_GETPROTOBYNAME
+
+/* Define to 1 if you have the `getpwuid' function. */
+#undef HAVE_GETPWUID
+
+/* Define to 1 if you have the `getrlimit' function. */
+#undef HAVE_GETRLIMIT
+
+/* Define to 1 if you have the getservbyport_r function. */
+#undef HAVE_GETSERVBYPORT_R
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+#undef HAVE_GLIBC_STRERROR_R
+
+/* Define to 1 if you have a working gmtime_r function. */
+#undef HAVE_GMTIME_R
+
+/* if you have the gssapi libraries */
+#undef HAVE_GSSAPI
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_GENERIC_H
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_H
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_KRB5_H
+
+/* if you have the GNU gssapi libraries */
+#undef HAVE_GSSGNU
+
+/* if you have the Heimdal gssapi libraries */
+#undef HAVE_GSSHEIMDAL
+
+/* if you have the MIT gssapi libraries */
+#undef HAVE_GSSMIT
+
+/* Define to 1 if you have the `idna_strerror' function. */
+#undef HAVE_IDNA_STRERROR
+
+/* Define to 1 if you have the `idn_free' function. */
+#undef HAVE_IDN_FREE
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+#undef HAVE_IDN_FREE_H
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#undef HAVE_IFADDRS_H
+
+/* Define to 1 if you have the `inet_addr' function. */
+#undef HAVE_INET_ADDR
+
+/* Define to 1 if you have the inet_ntoa_r function. */
+#undef HAVE_INET_NTOA_R
+
+/* inet_ntoa_r() takes 2 args */
+#undef HAVE_INET_NTOA_R_2
+
+/* inet_ntoa_r() takes 3 args */
+#undef HAVE_INET_NTOA_R_3
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#undef HAVE_INET_NTOP
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#undef HAVE_INET_PTON
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the ioctl function. */
+#undef HAVE_IOCTL
+
+/* Define to 1 if you have the ioctlsocket function. */
+#undef HAVE_IOCTLSOCKET
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+#undef HAVE_IOCTLSOCKET_CAMEL
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+   */
+#undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+#undef HAVE_IOCTLSOCKET_FIONBIO
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+#undef HAVE_IOCTL_FIONBIO
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+#undef HAVE_IOCTL_SIOCGIFADDR
+
+/* Define to 1 if you have the <io.h> header file. */
+#undef HAVE_IO_H
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+#undef HAVE_KRB4
+
+/* 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 lber.h header file. */
+#undef HAVE_LBER_H
+
+/* Define to 1 if you have the ldapssl.h header file. */
+#undef HAVE_LDAPSSL_H
+
+/* Define to 1 if you have the ldap.h header file. */
+#undef HAVE_LDAP_H
+
+/* Use LDAPS implementation */
+#undef HAVE_LDAP_SSL
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+#undef HAVE_LDAP_SSL_H
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+#undef HAVE_LDAP_URL_PARSE
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#undef HAVE_LIBGEN_H
+
+/* Define to 1 if you have the `idn' library (-lidn). */
+#undef HAVE_LIBIDN
+
+/* 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 `ssh2' library (-lssh2). */
+#undef HAVE_LIBSSH2
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+#undef HAVE_LIBSSH2_H
+
+/* Define to 1 if you have the `libssh2_version' function. */
+#undef HAVE_LIBSSH2_VERSION
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+#undef HAVE_LIBSSL
+
+/* if zlib is available */
+#undef HAVE_LIBZ
+
+/* Define to 1 if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* if your compiler supports LL */
+#undef HAVE_LL
+
+/* Define to 1 if you have the <locale.h> header file. */
+#undef HAVE_LOCALE_H
+
+/* Define to 1 if you have a working localtime_r function. */
+#undef HAVE_LOCALTIME_R
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#undef HAVE_LONGLONG
+
+/* Define to 1 if you have the malloc.h header file. */
+#undef HAVE_MALLOC_H
+
+/* Define to 1 if you have the memory.h header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the memrchr function or macro. */
+#undef HAVE_MEMRCHR
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+#undef HAVE_MSG_NOSIGNAL
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#undef HAVE_NETINET_TCP_H
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#undef HAVE_NET_IF_H
+
+/* Define to 1 if NI_WITHSCOPEID exists and works. */
+#undef HAVE_NI_WITHSCOPEID
+
+/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE
+   */
+#undef HAVE_OLD_GSSMIT
+
+/* 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/pkcs12.h> header file. */
+#undef HAVE_OPENSSL_PKCS12_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. */
+#undef HAVE_PERROR
+
+/* Define to 1 if you have the `pipe' function. */
+#undef HAVE_PIPE
+
+/* if you have the function PK11_CreateGenericObject */
+#undef HAVE_PK11_CREATEGENERICOBJECT
+
+/* Define to 1 if you have a working poll function. */
+#undef HAVE_POLL
+
+/* If you have a fine poll */
+#undef HAVE_POLL_FINE
+
+/* Define to 1 if you have the <poll.h> header file. */
+#undef HAVE_POLL_H
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+#undef HAVE_POSIX_STRERROR_R
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#undef HAVE_PWD_H
+
+/* 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 recv function. */
+#undef HAVE_RECV
+
+/* Define to 1 if you have the recvfrom function. */
+#undef HAVE_RECVFROM
+
+/* Define to 1 if you have the <rsa.h> header file. */
+#undef HAVE_RSA_H
+
+/* Define to 1 if you have the select function. */
+#undef HAVE_SELECT
+
+/* Define to 1 if you have the send function. */
+#undef HAVE_SEND
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#undef HAVE_SETJMP_H
+
+/* Define to 1 if you have the `setlocale' function. */
+#undef HAVE_SETLOCALE
+
+/* Define to 1 if you have the `setmode' function. */
+#undef HAVE_SETMODE
+
+/* Define to 1 if you have the `setrlimit' function. */
+#undef HAVE_SETRLIMIT
+
+/* Define to 1 if you have the setsockopt function. */
+#undef HAVE_SETSOCKOPT
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+#undef HAVE_SETSOCKOPT_SO_NONBLOCK
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+#undef HAVE_SGTTY_H
+
+/* Define to 1 if you have the sigaction function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the siginterrupt function. */
+#undef HAVE_SIGINTERRUPT
+
+/* Define to 1 if you have the signal function. */
+#undef HAVE_SIGNAL
+
+/* Define to 1 if you have the <signal.h> header file. */
+#undef HAVE_SIGNAL_H
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+#undef HAVE_SIGSETJMP
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#undef HAVE_SIG_ATOMIC_T
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+#undef HAVE_SIG_ATOMIC_T_VOLATILE
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+#undef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
+
+/* Define to 1 if you have the socket function. */
+#undef HAVE_SOCKET
+
+/* Define to 1 if you have the <socket.h> header file. */
+#undef HAVE_SOCKET_H
+
+/* Define this if you have the SPNEGO library fbopenssl */
+#undef HAVE_SPNEGO
+
+/* Define to 1 if you have the `SSL_get_shutdown' function. */
+#undef HAVE_SSL_GET_SHUTDOWN
+
+/* Define to 1 if you have the <ssl.h> header file. */
+#undef HAVE_SSL_H
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#undef HAVE_STDBOOL_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#undef HAVE_STDIO_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the strcasecmp function. */
+#undef HAVE_STRCASECMP
+
+/* Define to 1 if you have the strcasestr function. */
+#undef HAVE_STRCASESTR
+
+/* Define to 1 if you have the strcmpi function. */
+#undef HAVE_STRCMPI
+
+/* Define to 1 if you have the strdup function. */
+#undef HAVE_STRDUP
+
+/* Define to 1 if you have the strerror_r function. */
+#undef HAVE_STRERROR_R
+
+/* Define to 1 if you have the stricmp function. */
+#undef HAVE_STRICMP
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* 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 strncasecmp function. */
+#undef HAVE_STRNCASECMP
+
+/* Define to 1 if you have the strncmpi function. */
+#undef HAVE_STRNCMPI
+
+/* Define to 1 if you have the strnicmp function. */
+#undef HAVE_STRNICMP
+
+/* Define to 1 if you have the <stropts.h> header file. */
+#undef HAVE_STROPTS_H
+
+/* Define to 1 if you have the strstr function. */
+#undef HAVE_STRSTR
+
+/* Define to 1 if you have the strtok_r function. */
+#undef HAVE_STRTOK_R
+
+/* Define to 1 if you have the strtoll function. */
+#undef HAVE_STRTOLL
+
+/* if struct sockaddr_storage is defined */
+#undef HAVE_STRUCT_SOCKADDR_STORAGE
+
+/* Define to 1 if you have the timeval struct. */
+#undef HAVE_STRUCT_TIMEVAL
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#undef HAVE_SYS_FILIO_H
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#undef HAVE_SYS_POLL_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* 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. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#undef HAVE_SYS_UIO_H
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#undef HAVE_SYS_UN_H
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+#undef HAVE_SYS_UTIME_H
+
+/* Define to 1 if you have the <termios.h> header file. */
+#undef HAVE_TERMIOS_H
+
+/* Define to 1 if you have the <termio.h> header file. */
+#undef HAVE_TERMIO_H
+
+/* Define to 1 if you have the <time.h> header file. */
+#undef HAVE_TIME_H
+
+/* Define to 1 if you have the <tld.h> header file. */
+#undef HAVE_TLD_H
+
+/* Define to 1 if you have the `tld_strerror' function. */
+#undef HAVE_TLD_STRERROR
+
+/* Define to 1 if you have the `uname' function. */
+#undef HAVE_UNAME
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `utime' function. */
+#undef HAVE_UTIME
+
+/* Define to 1 if you have the <utime.h> header file. */
+#undef HAVE_UTIME_H
+
+/* Define to 1 if compiler supports C99 variadic macro style. */
+#undef HAVE_VARIADIC_MACROS_C99
+
+/* Define to 1 if compiler supports old gcc variadic macro style. */
+#undef HAVE_VARIADIC_MACROS_GCC
+
+/* Define to 1 if you have the winber.h header file. */
+#undef HAVE_WINBER_H
+
+/* Define to 1 if you have the windows.h header file. */
+#undef HAVE_WINDOWS_H
+
+/* Define to 1 if you have the winldap.h header file. */
+#undef HAVE_WINLDAP_H
+
+/* Define to 1 if you have the winsock2.h header file. */
+#undef HAVE_WINSOCK2_H
+
+/* Define to 1 if you have the winsock.h header file. */
+#undef HAVE_WINSOCK_H
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#undef HAVE_WRITABLE_ARGV
+
+/* Define to 1 if you have the writev function. */
+#undef HAVE_WRITEV
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+#undef HAVE_WS2TCPIP_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
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#undef LT_OBJDIR
+
+/* Define to 1 if you are building a native Windows target. */
+#undef NATIVE_WINDOWS
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+#undef NEED_LBER_H
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+#undef NEED_MALLOC_H
+
+/* Define to 1 if you need the memory.h header file even with stdlib.h */
+#undef NEED_MEMORY_H
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+#undef NEED_REENTRANT
+
+/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */
+#undef NEED_THREAD_SAFE
+
+/* cpu-machine-OS */
+#undef OS
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* a suitable file to read random data from */
+#undef RANDOM_FILE
+
+/* Define to the type of arg 1 for recvfrom. */
+#undef RECVFROM_TYPE_ARG1
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#undef RECVFROM_TYPE_ARG2
+
+/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */
+#undef RECVFROM_TYPE_ARG2_IS_VOID
+
+/* Define to the type of arg 3 for recvfrom. */
+#undef RECVFROM_TYPE_ARG3
+
+/* Define to the type of arg 4 for recvfrom. */
+#undef RECVFROM_TYPE_ARG4
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#undef RECVFROM_TYPE_ARG5
+
+/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */
+#undef RECVFROM_TYPE_ARG5_IS_VOID
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#undef RECVFROM_TYPE_ARG6
+
+/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */
+#undef RECVFROM_TYPE_ARG6_IS_VOID
+
+/* Define to the function return type for recvfrom. */
+#undef RECVFROM_TYPE_RETV
+
+/* Define to the type of arg 1 for recv. */
+#undef RECV_TYPE_ARG1
+
+/* Define to the type of arg 2 for recv. */
+#undef RECV_TYPE_ARG2
+
+/* Define to the type of arg 3 for recv. */
+#undef RECV_TYPE_ARG3
+
+/* Define to the type of arg 4 for recv. */
+#undef RECV_TYPE_ARG4
+
+/* Define to the function return type for recv. */
+#undef RECV_TYPE_RETV
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* Define to the type qualifier of arg 5 for select. */
+#undef SELECT_QUAL_ARG5
+
+/* Define to the type of arg 1 for select. */
+#undef SELECT_TYPE_ARG1
+
+/* Define to the type of args 2, 3 and 4 for select. */
+#undef SELECT_TYPE_ARG234
+
+/* Define to the type of arg 5 for select. */
+#undef SELECT_TYPE_ARG5
+
+/* Define to the function return type for select. */
+#undef SELECT_TYPE_RETV
+
+/* Define to the type qualifier of arg 2 for send. */
+#undef SEND_QUAL_ARG2
+
+/* Define to the type of arg 1 for send. */
+#undef SEND_TYPE_ARG1
+
+/* Define to the type of arg 2 for send. */
+#undef SEND_TYPE_ARG2
+
+/* Define to the type of arg 3 for send. */
+#undef SEND_TYPE_ARG3
+
+/* Define to the type of arg 4 for send. */
+#undef SEND_TYPE_ARG4
+
+/* Define to the function return type for send. */
+#undef SEND_TYPE_RETV
+
+/* The size of `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
+/* The size of `long', as computed by sizeof. */
+#undef SIZEOF_LONG
+
+/* The size of `off_t', as computed by sizeof. */
+#undef SIZEOF_OFF_T
+
+/* The size of `short', as computed by sizeof. */
+#undef SIZEOF_SHORT
+
+/* The size of `size_t', as computed by sizeof. */
+#undef SIZEOF_SIZE_T
+
+/* The size of `time_t', as computed by sizeof. */
+#undef SIZEOF_TIME_T
+
+/* The size of `void*', as computed by sizeof. */
+#undef SIZEOF_VOIDP
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to the type of arg 3 for strerror_r. */
+#undef STRERROR_R_TYPE_ARG3
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define to enable c-ares support */
+#undef USE_ARES
+
+/* Define to disable non-blocking sockets. */
+#undef USE_BLOCKING_SOCKETS
+
+/* if GnuTLS is enabled */
+#undef USE_GNUTLS
+
+/* if libSSH2 is in use */
+#undef USE_LIBSSH2
+
+/* If you want to build curl with the built-in manual */
+#undef USE_MANUAL
+
+/* if NSS is enabled */
+#undef USE_NSS
+
+/* if OpenSSL is in use */
+#undef USE_OPENSSL
+
+/* if SSL is enabled */
+#undef USE_SSLEAY
+
+/* Define to 1 if you are building a Windows target without large file
+   support. */
+#undef USE_WIN32_LARGE_FILES
+
+/* to enable SSPI support */
+#undef USE_WINDOWS_SSPI
+
+/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
+#undef USE_YASSLEMUL
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to avoid automatic inclusion of winsock.h */
+#undef WIN32_LEAN_AND_MEAN
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+#  undef _ALL_SOURCE
+#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. */
+#undef _LARGE_FILES
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+#undef in_addr_t
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
+
+/* the signed version of size_t */
+#undef ssize_t
diff --git a/lib/curl_ldap.h b/lib/curl_ldap.h
new file mode 100644
index 0000000..1f28afe
--- /dev/null
+++ b/lib/curl_ldap.h
@@ -0,0 +1,33 @@
+#ifndef __CURL_LDAP_H
+#define __CURL_LDAP_H
+
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, 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.
+ *
+ ***************************************************************************/
+#ifndef CURL_DISABLE_LDAP
+extern const struct Curl_handler Curl_handler_ldap;
+
+#ifdef HAVE_LDAP_SSL
+extern const struct Curl_handler Curl_handler_ldaps;
+#endif
+
+#endif
+#endif /* __CURL_LDAP_H */
diff --git a/lib/curl_md5.h b/lib/curl_md5.h
new file mode 100644
index 0000000..cab9915
--- /dev/null
+++ b/lib/curl_md5.h
@@ -0,0 +1,28 @@
+#ifndef HEADER_CURL_MD5_H
+#define HEADER_CURL_MD5_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+void Curl_md5it(unsigned char *output,
+                const unsigned char *input);
+
+#endif /* HEADER_CURL_MD5_H */
diff --git a/lib/curl_memory.h b/lib/curl_memory.h
new file mode 100644
index 0000000..e119458
--- /dev/null
+++ b/lib/curl_memory.h
@@ -0,0 +1,49 @@
+#ifndef HEADER_CURL_MEMORY_H
+#define HEADER_CURL_MEMORY_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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 <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 /* HEADER_CURL_MEMORY_H */
diff --git a/lib/curl_memrchr.c b/lib/curl_memrchr.c
new file mode 100644
index 0000000..a1e2bf0
--- /dev/null
+++ b/lib/curl_memrchr.c
@@ -0,0 +1,62 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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_memrchr.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifndef HAVE_MEMRCHR
+
+/*
+ * Curl_memrchr()
+ *
+ * Our memrchr() function clone for systems which lack this function. The
+ * memrchr() function is like the memchr() function, except that it searches
+ * backwards from the end of the n bytes pointed to by s instead of forward
+ * from the beginning.
+ */
+
+void *
+Curl_memrchr(const void *s, int c, size_t n)
+{
+  const unsigned char *p = s;
+  const unsigned char *q = s;
+
+  p += n - 1;
+
+  while (p >= q) {
+    if (*p == (unsigned char)c)
+      return (void *)p;
+    p--;
+  }
+
+  return NULL;
+}
+
+#endif /* HAVE_MEMRCHR */
diff --git a/lib/curl_memrchr.h b/lib/curl_memrchr.h
new file mode 100644
index 0000000..37061b6
--- /dev/null
+++ b/lib/curl_memrchr.h
@@ -0,0 +1,44 @@
+#ifndef HEADER_CURL_MEMRCHR_H
+#define HEADER_CURL_MEMRCHR_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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"
+
+#ifdef HAVE_MEMRCHR
+
+#ifdef HAVE_STRING_H
+#  include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+#  include <strings.h>
+#endif
+
+#else /* HAVE_MEMRCHR */
+
+void *Curl_memrchr(const void *s, int c, size_t n);
+
+#define memrchr(x,y,z) Curl_memrchr((x),(y),(z))
+
+#endif /* HAVE_MEMRCHR */
+
+#endif /* HEADER_CURL_MEMRCHR_H */
diff --git a/lib/curl_rand.c b/lib/curl_rand.c
new file mode 100644
index 0000000..047b7f3
--- /dev/null
+++ b/lib/curl_rand.c
@@ -0,0 +1,61 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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 "curl_rand.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* Private pseudo-random number seed. Unsigned integer >= 32bit. Threads
+   mutual exclusion is not implemented to acess it since we do not require
+   high quality random numbers (only used in form boudary generation). */
+
+static unsigned int randseed;
+
+/* Pseudo-random number support. */
+
+unsigned int Curl_rand(void)
+{
+  unsigned int r;
+  /* Return an unsigned 32-bit pseudo-random number. */
+  r = randseed = randseed * 1103515245 + 12345;
+  return (r << 16) | ((r >> 16) & 0xFFFF);
+}
+
+void Curl_srand(void)
+{
+  /* Randomize pseudo-random number sequence. */
+
+  randseed = (unsigned int) time(NULL);
+  Curl_rand();
+  Curl_rand();
+  Curl_rand();
+}
+
diff --git a/lib/curl_rand.h b/lib/curl_rand.h
new file mode 100644
index 0000000..26cfb7f
--- /dev/null
+++ b/lib/curl_rand.h
@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_RAND_H
+#define HEADER_CURL_RAND_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+void Curl_srand(void);
+
+unsigned int Curl_rand(void);
+
+#endif /* HEADER_CURL_RAND_H */
diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c
new file mode 100644
index 0000000..6b19b47
--- /dev/null
+++ b/lib/curl_sspi.c
@@ -0,0 +1,118 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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"
+
+#ifdef USE_WINDOWS_SSPI
+
+#include <curl/curl.h>
+
+#include "curl_sspi.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+
+/* Handle of security.dll or secur32.dll, depending on Windows version */
+HMODULE s_hSecDll = NULL;
+
+/* Pointer to SSPI dispatch table */
+PSecurityFunctionTableA s_pSecFn = NULL;
+
+
+/*
+ * Curl_sspi_global_init()
+ *
+ * This is used to load the Security Service Provider Interface (SSPI)
+ * dynamic link library portably across all Windows versions, without
+ * the need to directly link libcurl, nor the application using it, at
+ * build time.
+ *
+ * Once this function has been executed, Windows SSPI functions can be
+ * called through the Security Service Provider Interface dispatch table.
+ */
+
+CURLcode
+Curl_sspi_global_init(void)
+{
+  OSVERSIONINFO osver;
+  INIT_SECURITY_INTERFACE_A pInitSecurityInterface;
+
+  /* If security interface is not yet initialized try to do this */
+  if(s_hSecDll == NULL) {
+
+    /* Find out Windows version */
+    memset(&osver, 0, sizeof(osver));
+    osver.dwOSVersionInfoSize = sizeof(osver);
+    if(! GetVersionEx(&osver))
+      return CURLE_FAILED_INIT;
+
+    /* Security Service Provider Interface (SSPI) functions are located in
+     * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP
+     * have both these DLLs (security.dll forwards calls to secur32.dll) */
+
+    /* Load SSPI dll into the address space of the calling process */
+    if(osver.dwPlatformId == VER_PLATFORM_WIN32_NT
+      && osver.dwMajorVersion == 4)
+      s_hSecDll = LoadLibrary("security.dll");
+    else
+      s_hSecDll = LoadLibrary("secur32.dll");
+    if(! s_hSecDll)
+      return CURLE_FAILED_INIT;
+
+    /* Get address of the InitSecurityInterfaceA function from the SSPI dll */
+    pInitSecurityInterface = (INIT_SECURITY_INTERFACE_A)
+      GetProcAddress(s_hSecDll, "InitSecurityInterfaceA");
+    if(! pInitSecurityInterface)
+      return CURLE_FAILED_INIT;
+
+    /* Get pointer to Security Service Provider Interface dispatch table */
+    s_pSecFn = pInitSecurityInterface();
+    if(! s_pSecFn)
+      return CURLE_FAILED_INIT;
+
+  }
+  return CURLE_OK;
+}
+
+
+/*
+ * Curl_sspi_global_cleanup()
+ *
+ * This deinitializes the Security Service Provider Interface from libcurl.
+ */
+
+void
+Curl_sspi_global_cleanup(void)
+{
+  if(s_hSecDll) {
+    FreeLibrary(s_hSecDll);
+    s_hSecDll = NULL;
+    s_pSecFn = NULL;
+  }
+}
+
+#endif /* USE_WINDOWS_SSPI */
diff --git a/lib/curl_sspi.h b/lib/curl_sspi.h
new file mode 100644
index 0000000..221bce1
--- /dev/null
+++ b/lib/curl_sspi.h
@@ -0,0 +1,73 @@
+#ifndef HEADER_CURL_SSPI_H
+#define HEADER_CURL_SSPI_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+#ifdef USE_WINDOWS_SSPI
+
+#include <curl/curl.h>
+
+/*
+ * When including the folowing three headers, it is mandatory to define either
+ * SECURITY_WIN32 or SECURITY_KERNEL, indicating who is compiling the code.
+ */
+
+#undef SECURITY_WIN32
+#undef SECURITY_KERNEL
+#define SECURITY_WIN32 1
+#include <security.h>
+#include <sspi.h>
+#include <rpc.h>
+
+/* Provide some definitions missing in MinGW's headers */
+
+#ifndef SEC_I_CONTEXT_EXPIRED
+# define SEC_I_CONTEXT_EXPIRED ((HRESULT)0x00090317L)
+#endif
+#ifndef SEC_E_BUFFER_TOO_SMALL
+# define SEC_E_BUFFER_TOO_SMALL ((HRESULT)0x80090321L)
+#endif
+#ifndef SEC_E_CONTEXT_EXPIRED
+# define SEC_E_CONTEXT_EXPIRED ((HRESULT)0x80090317L)
+#endif
+#ifndef SEC_E_CRYPTO_SYSTEM_INVALID
+# define SEC_E_CRYPTO_SYSTEM_INVALID ((HRESULT)0x80090337L)
+#endif
+#ifndef SEC_E_MESSAGE_ALTERED
+# define SEC_E_MESSAGE_ALTERED ((HRESULT)0x8009030FL)
+#endif
+#ifndef SEC_E_OUT_OF_SEQUENCE
+# define SEC_E_OUT_OF_SEQUENCE ((HRESULT)0x80090310L)
+#endif
+
+CURLcode Curl_sspi_global_init(void);
+void Curl_sspi_global_cleanup(void);
+
+/* Forward-declaration of global variables defined in curl_sspi.c */
+
+extern HMODULE s_hSecDll;
+extern PSecurityFunctionTableA s_pSecFn;
+
+#endif /* USE_WINDOWS_SSPI */
+#endif /* HEADER_CURL_SSPI_H */
diff --git a/lib/curl_threads.c b/lib/curl_threads.c
new file mode 100644
index 0000000..fd10bd4
--- /dev/null
+++ b/lib/curl_threads.c
@@ -0,0 +1,127 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+#if defined(USE_THREADS_POSIX)
+#  ifdef HAVE_PTHREAD_H
+#    include <pthread.h>
+#  endif
+#elif defined(USE_THREADS_WIN32)
+#  ifdef HAVE_PROCESS_H
+#    include <process.h>
+#  endif
+#endif
+
+#include "curl_threads.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#if defined(USE_THREADS_POSIX)
+
+struct curl_actual_call {
+  unsigned int (*func)(void *);
+  void *arg;
+};
+
+static void *curl_thread_create_thunk(void *arg)
+{
+  struct curl_actual_call * ac = arg;
+  unsigned int (*func)(void *) = ac->func;
+  void *real_arg = ac->arg;
+
+  free(ac);
+
+  (*func)(real_arg);
+
+  return 0;
+}
+
+curl_thread_t Curl_thread_create(unsigned int (*func) (void*), void *arg)
+{
+  curl_thread_t t;
+  struct curl_actual_call *ac = malloc(sizeof(struct curl_actual_call));
+  if(!ac)
+    return curl_thread_t_null;
+
+  ac->func = func;
+  ac->arg = arg;
+
+  if(pthread_create(&t, NULL, curl_thread_create_thunk, ac) != 0) {
+    free(ac);
+    return curl_thread_t_null;
+  }
+
+  return t;
+}
+
+void Curl_thread_destroy(curl_thread_t hnd)
+{
+  if(hnd != curl_thread_t_null)
+    pthread_detach(hnd);
+}
+
+int Curl_thread_join(curl_thread_t *hnd)
+{
+  int ret = (pthread_join(*hnd, NULL) == 0);
+
+  *hnd = curl_thread_t_null;
+
+  return ret;
+}
+
+#elif defined(USE_THREADS_WIN32)
+
+curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void*), void *arg)
+{
+#ifdef _WIN32_WCE
+  return CreateThread(NULL, 0, func, arg, 0, NULL);
+#else
+  curl_thread_t t;
+  t = (curl_thread_t)_beginthreadex(NULL, 0, func, arg, 0, NULL);
+  if((t == 0) || (t == (curl_thread_t)-1L))
+    return curl_thread_t_null;
+  return t;
+#endif
+}
+
+void Curl_thread_destroy(curl_thread_t hnd)
+{
+  CloseHandle(hnd);
+}
+
+int Curl_thread_join(curl_thread_t *hnd)
+{
+  int ret = (WaitForSingleObject(*hnd, INFINITE) == WAIT_OBJECT_0);
+
+  Curl_thread_destroy(*hnd);
+
+  *hnd = curl_thread_t_null;
+
+  return ret;
+}
+
+#endif /* USE_THREADS_* */
diff --git a/lib/curl_threads.h b/lib/curl_threads.h
new file mode 100644
index 0000000..ba81054
--- /dev/null
+++ b/lib/curl_threads.h
@@ -0,0 +1,57 @@
+#ifndef HEADER_CURL_THREADS_H
+#define HEADER_CURL_THREADS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+#if defined(USE_THREADS_POSIX)
+#  define CURL_STDCALL
+#  define curl_mutex_t           pthread_mutex_t
+#  define curl_thread_t          pthread_t
+#  define curl_thread_t_null     (pthread_t)0
+#  define Curl_mutex_init(m)     pthread_mutex_init(m, NULL)
+#  define Curl_mutex_acquire(m)  pthread_mutex_lock(m)
+#  define Curl_mutex_release(m)  pthread_mutex_unlock(m)
+#  define Curl_mutex_destroy(m)  pthread_mutex_destroy(m)
+#elif defined(USE_THREADS_WIN32)
+#  define CURL_STDCALL           __stdcall
+#  define curl_mutex_t           CRITICAL_SECTION
+#  define curl_thread_t          HANDLE
+#  define curl_thread_t_null     (HANDLE)0
+#  define Curl_mutex_init(m)     InitializeCriticalSection(m)
+#  define Curl_mutex_acquire(m)  EnterCriticalSection(m)
+#  define Curl_mutex_release(m)  LeaveCriticalSection(m)
+#  define Curl_mutex_destroy(m)  DeleteCriticalSection(m)
+#endif
+
+#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
+
+curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void*),
+                                 void *arg);
+
+void Curl_thread_destroy(curl_thread_t hnd);
+
+int Curl_thread_join(curl_thread_t *hnd);
+
+#endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */
+
+#endif /* HEADER_CURL_THREADS_H */
diff --git a/lib/curlx.h b/lib/curlx.h
new file mode 100644
index 0000000..2b7fec5
--- /dev/null
+++ b/lib/curlx.h
@@ -0,0 +1,118 @@
+#ifndef __CURLX_H
+#define __CURLX_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2008, 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.
+ *
+ ***************************************************************************/
+
+/*
+ * 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()
+*/
+
+#include "nonblock.h"
+/* "nonblock.h" provides curlx_nonblock() */
+
+#include "warnless.h"
+/* "warnless.h" provides functions:
+
+  curlx_ultous()
+  curlx_ultouc()
+  curlx_uztosi()
+*/
+
+/* 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_raw_equal Curl_raw_equal
+#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. Undefine them first in case _MPRINTF_REPLACE
+   is set. */
+# undef printf
+# undef fprintf
+# undef sprintf
+# undef snprintf
+# undef vprintf
+# undef vfprintf
+# undef vsprintf
+# undef vsnprintf
+# undef aprintf
+# undef vaprintf
+
+# 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/lib/dict.c b/lib/dict.c
new file mode 100644
index 0000000..1deab76
--- /dev/null
+++ b/lib/dict.c
@@ -0,0 +1,305 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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"
+
+#ifndef CURL_DISABLE_DICT
+
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#ifdef WIN32
+#include <time.h>
+#include <io.h>
+#else
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <netinet/in.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#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
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#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"
+#include "rawstr.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+
+/*
+ * Forward declarations.
+ */
+
+static CURLcode dict_do(struct connectdata *conn, bool *done);
+
+/*
+ * DICT protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_dict = {
+  "DICT",                               /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  dict_do,                              /* do_it */
+  ZERO_NULL,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  ZERO_NULL,                            /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  PORT_DICT,                            /* defport */
+  PROT_DICT                             /* protocol */
+};
+
+static char *unescape_word(struct SessionHandle *data, const char *inputbuff)
+{
+  char *newp;
+  char *dictp;
+  char *ptr;
+  int len;
+  char byte;
+  int olen=0;
+
+  newp = curl_easy_unescape(data, inputbuff, 0, &len);
+  if(!newp)
+    return NULL;
+
+  dictp = malloc(((size_t)len)*2 + 1); /* add one for terminating zero */
+  if(dictp) {
+    /* According to RFC2229 section 2.2, these letters need to be escaped with
+       \[letter] */
+    for(ptr = newp;
+        (byte = *ptr) != 0;
+        ptr++) {
+      if((byte <= 32) || (byte == 127) ||
+          (byte == '\'') || (byte == '\"') || (byte == '\\')) {
+        dictp[olen++] = '\\';
+      }
+      dictp[olen++] = byte;
+    }
+    dictp[olen]=0;
+
+    free(newp);
+  }
+  return dictp;
+}
+
+static CURLcode dict_do(struct connectdata *conn, bool *done)
+{
+  char *word;
+  char *eword;
+  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=CURLE_OK;
+  struct SessionHandle *data=conn->data;
+  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+
+  char *path = data->state.path;
+  curl_off_t *bytecount = &data->req.bytecount;
+
+  *done = TRUE; /* unconditionally */
+
+  if(conn->bits.user_passwd) {
+    /* AUTH is missing */
+  }
+
+  if(Curl_raw_nequal(path, DICT_MATCH, sizeof(DICT_MATCH)-1) ||
+      Curl_raw_nequal(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) ||
+      Curl_raw_nequal(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)) {
+      infof(data, "lookup word is missing");
+      word=(char *)"default";
+    }
+    if((database == NULL) || (*database == (char)0)) {
+      database = (char *)"!";
+    }
+    if((strategy == NULL) || (*strategy == (char)0)) {
+      strategy = (char *)".";
+    }
+
+    eword = unescape_word(data, word);
+    if(!eword)
+      return CURLE_OUT_OF_MEMORY;
+
+    result = Curl_sendf(sockfd, conn,
+                        "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
+                        "MATCH "
+                        "%s "    /* database */
+                        "%s "    /* strategy */
+                        "%s\r\n" /* word */
+                        "QUIT\r\n",
+
+                        database,
+                        strategy,
+                        eword
+                        );
+
+    free(eword);
+
+    if(result)
+      failf(data, "Failed sending DICT request");
+    else
+      result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
+                                   -1, NULL); /* no upload */
+    if(result)
+      return result;
+  }
+  else if(Curl_raw_nequal(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
+           Curl_raw_nequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
+           Curl_raw_nequal(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)) {
+      infof(data, "lookup word is missing");
+      word=(char *)"default";
+    }
+    if((database == NULL) || (*database == (char)0)) {
+      database = (char *)"!";
+    }
+
+    eword = unescape_word(data, word);
+    if(!eword)
+      return CURLE_OUT_OF_MEMORY;
+
+    result = Curl_sendf(sockfd, conn,
+                        "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
+                        "DEFINE "
+                        "%s "     /* database */
+                        "%s\r\n"  /* word */
+                        "QUIT\r\n",
+                        database,
+                        eword);
+
+    free(eword);
+
+    if(result)
+      failf(data, "Failed sending DICT request");
+    else
+      result = Curl_setup_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 "\r\n"
+                          "%s\r\n"
+                          "QUIT\r\n", ppath);
+      if(result)
+        failf(data, "Failed sending DICT request");
+      else
+        result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
+                                     -1, NULL);
+      if(result)
+        return result;
+    }
+  }
+
+  return CURLE_OK;
+}
+#endif /*CURL_DISABLE_DICT*/
diff --git a/lib/dict.h b/lib/dict.h
new file mode 100644
index 0000000..44fd9d4
--- /dev/null
+++ b/lib/dict.h
@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_DICT_H
+#define HEADER_CURL_DICT_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+#ifndef CURL_DISABLE_DICT
+extern const struct Curl_handler Curl_handler_dict;
+#endif
+
+#endif /* HEADER_CURL_DICT_H */
diff --git a/lib/easy.c b/lib/easy.c
new file mode 100644
index 0000000..35fb018
--- /dev/null
+++ b/lib/easy.c
@@ -0,0 +1,1153 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "strequal.h"
+
+#ifdef WIN32
+#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
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#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
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#endif  /* WIN32 ... */
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sslgen.h"
+#include "url.h"
+#include "getinfo.h"
+#include "hostip.h"
+#include "share.h"
+#include "strdup.h"
+#include "curl_memory.h"
+#include "progress.h"
+#include "easyif.h"
+#include "select.h"
+#include "sendf.h" /* for failf function prototype */
+#include "http_ntlm.h"
+#include "connect.h" /* for Curl_getconnectinfo */
+#include "slist.h"
+#include "curl_rand.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
+#include <iconv.h>
+/* set default codesets for iconv */
+#ifndef CURL_ICONV_CODESET_OF_NETWORK
+#define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1"
+#endif
+#ifndef CURL_ICONV_CODESET_FOR_UTF8
+#define CURL_ICONV_CODESET_FOR_UTF8   "UTF-8"
+#endif
+#define ICONV_ERROR  (size_t)-1
+#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* win32_cleanup() is for win32 socket cleanup functionality, the opposite
+   of win32_init() */
+static void win32_cleanup(void)
+{
+#ifdef USE_WINSOCK
+  WSACleanup();
+#endif
+#ifdef USE_WINDOWS_SSPI
+  Curl_sspi_global_cleanup();
+#endif
+}
+
+/* win32_init() performs win32 socket initialization to properly setup the
+   stack to allow networking */
+static CURLcode win32_init(void)
+{
+#ifdef USE_WINSOCK
+  WORD wVersionRequested;
+  WSADATA wsaData;
+  int res;
+
+#if defined(ENABLE_IPV6) && (USE_WINSOCK < 2)
+  Error IPV6_requires_winsock2
+#endif
+
+  wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK);
+
+  res = WSAStartup(wVersionRequested, &wsaData);
+
+  if(res != 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. */
+#endif
+
+#ifdef USE_WINDOWS_SSPI
+  {
+    CURLcode err = Curl_sspi_global_init();
+    if (err != CURLE_OK)
+      return err;
+  }
+#endif
+
+  return CURLE_OK;
+}
+
+#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;
+static long          init_flags;
+
+/*
+ * strdup (and other memory functions) is redefined in complicated
+ * ways, but at this point it must be defined as the system-supplied strdup
+ * so the callback pointer is initialized correctly.
+ */
+#if defined(_WIN32_WCE)
+#define system_strdup _strdup
+#elif !defined(HAVE_STRDUP)
+#define system_strdup curlx_strdup
+#else
+#define system_strdup strdup
+#endif
+
+#if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__)
+#  pragma warning(disable:4232) /* MSVC extension, dllimport identity */
+#endif
+
+#ifndef __SYMBIAN32__
+/*
+ * 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)system_strdup;
+curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
+#else
+/*
+ * Symbian OS doesn't support initialization to code in writeable static data.
+ * Initialization will occur in the curl_global_init() call.
+ */
+curl_malloc_callback Curl_cmalloc;
+curl_free_callback Curl_cfree;
+curl_realloc_callback Curl_crealloc;
+curl_strdup_callback Curl_cstrdup;
+curl_calloc_callback Curl_ccalloc;
+#endif
+
+#if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__)
+#  pragma warning(default:4232) /* MSVC extension, dllimport identity */
+#endif
+
+/**
+ * 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)system_strdup;
+  Curl_ccalloc = (curl_calloc_callback)calloc;
+
+  if(flags & CURL_GLOBAL_SSL)
+    if(!Curl_ssl_init()) {
+      DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n"));
+      return CURLE_FAILED_INIT;
+    }
+
+  if(flags & CURL_GLOBAL_WIN32)
+    if(win32_init() != CURLE_OK) {
+      DEBUGF(fprintf(stderr, "Error: win32_init failed\n"));
+      return CURLE_FAILED_INIT;
+    }
+
+#ifdef __AMIGA__
+  if(!amiga_init()) {
+    DEBUGF(fprintf(stderr, "Error: amiga_init failed\n"));
+    return CURLE_FAILED_INIT;
+  }
+#endif
+
+#ifdef NETWARE
+  if(netware_init()) {
+    DEBUGF(fprintf(stderr, "Warning: LONG namespace not available\n"));
+  }
+#endif
+
+#ifdef USE_LIBIDN
+  idna_init();
+#endif
+
+#ifdef CARES_HAVE_ARES_LIBRARY_INIT
+  if(ares_library_init(ARES_LIB_INIT_ALL)) {
+    DEBUGF(fprintf(stderr, "Error: ares_library_init failed\n"));
+    return CURLE_FAILED_INIT;
+  }
+#endif
+
+  init_flags  = flags;
+
+  /* Preset pseudo-random number sequence. */
+
+  Curl_srand();
+
+  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 = CURLE_OK;
+
+  /* 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;
+
+  if(--initialized)
+    return;
+
+  Curl_global_host_cache_dtor();
+
+  if(init_flags & CURL_GLOBAL_SSL)
+    Curl_ssl_cleanup();
+
+#ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP
+  ares_library_cleanup();
+#endif
+
+  if(init_flags & CURL_GLOBAL_WIN32)
+    win32_cleanup();
+
+#ifdef __AMIGA__
+  amiga_cleanup();
+#endif
+
+  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 */
+      DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n"));
+      return NULL;
+    }
+  }
+
+  /* We use curl_open() with undefined URL so far */
+  res = Curl_open(&data);
+  if(res != CURLE_OK) {
+    DEBUGF(fprintf(stderr, "Error: Curl_open failed\n"));
+    return NULL;
+  }
+
+  return data;
+}
+
+/*
+ * curl_easy_setopt() is the external interface for setting options on an
+ * easy handle.
+ */
+
+#undef curl_easy_setopt
+CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
+{
+  va_list arg;
+  struct SessionHandle *data = curl;
+  CURLcode ret;
+
+  if(!curl)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  va_start(arg, tag);
+
+  ret = Curl_setopt(data, tag, arg);
+
+  va_end(arg);
+  return ret;
+}
+
+#ifdef CURL_MULTIEASY
+/***************************************************************************
+ * This function is still only for testing purposes. It makes a great way
+ * to run the full test suite on the multi interface instead of the easy one.
+ ***************************************************************************
+ *
+ * The *new* curl_easy_perform() is the external interface that performs a
+ * transfer previously setup.
+ *
+ * Wrapper-function that: creates a multi handle, adds the easy handle to it,
+ * runs curl_multi_perform() until the transfer is done, then detaches the
+ * easy handle, destroys the multi handle and returns the easy handle's return
+ * code. This will make everything internally use and assume multi interface.
+ */
+CURLcode curl_easy_perform(CURL *easy)
+{
+  CURLM *multi;
+  CURLMcode mcode;
+  CURLcode code = CURLE_OK;
+  int still_running;
+  struct timeval timeout;
+  int rc;
+  CURLMsg *msg;
+  fd_set fdread;
+  fd_set fdwrite;
+  fd_set fdexcep;
+  int maxfd;
+
+  if(!easy)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  multi = curl_multi_init();
+  if(!multi)
+    return CURLE_OUT_OF_MEMORY;
+
+  mcode = curl_multi_add_handle(multi, easy);
+  if(mcode) {
+    curl_multi_cleanup(multi);
+    if(mcode == CURLM_OUT_OF_MEMORY)
+      return CURLE_OUT_OF_MEMORY;
+    else
+      return CURLE_FAILED_INIT;
+  }
+
+  /* we start some action by calling perform right away */
+
+  do {
+    while(CURLM_CALL_MULTI_PERFORM ==
+          curl_multi_perform(multi, &still_running));
+
+    if(!still_running)
+      break;
+
+    FD_ZERO(&fdread);
+    FD_ZERO(&fdwrite);
+    FD_ZERO(&fdexcep);
+
+    /* timeout once per second */
+    timeout.tv_sec = 1;
+    timeout.tv_usec = 0;
+
+    /* Old deprecated style: get file descriptors from the transfers */
+    curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &maxfd);
+    rc = Curl_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
+
+    /* The way is to extract the sockets and wait for them without using
+       select. This whole alternative version should probably rather use the
+       curl_multi_socket() approach. */
+
+    if(rc == -1)
+      /* select error */
+      break;
+
+    /* timeout or data to send/receive => loop! */
+  } while(still_running);
+
+  msg = curl_multi_info_read(multi, &rc);
+  if(msg)
+    code = msg->data.result;
+
+  mcode = curl_multi_remove_handle(multi, easy);
+  /* what to do if it fails? */
+
+  mcode = curl_multi_cleanup(multi);
+  /* what to do if it fails? */
+
+  return code;
+}
+#else
+/*
+ * 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) ) {
+    /* this handle is not using a shared dns cache */
+
+    if(data->set.global_dns_cache &&
+       (data->dns.hostcachetype != HCACHE_GLOBAL)) {
+      /* global dns cache was requested but still isn't */
+      struct curl_hash *ptr;
+
+      if(data->dns.hostcachetype == HCACHE_PRIVATE) {
+        /* if the current cache is private, kill it first */
+        Curl_hash_destroy(data->dns.hostcache);
+        data->dns.hostcachetype = HCACHE_NONE;
+        data->dns.hostcache = NULL;
+      }
+
+      ptr = Curl_global_host_cache_init();
+      if(ptr) {
+        /* only do this if the global cache init works */
+        data->dns.hostcache = ptr;
+        data->dns.hostcachetype = HCACHE_GLOBAL;
+      }
+    }
+
+    if(!data->dns.hostcache) {
+      data->dns.hostcachetype = HCACHE_PRIVATE;
+      data->dns.hostcache = Curl_mk_dnscache();
+
+      if(!data->dns.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;
+    }
+
+  }
+
+  if(!data->state.connc) {
+    /* oops, no connection cache, make one up */
+    data->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, -1L);
+    if(!data->state.connc)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  return Curl_perform(data);
+}
+#endif
+
+/*
+ * 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;
+
+  Curl_close(data);
+}
+
+/*
+ * Store a pointed to the multi handle within the easy handle's data struct.
+ */
+void Curl_easy_addmulti(struct SessionHandle *data,
+                        void *multi)
+{
+  data->multi = multi;
+  if(multi == NULL)
+    /* the association is cleared, mark the easy handle as not used by an
+       interface */
+    data->state.used_interface = Curl_if_none;
+}
+
+void Curl_easy_initHandleData(struct SessionHandle *data)
+{
+    memset(&data->req, 0, sizeof(struct SingleRequest));
+
+    data->req.maxdownload = -1;
+}
+
+/*
+ * curl_easy_getinfo() is an external interface that allows an app to retrieve
+ * information from a performed transfer and similar.
+ */
+#undef curl_easy_getinfo
+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 = calloc(1, sizeof(struct SessionHandle));
+
+  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 = malloc(HEADERSIZE);
+    if(!outcurl->state.headerbuff) {
+      break;
+    }
+    outcurl->state.headersize=HEADERSIZE;
+
+    /* copy all userdefined values */
+    if(Curl_dupset(outcurl, data) != CURLE_OK)
+      break;
+
+    /* the connection cache is setup on demand */
+    outcurl->state.connc = NULL;
+
+    outcurl->state.lastconnect = -1;
+
+    outcurl->progress.flags    = data->progress.flags;
+    outcurl->progress.callback = data->progress.callback;
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+    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 !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+    if(data->change.cookielist) {
+      outcurl->change.cookielist =
+        Curl_slist_duplicate(data->change.cookielist);
+
+      if (!outcurl->change.cookielist)
+        break;
+    }
+#endif   /* CURL_DISABLE_HTTP */
+
+    if(data->change.url) {
+      outcurl->change.url = strdup(data->change.url);
+      if(!outcurl->change.url)
+        break;
+      outcurl->change.url_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
+
+#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
+    outcurl->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+                                     CURL_ICONV_CODESET_OF_NETWORK);
+    outcurl->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
+                                      CURL_ICONV_CODESET_OF_HOST);
+    outcurl->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+                                  CURL_ICONV_CODESET_FOR_UTF8);
+#endif
+
+    Curl_easy_initHandleData(outcurl);
+
+    outcurl->magic = CURLEASY_MAGIC_NUMBER;
+
+    fail = FALSE; /* we reach this point and thus we are OK */
+
+  } while(0);
+
+  if(fail) {
+    if(outcurl) {
+      if(outcurl->state.connc &&
+         (outcurl->state.connc->type == CONNCACHE_PRIVATE))
+        Curl_rm_connc(outcurl->state.connc);
+      if(outcurl->state.headerbuff)
+        free(outcurl->state.headerbuff);
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+      if(outcurl->change.cookielist)
+        curl_slist_free_all(outcurl->change.cookielist);
+#endif
+      if(outcurl->change.url)
+        free(outcurl->change.url);
+      if(outcurl->change.referer)
+        free(outcurl->change.referer);
+      Curl_freeset(outcurl);
+      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;
+
+  Curl_safefree(data->state.pathbuffer);
+  data->state.pathbuffer=NULL;
+
+  Curl_safefree(data->state.proto.generic);
+  data->state.proto.generic=NULL;
+
+  /* zero out UserDefined data: */
+  Curl_freeset(data);
+  memset(&data->set, 0, sizeof(struct UserDefined));
+  (void)Curl_init_userdefined(&data->set);
+
+  /* zero out Progress data: */
+  memset(&data->progress, 0, sizeof(struct Progress));
+
+  /* init Handle data */
+  Curl_easy_initHandleData(data);
+
+  data->progress.flags |= PGRS_HIDE;
+  data->state.current_speed = -1; /* init to negative == impossible */
+}
+
+/*
+ * curl_easy_pause() allows an application to pause or unpause a specific
+ * transfer and direction. This function sets the full new state for the
+ * current connection this easy handle operates on.
+ *
+ * NOTE: if you have the receiving paused and you call this function to remove
+ * the pausing, you may get your write callback called at this point.
+ *
+ * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h
+ */
+CURLcode curl_easy_pause(CURL *curl, int action)
+{
+  struct SessionHandle *data = (struct SessionHandle *)curl;
+  struct SingleRequest *k = &data->req;
+  CURLcode result = CURLE_OK;
+
+  /* first switch off both pause bits */
+  int newstate = k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE);
+
+  /* set the new desired pause bits */
+  newstate |= ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) |
+    ((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0);
+
+  /* put it back in the keepon */
+  k->keepon = newstate;
+
+  if(!(newstate & KEEP_RECV_PAUSE) && data->state.tempwrite) {
+    /* we have a buffer for sending that we now seem to be able to deliver since
+       the receive pausing is lifted! */
+
+    /* get the pointer, type and length in local copies since the function may
+       return PAUSE again and then we'll get a new copy allocted and stored in
+       the tempwrite variables */
+    char *tempwrite = data->state.tempwrite;
+    char *freewrite = tempwrite; /* store this pointer to free it later */
+    size_t tempsize = data->state.tempwritesize;
+    int temptype = data->state.tempwritetype;
+    size_t chunklen;
+
+    /* clear tempwrite here just to make sure it gets cleared if there's no
+       further use of it, and make sure we don't clear it after the function
+       invoke as it may have been set to a new value by then */
+    data->state.tempwrite = NULL;
+
+    /* since the write callback API is define to never exceed
+       CURL_MAX_WRITE_SIZE bytes in a single call, and since we may in fact
+       have more data than that in our buffer here, we must loop sending the
+       data in multiple calls until there's no data left or we get another
+       pause returned.
+
+       A tricky part is that the function we call will "buffer" the data
+       itself when it pauses on a particular buffer, so we may need to do some
+       extra trickery if we get a pause return here.
+    */
+    do {
+      chunklen = (tempsize > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:tempsize;
+
+      result = Curl_client_write(data->state.current_conn,
+                                 temptype, tempwrite, chunklen);
+      if(result)
+        /* failures abort the loop at once */
+        break;
+
+      if(data->state.tempwrite && (tempsize - chunklen)) {
+        /* Ouch, the reading is again paused and the block we send is now
+           "cached". If this is the final chunk we can leave it like this, but
+           if we have more chunks that are cached after this, we need to free
+           the newly cached one and put back a version that is truly the entire
+           contents that is saved for later
+        */
+        char *newptr;
+
+        /* note that tempsize is still the size as before the callback was
+           used, and thus the whole piece of data to keep */
+        newptr = realloc(data->state.tempwrite, tempsize);
+
+        if(!newptr) {
+          free(data->state.tempwrite); /* free old area */
+          data->state.tempwrite = NULL;
+          result = CURLE_OUT_OF_MEMORY;
+          /* tempwrite will be freed further down */
+          break;
+        }
+        data->state.tempwrite = newptr; /* store new pointer */
+        memcpy(newptr, tempwrite, tempsize);
+        data->state.tempwritesize = tempsize; /* store new size */
+        /* tempwrite will be freed further down */
+        break; /* go back to pausing until further notice */
+      }
+      else {
+        tempsize -= chunklen;  /* left after the call above */
+        tempwrite += chunklen; /* advance the pointer */
+      }
+
+    } while((result == CURLE_OK) && tempsize);
+
+    free(freewrite); /* this is unconditionally no longer used */
+  }
+
+  return result;
+}
+
+#ifdef CURL_DOES_CONVERSIONS
+/*
+ * Curl_convert_to_network() is an internal function
+ * for performing ASCII conversions on non-ASCII platforms.
+ */
+CURLcode Curl_convert_to_network(struct SessionHandle *data,
+                                 char *buffer, size_t length)
+{
+  CURLcode rc;
+
+  if(data->set.convtonetwork) {
+    /* use translation callback */
+    rc = data->set.convtonetwork(buffer, length);
+    if(rc != CURLE_OK) {
+      failf(data,
+            "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %d: %s",
+            (int)rc, curl_easy_strerror(rc));
+    }
+    return(rc);
+  }
+  else {
+#ifdef HAVE_ICONV
+    /* do the translation ourselves */
+    char *input_ptr, *output_ptr;
+    size_t in_bytes, out_bytes, rc;
+    int error;
+
+    /* open an iconv conversion descriptor if necessary */
+    if(data->outbound_cd == (iconv_t)-1) {
+      data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
+                                     CURL_ICONV_CODESET_OF_HOST);
+      if(data->outbound_cd == (iconv_t)-1) {
+        error = ERRNO;
+        failf(data,
+              "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
+               CURL_ICONV_CODESET_OF_NETWORK,
+               CURL_ICONV_CODESET_OF_HOST,
+               error, strerror(error));
+        return CURLE_CONV_FAILED;
+      }
+    }
+    /* call iconv */
+    input_ptr = output_ptr = buffer;
+    in_bytes = out_bytes = length;
+    rc = iconv(data->outbound_cd, (const char**)&input_ptr, &in_bytes,
+               &output_ptr, &out_bytes);
+    if((rc == ICONV_ERROR) || (in_bytes != 0)) {
+      error = ERRNO;
+      failf(data,
+        "The Curl_convert_to_network iconv call failed with errno %i: %s",
+             error, strerror(error));
+      return CURLE_CONV_FAILED;
+    }
+#else
+    failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required");
+    return CURLE_CONV_REQD;
+#endif /* HAVE_ICONV */
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_convert_from_network() is an internal function
+ * for performing ASCII conversions on non-ASCII platforms.
+ */
+CURLcode Curl_convert_from_network(struct SessionHandle *data,
+                                      char *buffer, size_t length)
+{
+  CURLcode rc;
+
+  if(data->set.convfromnetwork) {
+    /* use translation callback */
+    rc = data->set.convfromnetwork(buffer, length);
+    if(rc != CURLE_OK) {
+      failf(data,
+            "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %d: %s",
+            (int)rc, curl_easy_strerror(rc));
+    }
+    return(rc);
+  }
+  else {
+#ifdef HAVE_ICONV
+    /* do the translation ourselves */
+    char *input_ptr, *output_ptr;
+    size_t in_bytes, out_bytes, rc;
+    int error;
+
+    /* open an iconv conversion descriptor if necessary */
+    if(data->inbound_cd == (iconv_t)-1) {
+      data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+                                    CURL_ICONV_CODESET_OF_NETWORK);
+      if(data->inbound_cd == (iconv_t)-1) {
+        error = ERRNO;
+        failf(data,
+              "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
+              CURL_ICONV_CODESET_OF_HOST,
+              CURL_ICONV_CODESET_OF_NETWORK,
+              error, strerror(error));
+        return CURLE_CONV_FAILED;
+      }
+    }
+    /* call iconv */
+    input_ptr = output_ptr = buffer;
+    in_bytes = out_bytes = length;
+    rc = iconv(data->inbound_cd, (const char **)&input_ptr, &in_bytes,
+               &output_ptr, &out_bytes);
+    if((rc == ICONV_ERROR) || (in_bytes != 0)) {
+      error = ERRNO;
+      failf(data,
+            "The Curl_convert_from_network iconv call failed with errno %i: %s",
+            error, strerror(error));
+      return CURLE_CONV_FAILED;
+    }
+#else
+    failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required");
+    return CURLE_CONV_REQD;
+#endif /* HAVE_ICONV */
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_convert_from_utf8() is an internal function
+ * for performing UTF-8 conversions on non-ASCII platforms.
+ */
+CURLcode Curl_convert_from_utf8(struct SessionHandle *data,
+                                     char *buffer, size_t length)
+{
+  CURLcode rc;
+
+  if(data->set.convfromutf8) {
+    /* use translation callback */
+    rc = data->set.convfromutf8(buffer, length);
+    if(rc != CURLE_OK) {
+      failf(data,
+            "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %d: %s",
+            (int)rc, curl_easy_strerror(rc));
+    }
+    return(rc);
+  }
+  else {
+#ifdef HAVE_ICONV
+    /* do the translation ourselves */
+    const char *input_ptr;
+    char *output_ptr;
+    size_t in_bytes, out_bytes, rc;
+    int error;
+
+    /* open an iconv conversion descriptor if necessary */
+    if(data->utf8_cd == (iconv_t)-1) {
+      data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+                                 CURL_ICONV_CODESET_FOR_UTF8);
+      if(data->utf8_cd == (iconv_t)-1) {
+        error = ERRNO;
+        failf(data,
+              "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
+              CURL_ICONV_CODESET_OF_HOST,
+              CURL_ICONV_CODESET_FOR_UTF8,
+              error, strerror(error));
+        return CURLE_CONV_FAILED;
+      }
+    }
+    /* call iconv */
+    input_ptr = output_ptr = buffer;
+    in_bytes = out_bytes = length;
+    rc = iconv(data->utf8_cd, &input_ptr, &in_bytes,
+               &output_ptr, &out_bytes);
+    if((rc == ICONV_ERROR) || (in_bytes != 0)) {
+      error = ERRNO;
+      failf(data,
+            "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
+            error, strerror(error));
+      return CURLE_CONV_FAILED;
+    }
+    if(output_ptr < input_ptr) {
+      /* null terminate the now shorter output string */
+      *output_ptr = 0x00;
+    }
+#else
+    failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required");
+    return CURLE_CONV_REQD;
+#endif /* HAVE_ICONV */
+  }
+
+  return CURLE_OK;
+}
+
+#endif /* CURL_DOES_CONVERSIONS */
+
+static CURLcode easy_connection(struct SessionHandle *data,
+                                curl_socket_t *sfd,
+                                struct connectdata **connp)
+{
+  CURLcode ret;
+  long sockfd;
+
+  if(data == NULL)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
+  if(!data->set.connect_only) {
+    failf(data, "CONNECT_ONLY is required!");
+    return CURLE_UNSUPPORTED_PROTOCOL;
+  }
+
+  ret = Curl_getconnectinfo(data, &sockfd, connp);
+  if(ret != CURLE_OK)
+    return ret;
+
+  if(sockfd == -1) {
+    failf(data, "Failed to get recent socket");
+    return CURLE_UNSUPPORTED_PROTOCOL;
+  }
+
+  *sfd = (curl_socket_t)sockfd; /* we know that this is actually a socket
+                                   descriptor so the typecast is fine here */
+
+  return CURLE_OK;
+}
+
+/*
+ * Receives data from the connected socket. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ * Returns CURLE_OK on success, error code on error.
+ */
+CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n)
+{
+  curl_socket_t sfd;
+  CURLcode ret;
+  int ret1;
+  ssize_t n1;
+  struct connectdata *c;
+  struct SessionHandle *data = (struct SessionHandle *)curl;
+
+  ret = easy_connection(data, &sfd, &c);
+  if(ret)
+    return ret;
+
+  *n = 0;
+  ret1 = Curl_read(c, sfd, buffer, buflen, &n1);
+
+  if(ret1 == -1)
+    return CURLE_AGAIN;
+
+  if(ret1 != CURLE_OK)
+    return (CURLcode)ret1;
+
+  *n = (size_t)n1;
+
+  return CURLE_OK;
+}
+
+/*
+ * Sends data over the connected socket. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ */
+CURLcode curl_easy_send(CURL *curl, const void *buffer, size_t buflen,
+                        size_t *n)
+{
+  curl_socket_t sfd;
+  CURLcode ret;
+  ssize_t n1;
+  struct connectdata *c = NULL;
+  struct SessionHandle *data = (struct SessionHandle *)curl;
+
+  ret = easy_connection(data, &sfd, &c);
+  if(ret)
+    return ret;
+
+  *n = 0;
+  ret = Curl_write(c, sfd, buffer, buflen, &n1);
+
+  if(n1 == -1)
+    return CURLE_SEND_ERROR;
+
+  /* detect EAGAIN */
+  if((CURLE_OK == ret) && (0 == n1))
+    return CURLE_AGAIN;
+
+  *n = (size_t)n1;
+
+  return ret;
+}
diff --git a/lib/easyif.h b/lib/easyif.h
new file mode 100644
index 0000000..8a0a51c
--- /dev/null
+++ b/lib/easyif.h
@@ -0,0 +1,39 @@
+#ifndef __EASYIF_H
+#define __EASYIF_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * 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.
+ *
+ ***************************************************************************/
+
+/*
+ * Prototypes for library-wide functions provided by easy.c
+ */
+void Curl_easy_addmulti(struct SessionHandle *data, void *multi);
+
+void Curl_easy_initHandleData(struct SessionHandle *data);
+
+CURLcode Curl_convert_to_network(struct SessionHandle *data,
+                                 char *buffer, size_t length);
+CURLcode Curl_convert_from_network(struct SessionHandle *data,
+                                 char *buffer, size_t length);
+CURLcode Curl_convert_from_utf8(struct SessionHandle *data,
+                                 char *buffer, size_t length);
+
+#endif /* __EASYIF_H */
diff --git a/lib/escape.c b/lib/escape.c
new file mode 100644
index 0000000..37d21e7
--- /dev/null
+++ b/lib/escape.c
@@ -0,0 +1,210 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+/* 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"
+/* urldata.h and easyif.h are included for Curl_convert_... prototypes */
+#include "urldata.h"
+#include "easyif.h"
+#include "warnless.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* Portable character check (remember EBCDIC). Do not use isalnum() because
+its behavior is altered by the current locale. */
+static bool Curl_isalnum(unsigned char in)
+{
+  switch (in) {
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+    case 'a': case 'b': case 'c': case 'd': case 'e':
+    case 'f': case 'g': case 'h': case 'i': case 'j':
+    case 'k': case 'l': case 'm': case 'n': case 'o':
+    case 'p': case 'q': case 'r': case 's': case 't':
+    case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
+    case 'A': case 'B': case 'C': case 'D': case 'E':
+    case 'F': case 'G': case 'H': case 'I': case 'J':
+    case 'K': case 'L': case 'M': case 'N': case 'O':
+    case 'P': case 'Q': case 'R': case 'S': case 'T':
+    case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
+      return TRUE;
+    default:
+      break;
+  }
+  return FALSE;
+}
+
+/* for ABI-compatibility with previous versions */
+char *curl_escape(const char *string, int inlength)
+{
+  return curl_easy_escape(NULL, string, inlength);
+}
+
+/* for ABI-compatibility with previous versions */
+char *curl_unescape(const char *string, int length)
+{
+  return curl_easy_unescape(NULL, string, length, NULL);
+}
+
+char *curl_easy_escape(CURL *handle, const char *string, int inlength)
+{
+  size_t alloc = (inlength?(size_t)inlength:strlen(string))+1;
+  char *ns;
+  char *testing_ptr = NULL;
+  unsigned char in; /* we need to treat the characters unsigned */
+  size_t newlen = alloc;
+  int strindex=0;
+  size_t length;
+
+#ifndef CURL_DOES_CONVERSIONS
+  /* avoid compiler warnings */
+  (void)handle;
+#endif
+  ns = malloc(alloc);
+  if(!ns)
+    return NULL;
+
+  length = alloc-1;
+  while(length--) {
+    in = *string;
+
+    if (Curl_isalnum(in)) {
+      /* just copy this */
+      ns[strindex++]=in;
+    }
+    else {
+      /* 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;
+        }
+      }
+
+#ifdef CURL_DOES_CONVERSIONS
+/* escape sequences are always in ASCII so convert them on non-ASCII hosts */
+      if(!handle ||
+          (Curl_convert_to_network(handle, &in, 1) != CURLE_OK)) {
+        /* Curl_convert_to_network calls failf if unsuccessful */
+        free(ns);
+        return NULL;
+      }
+#endif /* CURL_DOES_CONVERSIONS */
+
+      snprintf(&ns[strindex], 4, "%%%02X", in);
+
+      strindex+=3;
+    }
+    string++;
+  }
+  ns[strindex]=0; /* terminate it */
+  return ns;
+}
+
+/*
+ * Unescapes the given URL escaped string of given length. Returns a
+ * pointer to a malloced string with length given in *olen.
+ * If length == 0, the length is assumed to be strlen(string).
+ * If olen == NULL, no output length is stored.
+ */
+char *curl_easy_unescape(CURL *handle, const char *string, int length,
+                         int *olen)
+{
+  int alloc = (length?length:(int)strlen(string))+1;
+  char *ns = malloc(alloc);
+  unsigned char in;
+  int strindex=0;
+  unsigned long hex;
+
+#ifndef CURL_DOES_CONVERSIONS
+  /* avoid compiler warnings */
+  (void)handle;
+#endif
+  if( !ns )
+    return NULL;
+
+  while(--alloc > 0) {
+    in = *string;
+    if(('%' == in) && ISXDIGIT(string[1]) && ISXDIGIT(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 = strtoul(hexstr, &ptr, 16);
+
+      in = curlx_ultouc(hex); /* this long is never bigger than 255 anyway */
+
+#ifdef CURL_DOES_CONVERSIONS
+/* escape sequences are always in ASCII so convert them on non-ASCII hosts */
+      if(!handle ||
+          (Curl_convert_from_network(handle, &in, 1) != CURLE_OK)) {
+        /* Curl_convert_from_network calls failf if unsuccessful */
+        free(ns);
+        return NULL;
+      }
+#endif /* CURL_DOES_CONVERSIONS */
+
+      string+=2;
+      alloc-=2;
+    }
+
+    ns[strindex++] = in;
+    string++;
+  }
+  ns[strindex]=0; /* terminate it */
+
+  if(olen)
+    /* store output size */
+    *olen = strindex;
+  return ns;
+}
+
+/* For operating systems/environments that use different malloc/free
+   systems 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/lib/escape.h b/lib/escape.h
new file mode 100644
index 0000000..04b06a9
--- /dev/null
+++ b/lib/escape.h
@@ -0,0 +1,29 @@
+#ifndef __ESCAPE_H
+#define __ESCAPE_H
+
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * 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.
+ *
+ ***************************************************************************/
+/* Escape and unescape URL encoding in strings. The functions return a new
+ * allocated string or NULL if an error occurred.  */
+
+
+#endif
diff --git a/lib/file.c b/lib/file.c
new file mode 100644
index 0000000..6c14ee8
--- /dev/null
+++ b/lib/file.c
@@ -0,0 +1,585 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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"
+
+#ifndef CURL_DISABLE_FILE
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#ifdef WIN32
+#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
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#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
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#endif /* WIN32 */
+
+#include "strtoofft.h"
+#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"
+#include "parsedate.h" /* for the week day and month names */
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#if defined(WIN32) || defined(MSDOS) || defined(__EMX__) || defined(__SYMBIAN32__)
+#define DOS_FILESYSTEM 1
+#endif
+
+#ifdef OPEN_NEEDS_ARG3
+#  define open_readonly(p,f) open((p),(f),(0))
+#else
+#  define open_readonly(p,f) open((p),(f))
+#endif
+
+/*
+ * Forward declarations.
+ */
+
+static CURLcode file_do(struct connectdata *, bool *done);
+static CURLcode file_done(struct connectdata *conn,
+                          CURLcode status, bool premature);
+static CURLcode file_connect(struct connectdata *conn, bool *done);
+
+/*
+ * FILE scheme handler.
+ */
+
+const struct Curl_handler Curl_handler_file = {
+  "FILE",                               /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  file_do,                              /* do_it */
+  file_done,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  file_connect,                         /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  0,                                    /* defport */
+  PROT_FILE                             /* protocol */
+};
+
+
+ /*
+  Check if this is a range download, and if so, set the internal variables
+  properly. This code is copied from the FTP implementation and might as
+  well be factored out.
+ */
+static CURLcode file_range(struct connectdata *conn)
+{
+  curl_off_t from, to;
+  curl_off_t totalsize=-1;
+  char *ptr;
+  char *ptr2;
+  struct SessionHandle *data = conn->data;
+
+  if(data->state.use_range && data->state.range) {
+    from=curlx_strtoofft(data->state.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 - */
+      data->state.resume_from = from;
+      DEBUGF(infof(data, "RANGE %" FORMAT_OFF_T " to end of file\n",
+                   from));
+    }
+    else if(from < 0) {
+      /* -Y */
+      totalsize = -from;
+      data->req.maxdownload = -from;
+      data->state.resume_from = from;
+      DEBUGF(infof(data, "RANGE the last %" FORMAT_OFF_T " bytes\n",
+                   totalsize));
+    }
+    else {
+      /* X-Y */
+      totalsize = to-from;
+      data->req.maxdownload = totalsize+1; /* include last byte */
+      data->state.resume_from = from;
+      DEBUGF(infof(data, "RANGE from %" FORMAT_OFF_T
+                   " getting %" FORMAT_OFF_T " bytes\n",
+                   from, data->req.maxdownload));
+    }
+    DEBUGF(infof(data, "range-download from %" FORMAT_OFF_T
+                 " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
+                 from, to, data->req.maxdownload));
+  }
+  else
+    data->req.maxdownload = -1;
+  return CURLE_OK;
+}
+
+/*
+ * 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
+ */
+static CURLcode file_connect(struct connectdata *conn, bool *done)
+{
+  struct SessionHandle *data = conn->data;
+  char *real_path = curl_easy_unescape(data, data->state.path, 0, NULL);
+  struct FILEPROTO *file;
+  int fd;
+#ifdef DOS_FILESYSTEM
+  int i;
+  char *actual_path;
+#endif
+
+  if(!real_path)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* If there already is a protocol-specific struct allocated for this
+     sessionhandle, deal with it */
+  Curl_reset_reqproto(conn);
+
+  if(!data->state.proto.file) {
+    file = calloc(1, sizeof(struct FILEPROTO));
+    if(!file) {
+      free(real_path);
+      return CURLE_OUT_OF_MEMORY;
+    }
+    data->state.proto.file = file;
+  }
+  else {
+    /* file is not a protocol that can deal with "persistancy" */
+    file = data->state.proto.file;
+    Curl_safefree(file->freepath);
+    if(file->fd != -1)
+      close(file->fd);
+    file->path = NULL;
+    file->freepath = NULL;
+    file->fd = -1;
+  }
+
+#ifdef DOS_FILESYSTEM
+  /* 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 DOS, Windows and OS/2 */
+  for (i=0; actual_path[i] != '\0'; ++i)
+    if(actual_path[i] == '/')
+      actual_path[i] = '\\';
+
+  fd = open_readonly(actual_path, O_RDONLY|O_BINARY); /* no CR/LF translation */
+  file->path = actual_path;
+#else
+  fd = open_readonly(real_path, O_RDONLY);
+  file->path = real_path;
+#endif
+  file->freepath = real_path; /* free this when done */
+
+  file->fd = fd;
+  if(!data->set.upload && (fd == -1)) {
+    failf(data, "Couldn't open file %s", data->state.path);
+    file_done(conn, CURLE_FILE_COULDNT_READ_FILE, FALSE);
+    return CURLE_FILE_COULDNT_READ_FILE;
+  }
+  *done = TRUE;
+
+  return CURLE_OK;
+}
+
+static CURLcode file_done(struct connectdata *conn,
+                               CURLcode status, bool premature)
+{
+  struct FILEPROTO *file = conn->data->state.proto.file;
+  (void)status; /* not used */
+  (void)premature; /* not used */
+  Curl_safefree(file->freepath);
+
+  if(file->fd != -1)
+    close(file->fd);
+
+  return CURLE_OK;
+}
+
+#ifdef DOS_FILESYSTEM
+#define DIRSEP '\\'
+#else
+#define DIRSEP '/'
+#endif
+
+static CURLcode file_upload(struct connectdata *conn)
+{
+  struct FILEPROTO *file = conn->data->state.proto.file;
+  const 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();
+  struct_stat file_stat;
+  const char* buf2;
+
+  /*
+   * Since FILE: doesn't do the full init, we need to provide some extra
+   * assignments here.
+   */
+  conn->fread_func = data->set.fread_func;
+  conn->fread_in = data->set.in;
+  conn->data->req.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 */
+
+  if(data->state.resume_from)
+    fp = fopen( file->path, "ab" );
+  else {
+    int fd;
+
+#ifdef DOS_FILESYSTEM
+    fd = open(file->path, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,
+              conn->data->set.new_file_perms);
+#else
+    fd = open(file->path, O_WRONLY|O_CREAT|O_TRUNC,
+              conn->data->set.new_file_perms);
+#endif
+    if(fd < 0) {
+      failf(data, "Can't open %s for writing", file->path);
+      return CURLE_WRITE_ERROR;
+    }
+    close(fd);
+    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);
+
+  /* treat the negative resume offset value as the case of "-" */
+  if(data->state.resume_from < 0) {
+    if(fstat(fileno(fp), &file_stat)) {
+      fclose(fp);
+      failf(data, "Can't get the size of %s", file->path);
+      return CURLE_WRITE_ERROR;
+    }
+    else
+      data->state.resume_from = (curl_off_t)file_stat.st_size;
+  }
+
+  while(res == CURLE_OK) {
+    int readcount;
+    res = Curl_fillreadbuffer(conn, BUFSIZE, &readcount);
+    if(res)
+      break;
+
+    if(readcount <= 0)  /* fix questionable compare error. curlvms */
+      break;
+
+    nread = (size_t)readcount;
+
+    /*skip bytes before resume point*/
+    if(data->state.resume_from) {
+      if( (curl_off_t)nread <= data->state.resume_from ) {
+        data->state.resume_from -= nread;
+        nread = 0;
+        buf2 = buf;
+      }
+      else {
+        buf2 = buf + data->state.resume_from;
+        nread -= (size_t)data->state.resume_from;
+        data->state.resume_from = 0;
+      }
+    }
+    else
+      buf2 = buf;
+
+    /* write the data to the target */
+    nwrite = fwrite(buf2, 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;
+}
+
+/*
+ * file_do() 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.
+ */
+static CURLcode file_do(struct connectdata *conn, bool *done)
+{
+  /* 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; /* struct_stat instead of struct stat just to allow the
+                          Windows version to have a different struct without
+                          having to redefine the simple word 'stat' */
+  curl_off_t expected_size=0;
+  bool fstated=FALSE;
+  ssize_t nread;
+  size_t bytestoread;
+  struct SessionHandle *data = conn->data;
+  char *buf = data->state.buffer;
+  curl_off_t bytecount = 0;
+  int fd;
+  struct timeval now = Curl_tvnow();
+
+  *done = TRUE; /* unconditionally */
+
+  Curl_initinfo(data);
+  Curl_pgrsStartNow(data);
+
+  if(data->set.upload)
+    return file_upload(conn);
+
+  /* get the fd from the connection phase */
+  fd = conn->data->state.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;
+    /* and store the modification time */
+    data->info.filetime = (long)statbuf.st_mtime;
+    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(data->set.opt_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(conn, CLIENTWRITE_BOTH, buf, 0);
+    if(result)
+      return result;
+
+    result = Curl_client_write(conn, CLIENTWRITE_BOTH,
+                               (char *)"Accept-ranges: bytes\r\n", 0);
+    if(result)
+      return result;
+
+    if(fstated) {
+      const struct tm *tm;
+      time_t filetime = (time_t)statbuf.st_mtime;
+#ifdef HAVE_GMTIME_R
+      struct tm buffer;
+      tm = (const struct tm *)gmtime_r(&filetime, &buffer);
+#else
+      tm = gmtime(&filetime);
+#endif
+      /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
+      snprintf(buf, BUFSIZE-1,
+               "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
+               Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+               tm->tm_mday,
+               Curl_month[tm->tm_mon],
+               tm->tm_year + 1900,
+               tm->tm_hour,
+               tm->tm_min,
+               tm->tm_sec);
+      result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
+    }
+    /* if we fstat()ed the file, set the file size to make it available post-
+       transfer */
+    if(fstated)
+      Curl_pgrsSetDownloadSize(data, expected_size);
+    return result;
+  }
+
+  /* Check whether file range has been specified */
+  file_range(conn);
+
+  /* Adjust the start offset in case we want to get the N last bytes
+   * of the stream iff the filesize could be determined */
+  if(data->state.resume_from < 0) {
+    if(!fstated) {
+      failf(data, "Can't get the size of file.");
+      return CURLE_READ_ERROR;
+    }
+    else
+      data->state.resume_from += (curl_off_t)statbuf.st_size;
+  }
+
+  if(data->state.resume_from <= expected_size)
+    expected_size -= data->state.resume_from;
+  else {
+    failf(data, "failed to resume file:// transfer");
+    return CURLE_BAD_DOWNLOAD_RESUME;
+  }
+
+  /* A high water mark has been specified so we obey... */
+  if (data->req.maxdownload > 0)
+    expected_size = data->req.maxdownload;
+
+  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(data->state.resume_from) {
+    if(data->state.resume_from !=
+       lseek(fd, data->state.resume_from, SEEK_SET))
+      return CURLE_BAD_DOWNLOAD_RESUME;
+  }
+
+  Curl_pgrsTime(data, TIMER_STARTTRANSFER);
+
+  while(res == CURLE_OK) {
+    /* Don't fill a whole buffer if we want less than all data */
+    bytestoread = (expected_size < BUFSIZE-1)?(size_t)expected_size:BUFSIZE-1;
+    nread = read(fd, buf, bytestoread);
+
+    if( nread > 0)
+      buf[nread] = 0;
+
+    if (nread <= 0 || expected_size == 0)
+      break;
+
+    bytecount += nread;
+    expected_size -= nread;
+
+    res = Curl_client_write(conn, 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;
+
+  return res;
+}
+
+#endif
diff --git a/lib/file.h b/lib/file.h
new file mode 100644
index 0000000..5e3bd75
--- /dev/null
+++ b/lib/file.h
@@ -0,0 +1,40 @@
+#ifndef __FILE_H
+#define __FILE_H
+
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+
+/****************************************************************************
+ * 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! */
+};
+
+#ifndef CURL_DISABLE_FILE
+extern const struct Curl_handler Curl_handler_file;
+#endif
+#endif
diff --git a/lib/formdata.c b/lib/formdata.c
new file mode 100644
index 0000000..c98246e
--- /dev/null
+++ b/lib/formdata.c
@@ -0,0 +1,1760 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+/*
+  Debug the form generator stand-alone by compiling this source file with:
+
+  gcc -DHAVE_CONFIG_H -I../ -g -D_FORM_DEBUG -DCURLDEBUG -o formdata \
+    -I../include formdata.c strequal.c memdebug.c mprintf.c strerror.c
+
+  (depending on circumstances you may need further externals added)
+
+  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: application/octet-stream
+vlue for PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE
+(or you might see v^@lue at the start)
+
+Content-Disposition: form-data; name="FILE1_+_CONTENTTYPE"; filename="formdata.h"
+Content-Type: text/html
+...
+
+Content-Disposition: form-data; name="FILE1_+_FILE2"
+Content-Type: multipart/mixed, boundary=curlz1s0dkticx49MV1KGcYP5cvfSsz
+...
+Content-Disposition: attachment; filename="formdata.h"
+Content-Type: application/octet-stream
+...
+Content-Disposition: attachment; filename="Makefile.b32"
+Content-Type: application/octet-stream
+...
+
+Content-Disposition: form-data; name="FILE1_+_FILE2_+_FILE3"
+Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1
+...
+Content-Disposition: attachment; filename="formdata.h"
+Content-Type: application/octet-stream
+...
+Content-Disposition: attachment; filename="Makefile.b32"
+Content-Type: application/octet-stream
+...
+Content-Disposition: attachment; filename="formdata.h"
+Content-Type: application/octet-stream
+...
+
+
+Content-Disposition: form-data; name="ARRAY: FILE1_+_FILE2_+_FILE3"
+Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1
+...
+Content-Disposition: attachment; filename="formdata.h"
+Content-Type: application/octet-stream
+...
+Content-Disposition: attachment; filename="Makefile.b32"
+Content-Type: application/octet-stream
+...
+Content-Disposition: attachment; filename="formdata.h"
+Content-Type: application/octet-stream
+...
+
+Content-Disposition: form-data; name="FILECONTENT"
+...
+
+ */
+
+#include "setup.h"
+#include <curl/curl.h>
+
+/* Length of the random boundary string. */
+#define BOUNDARY_LENGTH 40
+
+#if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <time.h>
+#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
+#include <libgen.h>
+#endif
+#include "urldata.h" /* for struct SessionHandle */
+#include "easyif.h" /* for Curl_convert_... prototypes */
+#include "formdata.h"
+#include "curl_rand.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"
+
+#endif  /* !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) */
+
+#ifndef CURL_DISABLE_HTTP
+
+#ifndef HAVE_BASENAME
+static char *Curl_basename(char *path);
+#define basename(x)  Curl_basename((x))
+#endif
+
+static size_t readfromfile(struct Form *form, char *buffer, size_t size);
+
+/* 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, char *userp,
+            struct curl_httppost *parent_post,
+            struct curl_httppost **httppost,
+            struct curl_httppost **last_post)
+{
+  struct curl_httppost *post;
+  post = calloc(1, sizeof(struct curl_httppost));
+  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->userp = userp,
+    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 = calloc(1, sizeof(struct FormInfo));
+  if(form_info) {
+    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 = NULL;
+  unsigned int i;
+  /*
+   * No type was specified, we scan through a few well-known
+   * extensions and pick the first we match!
+   */
+  struct ContentType {
+    char extension[6];
+    const char *type;
+  };
+  static const struct ContentType ctts[]={
+    {".gif",  "image/gif"},
+    {".jpg",  "image/jpeg"},
+    {".jpeg", "image/jpeg"},
+    {".txt",  "text/plain"},
+    {".html", "text/html"},
+    {".xml", "application/xml"}
+  };
+
+  if(prevtype)
+    /* default to the previously set/used! */
+    contenttype = prevtype;
+  else
+    contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
+
+  if(filename) { /* in case a NULL was passed in */
+    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 if(src) {
+    length = strlen(src);
+    add = TRUE;
+  }
+  else
+    /* no length and a NULL src pointer! */
+    return strdup("");
+
+  buffer = 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 = NULL;
+  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 = calloc(1, sizeof(struct FormInfo));
+  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 && forms ) {
+      /* 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:
+#ifdef CURL_DOES_CONVERSIONS
+      /* treat CURLFORM_PTR like CURLFORM_COPYNAME so we'll
+         have safe memory for the eventual conversion */
+#else
+      current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
+#endif
+    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?(size_t)array_value:(size_t)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?(size_t)array_value:(size_t)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 {
+        const 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:
+      {
+        const 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)) == NULL)
+                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:
+      {
+        const 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)) == NULL)
+                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?(size_t)array_value:(size_t)va_arg(params, long);
+      break;
+
+    case CURLFORM_STREAM:
+      current_form->flags |= HTTPPOST_CALLBACK;
+      if(current_form->userp)
+        return_value = CURL_FORMADD_OPTION_TWICE;
+      else {
+        char *userp =
+          array_state?array_value:va_arg(params, char *);
+        if(userp) {
+          current_form->userp = userp;
+          current_form->value = userp; /* this isn't strictly true but we
+                                          derive a value from this later on
+                                          and we need this non-NULL to be
+                                          accepted as a fine form part */
+        }
+        else
+          return_value = CURL_FORMADD_NULL;
+      }
+      break;
+
+    case CURLFORM_CONTENTTYPE:
+      {
+        const 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)) == NULL)
+                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 = array_state?
+          (struct curl_slist*)array_value:
+          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:
+      {
+        const 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 completeness 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) ) {
+          /* Note that there's small risk that form->name is NULL here if the
+             app passed in a bad combo, so we better check for that first. */
+          if(form->name)
+            /* 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 | HTTPPOST_READFILE |
+                             HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
+                             HTTPPOST_CALLBACK)) ) {
+          /* 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,
+                           form->userp,
+                           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 = malloc(sizeof(struct FormData));
+  if(!newform)
+    return CURLE_OUT_OF_MEMORY;
+  newform->next = NULL;
+
+  if(type <= FORM_CONTENT) {
+    /* we make it easier for plain strings: */
+    if(!length)
+      length = strlen((char *)line);
+
+    newform->line = 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 */
+  }
+  else
+    /* For callbacks and files we don't have any actual data so we just keep a
+       pointer to whatever this points to */
+    newform->line = (char *)line;
+
+  newform->type = type;
+
+  if(*formp) {
+    (*formp)->next = newform;
+    *formp = newform;
+  }
+  else
+    *formp = newform;
+
+  if(size) {
+    if(type != FORM_FILE)
+      /* for static content as well as callback data we add the size given
+         as input argument */
+      *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_ptr)
+{
+  struct FormData *next, *form;
+
+  form = *form_ptr;
+  if(!form)
+    return;
+
+  do {
+    next=form->next;  /* the following form line */
+    if(form->type <= FORM_CONTENT)
+      free(form->line); /* free the line */
+    free(form);       /* free the struct */
+
+  } while((form = next) != NULL); /* continue */
+
+  *form_ptr = NULL;
+}
+
+#ifdef CURL_DOES_CONVERSIONS
+/*
+ * Curl_formcovert() is used from http.c, this converts any
+   form items that need to be sent in the network encoding.
+   Returns CURLE_OK on success.
+ */
+CURLcode Curl_formconvert(struct SessionHandle *data, struct FormData *form)
+{
+  struct FormData *next;
+  CURLcode rc;
+
+  if(!form)
+    return CURLE_OK;
+
+  if(!data)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  do {
+    next=form->next;  /* the following form line */
+    if(form->type == FORM_DATA) {
+      rc = Curl_convert_to_network(data, form->line, form->length);
+      /* Curl_convert_to_network calls failf if unsuccessful */
+      if(rc != CURLE_OK)
+        return rc;
+    }
+  } while((form = next) != NULL); /* continue */
+  return CURLE_OK;
+}
+#endif /* CURL_DOES_CONVERSIONS */
+
+/*
+ * curl_formget()
+ * Serialize a curl_httppost struct.
+ * Returns 0 on success.
+ */
+int curl_formget(struct curl_httppost *form, void *arg,
+                 curl_formget_callback append)
+{
+  CURLcode rc;
+  curl_off_t size;
+  struct FormData *data, *ptr;
+
+  rc = Curl_getFormData(&data, form, NULL, &size);
+  if(rc != CURLE_OK)
+    return (int)rc;
+
+  for (ptr = data; ptr; ptr = ptr->next) {
+    if(ptr->type == FORM_FILE) {
+      char buffer[8192];
+      size_t nread;
+      struct Form temp;
+
+      Curl_FormInit(&temp, ptr);
+
+      do {
+        nread = readfromfile(&temp, buffer, sizeof(buffer));
+        if((nread == (size_t) -1) || (nread != append(arg, buffer, nread))) {
+          if(temp.fp) {
+            fclose(temp.fp);
+          }
+          Curl_formclean(&data);
+          return -1;
+        }
+      } while(nread == sizeof(buffer));
+    }
+    else {
+      if(ptr->length != append(arg, ptr->line, ptr->length)) {
+        Curl_formclean(&data);
+        return -1;
+      }
+    }
+  }
+  Curl_formclean(&data);
+  return 0;
+}
+
+/*
+ * 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|HTTPPOST_CALLBACK)) &&
+        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) != NULL); /* continue */
+}
+
+#ifndef HAVE_BASENAME
+/*
+  (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
+  Edition)
+
+  The basename() function shall take the pathname pointed to by path and
+  return a pointer to the final component of the pathname, deleting any
+  trailing '/' characters.
+
+  If the string pointed to by path consists entirely of the '/' character,
+  basename() shall return a pointer to the string "/". If the string pointed
+  to by path is exactly "//", it is implementation-defined whether '/' or "//"
+  is returned.
+
+  If path is a null pointer or points to an empty string, basename() shall
+  return a pointer to the string ".".
+
+  The basename() function may modify the string pointed to by path, and may
+  return a pointer to static storage that may then be overwritten by a
+  subsequent call to basename().
+
+  The basename() function need not be reentrant. A function that is not
+  required to be reentrant is not required to be thread-safe.
+
+*/
+static char *Curl_basename(char *path)
+{
+  /* Ignore all the details above for now and make a quick and simple
+     implementaion here */
+  char *s1;
+  char *s2;
+
+  s1=strrchr(path, '/');
+  s2=strrchr(path, '\\');
+
+  if(s1 && s2) {
+    path = (s1 > s2? s1 : s2)+1;
+  }
+  else if(s1)
+    path = s1 + 1;
+  else if(s2)
+    path = s2 + 1;
+
+  return path;
+}
+#endif
+
+static char *strippath(const char *fullfile)
+{
+  char *filename;
+  char *base;
+  filename = strdup(fullfile); /* duplicate since basename() may ruin the
+                                  buffer it works on */
+  if(!filename)
+    return NULL;
+  base = strdup(basename(filename));
+
+  free(filename); /* free temporary buffer */
+
+  return base; /* returns an allocated string or NULL ! */
+}
+
+/*
+ * 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.
+ * A multipart/form_data content-type is built, unless a custom content-type
+ * is passed in 'custom_content_type'.
+ */
+
+CURLcode Curl_getFormData(struct FormData **finalform,
+                          struct curl_httppost *post,
+                          const char *custom_content_type,
+                          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,
+                        "%s; boundary=%s\r\n",
+                        custom_content_type?custom_content_type:
+                        "Content-Type: multipart/form-data",
+                        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;
+
+    /* Maybe later this should be disabled when a custom_content_type is
+       passed, since Content-Disposition is not meaningful for all multipart
+       types.
+    */
+    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 */
+        char *filebasename= NULL;
+        if(!file->showfilename) {
+          filebasename = strippath(file->contents);
+          if(!filebasename) {
+            Curl_formclean(&firstform);
+            free(boundary);
+            return CURLE_OUT_OF_MEMORY;
+          }
+        }
+
+        result = AddFormDataf(&form, &size,
+                              "\r\n--%s\r\nContent-Disposition: "
+                              "attachment; filename=\"%s\"",
+                              fileboundary,
+                              (file->showfilename?file->showfilename:
+                               filebasename));
+        if(filebasename)
+          free(filebasename);
+        if(result)
+          break;
+      }
+      else if(post->flags & (HTTPPOST_FILENAME|HTTPPOST_BUFFER|
+                             HTTPPOST_CALLBACK)) {
+        /* it should be noted that for the HTTPPOST_FILENAME and
+           HTTPPOST_CALLBACK cases the ->showfilename struct member is always
+           assigned at this point */
+        char *filebasename=
+          (!post->showfilename)?strippath(post->contents):NULL;
+
+        result = AddFormDataf(&form, &size,
+                              "; filename=\"%s\"",
+                              (post->showfilename?post->showfilename:
+                               filebasename));
+        if(filebasename)
+          free(filebasename);
+
+        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 */
+        result = AddFormDataf(&form, &size,
+                              "\r\nContent-Transfer-Encoding: binary");
+        if(result)
+          break;
+      }
+#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)) != 0) {
+              result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size);
+              if(result)
+                break;
+            }
+          }
+
+          if(result) {
+            Curl_formclean(&firstform);
+            free(boundary);
+            return result;
+          }
+
+        }
+        else {
+#ifdef _FORM_DEBUG
+          fprintf(stderr,
+                  "\n==> Curl_getFormData couldn't open/read \"%s\"\n",
+                  file->contents);
+#endif
+          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_CONTENT, post->buffer,
+                             post->bufferlength, &size);
+          if(result)
+            break;
+      }
+      else if(post->flags & HTTPPOST_CALLBACK) {
+        /* the contents should be read with the callback and the size
+           is set with the contentslength */
+        result = AddFormData(&form, FORM_CALLBACK, post->userp,
+                             post->contentslength, &size);
+        if(result)
+          break;
+      }
+      else {
+        /* include the contents we got */
+        result = AddFormData(&form, FORM_CONTENT, post->contents,
+                             post->contentslength, &size);
+        if(result)
+          break;
+      }
+    } while((file = file->more) != NULL); /* 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) != NULL); /* 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;
+  form->fread_func = ZERO_NULL;
+
+  return 0;
+}
+
+static size_t readfromfile(struct Form *form, char *buffer,
+                           size_t size)
+{
+  size_t nread;
+  bool callback = (bool)(form->data->type == FORM_CALLBACK);
+
+  if(callback)
+    nread = form->fread_func(buffer, 1, size, form->data->line);
+  else {
+    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 (size_t)-1; /* failure */
+    }
+    nread = fread(buffer, 1, size, form->fp);
+  }
+  if(!nread || nread > size) {
+    /* this is the last chunk from the file, move on */
+    if(!callback) {
+      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) ||
+     (form->data->type == FORM_CALLBACK)) {
+    gotsize = readfromfile(form, buffer, wantedsize);
+
+    if(gotsize)
+      /* If positive or -1, return. If zero, continue! */
+      return gotsize;
+  }
+  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_CALLBACK));
+  /* 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. */
+
+  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(int argc, argv_item_t argv[])
+{
+  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 PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE";
+  char value7[] = "formdata.h";
+  char value8[] = "Makefile.b32";
+  char type2[] = "image/gif";
+  char type6[] = "text/plain";
+  char type7[] = "text/html";
+  int name3length = strlen(name3);
+  int value3length = strlen(value3);
+  int value5length = strlen(value5);
+  int value6length = strlen(value6);
+  int errors = 0;
+  CURLcode rc;
+  curl_off_t 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;
+
+  (void) argc;
+  (void) argv;
+
+  Curl_srand();         /* Because we do not call curl_global_init() here. */
+
+  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;
+
+  rc = Curl_getFormData(&form, httppost, NULL, &size);
+  if(rc != CURLE_OK) {
+    if(rc != CURLE_READ_ERROR) {
+      const char *errortext = curl_easy_strerror(rc);
+      fprintf(stdout, "\n==> Curl_getFormData error: %s\n", errortext);
+    }
+    return 0;
+  }
+
+  Curl_FormInit(&formread, form);
+
+  do {
+    nread = Curl_FormReader(buffer, 1, sizeof(buffer),
+                            (FILE *)&formread);
+
+    if(nread < 1)
+      break;
+    fwrite(buffer, nread, 1, stdout);
+  } while(1);
+
+  fprintf(stdout, "size: ");
+  fprintf(stdout, "%" FORMAT_OFF_T, size);
+  fprintf(stdout, "\n");
+  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  /* _FORM_DEBUG */
+
+#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;
+}
+
+int curl_formget(struct curl_httppost *form, void *arg,
+                 curl_formget_callback append)
+{
+  (void) form;
+  (void) arg;
+  (void) append;
+  return CURL_FORMADD_DISABLED;
+}
+
+void curl_formfree(struct curl_httppost *form)
+{
+  (void)form;
+  /* does nothing HTTP is disabled */
+}
+
+#endif  /* CURL_DISABLE_HTTP */
+
+#if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY)
+
+/*
+ * 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;
+  size_t i;
+
+  static const char table16[]="0123456789abcdef";
+
+  retstring = malloc(BOUNDARY_LENGTH+1);
+
+  if(!retstring)
+    return NULL; /* failed */
+
+  strcpy(retstring, "----------------------------");
+
+  for(i=strlen(retstring); i<BOUNDARY_LENGTH; i++)
+    retstring[i] = table16[Curl_rand()%16];
+
+  /* 28 dashes and 12 hexadecimal digits makes 12^16 (184884258895036416)
+     combinations */
+  retstring[BOUNDARY_LENGTH]=0; /* zero terminate */
+
+  return retstring;
+}
+
+#endif  /* !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) */
diff --git a/lib/formdata.h b/lib/formdata.h
new file mode 100644
index 0000000..0c9db44
--- /dev/null
+++ b/lib/formdata.h
@@ -0,0 +1,98 @@
+#ifndef HEADER_CURL_FORMDATA_H
+#define HEADER_CURL_FORMDATA_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+enum formtype {
+  FORM_DATA,    /* form metadata (convert to network encoding if necessary) */
+  FORM_CONTENT, /* form content  (never convert) */
+  FORM_CALLBACK, /* 'line' points to the custom pointer we pass to the callback
+                  */
+  FORM_FILE     /* 'line' points to a file name we should read from
+                   to create the form data (never convert) */
+};
+
+/* 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 */
+  curl_read_callback fread_func; /* fread callback pointer */
+};
+
+/* 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;
+  char *userp;        /* pointer for the read callback */
+  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,
+                 const char *custom_contenttype,
+                 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 **);
+
+CURLcode Curl_formconvert(struct SessionHandle *, struct FormData *);
+
+#endif /* HEADER_CURL_FORMDATA_H */
diff --git a/lib/ftp.c b/lib/ftp.c
new file mode 100644
index 0000000..f821d12
--- /dev/null
+++ b/lib/ftp.c
@@ -0,0 +1,3962 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+#ifndef CURL_DISABLE_FTP
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.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
+#ifdef HAVE_UTSNAME_H
+#include <sys/utsname.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.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 "easyif.h" /* for Curl_convert_... prototypes */
+
+#include "if2ip.h"
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "socks.h"
+#include "ftp.h"
+
+#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
+#include "krb4.h"
+#endif
+
+#include "strtoofft.h"
+#include "strequal.h"
+#include "sslgen.h"
+#include "connect.h"
+#include "strerror.h"
+#include "inet_ntop.h"
+#include "inet_pton.h"
+#include "select.h"
+#include "parsedate.h" /* for the week day and month names */
+#include "sockaddr.h" /* required for Curl_sockaddr_storage */
+#include "multiif.h"
+#include "url.h"
+#include "rawstr.h"
+#include "speedcheck.h"
+#include "warnless.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 1025
+#endif
+#ifndef INET_ADDRSTRLEN
+#define INET_ADDRSTRLEN 16
+#endif
+
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+#define ftp_pasv_verbose(a,b,c,d)  do { } while(0)
+#endif
+
+/* Local API functions */
+static CURLcode ftp_sendquote(struct connectdata *conn,
+                              struct curl_slist *quote);
+static CURLcode ftp_quit(struct connectdata *conn);
+static CURLcode ftp_parse_url_path(struct connectdata *conn);
+static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void ftp_pasv_verbose(struct connectdata *conn,
+                             Curl_addrinfo *ai,
+                             char *newhost, /* ascii version */
+                             int port);
+#endif
+static CURLcode ftp_state_post_rest(struct connectdata *conn);
+static CURLcode ftp_state_post_cwd(struct connectdata *conn);
+static CURLcode ftp_state_quote(struct connectdata *conn,
+                                bool init, ftpstate instate);
+static CURLcode ftp_nb_type(struct connectdata *conn,
+                            bool ascii, ftpstate newstate);
+static int ftp_need_type(struct connectdata *conn,
+                         bool ascii);
+static CURLcode ftp_do(struct connectdata *conn, bool *done);
+static CURLcode ftp_done(struct connectdata *conn,
+                         CURLcode, bool premature);
+static CURLcode ftp_connect(struct connectdata *conn, bool *done);
+static CURLcode ftp_disconnect(struct connectdata *conn);
+static CURLcode ftp_nextconnect(struct connectdata *conn);
+static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
+static int ftp_getsock(struct connectdata *conn,
+                       curl_socket_t *socks,
+                       int numsocks);
+static CURLcode ftp_doing(struct connectdata *conn,
+                          bool *dophase_done);
+static CURLcode ftp_setup_connection(struct connectdata * conn);
+
+/* easy-to-use macro: */
+#define FTPSENDF(x,y,z)    if((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \
+                              return result
+#define PPSENDF(x,y,z)  if((result = Curl_pp_sendf(x,y,z)) != CURLE_OK) \
+                              return result
+
+
+/*
+ * FTP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ftp = {
+  "FTP",                           /* scheme */
+  ftp_setup_connection,            /* setup_connection */
+  ftp_do,                          /* do_it */
+  ftp_done,                        /* done */
+  ftp_nextconnect,                 /* do_more */
+  ftp_connect,                     /* connect_it */
+  ftp_multi_statemach,             /* connecting */
+  ftp_doing,                       /* doing */
+  ftp_getsock,                     /* proto_getsock */
+  ftp_getsock,                     /* doing_getsock */
+  ZERO_NULL,                       /* perform_getsock */
+  ftp_disconnect,                  /* disconnect */
+  PORT_FTP,                        /* defport */
+  PROT_FTP                         /* protocol */
+};
+
+
+#ifdef USE_SSL
+/*
+ * FTPS protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ftps = {
+  "FTPS",                          /* scheme */
+  ftp_setup_connection,            /* setup_connection */
+  ftp_do,                          /* do_it */
+  ftp_done,                        /* done */
+  ftp_nextconnect,                 /* do_more */
+  ftp_connect,                     /* connect_it */
+  ftp_multi_statemach,             /* connecting */
+  ftp_doing,                       /* doing */
+  ftp_getsock,                     /* proto_getsock */
+  ftp_getsock,                     /* doing_getsock */
+  ZERO_NULL,                       /* perform_getsock */
+  ftp_disconnect,                  /* disconnect */
+  PORT_FTPS,                       /* defport */
+  PROT_FTP | PROT_FTPS | PROT_SSL  /* protocol */
+};
+#endif
+
+#ifndef CURL_DISABLE_HTTP
+/*
+ * HTTP-proxyed FTP protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_ftp_proxy = {
+  "FTP",                                /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  Curl_http,                            /* do_it */
+  Curl_http_done,                       /* done */
+  ZERO_NULL,                            /* do_more */
+  ZERO_NULL,                            /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  PORT_FTP,                             /* defport */
+  PROT_HTTP                             /* protocol */
+};
+
+
+#ifdef USE_SSL
+/*
+ * HTTP-proxyed FTPS protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_ftps_proxy = {
+  "FTPS",                               /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  Curl_http,                            /* do_it */
+  Curl_http_done,                       /* done */
+  ZERO_NULL,                            /* do_more */
+  ZERO_NULL,                            /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  PORT_FTPS,                            /* defport */
+  PROT_HTTP                             /* protocol */
+};
+#endif
+#endif
+
+
+/*
+ * NOTE: back in the old days, we added code in the FTP code that made NOBODY
+ * requests on files respond with headers passed to the client/stdout that
+ * looked like HTTP ones.
+ *
+ * This approach is not very elegant, it causes confusion and is error-prone.
+ * It is subject for removal at the next (or at least a future) soname bump.
+ * Until then you can test the effects of the removal by undefining the
+ * following define named CURL_FTP_HTTPSTYLE_HEAD.
+ */
+#define CURL_FTP_HTTPSTYLE_HEAD 1
+
+static void freedirs(struct ftp_conn *ftpc)
+{
+  int i;
+  if(ftpc->dirs) {
+    for (i=0; i < ftpc->dirdepth; i++){
+      if(ftpc->dirs[i]) {
+        free(ftpc->dirs[i]);
+        ftpc->dirs[i]=NULL;
+      }
+    }
+    free(ftpc->dirs);
+    ftpc->dirs = NULL;
+    ftpc->dirdepth = 0;
+  }
+  if(ftpc->file) {
+    free(ftpc->file);
+    ftpc->file = NULL;
+  }
+}
+
+/* Returns non-zero if the given string contains CR (\r) or LF (\n),
+   which are not allowed within RFC 959 <string>.
+   Note: The input string is in the client's encoding which might
+   not be ASCII, so escape sequences \r & \n must be used instead
+   of hex values 0x0d & 0x0a.
+*/
+static bool isBadFtpString(const char *string)
+{
+  return (bool)((NULL != strchr(string, '\r')) ||
+                (NULL != strchr(string, '\n')));
+}
+
+/***********************************************************************
+ *
+ * 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)
+{
+  struct SessionHandle *data = conn->data;
+  curl_socket_t sock = conn->sock[SECONDARYSOCKET];
+  long timeout_ms;
+  long interval_ms;
+  curl_socket_t s = CURL_SOCKET_BAD;
+#ifdef ENABLE_IPV6
+  struct Curl_sockaddr_storage add;
+#else
+  struct sockaddr_in add;
+#endif
+  curl_socklen_t size = (curl_socklen_t) sizeof(add);
+
+  for(;;) {
+    timeout_ms = Curl_timeleft(conn, NULL, TRUE);
+
+    if(timeout_ms <= 0) {
+      /* if a timeout was already reached, bail out */
+      failf(data, "Timeout while waiting for server connect");
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+
+    interval_ms = 1000;  /* use 1 second timeout intervals */
+    if(timeout_ms < interval_ms)
+      interval_ms = timeout_ms;
+
+    switch (Curl_socket_ready(sock, CURL_SOCKET_BAD, (int)interval_ms)) {
+    case -1: /* error */
+      /* let's die here */
+      failf(data, "Error while waiting for server connect");
+      return CURLE_FTP_PORT_FAILED;
+    case 0:  /* timeout */
+      break; /* loop */
+    default:
+      /* we have received data here */
+      if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
+        size = sizeof(add);
+
+        s=accept(sock, (struct sockaddr *) &add, &size);
+      }
+      sclose(sock); /* close the first socket */
+
+      if(CURL_SOCKET_BAD == s) {
+        failf(data, "Error accept()ing server connect");
+        return CURLE_FTP_PORT_FAILED;
+      }
+      infof(data, "Connection accepted from server\n");
+
+      conn->sock[SECONDARYSOCKET] = s;
+      curlx_nonblock(s, TRUE); /* enable non-blocking */
+      return CURLE_OK;
+    } /* switch() */
+  }
+  /* never reaches this point */
+}
+
+/* macro to check for a three-digit ftp status code at the start of the
+   given string */
+#define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) &&       \
+                          ISDIGIT(line[2]))
+
+/* macro to check for the last line in an FTP server response */
+#define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
+
+static int ftp_endofresp(struct pingpong *pp,
+                         int *code)
+{
+  char *line = pp->linestart_resp;
+  size_t len = pp->nread_resp;
+
+  if((len > 3) && LASTLINE(line)) {
+    *code = atoi(line);
+    return 1;
+  }
+  return 0;
+}
+
+static CURLcode ftp_readresp(curl_socket_t sockfd,
+                             struct pingpong *pp,
+                             int *ftpcode, /* return the ftp-code if done */
+                             size_t *size) /* size of the response */
+{
+  struct connectdata *conn = pp->conn;
+#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
+  struct SessionHandle *data = conn->data;
+  char * const buf = data->state.buffer;
+#endif
+  CURLcode result = CURLE_OK;
+  int code;
+
+  result = Curl_pp_readresp(sockfd, pp, &code, size);
+
+#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
+  /* handle the security-oriented responses 6xx ***/
+  /* FIXME: some errorchecking perhaps... ***/
+  switch(code) {
+  case 631:
+    code = Curl_sec_read_msg(conn, buf, prot_safe);
+    break;
+  case 632:
+    code = Curl_sec_read_msg(conn, buf, prot_private);
+    break;
+  case 633:
+    code = Curl_sec_read_msg(conn, buf, prot_confidential);
+    break;
+  default:
+    /* normal ftp stuff we pass through! */
+    break;
+  }
+#endif
+
+  /* store the latest code for later retrieval */
+  conn->data->info.httpcode=code;
+
+  if(ftpcode)
+    *ftpcode = code;
+
+  return result;
+}
+
+/* --- parse FTP server responses --- */
+
+/*
+ * Curl_GetFTPResponse() is a BLOCKING function to read the full response
+ * from a server after a command.
+ *
+ */
+
+CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
+                             struct connectdata *conn,
+                             int *ftpcode) /* return the ftp-code */
+{
+  /*
+   * We cannot read just one byte per read() and then go back to select() as
+   * the OpenSSL read() 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];
+  long timeout;              /* timeout in milliseconds */
+  long interval_ms;
+  struct SessionHandle *data = conn->data;
+  CURLcode result = CURLE_OK;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  struct pingpong *pp = &ftpc->pp;
+  size_t nread;
+  int cache_skip=0;
+  int value_to_be_ignored=0;
+
+  if(ftpcode)
+    *ftpcode = 0; /* 0 for errors */
+  else
+    /* make the pointer point to something for the rest of this function */
+    ftpcode = &value_to_be_ignored;
+
+  *nreadp=0;
+
+  while(!*ftpcode && !result) {
+    /* check and reset timeout value every lap */
+    timeout = Curl_pp_state_timeout(pp);
+
+    if(timeout <=0 ) {
+      failf(data, "FTP response timeout");
+      return CURLE_OPERATION_TIMEDOUT; /* already too little time */
+    }
+
+    interval_ms = 1000;  /* use 1 second timeout intervals */
+    if(timeout < interval_ms)
+      interval_ms = timeout;
+
+    /*
+     * Since this function is blocking, we need to wait here for input on the
+     * connection and only then we call the response reading function. We do
+     * timeout at least every second to make the timeout check run.
+     *
+     * A caution here is that the ftp_readresp() function has a cache that may
+     * contain pieces of a response from the previous invoke and we need to
+     * make sure we don't just wait for input while there is unhandled data in
+     * that cache. But also, if the cache is there, we call ftp_readresp() and
+     * the cache wasn't good enough to continue we must not just busy-loop
+     * around this function.
+     *
+     */
+
+    if(pp->cache && (cache_skip < 2)) {
+      /*
+       * There's a cache left since before. We then skipping the wait for
+       * socket action, unless this is the same cache like the previous round
+       * as then the cache was deemed not enough to act on and we then need to
+       * wait for more data anyway.
+       */
+    }
+    else {
+      switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, (int)interval_ms)) {
+      case -1: /* select() error, stop reading */
+        failf(data, "FTP response aborted due to select/poll error: %d",
+              SOCKERRNO);
+        return CURLE_RECV_ERROR;
+
+      case 0: /* timeout */
+        if(Curl_pgrsUpdate(conn))
+          return CURLE_ABORTED_BY_CALLBACK;
+        continue; /* just continue in our loop for the timeout duration */
+
+      default: /* for clarity */
+        break;
+      }
+    }
+    result = ftp_readresp(sockfd, pp, ftpcode, &nread);
+    if(result)
+      break;
+
+    if(!nread && pp->cache)
+      /* bump cache skip counter as on repeated skips we must wait for more
+         data */
+      cache_skip++;
+    else
+      /* when we got data or there is no cache left, we reset the cache skip
+         counter */
+      cache_skip=0;
+
+    *nreadp += nread;
+
+  } /* while there's buffer left and loop is requested */
+
+  pp->pending_resp = FALSE;
+
+  return result;
+}
+
+/* This is the ONLY way to change FTP state! */
+static void state(struct connectdata *conn,
+                  ftpstate newstate)
+{
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  /* for debug purposes */
+  static const char * const names[]={
+    "STOP",
+    "WAIT220",
+    "AUTH",
+    "USER",
+    "PASS",
+    "ACCT",
+    "PBSZ",
+    "PROT",
+    "CCC",
+    "PWD",
+    "SYST",
+    "NAMEFMT",
+    "QUOTE",
+    "RETR_PREQUOTE",
+    "STOR_PREQUOTE",
+    "POSTQUOTE",
+    "CWD",
+    "MKD",
+    "MDTM",
+    "TYPE",
+    "LIST_TYPE",
+    "RETR_TYPE",
+    "STOR_TYPE",
+    "SIZE",
+    "RETR_SIZE",
+    "STOR_SIZE",
+    "REST",
+    "RETR_REST",
+    "PORT",
+    "PRET",
+    "PASV",
+    "LIST",
+    "RETR",
+    "STOR",
+    "QUIT"
+  };
+#endif
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  if(ftpc->state != newstate)
+    infof(conn->data, "FTP %p state change from %s to %s\n",
+          ftpc, names[ftpc->state], names[newstate]);
+#endif
+  ftpc->state = newstate;
+}
+
+static CURLcode ftp_state_user(struct connectdata *conn)
+{
+  CURLcode result;
+  struct FTP *ftp = conn->data->state.proto.ftp;
+  /* send USER */
+  PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
+
+  state(conn, FTP_USER);
+  conn->data->state.ftp_trying_alternative = FALSE;
+
+  return CURLE_OK;
+}
+
+static CURLcode ftp_state_pwd(struct connectdata *conn)
+{
+  CURLcode result;
+
+  /* send PWD to discover our entry point */
+  PPSENDF(&conn->proto.ftpc.pp, "PWD", NULL);
+  state(conn, FTP_PWD);
+
+  return CURLE_OK;
+}
+
+/* For the FTP "protocol connect" and "doing" phases only */
+static int ftp_getsock(struct connectdata *conn,
+                       curl_socket_t *socks,
+                       int numsocks)
+{
+  return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
+}
+
+/* This is called after the FTP_QUOTE state is passed.
+
+   ftp_state_cwd() sends the range of CWD commands to the server to change to
+   the correct directory. It may also need to send MKD commands to create
+   missing ones, if that option is enabled.
+*/
+static CURLcode ftp_state_cwd(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  if(ftpc->cwddone)
+    /* already done and fine */
+    result = ftp_state_post_cwd(conn);
+  else {
+    ftpc->count2 = 0; /* count2 counts failed CWDs */
+
+    /* count3 is set to allow a MKD to fail once. In the case when first CWD
+       fails and then MKD fails (due to another session raced it to create the
+       dir) this then allows for a second try to CWD to it */
+    ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
+
+    if(conn->bits.reuse && ftpc->entrypath) {
+      /* This is a re-used connection. Since we change directory to where the
+         transfer is taking place, we must first get back to the original dir
+         where we ended up after login: */
+      ftpc->count1 = 0; /* we count this as the first path, then we add one
+                          for all upcoming ones in the ftp->dirs[] array */
+      PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
+      state(conn, FTP_CWD);
+    }
+    else {
+      if(ftpc->dirdepth) {
+        ftpc->count1 = 1;
+        /* issue the first CWD, the rest is sent when the CWD responses are
+           received... */
+        PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
+        state(conn, FTP_CWD);
+      }
+      else {
+        /* No CWD necessary */
+        result = ftp_state_post_cwd(conn);
+      }
+    }
+  }
+  return result;
+}
+
+typedef enum {
+  EPRT,
+  PORT,
+  DONE
+} ftpport;
+
+static CURLcode ftp_state_use_port(struct connectdata *conn,
+                                   ftpport fcmd) /* start with this */
+
+{
+  CURLcode result = CURLE_OK;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  struct SessionHandle *data=conn->data;
+  curl_socket_t portsock= CURL_SOCKET_BAD;
+  char myhost[256] = "";
+
+  struct Curl_sockaddr_storage ss;
+  Curl_addrinfo *res, *ai;
+  curl_socklen_t sslen;
+  char hbuf[NI_MAXHOST];
+  struct sockaddr *sa=(struct sockaddr *)&ss;
+  struct sockaddr_in * const sa4 = (void *)sa;
+#ifdef ENABLE_IPV6
+  struct sockaddr_in6 * const sa6 = (void *)sa;
+#endif
+  char tmp[1024];
+  static const char mode[][5] = { "EPRT", "PORT" };
+  int rc;
+  int error;
+  char *host=NULL;
+  char *string_ftpport = data->set.str[STRING_FTPPORT];
+  struct Curl_dns_entry *h=NULL;
+  unsigned short port_min = 0;
+  unsigned short port_max = 0;
+  unsigned short port;
+
+  char *addr = NULL;
+
+  /* Step 1, figure out what is requested,
+   * accepted format :
+   * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
+   */
+
+  if(data->set.str[STRING_FTPPORT] &&
+     (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
+
+#ifdef ENABLE_IPV6
+    size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
+      INET6_ADDRSTRLEN : strlen(string_ftpport);
+#else
+    size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
+      INET_ADDRSTRLEN : strlen(string_ftpport);
+#endif
+    char *ip_start = string_ftpport;
+    char *ip_end = NULL;
+    char *port_start = NULL;
+    char *port_sep = NULL;
+
+    addr = calloc(addrlen+1, 1);
+    if (!addr)
+      return CURLE_OUT_OF_MEMORY;
+
+#ifdef ENABLE_IPV6
+    if(*string_ftpport == '[') {
+      /* [ipv6]:port(-range) */
+      ip_start = string_ftpport + 1;
+      if((ip_end = strchr(string_ftpport, ']')) != NULL )
+        strncpy(addr, ip_start, ip_end - ip_start);
+    }
+    else
+#endif
+      if( *string_ftpport == ':') {
+        /* :port */
+        ip_end = string_ftpport;
+    }
+    else if( (ip_end = strchr(string_ftpport, ':')) != NULL) {
+        /* either ipv6 or (ipv4|domain|interface):port(-range) */
+#ifdef ENABLE_IPV6
+      if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
+        /* ipv6 */
+        port_min = port_max = 0;
+        strcpy(addr, string_ftpport);
+        ip_end = NULL; /* this got no port ! */
+      } else
+#endif
+      {
+        /* (ipv4|domain|interface):port(-range) */
+        strncpy(addr, string_ftpport, ip_end - ip_start );
+      }
+    }
+    else
+      /* ipv4|interface */
+      strcpy(addr, string_ftpport);
+
+    /* parse the port */
+    if( ip_end != NULL ) {
+      if((port_start = strchr(ip_end, ':')) != NULL) {
+        port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
+        if((port_sep = strchr(port_start, '-')) != NULL) {
+          port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
+        }
+        else
+          port_max = port_min;
+      }
+    }
+
+    /* correct errors like:
+     *  :1234-1230
+     *  :-4711 , in this case port_min is (unsigned)-1,
+     *           therefore port_min > port_max for all cases
+     *           but port_max = (unsigned)-1
+     */
+    if(port_min > port_max )
+      port_min = port_max = 0;
+
+
+    if(*addr != '\0') {
+      /* attempt to get the address of the given interface name */
+      if(!Curl_if2ip(conn->ip_addr->ai_family, addr,
+                     hbuf, sizeof(hbuf)))
+        /* not an interface, use the given string as host name instead */
+        host = addr;
+      else
+        host = hbuf; /* use the hbuf for host name */
+    }else
+      /* there was only a port(-range) given, default the host */
+      host = NULL;
+  } /* data->set.ftpport */
+
+  if(!host) {
+    /* not an interface and not a host name, get default by extracting
+       the IP from the control connection */
+
+    sslen = sizeof(ss);
+    if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
+      failf(data, "getsockname() failed: %s",
+          Curl_strerror(conn, SOCKERRNO) );
+      if (addr)
+        free(addr);
+      return CURLE_FTP_PORT_FAILED;
+    }
+    switch(sa->sa_family)
+    {
+#ifdef ENABLE_IPV6
+      case AF_INET6:
+        Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
+        break;
+#endif
+      default:
+        Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
+        break;
+    }
+    host = hbuf; /* use this host name */
+  }
+
+  /* resolv ip/host to ip */
+  rc = Curl_resolv(conn, host, 0, &h);
+  if(rc == CURLRESOLV_PENDING)
+    rc = Curl_wait_for_resolv(conn, &h);
+  if(h) {
+    res = 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) */
+  else
+    res = NULL; /* failure! */
+
+  if (addr)
+    free(addr);
+
+  if (res == NULL) {
+    failf(data, "Curl_resolv failed, we can not recover!");
+    return CURLE_FTP_PORT_FAILED;
+  }
+
+  /* step 2, create a socket for the requested address */
+
+  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 = conn->socktype;
+
+    portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+    if(portsock == CURL_SOCKET_BAD) {
+      error = SOCKERRNO;
+      continue;
+    }
+    break;
+  }
+  if(!ai) {
+    failf(data, "socket failure: %s", Curl_strerror(conn, error));
+    return CURLE_FTP_PORT_FAILED;
+  }
+
+  /* step 3, bind to a suitable local address */
+
+  memcpy(sa, ai->ai_addr, ai->ai_addrlen);
+  sslen = ai->ai_addrlen;
+
+  for( port = port_min; port <= port_max; ) {
+    if( sa->sa_family == AF_INET )
+      sa4->sin_port = htons(port);
+#ifdef ENABLE_IPV6
+    else
+      sa6->sin6_port = htons(port);
+#endif
+    /* Try binding the given address. */
+    if(bind(portsock, sa, sslen) ) {
+      /* It failed. */
+      error = SOCKERRNO;
+      if(error == EADDRNOTAVAIL) {
+
+        /* The requested bind address is not local.  Use the address used for
+         * the control connection instead and restart the port loop
+         */
+        failf(data, "bind(port=%hu) failed: %s", port,
+              Curl_strerror(conn, error) );
+
+        sslen = sizeof(ss);
+        if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
+          failf(data, "getsockname() failed: %s",
+                Curl_strerror(conn, SOCKERRNO) );
+          sclose(portsock);
+          return CURLE_FTP_PORT_FAILED;
+        }
+        port = port_min;
+        continue;
+      }
+      else if(error != EADDRINUSE && error != EACCES) {
+        failf(data, "bind(port=%hu) failed: %s", port,
+              Curl_strerror(conn, error) );
+        sclose(portsock);
+        return CURLE_FTP_PORT_FAILED;
+      }
+    }
+    else
+      break;
+
+    port++;
+  }
+
+  /* maybe all ports were in use already*/
+  if (port > port_max) {
+    failf(data, "bind() failed, we ran out of ports!");
+    sclose(portsock);
+    return CURLE_FTP_PORT_FAILED;
+  }
+
+  /* get the name again after the bind() so that we can extract the
+     port number it uses now */
+  sslen = sizeof(ss);
+  if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
+    failf(data, "getsockname() failed: %s",
+          Curl_strerror(conn, SOCKERRNO) );
+    sclose(portsock);
+    return CURLE_FTP_PORT_FAILED;
+  }
+
+  /* step 4, listen on the socket */
+
+  if(listen(portsock, 1)) {
+    failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
+    sclose(portsock);
+    return CURLE_FTP_PORT_FAILED;
+  }
+
+  /* step 5, send the proper FTP command */
+
+  /* get a plain printable version of the numerical address to work with
+     below */
+  Curl_printable_address(ai, myhost, sizeof(myhost));
+
+#ifdef ENABLE_IPV6
+  if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
+    /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
+       request and enable EPRT again! */
+    conn->bits.ftp_use_eprt = TRUE;
+#endif
+
+  for (; fcmd != DONE; fcmd++) {
+
+    if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
+      /* if disabled, goto next */
+      continue;
+
+    if((PORT == fcmd) && sa->sa_family != AF_INET)
+      /* PORT is ipv4 only */
+      continue;
+
+    switch (sa->sa_family) {
+    case AF_INET:
+      port = ntohs(sa4->sin_port);
+      break;
+#ifdef ENABLE_IPV6
+    case AF_INET6:
+      port = ntohs(sa6->sin6_port);
+      break;
+#endif
+    default:
+      continue; /* might as well skip this */
+    }
+
+    if(EPRT == fcmd) {
+      /*
+       * Two fine examples from RFC2428;
+       *
+       * EPRT |1|132.235.1.2|6275|
+       *
+       * EPRT |2|1080::8:800:200C:417A|5282|
+       */
+
+      result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
+                             sa->sa_family == AF_INET?1:2,
+                             myhost, port);
+      if(result)
+        return result;
+      break;
+    }
+    else if(PORT == fcmd) {
+      char *source = myhost;
+      char *dest = tmp;
+
+      /* translate x.x.x.x to x,x,x,x */
+      while(source && *source) {
+        if(*source == '.')
+          *dest=',';
+        else
+          *dest = *source;
+        dest++;
+        source++;
+      }
+      *dest = 0;
+      snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
+
+      result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
+      if(result)
+        return result;
+      break;
+    }
+  }
+
+  /* store which command was sent */
+  ftpc->count1 = fcmd;
+
+  /* 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 */
+  if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
+    sclose(conn->sock[SECONDARYSOCKET]);
+  conn->sock[SECONDARYSOCKET] = portsock;
+
+  /* this tcpconnect assignment below is a hackish work-around to make the
+     multi interface with active FTP work - as it will not wait for a
+     (passive) connect in Curl_is_connected().
+
+     The *proper* fix is to make sure that the active connection from the
+     server is done in a non-blocking way. Currently, it is still BLOCKING.
+  */
+  conn->bits.tcpconnect = TRUE;
+
+  state(conn, FTP_PORT);
+  return result;
+}
+
+static CURLcode ftp_state_use_pasv(struct connectdata *conn)
+{
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  CURLcode result = CURLE_OK;
+  /*
+    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|)
+
+  */
+
+  static const char mode[][5] = { "EPSV", "PASV" };
+  int modeoff;
+
+#ifdef PF_INET6
+  if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
+    /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
+       request and enable EPSV again! */
+    conn->bits.ftp_use_epsv = TRUE;
+#endif
+
+  modeoff = conn->bits.ftp_use_epsv?0:1;
+
+  PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
+
+  ftpc->count1 = modeoff;
+  state(conn, FTP_PASV);
+  infof(conn->data, "Connect data stream passively\n");
+
+  return result;
+}
+
+/* REST is the last command in the chain of commands when a "head"-like
+   request is made. Thus, if an actual transfer is to be made this is where
+   we take off for real. */
+static CURLcode ftp_state_post_rest(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct FTP *ftp = conn->data->state.proto.ftp;
+  struct SessionHandle *data = conn->data;
+
+  if(ftp->transfer != FTPTRANSFER_BODY) {
+    /* doesn't transfer any data */
+
+    /* still possibly do PRE QUOTE jobs */
+    state(conn, FTP_RETR_PREQUOTE);
+    result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
+  }
+  else if(data->set.ftp_use_port) {
+    /* We have chosen to use the PORT (or similar) command */
+    result = ftp_state_use_port(conn, EPRT);
+  }
+  else {
+    /* We have chosen (this is default) to use the PASV (or similar) command */
+    if(data->set.ftp_use_pret) {
+      /* The user has requested that we send a PRET command
+         to prepare the server for the upcoming PASV */
+      if(!conn->proto.ftpc.file) {
+        PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
+                data->set.str[STRING_CUSTOMREQUEST]?
+                data->set.str[STRING_CUSTOMREQUEST]:
+                (data->set.ftp_list_only?"NLST":"LIST"));
+      }
+      else if(data->set.upload) {
+        PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
+      }
+      else {
+        PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
+      }
+      state(conn, FTP_PRET);
+    }
+    else {
+      result = ftp_state_use_pasv(conn);
+    }
+  }
+  return result;
+}
+
+static CURLcode ftp_state_post_size(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct FTP *ftp = conn->data->state.proto.ftp;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
+    /* if a "head"-like request is being made (on a file) */
+
+    /* Determine if server can respond to REST command and therefore
+       whether it supports range */
+    PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
+
+    state(conn, FTP_REST);
+  }
+  else
+    result = ftp_state_post_rest(conn);
+
+  return result;
+}
+
+static CURLcode ftp_state_post_type(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct FTP *ftp = conn->data->state.proto.ftp;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
+    /* if a "head"-like request is being made (on a file) */
+
+    /* we know ftpc->file is a valid pointer to a file name */
+    PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
+
+    state(conn, FTP_SIZE);
+  }
+  else
+    result = ftp_state_post_size(conn);
+
+  return result;
+}
+
+static CURLcode ftp_state_post_listtype(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+
+  /* If this output is to be machine-parsed, the NLST command might be better
+     to use, since the LIST command output is not specified or standard in any
+     way. It has turned out that the NLST list output is not the same on all
+     servers either... */
+
+  /*
+     if FTPFILE_NOCWD was specified, we are currently in
+     the user's home directory, so we should add the path
+     as argument for the LIST / NLST / or custom command.
+     Whether the server will support this, is uncertain.
+
+     The other ftp_filemethods will CWD into dir/dir/ first and
+     then just do LIST (in that case: nothing to do here)
+  */
+  char *cmd,*lstArg,*slashPos;
+
+  lstArg = NULL;
+  if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
+     data->state.path &&
+     data->state.path[0] &&
+     strchr(data->state.path,'/')) {
+
+    lstArg = strdup(data->state.path);
+    if(!lstArg)
+      return CURLE_OUT_OF_MEMORY;
+
+    /* Check if path does not end with /, as then we cut off the file part */
+    if(lstArg[strlen(lstArg) - 1] != '/')  {
+
+      /* chop off the file part if format is dir/dir/file */
+      slashPos = strrchr(lstArg,'/');
+      if(slashPos)
+        *(slashPos+1) = '\0';
+    }
+  }
+
+  cmd = aprintf( "%s%s%s",
+                 data->set.str[STRING_CUSTOMREQUEST]?
+                 data->set.str[STRING_CUSTOMREQUEST]:
+                 (data->set.ftp_list_only?"NLST":"LIST"),
+                 lstArg? " ": "",
+                 lstArg? lstArg: "" );
+
+  if(!cmd) {
+    if(lstArg)
+      free(lstArg);
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  PPSENDF(&conn->proto.ftpc.pp, "%s",cmd);
+
+  if(lstArg)
+    free(lstArg);
+
+  free(cmd);
+
+  state(conn, FTP_LIST);
+
+  return result;
+}
+
+static CURLcode ftp_state_post_retrtype(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+
+  /* We've sent the TYPE, now we must send the list of prequote strings */
+
+  result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
+
+  return result;
+}
+
+static CURLcode ftp_state_post_stortype(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+
+  /* We've sent the TYPE, now we must send the list of prequote strings */
+
+  result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
+
+  return result;
+}
+
+static CURLcode ftp_state_post_mdtm(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct FTP *ftp = conn->data->state.proto.ftp;
+  struct SessionHandle *data = conn->data;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  /* 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(data->set.opt_no_body && ftpc->file &&
+     ftp_need_type(conn, data->set.prefer_ascii)) {
+    /* 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! */
+
+    ftp->transfer = FTPTRANSFER_INFO;
+    /* this means no actual transfer will be made */
+
+    /* Some servers return different sizes for different modes, and thus we
+       must set the proper type before we check the size */
+    result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
+    if(result)
+      return result;
+  }
+  else
+    result = ftp_state_post_type(conn);
+
+  return result;
+}
+
+/* This is called after the CWD commands have been done in the beginning of
+   the DO phase */
+static CURLcode ftp_state_post_cwd(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  /* Requested time of file or time-depended transfer? */
+  if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
+
+    /* we have requested to get the modified-time of the file, this is a white
+       spot as the MDTM is not mentioned in RFC959 */
+    PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
+
+    state(conn, FTP_MDTM);
+  }
+  else
+    result = ftp_state_post_mdtm(conn);
+
+  return result;
+}
+
+
+/* This is called after the TYPE and possible quote commands have been sent */
+static CURLcode ftp_state_ul_setup(struct connectdata *conn,
+                                   bool sizechecked)
+{
+  CURLcode result = CURLE_OK;
+  struct FTP *ftp = conn->data->state.proto.ftp;
+  struct SessionHandle *data = conn->data;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  int seekerr = CURL_SEEKFUNC_OK;
+
+  if((data->state.resume_from && !sizechecked) ||
+     ((data->state.resume_from > 0) && sizechecked)) {
+    /* 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(data->state.resume_from < 0 ) {
+      /* Got no given size to start from, figure it out */
+      PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
+      state(conn, FTP_STOR_SIZE);
+      return result;
+    }
+
+    /* enable append */
+    data->set.ftp_append = TRUE;
+
+    /* Let's read off the proper amount of bytes from the input. */
+    if(conn->seek_func) {
+      seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
+                                SEEK_SET);
+    }
+
+    if(seekerr != CURL_SEEKFUNC_OK) {
+      if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
+        failf(data, "Could not seek stream");
+        return CURLE_FTP_COULDNT_USE_REST;
+      }
+      /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
+      else {
+        curl_off_t passed=0;
+        do {
+          curl_off_t readthisamountnow = (data->state.resume_from - passed);
+          curl_off_t actuallyread;
+
+          if(readthisamountnow > BUFSIZE)
+            readthisamountnow = BUFSIZE;
+
+          actuallyread = (curl_off_t)
+            conn->fread_func(data->state.buffer, 1, (size_t)readthisamountnow,
+                             conn->fread_in);
+
+          passed += actuallyread;
+          if((actuallyread <= 0) || (actuallyread > readthisamountnow)) {
+            /* this checks for greater-than only to make sure that the
+               CURL_READFUNC_ABORT return code still aborts */
+            failf(data, "Failed to read data");
+            return CURLE_FTP_COULDNT_USE_REST;
+          }
+        } while(passed < data->state.resume_from);
+      }
+    }
+    /* now, decrease the size of the read */
+    if(data->set.infilesize>0) {
+      data->set.infilesize -= data->state.resume_from;
+
+      if(data->set.infilesize <= 0) {
+        infof(data, "File already completely uploaded\n");
+
+        /* no data to transfer */
+        result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+
+        /* Set ->transfer so that we won't get any error in
+         * ftp_done() because we didn't transfer anything! */
+        ftp->transfer = FTPTRANSFER_NONE;
+
+        state(conn, FTP_STOP);
+        return CURLE_OK;
+      }
+    }
+    /* we've passed, proceed as normal */
+  } /* resume_from */
+
+  PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
+          ftpc->file);
+
+  state(conn, FTP_STOR);
+
+  return result;
+}
+
+static CURLcode ftp_state_quote(struct connectdata *conn,
+                                bool init,
+                                ftpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  struct FTP *ftp = data->state.proto.ftp;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  bool quote=FALSE;
+  struct curl_slist *item;
+
+  switch(instate) {
+  case FTP_QUOTE:
+  default:
+    item = data->set.quote;
+    break;
+  case FTP_RETR_PREQUOTE:
+  case FTP_STOR_PREQUOTE:
+    item = data->set.prequote;
+    break;
+  case FTP_POSTQUOTE:
+    item = data->set.postquote;
+    break;
+  }
+
+  /*
+   * This state uses:
+   * 'count1' to iterate over the commands to send
+   * 'count2' to store wether to allow commands to fail
+   */
+
+  if(init)
+    ftpc->count1 = 0;
+  else
+    ftpc->count1++;
+
+  if(item) {
+    int i = 0;
+
+    /* Skip count1 items in the linked list */
+    while((i< ftpc->count1) && item) {
+      item = item->next;
+      i++;
+    }
+    if(item) {
+      char *cmd = item->data;
+      if(cmd[0] == '*') {
+        cmd++;
+        ftpc->count2 = 1; /* the sent command is allowed to fail */
+      }
+      else
+        ftpc->count2 = 0; /* failure means cancel operation */
+
+      PPSENDF(&ftpc->pp, "%s", cmd);
+      state(conn, instate);
+      quote = TRUE;
+    }
+  }
+
+  if(!quote) {
+    /* No more quote to send, continue to ... */
+    switch(instate) {
+    case FTP_QUOTE:
+    default:
+      result = ftp_state_cwd(conn);
+      break;
+    case FTP_RETR_PREQUOTE:
+      if(ftp->transfer != FTPTRANSFER_BODY)
+        state(conn, FTP_STOP);
+      else {
+        PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
+        state(conn, FTP_RETR_SIZE);
+      }
+      break;
+    case FTP_STOR_PREQUOTE:
+      result = ftp_state_ul_setup(conn, FALSE);
+      break;
+    case FTP_POSTQUOTE:
+      break;
+    }
+  }
+
+  return result;
+}
+
+static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
+                                    int ftpcode)
+{
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  CURLcode result;
+  struct SessionHandle *data=conn->data;
+  Curl_addrinfo *conninfo;
+  struct Curl_dns_entry *addr=NULL;
+  int rc;
+  unsigned short connectport; /* the local port connect() should use! */
+  unsigned short newport=0; /* remote port */
+  bool connected;
+
+  /* newhost must be able to hold a full IP-style address in ASCII, which
+     in the IPv6 case means 5*8-1 = 39 letters */
+#define NEWHOST_BUFSIZE 48
+  char newhost[NEWHOST_BUFSIZE];
+  char *str=&data->state.buffer[4];  /* start on the first letter */
+
+  if((ftpc->count1 == 0) &&
+     (ftpcode == 229)) {
+    /* positive EPSV response */
+    char *ptr = strchr(str, '(');
+    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])) {
+        const 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 = (unsigned short)(num & 0xffff);
+
+          if(conn->bits.tunnel_proxy ||
+             data->set.proxytype == CURLPROXY_SOCKS5 ||
+             data->set.proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
+             data->set.proxytype == CURLPROXY_SOCKS4 ||
+             data->set.proxytype == CURLPROXY_SOCKS4A)
+            /* proxy tunnel -> use other host info because ip_addr_str is the
+               proxy address not the ftp host */
+            snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
+          else
+            /* use the same IP we are already connected to */
+            snprintf(newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str);
+        }
+      }
+      else
+        ptr=NULL;
+    }
+    if(!ptr) {
+      failf(data, "Weirdly formatted EPSV reply");
+      return CURLE_FTP_WEIRD_PASV_REPLY;
+    }
+  }
+  else if((ftpc->count1 == 1) &&
+          (ftpcode == 227)) {
+    /* positive PASV response */
+    int ip[4];
+    int port[2];
+
+    /*
+     * Scan for a sequence of six comma-separated numbers and use 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 the 227-response");
+      return CURLE_FTP_WEIRD_227_FORMAT;
+    }
+
+    /* we got OK from server */
+    if(data->set.ftp_skip_ip) {
+      /* told to ignore the remotely given IP but instead use the one we used
+         for the control connection */
+      infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n",
+            ip[0], ip[1], ip[2], ip[3],
+            conn->ip_addr_str);
+      if(conn->bits.tunnel_proxy ||
+          data->set.proxytype == CURLPROXY_SOCKS5 ||
+          data->set.proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
+          data->set.proxytype == CURLPROXY_SOCKS4 ||
+          data->set.proxytype == CURLPROXY_SOCKS4A)
+        /* proxy tunnel -> use other host info because ip_addr_str is the
+           proxy address not the ftp host */
+        snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
+      else
+        snprintf(newhost, sizeof(newhost), "%s", conn->ip_addr_str);
+    }
+    else
+      snprintf(newhost, sizeof(newhost),
+               "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
+    newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
+  }
+  else if(ftpc->count1 == 0) {
+    /* EPSV failed, move on to PASV */
+
+    /* disable it for next transfer */
+    conn->bits.ftp_use_epsv = FALSE;
+    infof(data, "disabling EPSV usage\n");
+
+    PPSENDF(&ftpc->pp, "PASV", NULL);
+    ftpc->count1++;
+    /* remain in the FTP_PASV state */
+    return result;
+  }
+  else {
+    failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
+    return CURLE_FTP_WEIRD_PASV_REPLY;
+  }
+
+  if(data->set.str[STRING_PROXY] && *data->set.str[STRING_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)
+      /* BLOCKING */
+      rc = Curl_wait_for_resolv(conn, &addr);
+
+    connectport =
+      (unsigned short)conn->port; /* we connect to the proxy's port */
+
+    if(!addr) {
+      failf(data, "Can't resolve proxy host %s:%hu",
+            conn->proxy.name, connectport);
+      return CURLE_FTP_CANT_GET_HOST;
+    }
+  }
+  else {
+    /* normal, direct, ftp connection */
+    rc = Curl_resolv(conn, newhost, newport, &addr);
+    if(rc == CURLRESOLV_PENDING)
+      /* BLOCKING */
+      rc = Curl_wait_for_resolv(conn, &addr);
+
+    connectport = newport; /* we connect to the remote port */
+
+    if(!addr) {
+      failf(data, "Can't resolve new host %s:%hu", newhost, connectport);
+      return CURLE_FTP_CANT_GET_HOST;
+    }
+  }
+
+  result = Curl_connecthost(conn,
+                            addr,
+                            &conn->sock[SECONDARYSOCKET],
+                            &conninfo,
+                            &connected);
+
+  Curl_resolv_unlock(data, addr); /* we're done using this address */
+
+  if(result && ftpc->count1 == 0 && ftpcode == 229) {
+    infof(data, "got positive EPSV response, but can't connect. "
+          "Disabling EPSV\n");
+    /* disable it for next transfer */
+    conn->bits.ftp_use_epsv = FALSE;
+    data->state.errorbuf = FALSE; /* allow error message to get rewritten */
+    PPSENDF(&ftpc->pp, "PASV", NULL);
+    ftpc->count1++;
+    /* remain in the FTP_PASV state */
+    return result;
+ }
+
+  if(result)
+    return result;
+
+  conn->bits.tcpconnect = connected; /* simply TRUE or FALSE */
+
+  /*
+   * 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, newhost, connectport);
+
+  switch(data->set.proxytype) {
+#ifndef CURL_DISABLE_PROXY
+    /* FIX: this MUST wait for a proper connect first if 'connected' is
+     * FALSE */
+  case CURLPROXY_SOCKS5:
+  case CURLPROXY_SOCKS5_HOSTNAME:
+    result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost, newport,
+                         SECONDARYSOCKET, conn);
+    break;
+  case CURLPROXY_SOCKS4:
+    result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
+                         SECONDARYSOCKET, conn, FALSE);
+    break;
+  case CURLPROXY_SOCKS4A:
+    result = Curl_SOCKS4(conn->proxyuser, newhost, newport,
+                         SECONDARYSOCKET, conn, TRUE);
+    break;
+#endif /* CURL_DISABLE_PROXY */
+  case CURLPROXY_HTTP:
+  case CURLPROXY_HTTP_1_0:
+    /* do nothing here. handled later. */
+    break;
+  default:
+    failf(data, "unknown proxytype option given");
+    result = CURLE_COULDNT_CONNECT;
+    break;
+  }
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY)
+  if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
+    /* FIX: this MUST wait for a proper connect first if 'connected' is
+     * FALSE */
+
+    /* BLOCKING */
+    /* We want "seamless" FTP operations through HTTP proxy tunnel */
+
+    /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
+     * conn->proto.http; we want FTP through HTTP and we have to change the
+     * member temporarily for connecting to the HTTP proxy. After
+     * Curl_proxyCONNECT we have to set back the member to the original struct
+     * FTP pointer
+     */
+    struct HTTP http_proxy;
+    struct FTP *ftp_save = data->state.proto.ftp;
+    memset(&http_proxy, 0, sizeof(http_proxy));
+    data->state.proto.http = &http_proxy;
+
+    result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
+
+    data->state.proto.ftp = ftp_save;
+
+    if(CURLE_OK != result)
+      return result;
+  }
+#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */
+
+  state(conn, FTP_STOP); /* this phase is completed */
+
+  return result;
+}
+
+static CURLcode ftp_state_port_resp(struct connectdata *conn,
+                                    int ftpcode)
+{
+  struct SessionHandle *data = conn->data;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  ftpport fcmd = (ftpport)ftpc->count1;
+  CURLcode result = CURLE_OK;
+
+  if(ftpcode != 200) {
+    /* the command failed */
+
+    if(EPRT == fcmd) {
+      infof(data, "disabling EPRT usage\n");
+      conn->bits.ftp_use_eprt = FALSE;
+    }
+    fcmd++;
+
+    if(fcmd == DONE) {
+      failf(data, "Failed to do PORT");
+      result = CURLE_FTP_PORT_FAILED;
+    }
+    else
+      /* try next */
+      result = ftp_state_use_port(conn, fcmd);
+  }
+  else {
+    infof(data, "Connect data stream actively\n");
+    state(conn, FTP_STOP); /* end of DO phase */
+  }
+
+  return result;
+}
+
+static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
+                                    int ftpcode)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data=conn->data;
+  struct FTP *ftp = data->state.proto.ftp;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  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;
+      char *buf = data->state.buffer;
+      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);
+        /* using the good old yacc/bison yuck */
+        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: */
+        data->info.filetime = (long)curl_getdate(buf, &secs);
+      }
+
+#ifdef CURL_FTP_HTTPSTYLE_HEAD
+      /* 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. */
+
+      if(data->set.opt_no_body &&
+         ftpc->file &&
+         data->set.get_filetime &&
+         (data->info.filetime>=0) ) {
+        struct tm *tm;
+        time_t filetime = (time_t)data->info.filetime;
+#ifdef HAVE_GMTIME_R
+        struct tm buffer;
+        tm = (struct tm *)gmtime_r(&filetime, &buffer);
+#else
+        tm = gmtime(&filetime);
+#endif
+        /* format: "Tue, 15 Nov 1994 12:45:26" */
+        snprintf(buf, BUFSIZE-1,
+                 "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
+                 Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+                 tm->tm_mday,
+                 Curl_month[tm->tm_mon],
+                 tm->tm_year + 1900,
+                 tm->tm_hour,
+                 tm->tm_min,
+                 tm->tm_sec);
+        result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
+        if(result)
+          return result;
+      } /* end of a ridiculous amount of conditionals */
+#endif
+    }
+    break;
+  default:
+    infof(data, "unsupported MDTM reply format\n");
+    break;
+  case 550: /* "No such file or directory" */
+    failf(data, "Given file does not exist");
+    result = CURLE_FTP_COULDNT_RETR_FILE;
+    break;
+  }
+
+  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->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
+          data->info.timecond = TRUE;
+          state(conn, FTP_STOP);
+          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->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
+          data->info.timecond = TRUE;
+          state(conn, FTP_STOP);
+          return CURLE_OK;
+        }
+        break;
+      } /* switch */
+    }
+    else {
+      infof(data, "Skipping time comparison\n");
+    }
+  }
+
+  if(!result)
+    result = ftp_state_post_mdtm(conn);
+
+  return result;
+}
+
+static CURLcode ftp_state_type_resp(struct connectdata *conn,
+                                    int ftpcode,
+                                    ftpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data=conn->data;
+
+  if(ftpcode/100 != 2) {
+    /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
+       successful 'TYPE I'. While that is not as RFC959 says, it is still a
+       positive response code and we allow that. */
+    failf(data, "Couldn't set desired mode");
+    return CURLE_FTP_COULDNT_SET_TYPE;
+  }
+  if(ftpcode != 200)
+    infof(data, "Got a %03d response code instead of the assumed 200\n",
+          ftpcode);
+
+  if(instate == FTP_TYPE)
+    result = ftp_state_post_type(conn);
+  else if(instate == FTP_LIST_TYPE)
+    result = ftp_state_post_listtype(conn);
+  else if(instate == FTP_RETR_TYPE)
+    result = ftp_state_post_retrtype(conn);
+  else if(instate == FTP_STOR_TYPE)
+    result = ftp_state_post_stortype(conn);
+
+  return result;
+}
+
+static CURLcode ftp_state_post_retr_size(struct connectdata *conn,
+                                         curl_off_t filesize)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data=conn->data;
+  struct FTP *ftp = data->state.proto.ftp;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
+    failf(data, "Maximum file size exceeded");
+    return CURLE_FILESIZE_EXCEEDED;
+  }
+  ftp->downloadsize = filesize;
+
+  if(data->state.resume_from) {
+    /* We always (attempt to) get the size of downloads, so it is done before
+       this even when not doing resumes. */
+    if(filesize == -1) {
+      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(data->state.resume_from< 0) {
+        /* We're supposed to download the last abs(from) bytes */
+        if(filesize < -data->state.resume_from) {
+          failf(data, "Offset (%" FORMAT_OFF_T
+                ") was beyond file size (%" FORMAT_OFF_T ")",
+                data->state.resume_from, filesize);
+          return CURLE_BAD_DOWNLOAD_RESUME;
+        }
+        /* convert to size to download */
+        ftp->downloadsize = -data->state.resume_from;
+        /* download from where? */
+        data->state.resume_from = filesize - ftp->downloadsize;
+      }
+      else {
+        if(filesize < data->state.resume_from) {
+          failf(data, "Offset (%" FORMAT_OFF_T
+                ") was beyond file size (%" FORMAT_OFF_T ")",
+                data->state.resume_from, filesize);
+          return CURLE_BAD_DOWNLOAD_RESUME;
+        }
+        /* Now store the number of bytes we are expected to download */
+        ftp->downloadsize = filesize-data->state.resume_from;
+      }
+    }
+
+    if(ftp->downloadsize == 0) {
+      /* no data to transfer */
+      result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+      infof(data, "File already completely downloaded\n");
+
+      /* Set ->transfer so that we won't get any error in ftp_done()
+       * because we didn't transfer the any file */
+      ftp->transfer = FTPTRANSFER_NONE;
+      state(conn, FTP_STOP);
+      return CURLE_OK;
+    }
+
+    /* Set resume file transfer offset */
+    infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
+          "\n", data->state.resume_from);
+
+    PPSENDF(&ftpc->pp, "REST %" FORMAT_OFF_T, data->state.resume_from);
+
+    state(conn, FTP_RETR_REST);
+
+  }
+  else {
+    /* no resume */
+    PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
+    state(conn, FTP_RETR);
+  }
+
+  return result;
+}
+
+static CURLcode ftp_state_size_resp(struct connectdata *conn,
+                                    int ftpcode,
+                                    ftpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data=conn->data;
+  curl_off_t filesize;
+  char *buf = data->state.buffer;
+
+  /* get the size from the ascii string: */
+  filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
+
+  if(instate == FTP_SIZE) {
+#ifdef CURL_FTP_HTTPSTYLE_HEAD
+    if(-1 != filesize) {
+      snprintf(buf, sizeof(data->state.buffer),
+               "Content-Length: %" FORMAT_OFF_T "\r\n", filesize);
+      result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
+      if(result)
+        return result;
+    }
+#endif
+    Curl_pgrsSetDownloadSize(data, filesize);
+    result = ftp_state_post_size(conn);
+  }
+  else if(instate == FTP_RETR_SIZE) {
+    Curl_pgrsSetDownloadSize(data, filesize);
+    result = ftp_state_post_retr_size(conn, filesize);
+  }
+  else if(instate == FTP_STOR_SIZE) {
+    data->state.resume_from = filesize;
+    result = ftp_state_ul_setup(conn, TRUE);
+  }
+
+  return result;
+}
+
+static CURLcode ftp_state_rest_resp(struct connectdata *conn,
+                                    int ftpcode,
+                                    ftpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  switch(instate) {
+  case FTP_REST:
+  default:
+#ifdef CURL_FTP_HTTPSTYLE_HEAD
+    if(ftpcode == 350) {
+      char buffer[24]= { "Accept-ranges: bytes\r\n" };
+      result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
+      if(result)
+        return result;
+    }
+#endif
+    result = ftp_state_post_rest(conn);
+    break;
+
+  case FTP_RETR_REST:
+    if(ftpcode != 350) {
+      failf(conn->data, "Couldn't use REST");
+      result = CURLE_FTP_COULDNT_USE_REST;
+    }
+    else {
+      PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
+      state(conn, FTP_RETR);
+    }
+    break;
+  }
+
+  return result;
+}
+
+static CURLcode ftp_state_stor_resp(struct connectdata *conn,
+                                    int ftpcode)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  struct FTP *ftp = data->state.proto.ftp;
+
+  if(ftpcode>=400) {
+    failf(data, "Failed FTP upload: %0d", ftpcode);
+    /* oops, we never close the sockets! */
+    return CURLE_UPLOAD_FAILED;
+  }
+
+  if(data->set.ftp_use_port) {
+    /* BLOCKING */
+    /* 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");
+    /* BLOCKING */
+    result = Curl_ssl_connect(conn, SECONDARYSOCKET);
+    if(result)
+      return result;
+  }
+
+  *(ftp->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);
+
+  /* set the SO_SNDBUF for the secondary socket for those who need it */
+  Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
+
+  result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
+                               SECONDARYSOCKET, ftp->bytecountp);
+  state(conn, FTP_STOP);
+
+  conn->proto.ftpc.pp.pending_resp = TRUE; /* expect a server response */
+
+  return result;
+}
+
+/* for LIST and RETR responses */
+static CURLcode ftp_state_get_resp(struct connectdata *conn,
+                                    int ftpcode,
+                                    ftpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  struct FTP *ftp = data->state.proto.ftp;
+  char *buf = data->state.buffer;
+
+  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((instate != FTP_LIST) &&
+       !data->set.prefer_ascii &&
+       (ftp->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=(long)(bytes-buf);
+        /* this is a hint there is size information in there! ;-) */
+        while(--in) {
+          /* scan for the left parenthesis and break there */
+          if('(' == *bytes)
+            break;
+          /* skip only digits */
+          if(!ISDIGIT(*bytes)) {
+            bytes=NULL;
+            break;
+          }
+          /* one more estep backwards */
+          bytes--;
+        }
+        /* if we have nothing but digits: */
+        if(bytes++) {
+          /* get the number! */
+          size = curlx_strtoofft(bytes, NULL, 0);
+        }
+      }
+    }
+    else if(ftp->downloadsize > -1)
+      size = ftp->downloadsize;
+
+    if(data->set.ftp_use_port) {
+      /* BLOCKING */
+      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_ssl_connect(conn, SECONDARYSOCKET);
+      if(result)
+        return result;
+    }
+
+    if(size > data->req.maxdownload && data->req.maxdownload > 0)
+      size = data->req.size = data->req.maxdownload;
+    else if((instate != FTP_LIST) && (data->set.prefer_ascii))
+      size = -1; /* kludge for servers that understate ASCII mode file size */
+
+    infof(data, "Maxdownload = %" FORMAT_OFF_T "\n", data->req.maxdownload);
+
+    if(instate != FTP_LIST)
+      infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
+
+    /* FTP download: */
+    result=Curl_setup_transfer(conn, SECONDARYSOCKET, size, FALSE,
+                               ftp->bytecountp,
+                               -1, NULL); /* no upload here */
+    if(result)
+      return result;
+
+    conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
+    state(conn, FTP_STOP);
+  }
+  else {
+    if((instate == FTP_LIST) && (ftpcode == 450)) {
+      /* simply no matching files in the dir listing */
+      ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
+      state(conn, FTP_STOP); /* this phase is over */
+    }
+    else {
+      failf(data, "RETR response: %03d", ftpcode);
+      return instate == FTP_RETR && ftpcode == 550?
+        CURLE_REMOTE_FILE_NOT_FOUND:
+        CURLE_FTP_COULDNT_RETR_FILE;
+    }
+  }
+
+  return result;
+}
+
+/* after USER, PASS and ACCT */
+static CURLcode ftp_state_loggedin(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+
+#ifdef HAVE_KRB4
+  if(conn->data->set.krb) {
+    /* 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) {
+      /* BLOCKING */
+      result = Curl_krb_kauth(conn);
+      if(result)
+        return result;
+    }
+  }
+#endif
+  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.
+    */
+    PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
+    state(conn, FTP_PBSZ);
+  }
+  else {
+    result = ftp_state_pwd(conn);
+  }
+  return result;
+}
+
+/* for USER and PASS responses */
+static CURLcode ftp_state_user_resp(struct connectdata *conn,
+                                    int ftpcode,
+                                    ftpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  struct FTP *ftp = data->state.proto.ftp;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  (void)instate; /* no use for this yet */
+
+  /* some need password anyway, and others just return 2xx ignored */
+  if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
+    /* 331 Password required for ...
+       (the server requires to send the user's password too) */
+    PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
+    state(conn, FTP_PASS);
+  }
+  else if(ftpcode/100 == 2) {
+    /* 230 User ... logged in.
+       (the user logged in with or without password) */
+    result = ftp_state_loggedin(conn);
+  }
+  else if(ftpcode == 332) {
+    if(data->set.str[STRING_FTP_ACCOUNT]) {
+      PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
+      state(conn, FTP_ACCT);
+    }
+    else {
+      failf(data, "ACCT requested but none available");
+      result = CURLE_LOGIN_DENIED;
+    }
+  }
+  else {
+    /* All other response codes, like:
+
+    530 User ... access denied
+    (the server denies to log the specified user) */
+
+    if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
+        !conn->data->state.ftp_trying_alternative) {
+      /* Ok, USER failed.  Let's try the supplied command. */
+      PPSENDF(&conn->proto.ftpc.pp, "%s",
+              conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
+      conn->data->state.ftp_trying_alternative = TRUE;
+      state(conn, FTP_USER);
+      result = CURLE_OK;
+    }
+    else {
+      failf(data, "Access denied: %03d", ftpcode);
+      result = CURLE_LOGIN_DENIED;
+    }
+  }
+  return result;
+}
+
+/* for ACCT response */
+static CURLcode ftp_state_acct_resp(struct connectdata *conn,
+                                    int ftpcode)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  if(ftpcode != 230) {
+    failf(data, "ACCT rejected by server: %03d", ftpcode);
+    result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
+  }
+  else
+    result = ftp_state_loggedin(conn);
+
+  return result;
+}
+
+
+static CURLcode ftp_statemach_act(struct connectdata *conn)
+{
+  CURLcode result;
+  curl_socket_t sock = conn->sock[FIRSTSOCKET];
+  struct SessionHandle *data=conn->data;
+  int ftpcode;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  struct pingpong *pp = &ftpc->pp;
+  static const char ftpauth[][4]  = { "SSL", "TLS" };
+  size_t nread = 0;
+
+  if(pp->sendleft)
+    return Curl_pp_flushsend(pp);
+
+  /* we read a piece of response */
+  result = ftp_readresp(sock, pp, &ftpcode, &nread);
+  if(result)
+    return result;
+
+  if(ftpcode) {
+    /* we have now received a full FTP server response */
+    switch(ftpc->state) {
+    case FTP_WAIT220:
+      if(ftpcode != 220) {
+        failf(data, "Got a %03d ftp-server response when 220 was expected",
+              ftpcode);
+        return CURLE_FTP_WEIRD_SERVER_REPLY;
+      }
+
+      /* We have received a 220 response fine, now we proceed. */
+#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
+      if(data->set.krb) {
+        /* If not anonymous login, try a secure login. Note that this
+           procedure is still BLOCKING. */
+
+        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.str[STRING_KRB_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 yet, but FTPS is
+           requested. Try a FTPS connection now */
+
+        ftpc->count3=0;
+        switch(data->set.ftpsslauth) {
+        case CURLFTPAUTH_DEFAULT:
+        case CURLFTPAUTH_SSL:
+          ftpc->count2 = 1; /* add one to get next */
+          ftpc->count1 = 0;
+          break;
+        case CURLFTPAUTH_TLS:
+          ftpc->count2 = -1; /* subtract one to get next */
+          ftpc->count1 = 1;
+          break;
+        default:
+          failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
+                (int)data->set.ftpsslauth);
+          return CURLE_FAILED_INIT; /* we don't know what to do */
+        }
+        PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
+        state(conn, FTP_AUTH);
+      }
+      else {
+        result = ftp_state_user(conn);
+        if(result)
+          return result;
+      }
+
+      break;
+
+    case FTP_AUTH:
+      /* we have gotten the response to a previous AUTH command */
+
+      /* 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)) {
+        /* Curl_ssl_connect is BLOCKING */
+        result = Curl_ssl_connect(conn, FIRSTSOCKET);
+        if(CURLE_OK == result) {
+          conn->protocol |= PROT_FTPS;
+          conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
+          result = ftp_state_user(conn);
+        }
+      }
+      else if(ftpc->count3 < 1) {
+        ftpc->count3++;
+        ftpc->count1 += ftpc->count2; /* get next attempt */
+        result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
+        /* remain in this same state */
+      }
+      else {
+        if(data->set.ftp_ssl > CURLUSESSL_TRY)
+          /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
+          result = CURLE_USE_SSL_FAILED;
+        else
+          /* ignore the failure and continue */
+          result = ftp_state_user(conn);
+      }
+
+      if(result)
+        return result;
+      break;
+
+    case FTP_USER:
+    case FTP_PASS:
+      result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
+      break;
+
+    case FTP_ACCT:
+      result = ftp_state_acct_resp(conn, ftpcode);
+      break;
+
+    case FTP_PBSZ:
+      PPSENDF(&ftpc->pp, "PROT %c",
+              data->set.ftp_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
+      state(conn, FTP_PROT);
+
+      break;
+
+    case FTP_PROT:
+      if(ftpcode/100 == 2)
+        /* We have enabled SSL for the data connection! */
+        conn->ssl[SECONDARYSOCKET].use =
+          (bool)(data->set.ftp_ssl != CURLUSESSL_CONTROL);
+      /* FTP servers typically responds with 500 if they decide to reject
+         our 'P' request */
+      else if(data->set.ftp_ssl > CURLUSESSL_CONTROL)
+        /* we failed and bails out */
+        return CURLE_USE_SSL_FAILED;
+
+      if(data->set.ftp_ccc) {
+        /* CCC - Clear Command Channel
+         */
+        PPSENDF(&ftpc->pp, "CCC", NULL);
+        state(conn, FTP_CCC);
+      }
+      else {
+        result = ftp_state_pwd(conn);
+        if(result)
+          return result;
+      }
+      break;
+
+    case FTP_CCC:
+      if(ftpcode < 500) {
+        /* First shut down the SSL layer (note: this call will block) */
+        result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
+
+        if(result) {
+          failf(conn->data, "Failed to clear the command channel (CCC)");
+          return result;
+        }
+      }
+
+      /* Then continue as normal */
+      result = ftp_state_pwd(conn);
+      if(result)
+        return result;
+      break;
+
+    case FTP_PWD:
+      if(ftpcode == 257) {
+        char *ptr=&data->state.buffer[4];  /* start on the first letter */
+        char *dir;
+        char *store;
+
+        dir = malloc(nread + 1);
+        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++;
+          for (store = dir; *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++;
+          }
+          if(ftpc->entrypath)
+            free(ftpc->entrypath);
+          ftpc->entrypath =dir; /* remember this */
+          infof(data, "Entry path is '%s'\n", ftpc->entrypath);
+          /* also save it where getinfo can access it: */
+          data->state.most_recent_ftp_entrypath = ftpc->entrypath;
+
+          /* If the path name does not look like an absolute path (i.e.: it
+             does not start with a '/'), we probably need some server-dependent
+             adjustments. For example, this is the case when connecting to
+             an OS400 FTP server: this server supports two name syntaxes,
+             the default one being incompatible with standard pathes. In
+             addition, this server switches automatically to the regular path
+             syntax when one is encountered in a command: this results in
+             having an entrypath in the wrong syntax when later used in CWD.
+               The method used here is to check the server OS: we do it only
+             if the path name looks strange to minimize overhead on other
+             systems. */
+
+          if(!ftpc->server_os && ftpc->entrypath[0] != '/') {
+            PPSENDF(&ftpc->pp, "SYST", NULL);
+            state(conn, FTP_SYST);
+            break;
+          }
+        }
+        else {
+          /* couldn't get the path */
+          free(dir);
+          infof(data, "Failed to figure out path\n");
+        }
+      }
+      state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
+      DEBUGF(infof(data, "protocol connect phase DONE\n"));
+      break;
+
+    case FTP_SYST:
+      if(ftpcode == 215) {
+        char *ptr=&data->state.buffer[4];  /* start on the first letter */
+        char *os;
+        char *store;
+
+        os = malloc(nread + 1);
+        if(!os)
+          return CURLE_OUT_OF_MEMORY;
+
+        /* Reply format is like
+           215<space><OS-name><space><commentary>
+        */
+        while (*ptr == ' ')
+          ptr++;
+        for (store = os; *ptr && *ptr != ' ';)
+          *store++ = *ptr++;
+        *store = '\0'; /* zero terminate */
+        ftpc->server_os = os;
+
+        /* Check for special servers here. */
+
+        if(strequal(ftpc->server_os, "OS/400")) {
+          /* Force OS400 name format 1. */
+          PPSENDF(&ftpc->pp, "SITE NAMEFMT 1", NULL);
+          state(conn, FTP_NAMEFMT);
+          break;
+        }
+      else {
+        /* Nothing special for the target server. */
+       }
+      }
+      else {
+        /* Cannot identify server OS. Continue anyway and cross fingers. */
+      }
+
+      state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
+      DEBUGF(infof(data, "protocol connect phase DONE\n"));
+      break;
+
+    case FTP_NAMEFMT:
+      if(ftpcode == 250) {
+        /* Name format change successful: reload initial path. */
+        ftp_state_pwd(conn);
+        break;
+      }
+
+      state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
+      DEBUGF(infof(data, "protocol connect phase DONE\n"));
+      break;
+
+    case FTP_QUOTE:
+    case FTP_POSTQUOTE:
+    case FTP_RETR_PREQUOTE:
+    case FTP_STOR_PREQUOTE:
+      if((ftpcode >= 400) && !ftpc->count2) {
+        /* failure reponse code, and not allowed to fail */
+        failf(conn->data, "QUOT command failed with %03d", ftpcode);
+        return CURLE_QUOTE_ERROR;
+      }
+      result = ftp_state_quote(conn, FALSE, ftpc->state);
+      if(result)
+        return result;
+
+      break;
+
+    case FTP_CWD:
+      if(ftpcode/100 != 2) {
+        /* failure to CWD there */
+        if(conn->data->set.ftp_create_missing_dirs &&
+           ftpc->count1 && !ftpc->count2) {
+          /* try making it */
+          ftpc->count2++; /* counter to prevent CWD-MKD loops */
+          PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
+          state(conn, FTP_MKD);
+        }
+        else {
+          /* return failure */
+          failf(data, "Server denied you to change to the given directory");
+          ftpc->cwdfail = TRUE; /* don't remember this path as we failed
+                                   to enter it */
+          return CURLE_REMOTE_ACCESS_DENIED;
+        }
+      }
+      else {
+        /* success */
+        ftpc->count2=0;
+        if(++ftpc->count1 <= ftpc->dirdepth) {
+          /* send next CWD */
+          PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
+        }
+        else {
+          result = ftp_state_post_cwd(conn);
+          if(result)
+            return result;
+        }
+      }
+      break;
+
+    case FTP_MKD:
+      if((ftpcode/100 != 2) && !ftpc->count3--) {
+        /* failure to MKD the dir */
+        failf(data, "Failed to MKD dir: %03d", ftpcode);
+        return CURLE_REMOTE_ACCESS_DENIED;
+      }
+      state(conn, FTP_CWD);
+      /* send CWD */
+      PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
+      break;
+
+    case FTP_MDTM:
+      result = ftp_state_mdtm_resp(conn, ftpcode);
+      break;
+
+    case FTP_TYPE:
+    case FTP_LIST_TYPE:
+    case FTP_RETR_TYPE:
+    case FTP_STOR_TYPE:
+      result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
+      break;
+
+    case FTP_SIZE:
+    case FTP_RETR_SIZE:
+    case FTP_STOR_SIZE:
+      result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
+      break;
+
+    case FTP_REST:
+    case FTP_RETR_REST:
+      result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
+      break;
+
+    case FTP_PRET:
+      if(ftpcode != 200) {
+       /* there only is this one standard OK return code. */
+        failf(data, "PRET command not accepted: %03d", ftpcode);
+        return CURLE_FTP_PRET_FAILED;
+      }
+      result = ftp_state_use_pasv(conn);
+      break;
+
+    case FTP_PASV:
+      result = ftp_state_pasv_resp(conn, ftpcode);
+      break;
+
+    case FTP_PORT:
+      result = ftp_state_port_resp(conn, ftpcode);
+      break;
+
+    case FTP_LIST:
+    case FTP_RETR:
+      result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
+      break;
+
+    case FTP_STOR:
+      result = ftp_state_stor_resp(conn, ftpcode);
+      break;
+
+    case FTP_QUIT:
+      /* fallthrough, just stop! */
+    default:
+      /* internal error */
+      state(conn, FTP_STOP);
+      break;
+    }
+  } /* if(ftpcode) */
+
+  return result;
+}
+
+
+/* called repeatedly until done from multi.c */
+static CURLcode ftp_multi_statemach(struct connectdata *conn,
+                                    bool *done)
+{
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  CURLcode result = Curl_pp_multi_statemach(&ftpc->pp);
+
+  /* Check for the state outside of the Curl_socket_ready() return code checks
+     since at times we are in fact already in this state when this function
+     gets called. */
+  *done = (bool)(ftpc->state == FTP_STOP);
+
+  return result;
+}
+
+static CURLcode ftp_easy_statemach(struct connectdata *conn)
+{
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  struct pingpong *pp = &ftpc->pp;
+  CURLcode result = CURLE_OK;
+
+  while(ftpc->state != FTP_STOP) {
+    result = Curl_pp_easy_statemach(pp);
+    if(result)
+      break;
+  }
+
+  return result;
+}
+
+/*
+ * Allocate and initialize the struct FTP for the current SessionHandle.  If
+ * need be.
+ */
+
+#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
+    defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
+  /* workaround icc 9.1 optimizer issue */
+#pragma optimize("", off)
+#endif
+
+static CURLcode ftp_init(struct connectdata *conn)
+{
+  struct FTP *ftp;
+
+  if(NULL == conn->data->state.proto.ftp) {
+    conn->data->state.proto.ftp = malloc(sizeof(struct FTP));
+    if(NULL == conn->data->state.proto.ftp)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  ftp = conn->data->state.proto.ftp;
+
+  /* get some initial data into the ftp struct */
+  ftp->bytecountp = &conn->data->req.bytecount;
+  ftp->transfer = FTPTRANSFER_BODY;
+  ftp->downloadsize = 0;
+
+  /* No need to duplicate user+password, the connectdata struct won't change
+     during a session, but we re-init them here since on subsequent inits
+     since the conn struct may have changed or been replaced.
+  */
+  ftp->user = conn->user;
+  ftp->passwd = conn->passwd;
+  if(TRUE == isBadFtpString(ftp->user))
+    return CURLE_URL_MALFORMAT;
+  if(TRUE == isBadFtpString(ftp->passwd))
+    return CURLE_URL_MALFORMAT;
+
+  return CURLE_OK;
+}
+
+#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
+    defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
+  /* workaround icc 9.1 optimizer issue */
+#pragma optimize("", on)
+#endif
+
+/*
+ * ftp_connect() should do everything that is to be considered a part of
+ * the connection phase.
+ *
+ * The variable 'done' points to will be TRUE if the protocol-layer connect
+ * phase is done when this function returns, or FALSE is not. When called as
+ * a part of the easy interface, it will always be TRUE.
+ */
+static CURLcode ftp_connect(struct connectdata *conn,
+                                 bool *done) /* see description above */
+{
+  CURLcode result;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  struct SessionHandle *data=conn->data;
+  struct pingpong *pp = &ftpc->pp;
+
+  *done = FALSE; /* default to not done yet */
+
+  /* If there already is a protocol-specific struct allocated for this
+     sessionhandle, deal with it */
+  Curl_reset_reqproto(conn);
+
+  result = ftp_init(conn);
+  if(CURLE_OK != result)
+    return result;
+
+  /* We always support persistant connections on ftp */
+  conn->bits.close = FALSE;
+
+  pp->response_time = RESP_TIMEOUT; /* set default response time-out */
+  pp->statemach_act = ftp_statemach_act;
+  pp->endofresp = ftp_endofresp;
+  pp->conn = conn;
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY)
+  if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
+    /* for FTP over HTTP proxy */
+    struct HTTP http_proxy;
+    struct FTP *ftp_save;
+
+    /* BLOCKING */
+    /* We want "seamless" FTP operations through HTTP proxy tunnel */
+
+    /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
+     * conn->proto.http; we want FTP through HTTP and we have to change the
+     * member temporarily for connecting to the HTTP proxy. After
+     * Curl_proxyCONNECT we have to set back the member to the original struct
+     * FTP pointer
+     */
+    ftp_save = data->state.proto.ftp;
+    memset(&http_proxy, 0, sizeof(http_proxy));
+    data->state.proto.http = &http_proxy;
+
+    result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
+                               conn->host.name, conn->remote_port);
+
+    data->state.proto.ftp = ftp_save;
+
+    if(CURLE_OK != result)
+      return result;
+  }
+#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */
+
+  if(conn->protocol & PROT_FTPS) {
+    /* BLOCKING */
+    /* FTPS is simply ftp with SSL for the control channel */
+    /* now, perform the SSL initialization for this socket */
+    result = Curl_ssl_connect(conn, FIRSTSOCKET);
+    if(result)
+      return result;
+  }
+
+  Curl_pp_init(pp); /* init the generic pingpong data */
+
+  /* When we connect, we start in the state where we await the 220
+     response */
+  state(conn, FTP_WAIT220);
+
+  if(data->state.used_interface == Curl_if_multi)
+    result = ftp_multi_statemach(conn, done);
+  else {
+    result = ftp_easy_statemach(conn);
+    if(!result)
+      *done = TRUE;
+  }
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * 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.
+ */
+static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
+                              bool premature)
+{
+  struct SessionHandle *data = conn->data;
+  struct FTP *ftp = data->state.proto.ftp;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  struct pingpong *pp = &ftpc->pp;
+  ssize_t nread;
+  int ftpcode;
+  CURLcode result=CURLE_OK;
+  bool was_ctl_valid = ftpc->ctl_valid;
+  char *path;
+  const char *path_to_use = data->state.path;
+
+  if(!ftp)
+    /* When the easy handle is removed from the multi while libcurl is still
+     * trying to resolve the host name, it seems that the ftp struct is not
+     * yet initialized, but the removal action calls Curl_done() which calls
+     * this function. So we simply return success if no ftp pointer is set.
+     */
+    return CURLE_OK;
+
+  switch(status) {
+  case CURLE_BAD_DOWNLOAD_RESUME:
+  case CURLE_FTP_WEIRD_PASV_REPLY:
+  case CURLE_FTP_PORT_FAILED:
+  case CURLE_FTP_COULDNT_SET_TYPE:
+  case CURLE_FTP_COULDNT_RETR_FILE:
+  case CURLE_UPLOAD_FAILED:
+  case CURLE_REMOTE_ACCESS_DENIED:
+  case CURLE_FILESIZE_EXCEEDED:
+  case CURLE_REMOTE_FILE_NOT_FOUND:
+  case CURLE_WRITE_ERROR:
+    /* the connection stays alive fine even though this happened */
+    /* fall-through */
+  case CURLE_OK: /* doesn't affect the control connection's status */
+    if(!premature) {
+      ftpc->ctl_valid = was_ctl_valid;
+      break;
+    }
+    /* until we cope better with prematurely ended requests, let them
+     * fallback as if in complete failure */
+  default:       /* by default, an error means the control connection is
+                    wedged and should not be used anymore */
+    ftpc->ctl_valid = FALSE;
+    ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
+                             current path, as this connection is going */
+    conn->bits.close = TRUE; /* marked for closure */
+    result = status;      /* use the already set error code */
+    break;
+  }
+
+  /* now store a copy of the directory we are in */
+  if(ftpc->prevpath)
+    free(ftpc->prevpath);
+
+  /* get the "raw" path */
+  path = curl_easy_unescape(data, path_to_use, 0, NULL);
+  if(!path) {
+    /* out of memory, but we can limp along anyway (and should try to
+     * since we're in the out of memory cleanup path) */
+    ftpc->prevpath = NULL; /* no path */
+  }
+  else {
+    size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
+    size_t dlen = strlen(path)-flen;
+    if(!ftpc->cwdfail) {
+      if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
+        ftpc->prevpath = path;
+        if(flen)
+          /* if 'path' is not the whole string */
+          ftpc->prevpath[dlen]=0; /* terminate */
+      }
+      else {
+        /* we never changed dir */
+        ftpc->prevpath=strdup("");
+        free(path);
+      }
+      if(ftpc->prevpath)
+        infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
+    }
+    else {
+      ftpc->prevpath = NULL; /* no path */
+      free(path);
+    }
+  }
+  /* free the dir tree and file parts */
+  freedirs(ftpc);
+
+#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
+  Curl_sec_fflush_fd(conn, conn->sock[SECONDARYSOCKET]);
+#endif
+
+  /* shut down the socket to inform the server we're done */
+
+#ifdef _WIN32_WCE
+  shutdown(conn->sock[SECONDARYSOCKET],2);  /* SD_BOTH */
+#endif
+
+  if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
+    if(conn->ssl[SECONDARYSOCKET].use) {
+      /* The secondary socket is using SSL so we must close down that part
+         first before we close the socket for real */
+      Curl_ssl_close(conn, SECONDARYSOCKET);
+
+      /* Note that we keep "use" set to TRUE since that (next) connection is
+         still requested to use SSL */
+    }
+    if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
+      sclose(conn->sock[SECONDARYSOCKET]);
+      conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
+    }
+  }
+
+  if((ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
+     pp->pending_resp && !premature) {
+    /*
+     * 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.
+     */
+    long old_time = pp->response_time;
+
+    pp->response_time = 60*1000; /* give it only a minute for now */
+    pp->response = Curl_tvnow(); /* timeout relative now */
+
+    result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+
+    pp->response_time = old_time; /* set this back to previous value */
+
+    if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
+      failf(data, "control connection looks dead");
+      ftpc->ctl_valid = FALSE; /* mark control connection as bad */
+      conn->bits.close = TRUE; /* mark for closure */
+    }
+
+    if(result)
+      return result;
+
+    if(!ftpc->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);
+        result = CURLE_PARTIAL_FILE;
+      }
+    }
+  }
+
+  if(result || premature)
+    /* the response code from the transfer showed an error already so no
+       use checking further */
+    ;
+  else if(data->set.upload) {
+    if((-1 != data->set.infilesize) &&
+       (data->set.infilesize != *ftp->bytecountp) &&
+       !data->set.crlf &&
+       (ftp->transfer == FTPTRANSFER_BODY)) {
+      failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T
+            " out of %" FORMAT_OFF_T " bytes)",
+            *ftp->bytecountp, data->set.infilesize);
+      result = CURLE_PARTIAL_FILE;
+    }
+  }
+  else {
+    if((-1 != data->req.size) &&
+       (data->req.size != *ftp->bytecountp) &&
+#ifdef CURL_DO_LINEEND_CONV
+       /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
+        * we'll check to see if the discrepancy can be explained by the number
+        * of CRLFs we've changed to LFs.
+        */
+       ((data->req.size + data->state.crlf_conversions) !=
+        *ftp->bytecountp) &&
+#endif /* CURL_DO_LINEEND_CONV */
+       (data->req.maxdownload != *ftp->bytecountp)) {
+      failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
+            *ftp->bytecountp);
+      result = CURLE_PARTIAL_FILE;
+    }
+    else if(!ftpc->dont_check &&
+            !*ftp->bytecountp &&
+            (data->req.size>0)) {
+      failf(data, "No data was received!");
+      result = CURLE_FTP_COULDNT_RETR_FILE;
+    }
+  }
+
+  /* clear these for next connection */
+  ftp->transfer = FTPTRANSFER_BODY;
+  ftpc->dont_check = FALSE;
+
+  /* Send any post-transfer QUOTE strings? */
+  if(!status && !result && !premature && 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.
+ *
+ * BLOCKING
+ */
+
+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) {
+      char *cmd = item->data;
+      bool acceptfail = FALSE;
+
+      /* if a command starts with an asterisk, which a legal FTP command never
+         can, the command will be allowed to fail without it causing any
+         aborts or cancels etc. It will cause libcurl to act as if the command
+         is successful, whatever the server reponds. */
+
+      if(cmd[0] == '*') {
+        cmd++;
+        acceptfail = TRUE;
+      }
+
+      FTPSENDF(conn, "%s", cmd);
+
+      result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+      if(result)
+        return result;
+
+      if(!acceptfail && (ftpcode >= 400)) {
+        failf(conn->data, "QUOT string not accepted: %s", cmd);
+        return CURLE_QUOTE_ERROR;
+      }
+    }
+
+    item = item->next;
+  }
+
+  return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * ftp_need_type()
+ *
+ * Returns TRUE if we in the current situation should send TYPE
+ */
+static int ftp_need_type(struct connectdata *conn,
+                         bool ascii_wanted)
+{
+  return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
+}
+
+/***********************************************************************
+ *
+ * ftp_nb_type()
+ *
+ * Set TYPE. We only deal with ASCII or BINARY so this function
+ * sets one of them.
+ * If the transfer type is not sent, simulate on OK response in newstate
+ */
+static CURLcode ftp_nb_type(struct connectdata *conn,
+                            bool ascii, ftpstate newstate)
+{
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  CURLcode result;
+  char want = (char)(ascii?'A':'I');
+
+  if(ftpc->transfertype == want) {
+    state(conn, newstate);
+    return ftp_state_type_resp(conn, 200, newstate);
+  }
+
+  PPSENDF(&ftpc->pp, "TYPE %c", want);
+  state(conn, newstate);
+
+  /* keep track of our current transfer type */
+  ftpc->transfertype = want;
+  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.
+ *
+ */
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+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);
+}
+#endif
+
+/*
+  Check if this is a range download, and if so, set the internal variables
+  properly.
+ */
+
+static CURLcode ftp_range(struct connectdata *conn)
+{
+  curl_off_t from, to;
+  curl_off_t totalsize=-1;
+  char *ptr;
+  char *ptr2;
+  struct SessionHandle *data = conn->data;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  if(data->state.use_range && data->state.range) {
+    from=curlx_strtoofft(data->state.range, &ptr, 0);
+    while(ptr && *ptr && (ISSPACE(*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 - */
+      data->state.resume_from = from;
+      DEBUGF(infof(conn->data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n",
+                   from));
+    }
+    else if(from < 0) {
+      /* -Y */
+      totalsize = -from;
+      data->req.maxdownload = -from;
+      data->state.resume_from = from;
+      DEBUGF(infof(conn->data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n",
+                   totalsize));
+    }
+    else {
+      /* X-Y */
+      totalsize = to-from;
+      data->req.maxdownload = totalsize+1; /* include last byte */
+      data->state.resume_from = from;
+      DEBUGF(infof(conn->data, "FTP RANGE from %" FORMAT_OFF_T
+                   " getting %" FORMAT_OFF_T " bytes\n",
+                   from, data->req.maxdownload));
+    }
+    DEBUGF(infof(conn->data, "range-download from %" FORMAT_OFF_T
+                 " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
+                 from, to, data->req.maxdownload));
+    ftpc->dont_check = TRUE; /* dont check for successful transfer */
+  }
+  else
+    data->req.maxdownload = -1;
+  return CURLE_OK;
+}
+
+
+/*
+ * ftp_nextconnect()
+ *
+ * This function shall be called when the second FTP (data) connection is
+ * connected.
+ */
+
+static CURLcode ftp_nextconnect(struct connectdata *conn)
+{
+  struct SessionHandle *data=conn->data;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  CURLcode result = CURLE_OK;
+
+  /* the ftp struct is inited in ftp_connect() */
+  struct FTP *ftp = data->state.proto.ftp;
+
+  DEBUGF(infof(data, "DO-MORE phase starts\n"));
+
+  if(ftp->transfer <= FTPTRANSFER_INFO) {
+    /* a transfer is about to take place, or if not a file name was given
+       so we'll do a SIZE on it later and then we need the right TYPE first */
+
+    if(data->set.upload) {
+      result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
+      if(result)
+        return result;
+    }
+    else {
+      /* download */
+      ftp->downloadsize = -1; /* unknown as of yet */
+
+      result = ftp_range(conn);
+      if(result)
+        ;
+      else if(data->set.ftp_list_only || !ftpc->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. */
+
+        /* But only if a body transfer was requested. */
+        if(ftp->transfer == FTPTRANSFER_BODY) {
+          result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
+          if(result)
+            return result;
+        }
+        /* otherwise just fall through */
+      }
+      else {
+        result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
+        if(result)
+          return result;
+      }
+    }
+    result = ftp_easy_statemach(conn);
+  }
+
+  if((result == CURLE_OK) && (ftp->transfer != FTPTRANSFER_BODY))
+    /* no data to transfer. FIX: it feels like a kludge to have this here
+       too! */
+    result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+
+  /* end of transfer */
+  DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
+
+  return result;
+}
+
+
+
+/***********************************************************************
+ *
+ * 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,  /* connect status after PASV / PORT */
+                     bool *dophase_done)
+{
+  /* this is FTP and no proxy */
+  CURLcode result=CURLE_OK;
+
+  DEBUGF(infof(conn->data, "DO phase starts\n"));
+
+  if(conn->data->set.opt_no_body) {
+    /* requested no body means no transfer... */
+    struct FTP *ftp = conn->data->state.proto.ftp;
+    ftp->transfer = FTPTRANSFER_INFO;
+  }
+
+
+  *dophase_done = FALSE; /* not done yet */
+
+  /* start the first command in the DO phase */
+  result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
+  if(result)
+    return result;
+
+  /* run the state-machine */
+  if(conn->data->state.used_interface == Curl_if_multi)
+    result = ftp_multi_statemach(conn, dophase_done);
+  else {
+    result = ftp_easy_statemach(conn);
+    *dophase_done = TRUE; /* with the easy interface we are done here */
+  }
+  *connected = conn->bits.tcpconnect;
+
+  if(*dophase_done)
+    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_do()
+ *
+ * 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.
+ */
+static CURLcode ftp_do(struct connectdata *conn, bool *done)
+{
+  CURLcode retcode = CURLE_OK;
+
+  *done = FALSE; /* default to false */
+
+  /*
+    Since connections can be re-used between SessionHandles, this might be a
+    connection already existing but on a fresh SessionHandle struct so we must
+    make sure we have a good 'struct FTP' to play with. For new connections,
+    the struct FTP is allocated and setup in the ftp_connect() function.
+  */
+  Curl_reset_reqproto(conn);
+  retcode = ftp_init(conn);
+  if(retcode)
+    return retcode;
+
+  retcode = ftp_parse_url_path(conn);
+  if(retcode)
+    return retcode;
+
+  retcode = ftp_regular_transfer(conn, done);
+
+  return retcode;
+}
+
+
+CURLcode Curl_ftpsendf(struct connectdata *conn,
+                       const char *fmt, ...)
+{
+  ssize_t bytes_written;
+#define SBUF_SIZE 1024
+  char s[SBUF_SIZE];
+  size_t write_len;
+  char *sptr=s;
+  CURLcode res = CURLE_OK;
+#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
+  enum protection_level data_sec = conn->data_prot;
+#endif
+
+  va_list ap;
+  va_start(ap, fmt);
+  vsnprintf(s, SBUF_SIZE-3, fmt, ap);
+  va_end(ap);
+
+  strcat(s, "\r\n"); /* append a trailing CRLF */
+
+  bytes_written=0;
+  write_len = strlen(s);
+
+#ifdef CURL_DOES_CONVERSIONS
+  res = Curl_convert_to_network(conn->data, s, write_len);
+  /* Curl_convert_to_network calls failf if unsuccessful */
+  if(res != CURLE_OK) {
+    return(res);
+  }
+#endif /* CURL_DOES_CONVERSIONS */
+
+  for(;;) {
+#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
+    conn->data_prot = prot_cmd;
+#endif
+    res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
+                     &bytes_written);
+#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
+    conn->data_prot = data_sec;
+#endif
+
+    if(CURLE_OK != res)
+      break;
+
+    if(conn->data->set.verbose)
+      Curl_debug(conn->data, CURLINFO_HEADER_OUT,
+                 sptr, (size_t)bytes_written, conn);
+
+    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)
+{
+  CURLcode result = CURLE_OK;
+
+  if(conn->proto.ftpc.ctl_valid) {
+    PPSENDF(&conn->proto.ftpc.pp, "QUIT", NULL);
+    state(conn, FTP_QUIT);
+
+    result = ftp_easy_statemach(conn);
+  }
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_disconnect()
+ *
+ * Disconnect from an FTP server. Cleanup protocol-specific per-connection
+ * resources. BLOCKING.
+ */
+static CURLcode ftp_disconnect(struct connectdata *conn)
+{
+  struct ftp_conn *ftpc= &conn->proto.ftpc;
+  struct pingpong *pp = &ftpc->pp;
+
+  /* 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! */
+  (void)ftp_quit(conn); /* ignore errors on the QUIT */
+
+  if(ftpc->entrypath) {
+    struct SessionHandle *data = conn->data;
+    if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
+      data->state.most_recent_ftp_entrypath = NULL;
+    }
+    free(ftpc->entrypath);
+    ftpc->entrypath = NULL;
+  }
+
+  freedirs(ftpc);
+  if(ftpc->prevpath) {
+    free(ftpc->prevpath);
+    ftpc->prevpath = NULL;
+  }
+  if(ftpc->server_os) {
+    free(ftpc->server_os);
+    ftpc->server_os = NULL;
+  }
+
+  Curl_pp_disconnect(pp);
+
+  return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * ftp_parse_url_path()
+ *
+ * Parse the URL path into separate path components.
+ *
+ */
+static
+CURLcode ftp_parse_url_path(struct connectdata *conn)
+{
+  struct SessionHandle *data = conn->data;
+  /* the ftp struct is already inited in ftp_connect() */
+  struct FTP *ftp = data->state.proto.ftp;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  const char *slash_pos;  /* position of the first '/' char in curpos */
+  const char *path_to_use = data->state.path;
+  const char *cur_pos;
+  const char *filename = NULL;
+
+  cur_pos = path_to_use; /* current position in path. point at the begin
+                            of next path component */
+
+  ftpc->ctl_valid = FALSE;
+  ftpc->cwdfail = FALSE;
+
+  switch(data->set.ftp_filemethod) {
+  case FTPFILE_NOCWD:
+    /* fastest, but less standard-compliant */
+
+    /*
+      The best time to check whether the path is a file or directory is right
+      here. so:
+
+      the first condition in the if() right here, is there just in case
+      someone decides to set path to NULL one day
+   */
+    if(data->state.path &&
+       data->state.path[0] &&
+       (data->state.path[strlen(data->state.path) - 1] != '/') )
+      filename = data->state.path;  /* this is a full file path */
+      /*
+        ftpc->file is not used anywhere other than for operations on a file.
+        In other words, never for directory operations.
+        So we can safely leave filename as NULL here and use it as a
+        argument in dir/file decisions.
+      */
+    break;
+
+  case FTPFILE_SINGLECWD:
+    /* get the last slash */
+    if(!path_to_use[0]) {
+      /* no dir, no file */
+      ftpc->dirdepth = 0;
+      break;
+    }
+    slash_pos=strrchr(cur_pos, '/');
+    if(slash_pos || !*cur_pos) {
+      ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
+      if(!ftpc->dirs)
+        return CURLE_OUT_OF_MEMORY;
+
+      ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
+                                         slash_pos?(int)(slash_pos-cur_pos):1,
+                                         NULL);
+      if(!ftpc->dirs[0]) {
+        freedirs(ftpc);
+        return CURLE_OUT_OF_MEMORY;
+      }
+      ftpc->dirdepth = 1; /* we consider it to be a single dir */
+      filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
+    }
+    else
+      filename = cur_pos;  /* this is a file name only */
+    break;
+
+  default: /* allow pretty much anything */
+  case FTPFILE_MULTICWD:
+    ftpc->dirdepth = 0;
+    ftpc->diralloc = 5; /* default dir depth to allocate */
+    ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
+    if(!ftpc->dirs)
+      return CURLE_OUT_OF_MEMORY;
+
+    /* we have a special case for listing the root dir only */
+    if(strequal(path_to_use, "/")) {
+      cur_pos++; /* make it point to the zero byte */
+      ftpc->dirs[0] = strdup("/");
+      ftpc->dirdepth++;
+    }
+    else {
+      /* parse the URL path into separate path components */
+      while((slash_pos = strchr(cur_pos, '/')) != NULL) {
+        /* 1 or 0 to indicate absolute directory */
+        bool absolute_dir = (bool)((cur_pos - data->state.path > 0) &&
+                                   (ftpc->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);
+          ftpc->dirs[ftpc->dirdepth] =
+            curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL);
+          if(!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */
+            failf(data, "no memory");
+            freedirs(ftpc);
+            return CURLE_OUT_OF_MEMORY;
+          }
+          if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {
+            free(ftpc->dirs[ftpc->dirdepth]);
+            freedirs(ftpc);
+            return CURLE_URL_MALFORMAT;
+          }
+        }
+        else {
+          cur_pos = slash_pos + 1; /* jump to the rest of the string */
+          continue;
+        }
+
+        cur_pos = slash_pos + 1; /* jump to the rest of the string */
+        if(++ftpc->dirdepth >= ftpc->diralloc) {
+          /* enlarge array */
+          char *bigger;
+          ftpc->diralloc *= 2; /* double the size each time */
+          bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
+          if(!bigger) {
+            freedirs(ftpc);
+            return CURLE_OUT_OF_MEMORY;
+          }
+          ftpc->dirs = (char **)bigger;
+        }
+      }
+    }
+    filename = cur_pos;  /* the rest is the file name */
+    break;
+  } /* switch */
+
+  if(filename && *filename) {
+    ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL);
+    if(NULL == ftpc->file) {
+      freedirs(ftpc);
+      failf(data, "no memory");
+      return CURLE_OUT_OF_MEMORY;
+    }
+    if(isBadFtpString(ftpc->file)) {
+      freedirs(ftpc);
+      return CURLE_URL_MALFORMAT;
+    }
+  }
+  else
+    ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL
+                       pointer */
+
+  if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
+    /* We need a file name when uploading. Return error! */
+    failf(data, "Uploading to a URL without a file name!");
+    return CURLE_URL_MALFORMAT;
+  }
+
+  ftpc->cwddone = FALSE; /* default to not done */
+
+  if(ftpc->prevpath) {
+    /* prevpath is "raw" so we convert the input path before we compare the
+       strings */
+    int dlen;
+    char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen);
+    if(!path) {
+      freedirs(ftpc);
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    dlen -= ftpc->file?(int)strlen(ftpc->file):0;
+    if((dlen == (int)strlen(ftpc->prevpath)) &&
+       strnequal(path, ftpc->prevpath, dlen)) {
+      infof(data, "Request has same path as previous transfer\n");
+      ftpc->cwddone = TRUE;
+    }
+    free(path);
+  }
+
+  return CURLE_OK;
+}
+
+/* call this when the DO phase has completed */
+static CURLcode ftp_dophase_done(struct connectdata *conn,
+                                 bool connected)
+{
+  CURLcode result = CURLE_OK;
+  struct FTP *ftp = conn->data->state.proto.ftp;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+  if(connected)
+    result = ftp_nextconnect(conn);
+
+  if(result && (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;
+    return result;
+  }
+
+  if(ftp->transfer != FTPTRANSFER_BODY)
+    /* no data to transfer */
+    result=Curl_setup_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;
+
+  ftpc->ctl_valid = TRUE; /* seems good */
+
+  return result;
+}
+
+/* called from multi.c while DOing */
+static CURLcode ftp_doing(struct connectdata *conn,
+                               bool *dophase_done)
+{
+  CURLcode result;
+  result = ftp_multi_statemach(conn, dophase_done);
+
+  if(*dophase_done) {
+    result = ftp_dophase_done(conn, FALSE /* not connected */);
+
+    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+  }
+  return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_regular_transfer()
+ *
+ * The input argument is already checked for validity.
+ *
+ * Performs all commands done before a regular transfer between a local and a
+ * remote host.
+ *
+ * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
+ * ftp_done() function without finding any major problem.
+ */
+static
+CURLcode ftp_regular_transfer(struct connectdata *conn,
+                              bool *dophase_done)
+{
+  CURLcode result=CURLE_OK;
+  bool connected=FALSE;
+  struct SessionHandle *data = conn->data;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
+  data->req.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);
+
+  ftpc->ctl_valid = TRUE; /* starts good */
+
+  result = ftp_perform(conn,
+                       &connected, /* have we connected after PASV/PORT */
+                       dophase_done); /* all commands in the DO-phase done? */
+
+  if(CURLE_OK == result) {
+
+    if(!*dophase_done)
+      /* the DO phase has not completed yet */
+      return CURLE_OK;
+
+    result = ftp_dophase_done(conn, connected);
+    if(result)
+      return result;
+  }
+  else
+    freedirs(ftpc);
+
+  return result;
+}
+
+static CURLcode ftp_setup_connection(struct connectdata * conn)
+{
+  struct SessionHandle *data = conn->data;
+  char * type;
+  char command;
+
+  if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
+    /* Unless we have asked to tunnel ftp operations through the proxy, we
+       switch and use HTTP operations only */
+#ifndef CURL_DISABLE_HTTP
+    if(conn->handler == &Curl_handler_ftp)
+      conn->handler = &Curl_handler_ftp_proxy;
+    else {
+#ifdef USE_SSL
+      conn->handler = &Curl_handler_ftps_proxy;
+#else
+      failf(data, "FTPS not supported!");
+      return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+    }
+    /*
+     * We explicitly mark this connection as persistent here as we're doing
+     * FTP over HTTP and thus we accidentally avoid setting this value
+     * otherwise.
+     */
+    conn->bits.close = FALSE;
+#else
+    failf(data, "FTP over http proxy requires HTTP support built-in!");
+    return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+  }
+
+  data->state.path++;   /* don't include the initial slash */
+
+  /* FTP URLs support an extension like ";type=<typecode>" that
+   * we'll try to get now! */
+  type = strstr(data->state.path, ";type=");
+
+  if(!type)
+    type = strstr(conn->host.rawalloc, ";type=");
+
+  if(type) {
+    *type = 0;                     /* it was in the middle of the hostname */
+    command = Curl_raw_toupper(type[6]);
+
+    switch (command) {
+    case 'A': /* ASCII mode */
+      data->set.prefer_ascii = TRUE;
+      break;
+
+    case 'D': /* directory mode */
+      data->set.ftp_list_only = TRUE;
+      break;
+
+    case 'I': /* binary mode */
+    default:
+      /* switch off ASCII */
+      data->set.prefer_ascii = FALSE;
+      break;
+    }
+  }
+
+  return CURLE_OK;
+}
+
+#endif /* CURL_DISABLE_FTP */
diff --git a/lib/ftp.h b/lib/ftp.h
new file mode 100644
index 0000000..7a4f89e
--- /dev/null
+++ b/lib/ftp.h
@@ -0,0 +1,140 @@
+#ifndef HEADER_CURL_FTP_H
+#define HEADER_CURL_FTP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 "pingpong.h"
+
+#ifndef CURL_DISABLE_FTP
+extern const struct Curl_handler Curl_handler_ftp;
+
+#ifdef USE_SSL
+extern const struct Curl_handler Curl_handler_ftps;
+#endif
+
+CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...);
+CURLcode Curl_GetFTPResponse(ssize_t *nread, struct connectdata *conn,
+                             int *ftpcode);
+#endif /* CURL_DISABLE_FTP */
+
+/****************************************************************************
+ * FTP unique setup
+ ***************************************************************************/
+typedef enum {
+  FTP_STOP,    /* do nothing state, stops the state machine */
+  FTP_WAIT220, /* waiting for the initial 220 response immediately after
+                  a connect */
+  FTP_AUTH,
+  FTP_USER,
+  FTP_PASS,
+  FTP_ACCT,
+  FTP_PBSZ,
+  FTP_PROT,
+  FTP_CCC,
+  FTP_PWD,
+  FTP_SYST,
+  FTP_NAMEFMT,
+  FTP_QUOTE, /* waiting for a response to a command sent in a quote list */
+  FTP_RETR_PREQUOTE,
+  FTP_STOR_PREQUOTE,
+  FTP_POSTQUOTE,
+  FTP_CWD,  /* change dir */
+  FTP_MKD,  /* if the dir didn't exist */
+  FTP_MDTM, /* to figure out the datestamp */
+  FTP_TYPE, /* to set type when doing a head-like request */
+  FTP_LIST_TYPE, /* set type when about to do a dir list */
+  FTP_RETR_TYPE, /* set type when about to RETR a file */
+  FTP_STOR_TYPE, /* set type when about to STOR a file */
+  FTP_SIZE, /* get the remote file's size for head-like request */
+  FTP_RETR_SIZE, /* get the remote file's size for RETR */
+  FTP_STOR_SIZE, /* get the size for (resumed) STOR */
+  FTP_REST, /* when used to check if the server supports it in head-like */
+  FTP_RETR_REST, /* when asking for "resume" in for RETR */
+  FTP_PORT, /* generic state for PORT, LPRT and EPRT, check count1 */
+  FTP_PRET, /* generic state for PRET RETR, PRET STOR and PRET LIST/NLST */
+  FTP_PASV, /* generic state for PASV and EPSV, check count1 */
+  FTP_LIST, /* generic state for LIST, NLST or a custom list command */
+  FTP_RETR,
+  FTP_STOR, /* generic state for STOR and APPE */
+  FTP_QUIT,
+  FTP_LAST  /* never used */
+} ftpstate;
+
+typedef enum {
+  FTPFILE_MULTICWD  = 1, /* as defined by RFC1738 */
+  FTPFILE_NOCWD     = 2, /* use SIZE / RETR / STOR on the full path */
+  FTPFILE_SINGLECWD = 3  /* make one CWD, then SIZE / RETR / STOR on the file */
+} curl_ftpfile;
+
+typedef enum {
+  FTPTRANSFER_BODY, /* yes do transfer a body */
+  FTPTRANSFER_INFO, /* do still go through to get info/headers */
+  FTPTRANSFER_NONE, /* don't get anything and don't get info */
+  FTPTRANSFER_LAST  /* end of list marker, never used */
+} curl_ftptransfer;
+
+/* This FTP struct is used in the SessionHandle. All FTP data that is
+   connection-oriented must be in FTP_conn to properly deal with the fact that
+   perhaps the SessionHandle is changed between the times the connection is
+   used. */
+struct FTP {
+  curl_off_t *bytecountp;
+  char *user;    /* user name string */
+  char *passwd;  /* password string */
+
+  /* transfer a file/body or not, done as a typedefed enum just to make
+     debuggers display the full symbol and not just the numerical value */
+  curl_ftptransfer transfer;
+  curl_off_t downloadsize;
+};
+
+
+/* ftp_conn is used for struct connection-oriented data in the connectdata
+   struct */
+struct ftp_conn {
+  struct pingpong pp;
+  char *entrypath; /* the PWD reply when we logged on */
+  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 */
+  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 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() */
+  bool cwddone;     /* if it has been determined that the proper CWD combo
+                       already has been done */
+  bool cwdfail;     /* set TRUE if a CWD command fails, as then we must prevent
+                       caching the current directory */
+  char *prevpath;   /* conn->path from the previous transfer */
+  char transfertype; /* set by ftp_transfertype for use by Curl_client_write()a
+                        and others (A/I or zero) */
+  int count1; /* general purpose counter for the state machine */
+  int count2; /* general purpose counter for the state machine */
+  int count3; /* general purpose counter for the state machine */
+  ftpstate state; /* always use ftp.c:state() to change state! */
+  char * server_os;     /* The target server operating system. */
+};
+
+#endif /* HEADER_CURL_FTP_H */
diff --git a/lib/getenv.c b/lib/getenv.c
new file mode 100644
index 0000000..36fbb75
--- /dev/null
+++ b/lib/getenv.c
@@ -0,0 +1,65 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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_WCE
+  return NULL;
+#else
+#ifdef WIN32
+  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));
+  return (env[0] != '\0')?strdup(env):NULL;
+#else
+  char *env = getenv(variable);
+#ifdef __VMS
+  if(env && strcmp("HOME",variable) == 0)
+    env = decc_translate_vms(env);
+#endif
+  return (env && env[0])?strdup(env):NULL;
+#endif
+#endif
+}
+
+char *curl_getenv(const char *v)
+{
+  return GetEnv(v);
+}
diff --git a/lib/getinfo.c b/lib/getinfo.c
new file mode 100644
index 0000000..7a0ed71
--- /dev/null
+++ b/lib/getinfo.c
@@ -0,0 +1,254 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 "urldata.h"
+#include "getinfo.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include "curl_memory.h"
+#include "sslgen.h"
+#include "connect.h" /* Curl_getconnectinfo() */
+#include "progress.h"
+
+/* Make this the last #include */
+#include "memdebug.h"
+
+/*
+ * This is supposed to be called in the beginning of a perform() 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;
+  info->numconnects = 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;
+  struct curl_slist **param_slistp=NULL;
+  int type;
+
+  union {
+    struct curl_certinfo * to_certinfo;
+    struct curl_slist    * to_slist;
+  } ptr;
+
+  if(!data)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  va_start(arg, info);
+
+  type = CURLINFO_TYPEMASK & (int)info;
+  switch(type) {
+  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;
+  case CURLINFO_SLIST:
+    param_slistp = va_arg(arg, struct curl_slist **);
+    if(NULL == param_slistp)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    break;
+  default:
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+
+  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_APPCONNECT_TIME:
+    *param_doublep = data->progress.t_appconnect;
+    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 = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
+      (double)data->progress.size_dl:-1;
+    break;
+  case CURLINFO_CONTENT_LENGTH_UPLOAD:
+    *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
+      (double)data->progress.size_ul:-1;
+    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 = (char *) data->set.private_data;
+    break;
+  case CURLINFO_HTTPAUTH_AVAIL:
+    *param_longp = data->info.httpauthavail;
+    break;
+  case CURLINFO_PROXYAUTH_AVAIL:
+    *param_longp = data->info.proxyauthavail;
+    break;
+  case CURLINFO_OS_ERRNO:
+    *param_longp = data->state.os_errno;
+    break;
+  case CURLINFO_NUM_CONNECTS:
+    *param_longp = data->info.numconnects;
+    break;
+  case CURLINFO_SSL_ENGINES:
+    *param_slistp = Curl_ssl_engines_list(data);
+    break;
+  case CURLINFO_COOKIELIST:
+    *param_slistp = Curl_cookie_list(data);
+    break;
+  case CURLINFO_FTP_ENTRY_PATH:
+    /* Return the entrypath string from the most recent connection.
+       This pointer was copied from the connectdata structure by FTP.
+       The actual string may be free()ed by subsequent libcurl calls so
+       it must be copied to a safer area before the next libcurl call.
+       Callers must never free it themselves. */
+    *param_charp = data->state.most_recent_ftp_entrypath;
+    break;
+  case CURLINFO_LASTSOCKET:
+    (void)Curl_getconnectinfo(data, param_longp, NULL);
+    break;
+  case CURLINFO_REDIRECT_URL:
+    /* Return the URL this request would have been redirected to if that
+       option had been enabled! */
+    *param_charp = data->info.wouldredirect;
+    break;
+  case CURLINFO_PRIMARY_IP:
+    /* Return the ip address of the most recent (primary) connection */
+    *param_charp = data->info.ip;
+    break;
+  case CURLINFO_CERTINFO:
+    /* Return the a pointer to the certinfo struct. Not really an slist
+       pointer but we can pretend it is here */
+    ptr.to_certinfo = &data->info.certs;
+    *param_slistp = ptr.to_slist;
+    break;
+  case CURLINFO_CONDITION_UNMET:
+    /* return if the condition prevented the document to get transfered */
+    *param_longp = data->info.timecond;
+    break;
+  case CURLINFO_RTSP_SESSION_ID:
+    *param_charp = data->set.str[STRING_RTSP_SESSION_ID];
+    break;
+  case CURLINFO_RTSP_CLIENT_CSEQ:
+    *param_longp = data->state.rtsp_next_client_CSeq;
+    break;
+  case CURLINFO_RTSP_SERVER_CSEQ:
+    *param_longp = data->state.rtsp_next_server_CSeq;
+    break;
+  case CURLINFO_RTSP_CSEQ_RECV:
+    *param_longp = data->state.rtsp_CSeq_recv;
+    break;
+
+  default:
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+  return CURLE_OK;
+}
diff --git a/lib/getinfo.h b/lib/getinfo.h
new file mode 100644
index 0000000..3879ff7
--- /dev/null
+++ b/lib/getinfo.h
@@ -0,0 +1,27 @@
+#ifndef HEADER_CURL_GETINFO_H
+#define HEADER_CURL_GETINFO_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...);
+CURLcode Curl_initinfo(struct SessionHandle *data);
+
+#endif /* HEADER_CURL_GETINFO_H */
diff --git a/lib/gtls.c b/lib/gtls.c
new file mode 100644
index 0000000..b7fa3c9
--- /dev/null
+++ b/lib/gtls.c
@@ -0,0 +1,829 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code
+ * but sslgen.c should ever call or use these functions.
+ *
+ * Note: don't use the GnuTLS' *_t variable type names in this source code,
+ * since they were not present in 1.0.X.
+ */
+
+#include "setup.h"
+#ifdef USE_GNUTLS
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#include <gcrypt.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "inet_pton.h"
+#include "gtls.h"
+#include "sslgen.h"
+#include "parsedate.h"
+#include "connect.h" /* for the connect timeout */
+#include "select.h"
+#include "rawstr.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ Some hackish cast macros based on:
+ http://library.gnome.org/devel/glib/unstable/glib-Type-Conversion-Macros.html
+*/
+#ifndef GNUTLS_POINTER_TO_INT_CAST
+#define GNUTLS_POINTER_TO_INT_CAST(p) ((int) (long) (p))
+#endif
+#ifndef GNUTLS_INT_TO_POINTER_CAST
+#define GNUTLS_INT_TO_POINTER_CAST(i) ((void*) (long) (i))
+#endif
+
+/* Enable GnuTLS debugging by defining GTLSDEBUG */
+/*#define GTLSDEBUG */
+
+#ifdef GTLSDEBUG
+static void tls_log_func(int level, const char *str)
+{
+    fprintf(stderr, "|<%d>| %s", level, str);
+}
+#endif
+static bool gtls_inited = FALSE;
+/*
+ * Custom push and pull callback functions used by GNU TLS to read and write
+ * to the socket.  These functions are simple wrappers to send() and recv()
+ * (although here using the sread/swrite macros as defined by setup_once.h).
+ * We use custom functions rather than the GNU TLS defaults because it allows
+ * us to get specific about the fourth "flags" argument, and to use arbitrary
+ * private data with gnutls_transport_set_ptr if we wish.
+ */
+static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
+{
+  return swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
+}
+
+static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
+{
+  return sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
+}
+
+/* Curl_gtls_init()
+ *
+ * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that
+ * are not thread-safe and thus this function itself is not thread-safe and
+ * must only be called from within curl_global_init() to keep the thread
+ * situation under control!
+ */
+int Curl_gtls_init(void)
+{
+  int ret = 1;
+  if(!gtls_inited) {
+    ret = gnutls_global_init()?0:1;
+#ifdef GTLSDEBUG
+    gnutls_global_set_log_function(tls_log_func);
+    gnutls_global_set_log_level(2);
+#endif
+    gtls_inited = TRUE;
+  }
+  return ret;
+}
+
+int Curl_gtls_cleanup(void)
+{
+  if(gtls_inited) {
+    gnutls_global_deinit();
+    gtls_inited = FALSE;
+  }
+  return 1;
+}
+
+static void showtime(struct SessionHandle *data,
+                     const char *text,
+                     time_t stamp)
+{
+  struct tm *tm;
+#ifdef HAVE_GMTIME_R
+  struct tm buffer;
+  tm = (struct tm *)gmtime_r(&stamp, &buffer);
+#else
+  tm = gmtime(&stamp);
+#endif
+  snprintf(data->state.buffer,
+           BUFSIZE,
+           "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT\n",
+           text,
+           Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+           tm->tm_mday,
+           Curl_month[tm->tm_mon],
+           tm->tm_year + 1900,
+           tm->tm_hour,
+           tm->tm_min,
+           tm->tm_sec);
+  infof(data, "%s", data->state.buffer);
+}
+
+static gnutls_datum load_file (const char *file)
+{
+  FILE *f;
+  gnutls_datum loaded_file = { NULL, 0 };
+  long filelen;
+  void *ptr;
+
+  if (!(f = fopen(file, "r")))
+    return loaded_file;
+  if (fseek(f, 0, SEEK_END) != 0
+      || (filelen = ftell(f)) < 0
+      || fseek(f, 0, SEEK_SET) != 0
+      || !(ptr = malloc((size_t)filelen)))
+    goto out;
+  if (fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) {
+    free(ptr);
+    goto out;
+  }
+
+  loaded_file.data = ptr;
+  loaded_file.size = (unsigned int)filelen;
+out:
+  fclose(f);
+  return loaded_file;
+}
+
+static void unload_file(gnutls_datum data) {
+  free(data.data);
+}
+
+
+/* this function does a BLOCKING SSL/TLS (re-)handshake */
+static CURLcode handshake(struct connectdata *conn,
+                          gnutls_session session,
+                          int sockindex,
+                          bool duringconnect)
+{
+  struct SessionHandle *data = conn->data;
+  int rc;
+  if(!gtls_inited)
+    Curl_gtls_init();
+  do {
+    rc = gnutls_handshake(session);
+
+    if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
+      long timeout_ms = Curl_timeleft(conn, NULL, duringconnect);
+
+      if(timeout_ms < 0) {
+        /* a precaution, no need to continue if time already is up */
+        failf(data, "SSL connection timeout");
+        return CURLE_OPERATION_TIMEDOUT;
+      }
+
+      rc = Curl_socket_ready(conn->sock[sockindex],
+                       conn->sock[sockindex], (int)timeout_ms);
+      if(rc > 0)
+        /* reabable or writable, go loop*/
+        continue;
+      else if(0 == rc) {
+        /* timeout */
+        failf(data, "SSL connection timeout");
+        return CURLE_OPERATION_TIMEDOUT;
+      }
+      else {
+        /* anything that gets here is fatally bad */
+        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+    }
+    else
+      break;
+  } while(1);
+
+  if(rc < 0) {
+    failf(data, "gnutls_handshake() failed: %s", gnutls_strerror(rc));
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  return CURLE_OK;
+}
+
+static gnutls_x509_crt_fmt do_file_type(const char *type)
+{
+  if(!type || !type[0])
+    return GNUTLS_X509_FMT_PEM;
+  if(Curl_raw_equal(type, "PEM"))
+    return GNUTLS_X509_FMT_PEM;
+  if(Curl_raw_equal(type, "DER"))
+    return GNUTLS_X509_FMT_DER;
+  return -1;
+}
+
+
+/*
+ * This function is called after the TCP connect has completed. Setup the TLS
+ * layer and do all necessary magic.
+ */
+CURLcode
+Curl_gtls_connect(struct connectdata *conn,
+                  int sockindex)
+
+{
+  static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
+  struct SessionHandle *data = conn->data;
+  gnutls_session session;
+  int rc;
+  unsigned int cert_list_size;
+  const gnutls_datum *chainp;
+  unsigned int verify_status;
+  gnutls_x509_crt x509_cert,x509_issuer;
+  gnutls_datum issuerp;
+  char certbuf[256]; /* big enough? */
+  size_t size;
+  unsigned int algo;
+  unsigned int bits;
+  time_t certclock;
+  const char *ptr;
+  void *ssl_sessionid;
+  size_t ssl_idsize;
+  bool sni = TRUE; /* default is SNI enabled */
+#ifdef ENABLE_IPV6
+  struct in6_addr addr;
+#else
+  struct in_addr addr;
+#endif
+
+  if(conn->ssl[sockindex].state == ssl_connection_complete)
+    /* to make us tolerant against being called more than once for the
+       same connection */
+    return CURLE_OK;
+
+  if(!gtls_inited)
+    Curl_gtls_init();
+
+  /* GnuTLS only supports SSLv3 and TLSv1 */
+  if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) {
+    failf(data, "GnuTLS does not support SSLv2");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+  else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3)
+    sni = FALSE; /* SSLv3 has no SNI */
+
+  /* allocate a cred struct */
+  rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred);
+  if(rc != GNUTLS_E_SUCCESS) {
+    failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  if(data->set.ssl.CAfile) {
+    /* set the trusted CA cert bundle file */
+    gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred,
+                                        GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
+
+    rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred,
+                                                data->set.ssl.CAfile,
+                                                GNUTLS_X509_FMT_PEM);
+    if(rc < 0) {
+      infof(data, "error reading ca cert file %s (%s)\n",
+            data->set.ssl.CAfile, gnutls_strerror(rc));
+      if(data->set.ssl.verifypeer)
+        return CURLE_SSL_CACERT_BADFILE;
+    }
+    else
+      infof(data, "found %d certificates in %s\n",
+            rc, data->set.ssl.CAfile);
+  }
+
+  if(data->set.ssl.CRLfile) {
+    /* set the CRL list file */
+    rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred,
+                                              data->set.ssl.CRLfile,
+                                              GNUTLS_X509_FMT_PEM);
+    if(rc < 0) {
+      failf(data, "error reading crl file %s (%s)\n",
+            data->set.ssl.CRLfile, gnutls_strerror(rc));
+      return CURLE_SSL_CRL_BADFILE;
+    }
+    else
+      infof(data, "found %d CRL in %s\n",
+            rc, data->set.ssl.CRLfile);
+  }
+
+  /* Initialize TLS session as a client */
+  rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT);
+  if(rc != GNUTLS_E_SUCCESS) {
+    failf(data, "gnutls_init() failed: %d", rc);
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  /* convenient assign */
+  session = conn->ssl[sockindex].session;
+
+  if ((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) &&
+#ifdef ENABLE_IPV6
+      (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) &&
+#endif
+      sni &&
+      (gnutls_server_name_set(session, GNUTLS_NAME_DNS, conn->host.name,
+                              strlen(conn->host.name)) < 0))
+    infof(data, "WARNING: failed to configure server name indication (SNI) "
+          "TLS extension\n");
+
+  /* Use default priorities */
+  rc = gnutls_set_default_priority(session);
+  if(rc != GNUTLS_E_SUCCESS)
+    return CURLE_SSL_CONNECT_ERROR;
+
+  if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) {
+    static const int protocol_priority[] = { GNUTLS_SSL3, 0 };
+    gnutls_protocol_set_priority(session, protocol_priority);
+    if(rc != GNUTLS_E_SUCCESS)
+      return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  /* Sets the priority on the certificate types supported by gnutls. Priority
+     is higher for types specified before others. After specifying the types
+     you want, you must append a 0. */
+  rc = gnutls_certificate_type_set_priority(session, cert_type_priority);
+  if(rc != GNUTLS_E_SUCCESS)
+    return CURLE_SSL_CONNECT_ERROR;
+
+  if(data->set.str[STRING_CERT]) {
+    if( gnutls_certificate_set_x509_key_file(
+          conn->ssl[sockindex].cred,
+          data->set.str[STRING_CERT],
+          data->set.str[STRING_KEY] ?
+          data->set.str[STRING_KEY] : data->set.str[STRING_CERT],
+          do_file_type(data->set.str[STRING_CERT_TYPE]) ) != GNUTLS_E_SUCCESS) {
+      failf(data, "error reading X.509 key or certificate file");
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+  }
+
+  /* put the credentials to the current session */
+  rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
+                              conn->ssl[sockindex].cred);
+
+  /* set the connection handle (file descriptor for the socket) */
+  gnutls_transport_set_ptr(session,
+                           GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex]));
+
+  /* register callback functions to send and receive data. */
+  gnutls_transport_set_push_function(session, Curl_gtls_push);
+  gnutls_transport_set_pull_function(session, Curl_gtls_pull);
+
+  /* lowat must be set to zero when using custom push and pull functions. */
+  gnutls_transport_set_lowat(session, 0);
+
+  /* This might be a reconnect, so we check for a session ID in the cache
+     to speed up things */
+
+  if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) {
+    /* we got a session id, use it! */
+    gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
+
+    /* Informational message */
+    infof (data, "SSL re-using session ID\n");
+  }
+
+  rc = handshake(conn, session, sockindex, TRUE);
+  if(rc)
+    /* handshake() sets its own error message with failf() */
+    return rc;
+
+  /* This function will return the peer's raw certificate (chain) as sent by
+     the peer. These certificates are in raw format (DER encoded for
+     X.509). In case of a X.509 then a certificate list may be present. The
+     first certificate in the list is the peer's certificate, following the
+     issuer's certificate, then the issuer's issuer etc. */
+
+  chainp = gnutls_certificate_get_peers(session, &cert_list_size);
+  if(!chainp) {
+    if(data->set.ssl.verifypeer ||
+       data->set.ssl.verifyhost ||
+       data->set.ssl.issuercert) {
+      failf(data, "failed to get server cert");
+      return CURLE_PEER_FAILED_VERIFICATION;
+    }
+    infof(data, "\t common name: WARNING couldn't obtain\n");
+  }
+
+  if(data->set.ssl.verifypeer) {
+    /* This function will try to verify the peer's certificate and return its
+       status (trusted, invalid etc.). The value of status should be one or
+       more of the gnutls_certificate_status_t enumerated elements bitwise
+       or'd. To avoid denial of service attacks some default upper limits
+       regarding the certificate key size and chain size are set. To override
+       them use gnutls_certificate_set_verify_limits(). */
+
+    rc = gnutls_certificate_verify_peers2(session, &verify_status);
+    if(rc < 0) {
+      failf(data, "server cert verify failed: %d", rc);
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+
+    /* verify_status is a bitmask of gnutls_certificate_status bits */
+    if(verify_status & GNUTLS_CERT_INVALID) {
+      if(data->set.ssl.verifypeer) {
+        failf(data, "server certificate verification failed. CAfile: %s "
+              "CRLfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none",
+              data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none");
+        return CURLE_SSL_CACERT;
+      }
+      else
+        infof(data, "\t server certificate verification FAILED\n");
+    }
+    else
+      infof(data, "\t server certificate verification OK\n");
+  }
+  else
+    infof(data, "\t server certificate verification SKIPPED\n");
+
+  /* initialize an X.509 certificate structure. */
+  gnutls_x509_crt_init(&x509_cert);
+
+  /* convert the given DER or PEM encoded Certificate to the native
+     gnutls_x509_crt_t format */
+  gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
+
+  if (data->set.ssl.issuercert) {
+    gnutls_x509_crt_init(&x509_issuer);
+    issuerp = load_file(data->set.ssl.issuercert);
+    gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
+    rc = gnutls_x509_crt_check_issuer(x509_cert,x509_issuer);
+    unload_file(issuerp);
+    if (rc <= 0) {
+      failf(data, "server certificate issuer check failed (IssuerCert: %s)",
+            data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
+      return CURLE_SSL_ISSUER_ERROR;
+    }
+    infof(data,"\t server certificate issuer check OK (Issuer Cert: %s)\n",
+          data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
+  }
+
+  size=sizeof(certbuf);
+  rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME,
+                                     0, /* the first and only one */
+                                     FALSE,
+                                     certbuf,
+                                     &size);
+  if(rc) {
+    infof(data, "error fetching CN from cert:%s\n",
+          gnutls_strerror(rc));
+  }
+
+  /* This function will check if the given certificate's subject matches the
+     given hostname. This is a basic implementation of the matching described
+     in RFC2818 (HTTPS), which takes into account wildcards, and the subject
+     alternative name PKIX extension. Returns non zero on success, and zero on
+     failure. */
+  rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name);
+
+  if(!rc) {
+    if(data->set.ssl.verifyhost > 1) {
+      failf(data, "SSL: certificate subject name (%s) does not match "
+            "target host name '%s'", certbuf, conn->host.dispname);
+      gnutls_x509_crt_deinit(x509_cert);
+      return CURLE_PEER_FAILED_VERIFICATION;
+    }
+    else
+      infof(data, "\t common name: %s (does not match '%s')\n",
+            certbuf, conn->host.dispname);
+  }
+  else
+    infof(data, "\t common name: %s (matched)\n", certbuf);
+
+  /* Check for time-based validity */
+  certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
+
+  if(certclock == (time_t)-1) {
+    failf(data, "server cert expiration date verify failed");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  if(certclock < time(NULL)) {
+    if(data->set.ssl.verifypeer) {
+      failf(data, "server certificate expiration date has passed.");
+      return CURLE_PEER_FAILED_VERIFICATION;
+    }
+    else
+      infof(data, "\t server certificate expiration date FAILED\n");
+  }
+  else
+    infof(data, "\t server certificate expiration date OK\n");
+
+  certclock = gnutls_x509_crt_get_activation_time(x509_cert);
+
+  if(certclock == (time_t)-1) {
+    failf(data, "server cert activation date verify failed");
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  if(certclock > time(NULL)) {
+    if(data->set.ssl.verifypeer) {
+      failf(data, "server certificate not activated yet.");
+      return CURLE_PEER_FAILED_VERIFICATION;
+    }
+    else
+      infof(data, "\t server certificate activation date FAILED\n");
+  }
+  else
+    infof(data, "\t server certificate activation date OK\n");
+
+  /* Show:
+
+  - ciphers used
+  - subject
+  - start date
+  - expire date
+  - common name
+  - issuer
+
+  */
+
+  /* public key algorithm's parameters */
+  algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
+  infof(data, "\t certificate public key: %s\n",
+        gnutls_pk_algorithm_get_name(algo));
+
+  /* version of the X.509 certificate. */
+  infof(data, "\t certificate version: #%d\n",
+        gnutls_x509_crt_get_version(x509_cert));
+
+
+  size = sizeof(certbuf);
+  gnutls_x509_crt_get_dn(x509_cert, certbuf, &size);
+  infof(data, "\t subject: %s\n", certbuf);
+
+  certclock = gnutls_x509_crt_get_activation_time(x509_cert);
+  showtime(data, "start date", certclock);
+
+  certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
+  showtime(data, "expire date", certclock);
+
+  size = sizeof(certbuf);
+  gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size);
+  infof(data, "\t issuer: %s\n", certbuf);
+
+  gnutls_x509_crt_deinit(x509_cert);
+
+  /* compression algorithm (if any) */
+  ptr = gnutls_compression_get_name(gnutls_compression_get(session));
+  /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */
+  infof(data, "\t compression: %s\n", ptr);
+
+  /* the name of the cipher used. ie 3DES. */
+  ptr = gnutls_cipher_get_name(gnutls_cipher_get(session));
+  infof(data, "\t cipher: %s\n", ptr);
+
+  /* the MAC algorithms name. ie SHA1 */
+  ptr = gnutls_mac_get_name(gnutls_mac_get(session));
+  infof(data, "\t MAC: %s\n", ptr);
+
+  conn->ssl[sockindex].state = ssl_connection_complete;
+
+  {
+    /* we always unconditionally get the session id here, as even if we
+       already got it from the cache and asked to use it in the connection, it
+       might've been rejected and then a new one is in use now and we need to
+       detect that. */
+    void *connect_sessionid;
+    size_t connect_idsize;
+
+    /* get the session ID data size */
+    gnutls_session_get_data(session, NULL, &connect_idsize);
+    connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
+
+    if(connect_sessionid) {
+      /* extract session ID to the allocated buffer */
+      gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
+
+      if(ssl_sessionid)
+        /* there was one before in the cache, so instead of risking that the
+           previous one was rejected, we just kill that and store the new */
+        Curl_ssl_delsessionid(conn, ssl_sessionid);
+
+      /* store this session id */
+      return Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize);
+    }
+
+  }
+
+  return CURLE_OK;
+}
+
+
+/* for documentation see Curl_ssl_send() in sslgen.h */
+ssize_t Curl_gtls_send(struct connectdata *conn,
+                       int sockindex,
+                       const void *mem,
+                       size_t len,
+                       int *curlcode)
+{
+  ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len);
+
+  if(rc < 0 ) {
+    *curlcode = (rc == GNUTLS_E_AGAIN)
+      ? /* EWOULDBLOCK */ -1
+      : CURLE_SEND_ERROR;
+
+    rc = -1;
+  }
+
+  return rc;
+}
+
+void Curl_gtls_close_all(struct SessionHandle *data)
+{
+  /* FIX: make the OpenSSL code more generic and use parts of it here */
+  (void)data;
+}
+
+static void close_one(struct connectdata *conn,
+                      int idx)
+{
+  if(conn->ssl[idx].session) {
+    gnutls_bye(conn->ssl[idx].session, GNUTLS_SHUT_RDWR);
+    gnutls_deinit(conn->ssl[idx].session);
+    conn->ssl[idx].session = NULL;
+  }
+  if(conn->ssl[idx].cred) {
+    gnutls_certificate_free_credentials(conn->ssl[idx].cred);
+    conn->ssl[idx].cred = NULL;
+  }
+}
+
+void Curl_gtls_close(struct connectdata *conn, int sockindex)
+{
+  close_one(conn, sockindex);
+}
+
+/*
+ * This function is called to shut down the SSL layer but keep the
+ * socket open (CCC - Clear Command Channel)
+ */
+int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
+{
+  ssize_t result;
+  int retval = 0;
+  struct SessionHandle *data = conn->data;
+  int done = 0;
+  char buf[120];
+
+  /* This has only been tested on the proftpd server, and the mod_tls code
+     sends a close notify alert without waiting for a close notify alert in
+     response. Thus we wait for a close notify alert from the server, but
+     we do not send one. Let's hope other servers do the same... */
+
+  if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
+      gnutls_bye(conn->ssl[sockindex].session, GNUTLS_SHUT_WR);
+
+  if(conn->ssl[sockindex].session) {
+    while(!done) {
+      int what = Curl_socket_ready(conn->sock[sockindex],
+                             CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
+      if(what > 0) {
+        /* Something to read, let's do it and hope that it is the close
+           notify alert from the server */
+        result = gnutls_record_recv(conn->ssl[sockindex].session,
+                                    buf, sizeof(buf));
+        switch(result) {
+        case 0:
+          /* This is the expected response. There was no data but only
+             the close notify alert */
+          done = 1;
+          break;
+        case GNUTLS_E_AGAIN:
+        case GNUTLS_E_INTERRUPTED:
+          infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n");
+          break;
+        default:
+          retval = -1;
+          done = 1;
+          break;
+        }
+      }
+      else if(0 == what) {
+        /* timeout */
+        failf(data, "SSL shutdown timeout");
+        done = 1;
+        break;
+      }
+      else {
+        /* anything that gets here is fatally bad */
+        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+        retval = -1;
+        done = 1;
+      }
+    }
+    gnutls_deinit(conn->ssl[sockindex].session);
+  }
+  gnutls_certificate_free_credentials(conn->ssl[sockindex].cred);
+
+  conn->ssl[sockindex].cred = NULL;
+  conn->ssl[sockindex].session = NULL;
+
+  return retval;
+}
+
+/* for documentation see Curl_ssl_recv() in sslgen.h */
+ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */
+                       int num,                  /* socketindex */
+                       char *buf,                /* store read data here */
+                       size_t buffersize,        /* max amount to read */
+                       int *curlcode)
+{
+  ssize_t ret;
+
+  ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize);
+  if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
+    *curlcode = -1;
+    return -1;
+  }
+
+  if(ret == GNUTLS_E_REHANDSHAKE) {
+    /* BLOCKING call, this is bad but a work-around for now. Fixing this "the
+       proper way" takes a whole lot of work. */
+    CURLcode rc = handshake(conn, conn->ssl[num].session, num, FALSE);
+    if(rc)
+      /* handshake() writes error message on its own */
+      *curlcode = rc;
+    else
+      *curlcode = -1; /* then return as if this was a wouldblock */
+    return -1;
+  }
+
+  if(!ret) {
+    failf(conn->data, "Peer closed the TLS connection");
+    *curlcode = CURLE_RECV_ERROR;
+    return -1;
+  }
+
+  if(ret < 0) {
+    failf(conn->data, "GnuTLS recv error (%d): %s",
+          (int)ret, gnutls_strerror((int)ret));
+    *curlcode = CURLE_RECV_ERROR;
+    return -1;
+  }
+
+  return ret;
+}
+
+void Curl_gtls_session_free(void *ptr)
+{
+  free(ptr);
+}
+
+size_t Curl_gtls_version(char *buffer, size_t size)
+{
+  return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
+}
+
+int Curl_gtls_seed(struct SessionHandle *data)
+{
+  /* we have the "SSL is seeded" boolean static to prevent multiple
+     time-consuming seedings in vain */
+  static bool ssl_seeded = FALSE;
+
+  /* Quickly add a bit of entropy */
+  gcry_fast_random_poll();
+
+  if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
+     data->set.str[STRING_SSL_EGDSOCKET]) {
+
+    /* TODO: to a good job seeding the RNG
+       This may involve the gcry_control function and these options:
+       GCRYCTL_SET_RANDOM_SEED_FILE
+       GCRYCTL_SET_RNDEGD_SOCKET
+    */
+    ssl_seeded = TRUE;
+  }
+  return 0;
+}
+
+#endif /* USE_GNUTLS */
diff --git a/lib/gtls.h b/lib/gtls.h
new file mode 100644
index 0000000..9fe618a
--- /dev/null
+++ b/lib/gtls.h
@@ -0,0 +1,69 @@
+#ifndef __GTLS_H
+#define __GTLS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+#ifdef USE_GNUTLS
+
+int Curl_gtls_init(void);
+int Curl_gtls_cleanup(void);
+CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex);
+
+/* tell GnuTLS to close down all open information regarding connections (and
+   thus session ID caching etc) */
+void Curl_gtls_close_all(struct SessionHandle *data);
+
+ /* close a SSL connection */
+void Curl_gtls_close(struct connectdata *conn, int sockindex);
+
+/* for documentation see Curl_ssl_send() in sslgen.h */
+ssize_t Curl_gtls_send(struct connectdata *conn, int sockindex,
+                       const void *mem, size_t len, int *curlcode);
+
+/* for documentation see Curl_ssl_recv() in sslgen.h */
+ssize_t Curl_gtls_recv(struct connectdata *conn, int num, char *buf,
+                       size_t buffersize, int *curlcode);
+
+void Curl_gtls_session_free(void *ptr);
+size_t Curl_gtls_version(char *buffer, size_t size);
+int Curl_gtls_shutdown(struct connectdata *conn, int sockindex);
+int Curl_gtls_seed(struct SessionHandle *data);
+
+/* API setup for GnuTLS */
+#define curlssl_init Curl_gtls_init
+#define curlssl_cleanup Curl_gtls_cleanup
+#define curlssl_connect Curl_gtls_connect
+#define curlssl_session_free(x)  Curl_gtls_session_free(x)
+#define curlssl_close_all Curl_gtls_close_all
+#define curlssl_close Curl_gtls_close
+#define curlssl_shutdown(x,y) Curl_gtls_shutdown(x,y)
+#define curlssl_set_engine(x,y) (x=x, y=y, CURLE_FAILED_INIT)
+#define curlssl_set_engine_default(x) (x=x, CURLE_FAILED_INIT)
+#define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL)
+#define curlssl_send Curl_gtls_send
+#define curlssl_recv Curl_gtls_recv
+#define curlssl_version Curl_gtls_version
+#define curlssl_check_cxn(x) (x=x, -1)
+#define curlssl_data_pending(x,y) (x=x, y=y, 0)
+
+#endif /* USE_GNUTLS */
+#endif
diff --git a/lib/hash.c b/lib/hash.c
new file mode 100644
index 0000000..cdcd260
--- /dev/null
+++ b/lib/hash.c
@@ -0,0 +1,339 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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 <string.h>
+#include <stdlib.h>
+
+#include "hash.h"
+#include "llist.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+static void
+hash_element_dtor(void *user, void *element)
+{
+  struct curl_hash *h = (struct curl_hash *) user;
+  struct curl_hash_element *e = (struct curl_hash_element *) element;
+
+  if(e->key)
+    free(e->key);
+
+  if(e->ptr)
+    h->dtor(e->ptr);
+
+  free(e);
+}
+
+/* return 1 on error, 0 is fine */
+int
+Curl_hash_init(struct curl_hash *h,
+               int slots,
+               hash_function hfunc,
+               comp_function comparator,
+               curl_hash_dtor dtor)
+{
+  int i;
+
+  if(!slots || !hfunc || !comparator ||!dtor) {
+    return 1; /* failure */
+  }
+
+  h->hash_func = hfunc;
+  h->comp_func = comparator;
+  h->dtor = dtor;
+  h->size = 0;
+  h->slots = slots;
+
+  h->table = malloc(slots * sizeof(struct 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 */
+}
+
+struct curl_hash *
+Curl_hash_alloc(int slots,
+                hash_function hfunc,
+                comp_function comparator,
+                curl_hash_dtor dtor)
+{
+  struct curl_hash *h;
+
+  if(!slots || !hfunc || !comparator ||!dtor) {
+    return NULL; /* failure */
+  }
+
+  h = malloc(sizeof(struct curl_hash));
+  if(h) {
+    if(Curl_hash_init(h, slots, hfunc, comparator, dtor)) {
+      /* failure */
+      free(h);
+      h = NULL;
+    }
+  }
+
+  return h;
+}
+
+
+
+static struct curl_hash_element *
+mk_hash_element(const void *key, size_t key_len, const void *p)
+{
+  struct curl_hash_element *he = malloc(sizeof(struct curl_hash_element));
+
+  if(he) {
+    void *dupkey = malloc(key_len);
+    if(dupkey) {
+      /* copy the key */
+      memcpy(dupkey, key, key_len);
+
+      he->key = dupkey;
+      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 FETCH_LIST(x,y,z) x->table[x->hash_func(y, z, x->slots)]
+
+/* Insert the data in the hash. If there already was a match in the hash,
+   that data is replaced. */
+void *
+Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p)
+{
+  struct curl_hash_element  *he;
+  struct curl_llist_element *le;
+  struct curl_llist *l = FETCH_LIST (h, key, key_len);
+
+  for (le = l->head; le; le = le->next) {
+    he = (struct curl_hash_element *) le->ptr;
+    if(h->comp_func(he->key, he->key_len, key, key_len)) {
+      Curl_llist_remove(l, le, (void *)h);
+      --h->size;
+      break;
+    }
+  }
+
+  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 */
+}
+
+/* remove the identified hash entry, returns non-zero on failure */
+int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len)
+{
+  struct curl_llist_element *le;
+  struct curl_hash_element  *he;
+  struct curl_llist *l = FETCH_LIST(h, key, key_len);
+
+  for (le = l->head; le; le = le->next) {
+    he = le->ptr;
+    if(h->comp_func(he->key, he->key_len, key, key_len)) {
+      Curl_llist_remove(l, le, (void *) h);
+      return 0;
+    }
+  }
+  return 1;
+}
+
+void *
+Curl_hash_pick(struct curl_hash *h, void *key, size_t key_len)
+{
+  struct curl_llist_element *le;
+  struct curl_hash_element  *he;
+  struct curl_llist *l = FETCH_LIST(h, key, key_len);
+
+  for (le = l->head; le; le = le->next) {
+    he = le->ptr;
+    if(h->comp_func(he->key, he->key_len, key, key_len)) {
+      return he->ptr;
+    }
+  }
+
+  return NULL;
+}
+
+#if defined(DEBUGBUILD) && defined(AGGRESIVE_TEST)
+void
+Curl_hash_apply(curl_hash *h, void *user,
+                void (*cb)(void *user, void *ptr))
+{
+  struct 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(struct curl_hash *h)
+{
+  int i;
+
+  for (i = 0; i < h->slots; ++i) {
+    Curl_llist_destroy(h->table[i], (void *) h);
+    h->table[i] = NULL;
+  }
+
+  free(h->table);
+}
+
+void
+Curl_hash_clean_with_criterium(struct curl_hash *h, void *user,
+                               int (*comp)(void *, void *))
+{
+  struct curl_llist_element *le;
+  struct curl_llist_element *lnext;
+  struct 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) {
+      struct 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(struct curl_hash *h)
+{
+  if(!h)
+    return;
+
+  Curl_hash_clean(h);
+
+  free(h);
+}
+
+size_t Curl_hash_str(void* key, size_t key_length, size_t slots_num)
+{
+  const char* key_str = (const char *) key;
+  const char *end = key_str + key_length;
+  unsigned long h = 5381;
+
+  while(key_str < end) {
+    h += h << 5;
+    h ^= (unsigned long) *key_str++;
+  }
+
+  return (h % slots_num);
+}
+
+size_t Curl_str_key_compare(void*k1, size_t key1_len, void*k2, size_t key2_len)
+{
+  char *key1 = (char *)k1;
+  char *key2 = (char *)k2;
+
+  if(key1_len == key2_len &&
+      *key1 == *key2 &&
+      memcmp(key1, key2, key1_len) == 0) {
+    return 1;
+  }
+
+  return 0;
+}
+
+#if 0 /* useful function for debugging hashes and their contents */
+void Curl_hash_print(struct curl_hash *h,
+                     void (*func)(void *))
+{
+  int i;
+  struct curl_llist_element *le;
+  struct curl_llist *list;
+  struct curl_hash_element  *he;
+  if(!h)
+    return;
+
+  fprintf(stderr, "=Hash dump=\n");
+
+  for (i = 0; i < h->slots; i++) {
+    list = h->table[i];
+    le = list->head; /* get first list entry */
+    if(le) {
+      fprintf(stderr, "index %d:", i);
+      while(le) {
+        he = le->ptr;
+        if(func)
+          func(he->ptr);
+        else
+          fprintf(stderr, " [%p]", he->ptr);
+        le = le->next;
+      }
+      fprintf(stderr, "\n");
+    }
+  }
+}
+#endif
diff --git a/lib/hash.h b/lib/hash.h
new file mode 100644
index 0000000..993aaed
--- /dev/null
+++ b/lib/hash.h
@@ -0,0 +1,92 @@
+#ifndef __HASH_H
+#define __HASH_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, 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 <stddef.h>
+
+#include "llist.h"
+
+/* Hash function prototype */
+typedef size_t (*hash_function) (void* key,
+                                 size_t key_length,
+                                 size_t slots_num);
+
+/*
+   Comparator function prototype. Compares two keys.
+*/
+typedef size_t (*comp_function) (void* key1,
+                                 size_t key1_len,
+                                 void*key2,
+                                 size_t key2_len);
+
+typedef void (*curl_hash_dtor)(void *);
+
+struct curl_hash {
+  struct curl_llist **table;
+
+  /* Hash function to be used for this hash table */
+  hash_function hash_func;
+
+  /* Comparator function to compare keys */
+  comp_function comp_func;
+  curl_hash_dtor   dtor;
+  int slots;
+  size_t size;
+};
+
+struct curl_hash_element {
+  void   *ptr;
+  char   *key;
+  size_t key_len;
+};
+
+
+int Curl_hash_init(struct curl_hash *h,
+                   int slots,
+                   hash_function hfunc,
+                   comp_function comparator,
+                   curl_hash_dtor dtor);
+
+struct curl_hash *Curl_hash_alloc(int slots,
+                                  hash_function hfunc,
+                                  comp_function comparator,
+                                  curl_hash_dtor dtor);
+
+void *Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p);
+int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len);
+void *Curl_hash_pick(struct curl_hash *, void * key, size_t key_len);
+void Curl_hash_apply(struct curl_hash *h, void *user,
+                     void (*cb)(void *user, void *ptr));
+int Curl_hash_count(struct curl_hash *h);
+void Curl_hash_clean(struct curl_hash *h);
+void Curl_hash_clean_with_criterium(struct curl_hash *h, void *user,
+                                    int (*comp)(void *, void *));
+void Curl_hash_destroy(struct curl_hash *h);
+
+size_t Curl_hash_str(void* key, size_t key_length, size_t slots_num);
+size_t Curl_str_key_compare(void*k1, size_t key1_len, void*k2,
+                            size_t key2_len);
+
+#endif
diff --git a/lib/hostares.c b/lib/hostares.c
new file mode 100644
index 0000000..01b2142
--- /dev/null
+++ b/lib/hostares.c
@@ -0,0 +1,416 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 <string.h>
+
+#ifdef HAVE_LIMITS_H
+#include <limits.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
+
+#ifdef HAVE_PROCESS_H
+#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 "multiif.h"
+#include "inet_pton.h"
+#include "connect.h"
+#include "select.h"
+#include "progress.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for ares-enabled builds
+ **********************************************************************/
+
+#ifdef CURLRES_ARES
+
+/*
+ * Curl_resolv_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!
+ */
+
+int Curl_resolv_getsock(struct connectdata *conn,
+                        curl_socket_t *socks,
+                        int numsocks)
+
+{
+  struct timeval maxtime;
+  struct timeval timebuf;
+  struct timeval *timeout;
+  int max = ares_getsock(conn->data->state.areschannel,
+                         (ares_socket_t *)socks, numsocks);
+
+
+  maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
+  maxtime.tv_usec = 0;
+
+  timeout = ares_timeout(conn->data->state.areschannel, &maxtime, &timebuf);
+
+  Curl_expire(conn->data,
+              (timeout->tv_sec * 1000) + (timeout->tv_usec/1000));
+
+  return max;
+}
+
+/*
+ * waitperform()
+ *
+ * 1) Ask ares what sockets it currently plays with, then
+ * 2) wait for the timeout period to check for action on ares' sockets.
+ * 3) tell ares to act on all the sockets marked as "with action"
+ *
+ * return number of sockets it worked on
+ */
+
+static int waitperform(struct connectdata *conn, int timeout_ms)
+{
+  struct SessionHandle *data = conn->data;
+  int nfds;
+  int bitmask;
+  ares_socket_t socks[ARES_GETSOCK_MAXNUM];
+  struct pollfd pfd[ARES_GETSOCK_MAXNUM];
+  int i;
+  int num = 0;
+
+  bitmask = ares_getsock(data->state.areschannel, socks, ARES_GETSOCK_MAXNUM);
+
+  for(i=0; i < ARES_GETSOCK_MAXNUM; i++) {
+    pfd[i].events = 0;
+    pfd[i].revents = 0;
+    if(ARES_GETSOCK_READABLE(bitmask, i)) {
+      pfd[i].fd = socks[i];
+      pfd[i].events |= POLLRDNORM|POLLIN;
+    }
+    if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
+      pfd[i].fd = socks[i];
+      pfd[i].events |= POLLWRNORM|POLLOUT;
+    }
+    if(pfd[i].events != 0)
+      num++;
+    else
+      break;
+  }
+
+  if(num)
+    nfds = Curl_poll(pfd, num, timeout_ms);
+  else
+    nfds = 0;
+
+  if(!nfds)
+    /* Call ares_process() unconditonally here, even if we simply timed out
+       above, as otherwise the ares name resolve won't timeout! */
+    ares_process_fd(data->state.areschannel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
+  else {
+    /* move through the descriptors and ask for processing on them */
+    for(i=0; i < num; i++)
+      ares_process_fd(data->state.areschannel,
+                      pfd[i].revents & (POLLRDNORM|POLLIN)?
+                      pfd[i].fd:ARES_SOCKET_BAD,
+                      pfd[i].revents & (POLLWRNORM|POLLOUT)?
+                      pfd[i].fd:ARES_SOCKET_BAD);
+  }
+  return nfds;
+}
+
+/*
+ * 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)
+{
+  struct SessionHandle *data = conn->data;
+
+  *dns = NULL;
+
+  waitperform(conn, 0);
+
+  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;
+  struct timeval now = Curl_tvnow();
+
+  /* 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;
+  else
+    timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */
+
+  /* Wait for the name resolve query to complete. */
+  while(1) {
+    struct timeval *tvp, tv, store;
+    long timediff;
+    int itimeout;
+    int timeout_ms;
+
+    itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeout;
+
+    store.tv_sec = itimeout/1000;
+    store.tv_usec = (itimeout%1000)*1000;
+
+    tvp = ares_timeout(data->state.areschannel, &store, &tv);
+
+    /* use the timeout period ares returned to us above if less than one
+       second is left, otherwise just use 1000ms to make sure the progress
+       callback gets called frequent enough */
+    if(!tvp->tv_sec)
+      timeout_ms = tvp->tv_usec/1000;
+    else
+      timeout_ms = 1000;
+
+    waitperform(conn, timeout_ms);
+
+    if(conn->async.done)
+      break;
+
+    if(Curl_pgrsUpdate(conn)) {
+      rc = CURLE_ABORTED_BY_CALLBACK;
+      timeout = -1; /* trigger the cancel below */
+    }
+    else {
+      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)) {
+      if (conn->bits.httpproxy) {
+        failf(data, "Resolving proxy timed out: %s", conn->proxy.dispname);
+        rc = CURLE_COULDNT_RESOLVE_PROXY;
+      }
+      else {
+        failf(data, "Resolving host timed out: %s", conn->host.dispname);
+        rc = CURLE_COULDNT_RESOLVE_HOST;
+      }
+    }
+    else if(conn->async.done) {
+      if (conn->bits.httpproxy) {
+        failf(data, "Could not resolve proxy: %s (%s)", conn->proxy.dispname,
+              ares_strerror(conn->async.status));
+        rc = CURLE_COULDNT_RESOLVE_PROXY;
+      }
+      else {
+        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 */
+    conn->bits.close = TRUE;
+  }
+
+  return rc;
+}
+
+/*
+ * ares_query_completed_cb() is the callback that ares will call when
+ * the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(),
+ * when using ares, is completed either successfully or with failure.
+ */
+static void ares_query_completed_cb(void *arg,  /* (struct connectdata *) */
+                                    int status,
+#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
+                                    int timeouts,
+#endif
+                                    struct hostent *hostent)
+{
+  struct connectdata *conn = (struct connectdata *)arg;
+  struct Curl_addrinfo * ai = NULL;
+
+#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
+  (void)timeouts; /* ignored */
+#endif
+
+  if (status == CURL_ASYNC_SUCCESS) {
+    ai = Curl_he2ai(hostent, conn->async.port);
+  }
+
+  (void)Curl_addrinfo_callback(arg, status, ai);
+}
+
+/*
+ * 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,
+                                const char *hostname,
+                                int port,
+                                int *waitp)
+{
+  char *bufp;
+  struct SessionHandle *data = conn->data;
+  struct in_addr in;
+  int family = PF_INET;
+#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
+  struct in6_addr in6;
+#endif /* CURLRES_IPV6 */
+
+  *waitp = 0; /* default to synchronous response */
+
+  /* First check if this is an IPv4 address string */
+  if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
+    /* This is a dotted IP address 123.123.123.123-style */
+    return Curl_ip2addr(AF_INET, &in, hostname, port);
+  }
+
+#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
+  /* Otherwise, check if this is an IPv6 address string */
+  if (Curl_inet_pton (AF_INET6, hostname, &in6) > 0) {
+    /* This must be an IPv6 address literal.  */
+    return Curl_ip2addr(AF_INET6, &in6, hostname, port);
+  }
+
+  switch(data->set.ip_version) {
+  default:
+#if ARES_VERSION >= 0x010601
+    family = PF_UNSPEC; /* supported by c-ares since 1.6.1, so for older
+                           c-ares versions this just falls through and defaults
+                           to PF_INET */
+    break;
+#endif
+  case CURL_IPRESOLVE_V4:
+    family = PF_INET;
+    break;
+  case CURL_IPRESOLVE_V6:
+    family = PF_INET6;
+    break;
+  }
+#endif /* CURLRES_IPV6 */
+
+  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, family,
+                       (ares_host_callback)ares_query_completed_cb, conn);
+
+    *waitp = 1; /* expect asynchronous response */
+  }
+  return NULL; /* no struct yet */
+}
+#endif /* CURLRES_ARES */
diff --git a/lib/hostasyn.c b/lib/hostasyn.c
new file mode 100644
index 0000000..127b8d3
--- /dev/null
+++ b/lib/hostasyn.c
@@ -0,0 +1,129 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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 <string.h>
+
+#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
+
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#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 "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for builds using asynchronous name resolves
+ **********************************************************************/
+#ifdef CURLRES_ASYNCH
+
+/*
+ * Curl_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, this function takes
+ * ownership of the Curl_addrinfo passed, storing the resolved data
+ * in the DNS cache.
+ *
+ * The storage operation locks and unlocks the DNS cache.
+ */
+CURLcode Curl_addrinfo_callback(struct connectdata * conn,
+                                int status,
+                                struct Curl_addrinfo *ai)
+{
+  struct Curl_dns_entry *dns = NULL;
+  CURLcode rc = CURLE_OK;
+
+  conn->async.status = status;
+
+  if(CURL_ASYNC_SUCCESS == status) {
+    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);
+        rc = CURLE_OUT_OF_MEMORY;
+      }
+
+      if(data->share)
+        Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+    }
+    else
+      rc = CURLE_OUT_OF_MEMORY;
+  }
+
+  conn->async.dns = dns;
+
+ /* Set async.done TRUE last in this function since it may be used multi-
+    threaded and once this is TRUE the other thread may read fields from the
+    async struct */
+  conn->async.done = TRUE;
+
+  /* ipv4: The input hostent struct will be freed by ares when we return from
+     this function */
+  return rc;
+}
+
+#endif /* CURLRES_ASYNCH */
diff --git a/lib/hostip.c b/lib/hostip.c
new file mode 100644
index 0000000..8f6a52e
--- /dev/null
+++ b/lib/hostip.c
@@ -0,0 +1,723 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 <string.h>
+
+#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
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#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>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#if defined(CURLRES_SYNCH) && \
+    defined(HAVE_ALARM) && defined(SIGALRM) && defined(HAVE_SIGSETJMP)
+/* alarm-based timeouts can only be used with all the dependencies satisfied */
+#define USE_ALARM_TIMEOUT
+#endif
+
+/*
+ * 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. 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 struct 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!
+ *
+ * Returns a struct curl_hash pointer on success, NULL on failure.
+ */
+struct curl_hash *Curl_global_host_cache_init(void)
+{
+  int rc = 0;
+  if(!host_cache_initialized) {
+    rc = Curl_hash_init(&hostname_cache, 7, Curl_hash_str,
+                        Curl_str_key_compare, freednsentry);
+    if(!rc)
+      host_cache_initialized = 1;
+  }
+  return rc?NULL:&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 = 0;
+  while(addr) {
+    addr = addr->ai_next;
+    i++;
+  }
+  return i;
+}
+
+/*
+ * Curl_printable_address() returns a printable version of the 1st address
+ * given in the 'ai' 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 *ai, char *buf, size_t bufsize)
+{
+  const struct sockaddr_in *sa4;
+  const struct in_addr *ipaddr4;
+#ifdef ENABLE_IPV6
+  const struct sockaddr_in6 *sa6;
+  const struct in6_addr *ipaddr6;
+#endif
+
+  switch (ai->ai_family) {
+    case AF_INET:
+      sa4 = (const void *)ai->ai_addr;
+      ipaddr4 = &sa4->sin_addr;
+      return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf,
+                            bufsize);
+#ifdef ENABLE_IPV6
+    case AF_INET6:
+      sa6 = (const void *)ai->ai_addr;
+      ipaddr6 = &sa6->sin6_addr;
+      return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf,
+                            bufsize);
+#endif
+    default:
+      break;
+  }
+  return NULL;
+}
+
+/*
+ * Return a hostcache id string for the providing host + port, to be used by
+ * the DNS caching.
+ */
+static char *
+create_hostcache_id(const char *server, int port)
+{
+  /* create and return the new allocated entry */
+  return aprintf("%s:%d", server, port);
+}
+
+struct hostcache_prune_data {
+  long 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;
+
+  return (data->now - c->timestamp >= data->cache_timeout);
+}
+
+/*
+ * Prune the DNS cache. This assumes that a lock has already been taken.
+ */
+static void
+hostcache_prune(struct curl_hash *hostcache, long 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) || !data->dns.hostcache)
+    /* cache forever means never prune, and NULL hostcache means
+       we can't do it */
+    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->dns.hostcache,
+                  data->set.dns_cache_timeout,
+                  now);
+
+  if(data->share)
+    Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+}
+
+/*
+ * Check if the entry should be pruned. Assumes a locked cache.
+ */
+static int
+remove_entry_if_stale(struct SessionHandle *data, struct Curl_dns_entry *dns)
+{
+  struct hostcache_prune_data user;
+
+  if( !dns || (data->set.dns_cache_timeout == -1) || !data->dns.hostcache)
+    /* cache forever means never prune, and NULL hostcache means
+       we can't do it */
+    return 0;
+
+  time(&user.now);
+  user.cache_timeout = data->set.dns_cache_timeout;
+
+  if( !hostcache_timestamp_remove(&user,dns) )
+    return 0;
+
+  Curl_hash_clean_with_criterium(data->dns.hostcache,
+                                 (void *) &user,
+                                 hostcache_timestamp_remove);
+
+  return 1;
+}
+
+
+#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,
+                const char *hostname,
+                int port)
+{
+  char *entry_id;
+  size_t entry_len;
+  struct Curl_dns_entry *dns;
+  struct Curl_dns_entry *dns2;
+
+  /* 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 = calloc(1, 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) */
+  time(&dns->timestamp);
+  if(dns->timestamp == 0)
+    dns->timestamp = 1;   /* zero indicates that entry isn't in hash table */
+
+  /* Store the resolved data in our DNS cache. */
+  dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len+1,
+                       (void *)dns);
+  if(!dns2) {
+    free(dns);
+    free(entry_id);
+    return NULL;
+  }
+
+  dns = dns2;
+  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.
+ *
+ * In debug mode, we specifically test for an interface name "LocalHost"
+ * and resolve "localhost" instead as a means to permit test cases
+ * to connect to a local test server with any host name.
+ *
+ * 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,
+                const char *hostname,
+                int port,
+                struct Curl_dns_entry **entry)
+{
+  char *entry_id = NULL;
+  struct Curl_dns_entry *dns = NULL;
+  size_t entry_len;
+  struct SessionHandle *data = conn->data;
+  CURLcode result;
+  int rc = CURLRESOLV_ERROR; /* default to failure */
+
+  *entry = NULL;
+
+  /* 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 rc;
+
+  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->dns.hostcache, entry_id, entry_len+1);
+
+  /* See whether the returned entry is stale. Done before we release lock */
+  if( remove_entry_if_stale(data, dns) )
+    dns = NULL; /* the memory deallocation is being handled by the hash */
+
+  if(dns) {
+    dns->inuse++; /* we use it! */
+    rc = CURLRESOLV_RESOLVED;
+  }
+
+  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;
+    int respwait;
+
+    /* 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, 'respwait' 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,
+#ifdef DEBUGBUILD
+                            (data->set.str[STRING_DEVICE]
+                             && !strcmp(data->set.str[STRING_DEVICE],
+                                        "LocalHost"))?"localhost":
+#endif
+                            hostname, port, &respwait);
+
+    if(!addr) {
+      if(respwait) {
+        /* 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;
+    }
+  }
+
+  *entry = dns;
+
+  return rc;
+}
+
+#ifdef USE_ALARM_TIMEOUT
+/*
+ * This signal handler jumps back into the main libcurl code and continues
+ * execution.  This effectively causes the remainder of the application to run
+ * within a signal handler which is nonportable and could lead to problems.
+ */
+static
+RETSIGTYPE alarmfunc(int sig)
+{
+  /* this is for "-ansi -Wall -pedantic" to stop complaining!   (rabe) */
+  (void)sig;
+  siglongjmp(curl_jmpenv, 1);
+  return;
+}
+#endif /* USE_ALARM_TIMEOUT */
+
+/*
+ * Curl_resolv_timeout() is the same as Curl_resolv() but specifies a
+ * timeout.  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.
+ *
+ * If built with a synchronous resolver and use of signals is not
+ * disabled by the application, then a nonzero timeout will cause a
+ * timeout after the specified number of milliseconds. Otherwise, timeout
+ * is ignored.
+ *
+ * Return codes:
+ *
+ * CURLRESOLV_TIMEDOUT(-2) = warning, time too short or previous alarm expired
+ * CURLRESOLV_ERROR   (-1) = error, no pointer
+ * CURLRESOLV_RESOLVED (0) = OK, pointer provided
+ * CURLRESOLV_PENDING  (1) = waiting for response, no pointer
+ */
+
+int Curl_resolv_timeout(struct connectdata *conn,
+                        const char *hostname,
+                        int port,
+                        struct Curl_dns_entry **entry,
+                        long timeoutms)
+{
+#ifdef USE_ALARM_TIMEOUT
+#ifdef HAVE_SIGACTION
+  struct sigaction keep_sigact;   /* store the old struct here */
+  volatile bool keep_copysig = FALSE; /* wether old sigact has been saved */
+  struct sigaction sigact;
+#else
+#ifdef HAVE_SIGNAL
+  void (*keep_sigact)(int);       /* store the old handler here */
+#endif /* HAVE_SIGNAL */
+#endif /* HAVE_SIGACTION */
+  volatile long timeout;
+  volatile unsigned int prev_alarm = 0;
+  struct SessionHandle *data = conn->data;
+#endif /* USE_ALARM_TIMEOUT */
+  int rc;
+
+  *entry = NULL;
+
+#ifdef USE_ALARM_TIMEOUT
+  if (data->set.no_signal)
+    /* Ignore the timeout when signals are disabled */
+    timeout = 0;
+  else
+    timeout = timeoutms;
+
+  if(!timeout)
+    /* USE_ALARM_TIMEOUT defined, but no timeout actually requested */
+    return Curl_resolv(conn, hostname, port, entry);
+
+  if(timeout < 1000)
+    /* The alarm() function only provides integer second resolution, so if
+       we want to wait less than one second we must bail out already now. */
+    return CURLRESOLV_TIMEDOUT;
+
+  /*************************************************************
+   * Set signal handler to catch SIGALRM
+   * Store the old value to be able to set it back later!
+   *************************************************************/
+#ifdef HAVE_SIGACTION
+  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 */
+
+  /* alarm() makes a signal get sent when the timeout fires off, and that
+     will abort system calls */
+  prev_alarm = alarm((unsigned int) (timeout/1000L));
+
+  /* This allows us to time-out from the name resolver, as the timeout
+     will generate a signal and we will siglongjmp() from that here.
+     This technique has problems (see alarmfunc).
+     This should be the last thing we do before calling Curl_resolv(),
+     as otherwise we'd have to worry about variables that get modified
+     before we invoke Curl_resolv() (and thus use "volatile"). */
+  if(sigsetjmp(curl_jmpenv, 1)) {
+    /* this is coming from a siglongjmp() after an alarm signal */
+    failf(data, "name lookup timed out");
+    rc = CURLRESOLV_ERROR;
+    goto clean_up;
+  }
+
+#else
+#ifndef CURLRES_ASYNCH
+  if(timeoutms)
+    infof(conn->data, "timeout on name lookup is not supported\n");
+#else
+  (void)timeoutms; /* timeoutms not used with an async resolver */
+#endif
+#endif /* USE_ALARM_TIMEOUT */
+
+  /* Perform the actual name resolution. This might be interrupted by an
+   * alarm if it takes too long.
+   */
+  rc = Curl_resolv(conn, hostname, port, entry);
+
+#ifdef USE_ALARM_TIMEOUT
+clean_up:
+
+  if(!prev_alarm)
+    /* deactivate a possibly active alarm before uninstalling the handler */
+    alarm(0);
+
+#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);
+
+    /* the alarm period is counted in even number of seconds */
+    unsigned long 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);
+      rc = CURLRESOLV_TIMEDOUT;
+      failf(data, "Previous alarm fired off!");
+    }
+    else
+      alarm((unsigned int)alarm_set);
+  }
+#endif /* USE_ALARM_TIMEOUT */
+
+  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)
+{
+  DEBUGASSERT(dns && (dns->inuse>0));
+
+  if(data->share)
+    Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+  dns->inuse--;
+  /* only free if nobody is using AND it is not in hostcache (timestamp ==
+     0) */
+  if (dns->inuse == 0 && dns->timestamp == 0) {
+    Curl_freeaddrinfo(dns->addr);
+    free(dns);
+  }
+
+  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;
+
+  /* mark the entry as not in hostcache */
+  p->timestamp = 0;
+  if (p->inuse == 0) {
+    Curl_freeaddrinfo(p->addr);
+    free(p);
+  }
+}
+
+/*
+ * Curl_mk_dnscache() creates a new DNS cache and returns the handle for it.
+ */
+struct curl_hash *Curl_mk_dnscache(void)
+{
+  return Curl_hash_alloc(7, Curl_hash_str, Curl_str_key_compare, freednsentry);
+}
+
+
diff --git a/lib/hostip.h b/lib/hostip.h
new file mode 100644
index 0000000..33e573c
--- /dev/null
+++ b/lib/hostip.h
@@ -0,0 +1,219 @@
+#ifndef HEADER_CURL_HOSTIP_H
+#define HEADER_CURL_HOSTIP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 "hash.h"
+#include "curl_addrinfo.h"
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#ifdef NETWARE
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+/*
+ * Comfortable CURLRES_* definitions are included from setup.h
+ */
+
+#ifdef USE_ARES
+#include <ares_version.h>
+#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
+#if ARES_VERSION >= 0x010500
+/* c-ares 1.5.0 or later, the callback proto is modified */
+#define HAVE_CARES_CALLBACK_TIMEOUTS 1
+#endif
+#else
+#define CURL_ASYNC_SUCCESS CURLE_OK
+#define ares_cancel(x) do {} while(0)
+#define ares_destroy(x) do {} while(0)
+#endif
+
+struct addrinfo;
+struct hostent;
+struct SessionHandle;
+struct connectdata;
+
+/*
+ * 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!
+ *
+ * Returns a struct curl_hash pointer on success, NULL on failure.
+ */
+struct curl_hash *Curl_global_host_cache_init(void);
+void Curl_global_host_cache_dtor(void);
+
+struct Curl_dns_entry {
+  Curl_addrinfo *addr;
+  /* timestamp == 0 -- entry not in hostcache
+     timestamp != 0 -- entry is in hostcache */
+  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_TIMEDOUT -2
+#define CURLRESOLV_ERROR    -1
+#define CURLRESOLV_RESOLVED  0
+#define CURLRESOLV_PENDING   1
+int Curl_resolv(struct connectdata *conn, const char *hostname,
+                int port, struct Curl_dns_entry **dnsentry);
+int Curl_resolv_timeout(struct connectdata *conn, const char *hostname,
+                        int port, struct Curl_dns_entry **dnsentry,
+                        long timeoutms);
+
+/*
+ * 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,
+                                const 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_resolv_getsock() 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 multi_getsock() function.  'sock' is a pointer
+   to an array to hold the file descriptors, with 'numsock' being the size of
+   that array (in number of entries). This function is supposed to return
+   bitmask indicating what file descriptors (referring to array indexes in the
+   'sock' array) to wait for, read/write. */
+int Curl_resolv_getsock(struct connectdata *conn, curl_socket_t *sock,
+                        int numsocks);
+
+/* 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);
+
+/* make a new dns cache and return the handle */
+struct 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);
+
+#if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO)
+int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
+                       GETNAMEINFO_TYPE_ARG2 salen,
+                       char *host, GETNAMEINFO_TYPE_ARG46 hostlen,
+                       char *serv, GETNAMEINFO_TYPE_ARG46 servlen,
+                       GETNAMEINFO_TYPE_ARG7 flags,
+                       int line, const char *source);
+#endif
+
+/* IPv4 threadsafe resolve function used for synch and asynch builds */
+Curl_addrinfo *Curl_ipv4_resolve_r(const char * hostname, int port);
+
+/*
+ * Curl_addrinfo_callback() is used when we build with any asynch specialty.
+ * Handles end of async request processing. Inserts ai into hostcache when
+ * status is CURL_ASYNC_SUCCESS. Twiddles fields in conn to indicate async
+ * request completed wether successfull or failed.
+ */
+CURLcode Curl_addrinfo_callback(struct connectdata *conn,
+                                int status,
+                                Curl_addrinfo *ai);
+
+/*
+ * 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,
+                const char *hostname, int port);
+
+/*
+ * Curl_destroy_thread_data() cleans up async resolver data.
+ * Complementary of ares_destroy.
+ */
+struct Curl_async; /* forward-declaration */
+void Curl_destroy_thread_data(struct Curl_async *async);
+
+#ifndef INADDR_NONE
+#define CURL_INADDR_NONE (in_addr_t) ~0
+#else
+#define CURL_INADDR_NONE INADDR_NONE
+#endif
+
+#ifdef HAVE_SIGSETJMP
+/* Forward-declaration of variable defined in hostip.c. 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.
+ */
+extern sigjmp_buf curl_jmpenv;
+#endif
+
+#endif /* HEADER_CURL_HOSTIP_H */
diff --git a/lib/hostip4.c b/lib/hostip4.c
new file mode 100644
index 0000000..fbc7d49
--- /dev/null
+++ b/lib/hostip4.c
@@ -0,0 +1,319 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 <string.h>
+#include <errno.h>
+
+#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
+
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+#include "inet_pton.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#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 */
+/*
+ * 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 */
+}
+
+#ifdef CURLRES_SYNCH
+/*
+ * Curl_getaddrinfo() - the ipv4 synchronous version.
+ *
+ * The original code to this function was 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,
+                                const char *hostname,
+                                int port,
+                                int *waitp)
+{
+  Curl_addrinfo *ai = NULL;
+
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+  (void)conn;
+#endif
+
+  *waitp = 0; /* synchronous response only */
+
+  ai = Curl_ipv4_resolve_r(hostname, port);
+  if(!ai)
+    infof(conn->data, "Curl_ipv4_resolve_r failed for %s\n", hostname);
+
+  return ai;
+}
+#endif /* CURLRES_SYNCH */
+#endif /* CURLRES_IPV4 */
+
+/*
+ * Curl_ipv4_resolve_r() - ipv4 threadsafe resolver function.
+ *
+ * This is used for both synchronous and asynchronous resolver builds,
+ * implying that only threadsafe code and function calls may be used.
+ *
+ */
+Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
+                                   int port)
+{
+#if !defined(HAVE_GETADDRINFO_THREADSAFE) && defined(HAVE_GETHOSTBYNAME_R_3)
+  int res;
+#endif
+  Curl_addrinfo *ai = NULL;
+  struct hostent *h = NULL;
+  struct in_addr in;
+  struct hostent *buf = NULL;
+
+  if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
+    /* This is a dotted IP address 123.123.123.123-style */
+    return Curl_ip2addr(AF_INET, &in, hostname, port);
+
+#if defined(HAVE_GETADDRINFO_THREADSAFE)
+  else {
+    struct addrinfo hints;
+    char sbuf[NI_MAXSERV];
+    char *sbufptr = NULL;
+
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = PF_INET;
+    hints.ai_socktype = SOCK_STREAM;
+    if(port) {
+      snprintf(sbuf, sizeof(sbuf), "%d", port);
+      sbufptr = sbuf;
+    }
+    hints.ai_flags = AI_CANONNAME;
+    (void)Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &ai);
+
+#elif 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;
+
+    buf = calloc(1, CURL_HOSTENT_SIZE);
+    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.
+     */
+
+#if defined(HAVE_GETHOSTBYNAME_R_5)
+    /* Solaris, IRIX and more */
+    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
+#elif defined(HAVE_GETHOSTBYNAME_R_6)
+    /* Linux */
+
+    (void)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 */
+#elif defined(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 = SOCKERRNO; /* 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_...BYNAME_R_5 || HAVE_...BYNAME_R_6 || HAVE_...BYNAME_R_3 */
+    {
+      h = NULL; /* set return code to NULL */
+      free(buf);
+    }
+#else /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */
+    /*
+     * Here is code for platforms that don't have a thread safe
+     * getaddrinfo() nor gethostbyname_r() function or for which
+     * gethostbyname() is the preferred one.
+     */
+  else {
+    h = gethostbyname((void*)hostname);
+#endif /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */
+  }
+
+  if(h) {
+    ai = Curl_he2ai(h, port);
+
+    if(buf) /* used a *_r() function */
+      free(buf);
+  }
+
+  return ai;
+}
diff --git a/lib/hostip6.c b/lib/hostip6.c
new file mode 100644
index 0000000..fb3ad0c
--- /dev/null
+++ b/lib/hostip6.c
@@ -0,0 +1,238 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 <string.h>
+
+#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
+
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+#include "inet_pton.h"
+#include "connect.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for ipv6-enabled builds
+ **********************************************************************/
+#ifdef CURLRES_IPV6
+
+
+#if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO)
+/* 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
+ */
+
+/*
+ * For CURLRES_ARS, this should be written using ares_gethostbyaddr()
+ * (ignoring the fact c-ares doesn't return 'serv').
+ */
+
+int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
+                       GETNAMEINFO_TYPE_ARG2 salen,
+                       char *host, GETNAMEINFO_TYPE_ARG46 hostlen,
+                       char *serv, GETNAMEINFO_TYPE_ARG46 servlen,
+                       GETNAMEINFO_TYPE_ARG7 flags,
+                       int line, const char *source)
+{
+  int res = (getnameinfo)(sa, salen,
+                          host, hostlen,
+                          serv, servlen,
+                          flags);
+  if(0 == res)
+    /* success */
+    curl_memlog("GETNAME %s:%d getnameinfo()\n",
+                source, line);
+  else
+    curl_memlog("GETNAME %s:%d getnameinfo() failed = %d\n",
+                source, line, res);
+  return res;
+}
+#endif /* defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO) */
+
+/*
+ * 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;
+}
+
+#if defined(CURLRES_SYNCH)
+
+#ifdef DEBUG_ADDRINFO
+static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai)
+{
+  printf("dump_addrinfo:\n");
+  for ( ; ai; ai = ai->ai_next) {
+    char  buf[INET6_ADDRSTRLEN];
+
+    printf("    fam %2d, CNAME %s, ",
+           ai->ai_family, ai->ai_canonname ? ai->ai_canonname : "<none>");
+    if(Curl_printable_address(ai, buf, sizeof(buf)))
+      printf("%s\n", buf);
+    else
+      printf("failed; %s\n", Curl_strerror(conn, SOCKERRNO));
+  }
+}
+#else
+#define dump_addrinfo(x,y)
+#endif
+
+/*
+ * Curl_getaddrinfo() when built ipv6-enabled (non-threading and
+ * non-ares 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,
+                                const char *hostname,
+                                int port,
+                                int *waitp)
+{
+  struct addrinfo hints;
+  Curl_addrinfo *res;
+  int error;
+  char sbuf[NI_MAXSERV];
+  char *sbufptr = NULL;
+  char addrbuf[128];
+  int pf;
+  struct SessionHandle *data = conn->data;
+
+  *waitp = 0; /* synchronous response only */
+
+  /*
+   * Check if a 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;
+  }
+
+  if (pf != PF_INET) {
+    /* see if we have an IPv6 stack */
+    curl_socket_t 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);
+    }
+  }
+
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = pf;
+  hints.ai_socktype = conn->socktype;
+
+  if((1 == Curl_inet_pton(AF_INET, hostname, addrbuf)) ||
+     (1 == Curl_inet_pton(AF_INET6, hostname, addrbuf))) {
+    /* the given address is numerical only, prevent a reverse lookup */
+    hints.ai_flags = AI_NUMERICHOST;
+  }
+#ifdef HAVE_GSSAPI
+  if(conn->data->set.krb)
+    /* if krb is used, we (might) need the canonical host name */
+    hints.ai_flags |= AI_CANONNAME;
+#endif
+
+  if(port) {
+    snprintf(sbuf, sizeof(sbuf), "%d", port);
+    sbufptr=sbuf;
+  }
+  error = Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &res);
+  if(error) {
+    infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port);
+    return NULL;
+  }
+
+  dump_addrinfo(conn, res);
+
+  return res;
+}
+#endif /* CURLRES_SYNCH */
+#endif /* CURLRES_IPV6 */
+
diff --git a/lib/hostsyn.c b/lib/hostsyn.c
new file mode 100644
index 0000000..b68e470
--- /dev/null
+++ b/lib/hostsyn.c
@@ -0,0 +1,123 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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 <string.h>
+
+#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
+
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#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 "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
+ */
+
+int Curl_resolv_getsock(struct connectdata *conn,
+                        curl_socket_t *sock,
+                        int numsocks)
+{
+  (void)conn;
+  (void)sock;
+  (void)numsocks;
+
+  return 0; /* no bits since we don't use any socks */
+}
+
+#endif /* truly sync */
diff --git a/lib/hostthre.c b/lib/hostthre.c
new file mode 100644
index 0000000..1e4845e
--- /dev/null
+++ b/lib/hostthre.c
@@ -0,0 +1,590 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 <string.h>
+#include <errno.h>
+
+#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
+
+#if defined(USE_THREADS_POSIX)
+#  ifdef HAVE_PTHREAD_H
+#    include <pthread.h>
+#  endif
+#elif defined(USE_THREADS_WIN32)
+#  ifdef HAVE_PROCESS_H
+#    include <process.h>
+#  endif
+#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 "multiif.h"
+#include "inet_pton.h"
+#include "inet_ntop.h"
+#include "curl_threads.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for 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 struct addrinfo *hints);
+
+
+/* Data for synchronization between resolver thread and its parent */
+struct thread_sync_data {
+  curl_mutex_t * mtx;
+  int done;
+
+  char * hostname;        /* hostname to resolve, Curl_async.hostname
+                             duplicate */
+  int port;
+  int sock_error;
+  Curl_addrinfo *res;
+#ifdef HAVE_GETADDRINFO
+  struct addrinfo hints;
+#endif
+};
+
+struct thread_data {
+  curl_thread_t thread_hnd;
+  curl_socket_t dummy_sock;
+  unsigned int poll_interval;
+  int interval_end;
+  struct thread_sync_data tsd;
+};
+
+static struct thread_sync_data * conn_thread_sync_data(struct connectdata *conn)
+{
+  return &(((struct thread_data *)conn->async.os_specific)->tsd);
+}
+
+#define CONN_THREAD_SYNC_DATA(conn) &(((conn)->async.os_specific)->tsd);
+
+/* Destroy resolver thread synchronization data */
+static
+void destroy_thread_sync_data(struct thread_sync_data * tsd)
+{
+  if (tsd->mtx) {
+    Curl_mutex_destroy(tsd->mtx);
+    free(tsd->mtx);
+  }
+
+  if(tsd->hostname)
+    free(tsd->hostname);
+
+  if (tsd->res)
+    Curl_freeaddrinfo(tsd->res);
+
+  memset(tsd,0,sizeof(*tsd));
+}
+
+/* Initialize resolver thread synchronization data */
+static
+int init_thread_sync_data(struct thread_sync_data * tsd,
+                           const char * hostname,
+                           int port,
+                           const struct addrinfo *hints)
+{
+  memset(tsd, 0, sizeof(*tsd));
+
+  tsd->port = port;
+#ifdef CURLRES_IPV6
+  DEBUGASSERT(hints);
+  tsd->hints = *hints;
+#else
+  (void) hints;
+#endif
+
+  tsd->mtx = malloc(sizeof(curl_mutex_t));
+  if (tsd->mtx == NULL) goto err_exit;
+
+  Curl_mutex_init(tsd->mtx);
+
+  tsd->sock_error = CURL_ASYNC_SUCCESS;
+
+  /* Copying hostname string because original can be destroyed by parent
+   * thread during gethostbyname execution.
+   */
+  tsd->hostname = strdup(hostname);
+  if (!tsd->hostname) goto err_exit;
+
+  return 1;
+
+ err_exit:
+  /* Memory allocation failed */
+  destroy_thread_sync_data(tsd);
+  return 0;
+}
+
+static int getaddrinfo_complete(struct connectdata *conn)
+{
+  struct thread_sync_data *tsd = conn_thread_sync_data(conn);
+  int rc;
+
+  rc = Curl_addrinfo_callback(conn, tsd->sock_error, tsd->res);
+  /* The tsd->res structure has been copied to async.dns and perhaps the DNS cache.
+     Set our copy to NULL so destroy_thread_sync_data doesn't free it.
+   */
+  tsd->res = NULL;
+
+  return rc;
+}
+
+
+#ifdef HAVE_GETADDRINFO
+
+/*
+ * getaddrinfo_thread() resolves a name and then exits.
+ *
+ * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
+ * and wait on it.
+ */
+static unsigned int CURL_STDCALL getaddrinfo_thread (void *arg)
+{
+  struct thread_sync_data *tsd = (struct thread_sync_data*)arg;
+  char   service [NI_MAXSERV];
+  int rc;
+
+  snprintf(service, sizeof(service), "%d", tsd->port);
+
+  rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
+
+  if (rc != 0) {
+    tsd->sock_error = SOCKERRNO;
+    if (tsd->sock_error == 0)
+      tsd->sock_error = ENOMEM;
+  }
+
+  Curl_mutex_acquire(tsd->mtx);
+  tsd->done = 1;
+  Curl_mutex_release(tsd->mtx);
+
+  return 0;
+}
+
+#else /* HAVE_GETADDRINFO */
+
+/*
+ * gethostbyname_thread() resolves a name and then exits.
+ */
+static unsigned int CURL_STDCALL gethostbyname_thread (void *arg)
+{
+  struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
+
+  tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);
+
+  if (!tsd->res) {
+    tsd->sock_error = SOCKERRNO;
+    if (tsd->sock_error == 0)
+      tsd->sock_error = ENOMEM;
+  }
+
+  Curl_mutex_acquire(tsd->mtx);
+  tsd->done = 1;
+  Curl_mutex_release(tsd->mtx);
+
+  return 0;
+}
+
+#endif /* HAVE_GETADDRINFO */
+
+/*
+ * Curl_destroy_thread_data() cleans up async resolver data and thread handle.
+ * Complementary of ares_destroy.
+ */
+void Curl_destroy_thread_data (struct Curl_async *async)
+{
+  if(async->hostname)
+    free(async->hostname);
+
+  if(async->os_specific) {
+    struct thread_data *td = (struct thread_data*) async->os_specific;
+
+    if (td->dummy_sock != CURL_SOCKET_BAD)
+      sclose(td->dummy_sock);
+
+    if (td->thread_hnd != curl_thread_t_null)
+      Curl_thread_join(&td->thread_hnd);
+
+    destroy_thread_sync_data(&td->tsd);
+
+    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 struct addrinfo *hints)
+{
+  struct thread_data *td = calloc(1, sizeof(struct thread_data));
+  int err = ENOMEM;
+
+  conn->async.os_specific = (void*) td;
+  if(!td)
+    goto err_exit;
+
+  conn->async.port = port;
+  conn->async.done = FALSE;
+  conn->async.status = 0;
+  conn->async.dns = NULL;
+  td->dummy_sock = CURL_SOCKET_BAD;
+  td->thread_hnd = curl_thread_t_null;
+
+  if (!init_thread_sync_data(&td->tsd, hostname, port, hints))
+    goto err_exit;
+
+  Curl_safefree(conn->async.hostname);
+  conn->async.hostname = strdup(hostname);
+  if(!conn->async.hostname)
+    goto err_exit;
+
+#ifdef WIN32
+  /* This socket is only to keep Curl_resolv_fdset() and select() happy;
+   * should never become signalled for read since it's unbound but
+   * Windows needs at least 1 socket in select().
+   */
+  td->dummy_sock = socket(AF_INET, SOCK_DGRAM, 0);
+  if (td->dummy_sock == CURL_SOCKET_BAD)
+    goto err_exit;
+#endif
+
+#ifdef HAVE_GETADDRINFO
+  td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
+#else
+  td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
+#endif
+
+  if(!td->thread_hnd) {
+#ifndef _WIN32_WCE
+    err = errno;
+#endif
+    goto err_exit;
+  }
+
+  return TRUE;
+
+ err_exit:
+  Curl_destroy_thread_data(&conn->async);
+
+  SET_ERRNO(err);
+
+  return FALSE;
+}
+
+
+/*
+ * 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;
+  CURLcode rc = CURLE_OK;
+
+  DEBUGASSERT(conn && td);
+
+  /* wait for the thread to resolve the name */
+  if (Curl_thread_join(&td->thread_hnd)) {
+    rc = getaddrinfo_complete(conn);
+  } else {
+    DEBUGASSERT(0);
+  }
+
+  conn->async.done = TRUE;
+
+  if(entry)
+    *entry = conn->async.dns;
+
+  if(!conn->async.dns) {
+    /* a name was not resolved */
+    if (conn->bits.httpproxy) {
+      failf(data, "Could not resolve proxy: %s; %s",
+            conn->async.hostname, Curl_strerror(conn, conn->async.status));
+      rc = CURLE_COULDNT_RESOLVE_PROXY;
+    } else {
+      failf(data, "Could not resolve host: %s; %s",
+            conn->async.hostname, Curl_strerror(conn, conn->async.status));
+      rc = CURLE_COULDNT_RESOLVE_HOST;
+    }
+  }
+
+  Curl_destroy_thread_data(&conn->async);
+
+  if(!conn->async.dns)
+    conn->bits.close = TRUE;
+
+  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)
+{
+  struct SessionHandle *data = conn->data;
+  struct thread_data   *td = (struct thread_data*) conn->async.os_specific;
+  int done = 0;
+
+  *entry = NULL;
+
+  if (!td) {
+    DEBUGASSERT(td);
+    return CURLE_COULDNT_RESOLVE_HOST;
+  }
+
+  Curl_mutex_acquire(td->tsd.mtx);
+  done = td->tsd.done;
+  Curl_mutex_release(td->tsd.mtx);
+
+  if (done) {
+    getaddrinfo_complete(conn);
+    if (td->poll_interval != 0)
+        Curl_expire(conn->data, 0);
+    Curl_destroy_thread_data(&conn->async);
+
+    if(!conn->async.dns) {
+      failf(data, "Could not resolve host: %s; %s",
+            conn->host.name, Curl_strerror(conn, conn->async.status));
+      return CURLE_COULDNT_RESOLVE_HOST;
+    }
+    *entry = conn->async.dns;
+  } else {
+    /* poll for name lookup done with exponential backoff up to 250ms */
+    int elapsed;
+
+    elapsed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
+    if (elapsed < 0) {
+      elapsed = 0;
+    }
+
+    if (td->poll_interval == 0) {
+      /* Start at 1ms poll interval */
+      td->poll_interval = 1;
+    } else if (elapsed >= td->interval_end) {
+      /* Back-off exponentially if last interval expired  */
+      td->poll_interval *= 2;
+    }
+
+    if (td->poll_interval > 250)
+      td->poll_interval = 250;
+
+    td->interval_end = elapsed + td->poll_interval;
+
+    Curl_expire(conn->data, td->poll_interval);
+  }
+
+  return CURLE_OK;
+}
+
+int Curl_resolv_getsock(struct connectdata *conn,
+                        curl_socket_t *socks,
+                        int numsocks)
+{
+  const struct thread_data *td =
+    (const struct thread_data *) conn->async.os_specific;
+
+  if(td && td->dummy_sock != CURL_SOCKET_BAD) {
+    if(numsocks) {
+      /* return one socket waiting for readable, even though this is just
+         a dummy */
+      socks[0] = td->dummy_sock;
+      return GETSOCK_READSOCK(0);
+    }
+  }
+  return 0;
+}
+
+#ifndef HAVE_GETADDRINFO
+/*
+ * Curl_getaddrinfo() - for platforms without getaddrinfo
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+                                const char *hostname,
+                                int port,
+                                int *waitp)
+{
+  struct hostent *h = NULL;
+  struct SessionHandle *data = conn->data;
+  struct in_addr in;
+
+  *waitp = 0; /* default to synchronous response */
+
+  if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
+    /* This is a dotted IP address 123.123.123.123-style */
+    return Curl_ip2addr(AF_INET, &in, hostname, port);
+
+  /* fire up a new resolver thread! */
+  if(init_resolve_thread(conn, hostname, port, NULL)) {
+    *waitp = 1; /* expect asynchronous response */
+    return NULL;
+  }
+
+  /* fall-back to blocking version */
+  return Curl_ipv4_resolve_r(hostname, port);
+}
+
+#else /* !HAVE_GETADDRINFO */
+
+/*
+ * Curl_getaddrinfo() - for getaddrinfo
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+                                const char *hostname,
+                                int port,
+                                int *waitp)
+{
+  struct addrinfo hints;
+  Curl_addrinfo *res;
+  int error;
+  char sbuf[NI_MAXSERV];
+  int pf = PF_INET;
+  struct SessionHandle *data = conn->data;
+
+  *waitp = 0; /* default to synchronous response */
+
+#ifndef CURLRES_IPV4
+  /*
+   * Check if a 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;
+  }
+
+  if (pf != PF_INET) {
+    /* see if we have an IPv6 stack */
+    curl_socket_t 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);
+    }
+  }
+#endif /* !CURLRES_IPV4 */
+
+  memset(&hints, 0, sizeof(hints));
+  hints.ai_family = pf;
+  hints.ai_socktype = conn->socktype;
+#if 0 /* removed nov 8 2005 before 7.15.1 */
+  hints.ai_flags = AI_CANONNAME;
+#endif
+  snprintf(sbuf, sizeof(sbuf), "%d", port);
+
+  /* fire up a new resolver thread! */
+  if(init_resolve_thread(conn, hostname, port, &hints)) {
+    *waitp = 1; /* expect asynchronous response */
+    return NULL;
+  }
+
+  /* fall-back to blocking version */
+  infof(data, "init_resolve_thread() failed for %s; %s\n",
+        hostname, Curl_strerror(conn, ERRNO));
+
+  error = Curl_getaddrinfo_ex(hostname, sbuf, &hints, &res);
+  if(error) {
+    infof(data, "getaddrinfo() failed for %s:%d; %s\n",
+          hostname, port, Curl_strerror(conn, SOCKERRNO));
+    return NULL;
+  }
+  return res;
+}
+
+#endif /* !HAVE_GETADDRINFO */
+
+#endif /* CURLRES_THREADED */
diff --git a/lib/http.c b/lib/http.c
new file mode 100644
index 0000000..7ffc34d
--- /dev/null
+++ b/lib/http.c
@@ -0,0 +1,3807 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+#ifndef CURL_DISABLE_HTTP
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#ifdef WIN32
+#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
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_TIME_H
+#ifdef TIME_WITH_SYS_TIME
+#include <time.h>
+#endif
+#endif
+
+#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
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "easyif.h" /* for Curl_convert_... prototypes */
+#include "formdata.h"
+#include "progress.h"
+#include "curl_base64.h"
+#include "cookie.h"
+#include "strequal.h"
+#include "sslgen.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"
+#include "select.h"
+#include "parsedate.h" /* for the week day and month names */
+#include "strtoofft.h"
+#include "multiif.h"
+#include "rawstr.h"
+#include "content_encoding.h"
+#include "rtsp.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* Default proxy timeout in milliseconds */
+#define PROXY_TIMEOUT (3600*1000)
+
+/*
+ * Forward declarations.
+ */
+
+static int http_getsock_do(struct connectdata *conn,
+                           curl_socket_t *socks,
+                           int numsocks);
+#ifdef USE_SSL
+static CURLcode https_connecting(struct connectdata *conn, bool *done);
+static int https_getsock(struct connectdata *conn,
+                         curl_socket_t *socks,
+                         int numsocks);
+#else
+#define https_connecting(x,y) CURLE_COULDNT_CONNECT
+#endif
+
+/*
+ * HTTP handler interface.
+ */
+const struct Curl_handler Curl_handler_http = {
+  "HTTP",                               /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  Curl_http,                            /* do_it */
+  Curl_http_done,                       /* done */
+  ZERO_NULL,                            /* do_more */
+  Curl_http_connect,                    /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  http_getsock_do,                      /* doing_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  PORT_HTTP,                            /* defport */
+  PROT_HTTP,                            /* protocol */
+};
+
+#ifdef USE_SSL
+/*
+ * HTTPS handler interface.
+ */
+const struct Curl_handler Curl_handler_https = {
+  "HTTPS",                              /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  Curl_http,                            /* do_it */
+  Curl_http_done,                       /* done */
+  ZERO_NULL,                            /* do_more */
+  Curl_http_connect,                    /* connect_it */
+  https_connecting,                     /* connecting */
+  ZERO_NULL,                            /* doing */
+  https_getsock,                        /* proto_getsock */
+  http_getsock_do,                      /* doing_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  PORT_HTTPS,                           /* defport */
+  PROT_HTTP | PROT_HTTPS | PROT_SSL     /* protocol */
+};
+#endif
+
+
+/*
+ * 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.
+ */
+char *Curl_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(Curl_raw_nequal(head->data, thisheader, thislen))
+      return head->data;
+  }
+  return NULL;
+}
+
+/*
+ * Strip off leading and trailing whitespace from the value in the
+ * given HTTP header line and return a strdupped copy. Returns NULL in
+ * case of allocation failure. Returns an empty string if the header value
+ * consists entirely of whitespace.
+ */
+char *Curl_copy_header_value(const char *h)
+{
+  const char *start;
+  const char *end;
+  char *value;
+  size_t len;
+
+  DEBUGASSERT(h);
+
+  /* Find the end of the header name */
+  while (*h && (*h != ':'))
+    ++h;
+
+  if (*h)
+    /* Skip over colon */
+    ++h;
+
+  /* Find the first non-space letter */
+  start = h;
+  while(*start && ISSPACE(*start))
+    start++;
+
+  /* data is in the host encoding so
+     use '\r' and '\n' instead of 0x0d and 0x0a */
+  end = strchr(start, '\r');
+  if(!end)
+    end = strchr(start, '\n');
+  if(!end)
+    end = strchr(start, '\0');
+  if(!end)
+    return NULL;
+
+  /* skip all trailing space letters */
+  while((end > start) && ISSPACE(*end))
+    end--;
+
+  /* get length of the type */
+  len = end-start+1;
+
+  value = malloc(len + 1);
+  if(!value)
+    return NULL;
+
+  memcpy(value, start, len);
+  value[len] = 0; /* zero terminate */
+
+  return value;
+}
+
+/*
+ * http_output_basic() sets up an Authorization: header (or the proxy version)
+ * for HTTP Basic authentication.
+ *
+ * Returns CURLcode.
+ */
+static CURLcode http_output_basic(struct connectdata *conn, bool proxy)
+{
+  char *authorization;
+  struct SessionHandle *data=conn->data;
+  char **userp;
+  const char *user;
+  const 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, data->state.buffer,
+                        strlen(data->state.buffer),
+                        &authorization) > 0) {
+    if(*userp)
+      free(*userp);
+    *userp = aprintf( "%sAuthorization: Basic %s\r\n",
+                      proxy?"Proxy-":"",
+                      authorization);
+    free(authorization);
+    if(!*userp)
+      return CURLE_OUT_OF_MEMORY;
+  }
+  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 existence 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_perhapsrewind()
+ *
+ * If we are doing POST or PUT {
+ *   If we have more data to send {
+ *     If we are doing NTLM {
+ *       Keep sending since we must not disconnect
+ *     }
+ *     else {
+ *       If there is more than just a little data left to send, close
+ *       the current connection by force.
+ *     }
+ *   }
+ *   If we have sent any data {
+ *     If we don't have track of all the data {
+ *       call app to tell it to rewind
+ *     }
+ *     else {
+ *       rewind internally so that the operation can restart fine
+ *     }
+ *   }
+ * }
+ */
+CURLcode Curl_http_perhapsrewind(struct connectdata *conn)
+{
+  struct SessionHandle *data = conn->data;
+  struct HTTP *http = data->state.proto.http;
+  curl_off_t bytessent;
+  curl_off_t expectsend = -1; /* default is unknown */
+
+  if(!http || !(conn->protocol & PROT_HTTP))
+    /* If this is still NULL, we have not reach very far and we can
+       safely skip this rewinding stuff, or this is attempted to get used
+       when HTTP isn't activated */
+    return CURLE_OK;
+
+  switch(data->set.httpreq) {
+  case HTTPREQ_GET:
+  case HTTPREQ_HEAD:
+    return CURLE_OK;
+  default:
+    break;
+  }
+
+  bytessent = http->writebytecount;
+
+  if(conn->bits.authneg)
+    /* This is a state where we are known to be negotiating and we don't send
+       any data then. */
+    expectsend = 0;
+  else {
+    /* figure out how much data we are expected to send */
+    switch(data->set.httpreq) {
+    case HTTPREQ_POST:
+      if(data->set.postfieldsize != -1)
+        expectsend = data->set.postfieldsize;
+      else if(data->set.postfields)
+        expectsend = (curl_off_t)strlen(data->set.postfields);
+      break;
+    case HTTPREQ_PUT:
+      if(data->set.infilesize != -1)
+        expectsend = data->set.infilesize;
+      break;
+    case HTTPREQ_POST_FORM:
+      expectsend = http->postsize;
+      break;
+    default:
+      break;
+    }
+  }
+
+  conn->bits.rewindaftersend = FALSE; /* default */
+
+  if((expectsend == -1) || (expectsend > bytessent)) {
+    /* There is still data left to send */
+    if((data->state.authproxy.picked == CURLAUTH_NTLM) ||
+       (data->state.authhost.picked == CURLAUTH_NTLM)) {
+      if(((expectsend - bytessent) < 2000) ||
+         (conn->ntlm.state != NTLMSTATE_NONE)) {
+        /* The NTLM-negotiation has started *OR* there is just a little (<2K)
+           data left to send, keep on sending. */
+
+        /* rewind data when completely done sending! */
+        if(!conn->bits.authneg)
+          conn->bits.rewindaftersend = TRUE;
+
+        return CURLE_OK;
+      }
+      if(conn->bits.close)
+        /* this is already marked to get closed */
+        return CURLE_OK;
+
+      infof(data, "NTLM send, close instead of sending %" FORMAT_OFF_T
+            " bytes\n", (curl_off_t)(expectsend - bytessent));
+    }
+
+    /* This is not NTLM or NTLM with many bytes left to send: close
+     */
+    conn->bits.close = TRUE;
+    data->req.size = 0; /* don't download any more than 0 bytes */
+
+    /* There still is data left to send, but this connection is marked for
+       closure so we can safely do the rewind right now */
+  }
+
+  if(bytessent)
+    /* we rewind now at once since if we already sent something */
+    return Curl_readrewind(conn);
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_http_auth_act() gets called when 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 method 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(100 <= data->req.httpcode && 199 >= data->req.httpcode)
+    /* this is a transient response code, ignore */
+    return CURLE_OK;
+
+  if(data->state.authproblem)
+    return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK;
+
+  if(conn->bits.user_passwd &&
+     ((data->req.httpcode == 401) ||
+      (conn->bits.authneg && data->req.httpcode < 300))) {
+    pickhost = pickoneauth(&data->state.authhost);
+    if(!pickhost)
+      data->state.authproblem = TRUE;
+  }
+  if(conn->bits.proxy_user_passwd &&
+     ((data->req.httpcode == 407) ||
+      (conn->bits.authneg && data->req.httpcode < 300))) {
+    pickproxy = pickoneauth(&data->state.authproxy);
+    if(!pickproxy)
+      data->state.authproblem = TRUE;
+  }
+
+  if(pickhost || pickproxy) {
+    /* In case this is GSS auth, the newurl field is already allocated so
+       we must make sure to free it before allocating a new one. As figured
+       out in bug #2284386 */
+    Curl_safefree(data->req.newurl);
+    data->req.newurl = strdup(data->change.url); /* clone URL */
+    if(!data->req.newurl)
+      return CURLE_OUT_OF_MEMORY;
+
+    if((data->set.httpreq != HTTPREQ_GET) &&
+       (data->set.httpreq != HTTPREQ_HEAD) &&
+       !conn->bits.rewindaftersend) {
+      code = Curl_http_perhapsrewind(conn);
+      if(code)
+        return code;
+    }
+  }
+
+  else if((data->req.httpcode < 300) &&
+          (!data->state.authhost.done) &&
+          conn->bits.authneg) {
+    /* 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)) {
+      data->req.newurl = strdup(data->change.url); /* clone URL */
+      if(!data->req.newurl)
+        return CURLE_OUT_OF_MEMORY;
+      data->state.authhost.done = TRUE;
+    }
+  }
+  if(Curl_http_should_fail(conn)) {
+    failf (data, "The requested URL returned error: %d",
+           data->req.httpcode);
+    code = CURLE_HTTP_RETURNED_ERROR;
+  }
+
+  return code;
+}
+
+
+/*
+ * Output the correct authentication header depending on the auth type
+ * and whether or not it is to a proxy.
+ */
+static CURLcode
+output_auth_headers(struct connectdata *conn,
+                    struct auth *authstatus,
+                    const char *request,
+                    const char *path,
+                    bool proxy)
+{
+  struct SessionHandle *data = conn->data;
+  const char *auth=NULL;
+  CURLcode result = CURLE_OK;
+#ifdef HAVE_GSSAPI
+  struct negotiatedata *negdata = proxy?
+    &data->state.proxyneg:&data->state.negotiate;
+#endif
+
+#ifdef CURL_DISABLE_CRYPTO_AUTH
+  (void)request;
+  (void)path;
+#endif
+
+#ifdef HAVE_GSSAPI
+  if((authstatus->picked == CURLAUTH_GSSNEGOTIATE) &&
+     negdata->context && !GSS_ERROR(negdata->status)) {
+    auth="GSS-Negotiate";
+    result = Curl_output_negotiate(conn, proxy);
+    if(result)
+      return result;
+    authstatus->done = TRUE;
+    negdata->state = GSS_AUTHSENT;
+  }
+  else
+#endif
+#ifdef USE_NTLM
+  if(authstatus->picked == CURLAUTH_NTLM) {
+    auth="NTLM";
+    result = Curl_output_ntlm(conn, proxy);
+    if(result)
+      return result;
+  }
+  else
+#endif
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+  if(authstatus->picked == CURLAUTH_DIGEST) {
+    auth="Digest";
+    result = Curl_output_digest(conn,
+                                proxy,
+                                (const unsigned char *)request,
+                                (const unsigned char *)path);
+    if(result)
+      return result;
+  }
+  else
+#endif
+  if(authstatus->picked == CURLAUTH_BASIC) {
+    /* Basic */
+    if((proxy && conn->bits.proxy_user_passwd &&
+       !Curl_checkheaders(data, "Proxy-authorization:")) ||
+       (!proxy && conn->bits.user_passwd &&
+       !Curl_checkheaders(data, "Authorization:"))) {
+      auth="Basic";
+      result = http_output_basic(conn, proxy);
+      if(result)
+        return result;
+    }
+    /* NOTE: this function should set 'done' TRUE, as the other auth
+       functions work that way */
+    authstatus->done = TRUE;
+  }
+
+  if(auth) {
+    infof(data, "%s auth using %s with user '%s'\n",
+          proxy?"Proxy":"Server", auth,
+          proxy?(conn->proxyuser?conn->proxyuser:""):
+                (conn->user?conn->user:""));
+    authstatus->multi = (bool)(!authstatus->done);
+  }
+  else
+    authstatus->multi = FALSE;
+
+  return CURLE_OK;
+}
+
+/**
+ * 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
+http_output_auth(struct connectdata *conn,
+                 const char *request,
+                 const char *path,
+                 bool proxytunnel) /* TRUE if this is the request setting
+                                      up the proxy tunnel */
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  struct auth *authhost;
+  struct auth *authproxy;
+
+  DEBUGASSERT(data);
+
+  authhost = &data->state.authhost;
+  authproxy = &data->state.authproxy;
+
+  if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
+     conn->bits.user_passwd)
+    /* continue please */ ;
+  else {
+    authhost->done = TRUE;
+    authproxy->done = TRUE;
+    return CURLE_OK; /* no authentication with no user or password */
+  }
+
+  if(authhost->want && !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. */
+    authhost->picked = authhost->want;
+
+  if(authproxy->want && !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. */
+    authproxy->picked = authproxy->want;
+
+#ifndef CURL_DISABLE_PROXY
+  /* Send proxy authentication header if needed */
+  if(conn->bits.httpproxy &&
+      (conn->bits.tunnel_proxy == proxytunnel)) {
+    result = output_auth_headers(conn, authproxy, request, path, TRUE);
+    if(result)
+      return result;
+  }
+  else
+#else
+  (void)proxytunnel;
+#endif /* CURL_DISABLE_PROXY */
+    /* we have no proxy so let's pretend we're done authenticating
+       with it */
+    authproxy->done = TRUE;
+
+  /* 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 ||
+     conn->bits.netrc ||
+     !data->state.first_host ||
+     data->set.http_disable_hostname_check_before_authentication ||
+     Curl_raw_equal(data->state.first_host, conn->host.name)) {
+    result = output_auth_headers(conn, authhost, request, path, FALSE);
+  }
+  else
+    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,
+                              const char *header) /* the first non-space */
+{
+  /*
+   * This resource requires authentication
+   */
+  struct SessionHandle *data = conn->data;
+
+  long *availp;
+  const 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(*start))
+    start++;
+
+  /*
+   * Here we check if we want the specific single authentication (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 authentication type to the authavail
+   * variable.
+   *
+   * Note:
+   *
+   * ->picked is first set to the 'want' value (one or more bits) before the
+   * request is sent, and then it is again set _after_ all response 401/407
+   * headers have been received but then only to a single preferred method
+   * (bit).
+   *
+   */
+
+#ifdef HAVE_GSSAPI
+  if(checkprefix("GSS-Negotiate", start) ||
+      checkprefix("Negotiate", start)) {
+    int neg;
+    *availp |= CURLAUTH_GSSNEGOTIATE;
+    authp->avail |= CURLAUTH_GSSNEGOTIATE;
+
+    if(data->state.negotiate.state == GSS_AUTHSENT) {
+      /* if we sent GSS authentication in the outgoing request and we get this
+         back, we're in trouble */
+      infof(data, "Authentication problem. Ignoring this.\n");
+      data->state.authproblem = TRUE;
+    }
+    else {
+      neg = Curl_input_negotiate(conn, (bool)(httpcode == 407), start);
+      if(neg == 0) {
+        DEBUGASSERT(!data->req.newurl);
+        data->req.newurl = strdup(data->change.url);
+        if(!data->req.newurl)
+          return CURLE_OUT_OF_MEMORY;
+        data->state.authproblem = FALSE;
+        /* we received GSS auth info and we dealt with it fine */
+        data->state.negotiate.state = GSS_AUTHRECV;
+      }
+      else {
+        data->state.authproblem = TRUE;
+      }
+    }
+  }
+  else
+#endif
+#ifdef USE_NTLM
+    /* 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
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+      if(checkprefix("Digest", start)) {
+        if((authp->avail & CURLAUTH_DIGEST) != 0) {
+          infof(data, "Ignoring duplicate digest auth header.\n");
+        }
+        else {
+          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
+#endif
+      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 basically 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;
+  int httpcode;
+
+  DEBUGASSERT(conn);
+  data = conn->data;
+  DEBUGASSERT(data);
+
+  httpcode = data->req.httpcode;
+
+  /*
+  ** 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(httpcode < 400)
+    return 0;
+
+  if(data->state.resume_from &&
+     (data->set.httpreq==HTTPREQ_GET) &&
+     (httpcode == 416)) {
+    /* "Requested Range Not Satisfiable", just proceed and
+       pretend this is no error */
+    return 0;
+  }
+
+  /*
+  ** Any code >= 400 that's not 401 or 407 is always
+  ** a terminal error
+  */
+  if((httpcode != 401) &&
+      (httpcode != 407))
+    return 1;
+
+  /*
+  ** All we have left to deal with is 401 and 407
+  */
+  DEBUGASSERT((httpcode == 401) || (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__,data->req.newurl ?
+        data->req.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((httpcode == 401) && !conn->bits.user_passwd)
+    return TRUE;
+  if((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->data->state.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->data->req.forbidchunk = (bool)(http->sending == HTTPSEND_REQUEST);
+
+  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_func = http->backup.fread_func;
+      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;
+}
+
+/* ------------------------------------------------------------------------- */
+/* add_buffer functions */
+
+/*
+ * Curl_add_buffer_init() sets up and returns a fine buffer struct
+ */
+Curl_send_buffer *Curl_add_buffer_init(void)
+{
+  return calloc(1, sizeof(Curl_send_buffer));
+}
+
+/*
+ * Curl_add_buffer_send() sends a header buffer and frees all associated
+ * memory.  Body data may be appended to the header data if desired.
+ *
+ * Returns CURLcode
+ */
+CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
+                         struct connectdata *conn,
+                         long *bytes_written, /* add the number of sent bytes
+                                                 to this counter */
+                         size_t included_body_bytes, /* how much of the buffer
+                                                        contains body data */
+                         int socketindex)
+
+{
+  ssize_t amount;
+  CURLcode res;
+  char *ptr;
+  size_t size;
+  struct HTTP *http = conn->data->state.proto.http;
+  size_t sendsize;
+  curl_socket_t sockfd;
+  size_t headersize;
+
+  DEBUGASSERT(socketindex <= SECONDARYSOCKET);
+
+  sockfd = conn->sock[socketindex];
+
+  /* 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;
+
+  headersize = size - included_body_bytes; /* the initial part that isn't body
+                                              is header */
+
+  DEBUGASSERT(size > included_body_bytes);
+
+#ifdef CURL_DOES_CONVERSIONS
+  res = Curl_convert_to_network(conn->data, ptr, headersize);
+  /* Curl_convert_to_network calls failf if unsuccessful */
+  if(res != CURLE_OK) {
+    /* conversion failed, free memory and return to the caller */
+    if(in->buffer)
+      free(in->buffer);
+    free(in);
+    return res;
+  }
+#endif /* CURL_DOES_CONVERSIONS */
+
+  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) {
+    /*
+     * Note that we may not send the entire chunk at once, and we have a set
+     * number of data bytes at the end of the big buffer (out of which we may
+     * only send away a part).
+     */
+    /* how much of the header that was sent */
+    size_t headlen = (size_t)amount>headersize?headersize:(size_t)amount;
+    size_t bodylen = amount - headlen;
+
+    if(conn->data->set.verbose) {
+      /* this data _may_ contain binary stuff */
+      Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, headlen, conn);
+      if((size_t)amount > headlen) {
+        /* there was body data sent beyond the initial header part, pass that
+           on to the debug callback too */
+        Curl_debug(conn->data, CURLINFO_DATA_OUT,
+                   ptr+headlen, bodylen, conn);
+      }
+    }
+    if(bodylen)
+      /* since we sent a piece of the body here, up the byte counter for it
+         accordingly */
+      http->writebytecount += bodylen;
+
+    *bytes_written += amount;
+
+    if(http) {
+      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_func = conn->fread_func;
+        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_func = (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 */
+    }
+    else {
+      if((size_t)amount != size)
+        /* We have no continue-send mechanism now, fail. This can only happen
+           when this function is used from the CONNECT sending function. We
+           currently (stupidly) assume that the whole request is always sent
+           away in the first single chunk.
+
+           This needs FIXing.
+        */
+        return CURLE_SEND_ERROR;
+      else
+        conn->writechannel_inuse = FALSE;
+    }
+  }
+  if(in->buffer)
+    free(in->buffer);
+  free(in);
+
+  return res;
+}
+
+
+/*
+ * add_bufferf() add the formatted input to the buffer.
+ */
+CURLcode Curl_add_bufferf(Curl_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 = Curl_add_buffer(in, s, strlen(s));
+    free(s);
+    return result;
+  }
+  /* 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
+ */
+CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size)
+{
+  char *new_rb;
+  size_t new_size;
+
+  if(~size < in->size_used) {
+    /* If resulting used size of send buffer would wrap size_t, cleanup
+       the whole buffer and return error. Otherwise the required buffer
+       size will fit into a single allocatable memory chunk */
+    Curl_safefree(in->buffer);
+    free(in);
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(!in->buffer ||
+     ((in->size_used + size) > (in->size_max - 1))) {
+
+    /* If current buffer size isn't enough to hold the result, use a
+       buffer size that doubles the required size. If this new size
+       would wrap size_t, then just use the largest possible one */
+
+    if((size > (size_t)-1/2) || (in->size_used > (size_t)-1/2) ||
+       (~(size*2) < (in->size_used*2)))
+      new_size = (size_t)-1;
+    else
+      new_size = (in->size_used+size)*2;
+
+    if(in->buffer)
+      /* we have a buffer, enlarge the existing one */
+      new_rb = realloc(in->buffer, new_size);
+    else
+      /* create a new buffer */
+      new_rb = malloc(new_size);
+
+    if(!new_rb) {
+      /* If we failed, we cleanup the whole buffer and return error */
+      Curl_safefree(in->buffer);
+      free(in);
+      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(const 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;
+  const char *start;
+  const char *end;
+
+  if(!Curl_raw_nequal(headerline, header, hlen))
+    return FALSE; /* doesn't start with header */
+
+  /* pass the header */
+  start = &headerline[hlen];
+
+  /* pass all white spaces */
+  while(*start && ISSPACE(*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(Curl_raw_nequal(start, content, clen))
+      return TRUE; /* match! */
+  }
+
+  return FALSE; /* no match */
+}
+
+#ifndef CURL_DISABLE_PROXY
+/*
+ * Curl_proxyCONNECT() 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.
+ *
+ * This badly needs to be rewritten. CONNECT should be sent and dealt with
+ * like any ordinary HTTP request, and not specially crafted like this. This
+ * function only remains here like this for now since the rewrite is a bit too
+ * much work to do at the moment.
+ *
+ * This function is BLOCKING which is nasty for all multi interface using apps.
+ */
+
+CURLcode Curl_proxyCONNECT(struct connectdata *conn,
+                           int sockindex,
+                           const char *hostname,
+                           unsigned short remote_port)
+{
+  int subversion=0;
+  struct SessionHandle *data=conn->data;
+  struct SingleRequest *k = &data->req;
+  CURLcode result;
+  int res;
+  long timeout =
+    data->set.timeout?data->set.timeout:PROXY_TIMEOUT; /* in milliseconds */
+  curl_socket_t tunnelsocket = conn->sock[sockindex];
+  curl_off_t cl=0;
+  bool closeConnection = FALSE;
+  bool chunked_encoding = FALSE;
+  long check;
+
+#define SELECT_OK      0
+#define SELECT_ERROR   1
+#define SELECT_TIMEOUT 2
+  int error = SELECT_OK;
+
+  conn->bits.proxy_connect_closed = FALSE;
+
+  do {
+    if(!conn->bits.tunnel_connecting) { /* BEGIN CONNECT PHASE */
+      char *host_port;
+      Curl_send_buffer *req_buffer;
+
+      infof(data, "Establish HTTP proxy tunnel to %s:%hu\n",
+            hostname, remote_port);
+
+      if(data->req.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(data->req.newurl);
+        data->req.newurl = NULL;
+      }
+
+      /* initialize a dynamic send-buffer */
+      req_buffer = Curl_add_buffer_init();
+
+      if(!req_buffer)
+        return CURLE_OUT_OF_MEMORY;
+
+      host_port = aprintf("%s:%hu", hostname, remote_port);
+      if(!host_port) {
+        free(req_buffer);
+        return CURLE_OUT_OF_MEMORY;
+      }
+
+      /* Setup the proxy-authorization header, if any */
+      result = http_output_auth(conn, "CONNECT", host_port, TRUE);
+
+      if(CURLE_OK == result) {
+        char *host=(char *)"";
+        const char *proxyconn="";
+        const char *useragent="";
+        const char *http = (conn->proxytype == CURLPROXY_HTTP_1_0) ?
+          "1.0" : "1.1";
+
+        if(!Curl_checkheaders(data, "Host:")) {
+          host = aprintf("Host: %s\r\n", host_port);
+          if(!host) {
+            free(req_buffer);
+            free(host_port);
+            return CURLE_OUT_OF_MEMORY;
+          }
+        }
+        if(!Curl_checkheaders(data, "Proxy-Connection:"))
+          proxyconn = "Proxy-Connection: Keep-Alive\r\n";
+
+        if(!Curl_checkheaders(data, "User-Agent:") &&
+           data->set.str[STRING_USERAGENT])
+          useragent = conn->allocptr.uagent;
+
+        /* Send the connect request to the proxy */
+        /* BLOCKING */
+        result =
+          Curl_add_bufferf(req_buffer,
+                      "CONNECT %s:%hu HTTP/%s\r\n"
+                      "%s"  /* Host: */
+                      "%s"  /* Proxy-Authorization */
+                      "%s"  /* User-Agent */
+                      "%s", /* Proxy-Connection */
+                      hostname, remote_port, http,
+                      host,
+                      conn->allocptr.proxyuserpwd?
+                      conn->allocptr.proxyuserpwd:"",
+                      useragent,
+                      proxyconn);
+
+        if(host && *host)
+          free(host);
+
+        if(CURLE_OK == result)
+          result = Curl_add_custom_headers(conn, req_buffer);
+
+        if(CURLE_OK == result)
+          /* CRLF terminate the request */
+          result = Curl_add_bufferf(req_buffer, "\r\n");
+
+        if(CURLE_OK == result) {
+          /* Now send off the request */
+          result = Curl_add_buffer_send(req_buffer, conn,
+                                   &data->info.request_size, 0, sockindex);
+        }
+        req_buffer = NULL;
+        if(result)
+          failf(data, "Failed sending CONNECT to proxy");
+      }
+      free(host_port);
+      Curl_safefree(req_buffer);
+      if(result)
+        return result;
+
+      conn->bits.tunnel_connecting = TRUE;
+    } /* END CONNECT PHASE */
+
+    /* now we've issued the CONNECT and we're waiting to hear back -
+       we try not to block here in multi-mode because that might be a LONG
+       wait if the proxy cannot connect-through to the remote host. */
+
+    /* if timeout is requested, find out how much remaining time we have */
+    check = timeout - /* timeout time */
+      Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
+    if(check <= 0) {
+      failf(data, "Proxy CONNECT aborted due to timeout");
+      return CURLE_RECV_ERROR;
+    }
+
+    /* if we're in multi-mode and we would block, return instead for a retry */
+    if(Curl_if_multi == data->state.used_interface) {
+      if(0 == Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, 0))
+        /* return so we'll be called again polling-style */
+        return CURLE_OK;
+      else {
+        DEBUGF(infof(data,
+                     "Multi mode finished polling for response from "
+                     "proxy CONNECT."));
+      }
+    }
+    else {
+      DEBUGF(infof(data, "Easy mode waiting response from proxy CONNECT."));
+    }
+
+    /* at this point, either:
+       1) we're in easy-mode and so it's okay to block waiting for a CONNECT
+       response
+       2) we're in multi-mode and we didn't block - it's either an error or we
+       now have some data waiting.
+       In any case, the tunnel_connecting phase is over. */
+    conn->bits.tunnel_connecting = FALSE;
+
+    { /* BEGIN NEGOTIATION PHASE */
+      size_t nread;   /* total size read */
+      int perline; /* count bytes per line */
+      int keepon=TRUE;
+      ssize_t gotbytes;
+      char *ptr;
+      char *line_start;
+
+      ptr=data->state.buffer;
+      line_start = ptr;
+
+      nread=0;
+      perline=0;
+      keepon=TRUE;
+
+      while((nread<BUFSIZE) && (keepon && !error)) {
+
+        /* if timeout is requested, find out how much remaining time we have */
+        check = timeout - /* timeout time */
+          Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
+        if(check <= 0) {
+          failf(data, "Proxy CONNECT aborted due to timeout");
+          error = SELECT_TIMEOUT; /* already too little time */
+          break;
+        }
+
+        /* loop every second at least, less if the timeout is near */
+        switch (Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD,
+                            check<1000L?(int)check:1000)) {
+        case -1: /* select() error, stop reading */
+          error = SELECT_ERROR;
+          failf(data, "Proxy CONNECT aborted due to select/poll error");
+          break;
+        case 0: /* timeout */
+          break;
+        default:
+          DEBUGASSERT(ptr+BUFSIZE-nread <= data->state.buffer+BUFSIZE+1);
+          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;
+            if(data->set.proxyauth && data->state.authproxy.avail) {
+              /* proxy auth was requested and there was proxy auth available,
+                 then deem this as "mere" proxy disconnect */
+              conn->bits.proxy_connect_closed = TRUE;
+            }
+            else {
+              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.
+             */
+            int i;
+
+            nread += gotbytes;
+
+            if(keepon > TRUE) {
+              /* This means we are currently ignoring a response-body */
+
+              nread = 0; /* make next read start over in the read buffer */
+              ptr=data->state.buffer;
+              if(cl) {
+                /* A Content-Length based body: simply count down the counter
+                   and make sure to break out of the loop when we're done! */
+                cl -= gotbytes;
+                if(cl<=0) {
+                  keepon = FALSE;
+                  break;
+                }
+              }
+              else {
+                /* chunked-encoded body, so we need to do the chunked dance
+                   properly to know when the end of the body is reached */
+                CHUNKcode r;
+                ssize_t tookcareof=0;
+
+                /* now parse the chunked piece of data so that we can
+                   properly tell when the stream ends */
+                r = Curl_httpchunk_read(conn, ptr, gotbytes, &tookcareof);
+                if(r == CHUNKE_STOP) {
+                  /* we're done reading chunks! */
+                  infof(data, "chunk reading DONE\n");
+                  keepon = FALSE;
+                }
+                else
+                  infof(data, "Read %zd bytes of chunk, continue\n",
+                        tookcareof);
+              }
+            }
+            else
+              for(i = 0; i < gotbytes; ptr++, i++) {
+                perline++; /* amount of bytes in this line so far */
+                if(*ptr == 0x0a) {
+                  char letter;
+                  int writetype;
+
+#ifdef CURL_DOES_CONVERSIONS
+                  /* convert from the network encoding */
+                  result = Curl_convert_from_network(data, line_start,
+                                                     perline);
+                  /* Curl_convert_from_network calls failf if unsuccessful */
+                  if(result)
+                    return result;
+#endif /* CURL_DOES_CONVERSIONS */
+
+                  /* output debug if that is requested */
+                  if(data->set.verbose)
+                    Curl_debug(data, CURLINFO_HEADER_IN,
+                               line_start, (size_t)perline, conn);
+
+                  /* send the header to the callback */
+                  writetype = CLIENTWRITE_HEADER;
+                  if(data->set.include_header)
+                    writetype |= CLIENTWRITE_BODY;
+
+                  result = Curl_client_write(conn, 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 */
+                    nread = 0; /* make next read start over in the read
+                                  buffer */
+                    ptr=data->state.buffer;
+                    if((407 == k->httpcode) && !data->state.authproblem) {
+                      /* If we get a 407 response code with content length
+                         when we have no auth problem, we must ignore the
+                         whole response-body */
+                      keepon = 2;
+
+                      if(cl) {
+
+                        infof(data, "Ignore %" FORMAT_OFF_T
+                              " bytes of response-body\n", cl);
+                        /* remove the remaining chunk of what we already
+                           read */
+                        cl -= (gotbytes - i);
+
+                        if(cl<=0)
+                          /* if the whole thing was already read, we are done!
+                           */
+                          keepon=FALSE;
+                      }
+                      else if(chunked_encoding) {
+                        CHUNKcode r;
+                        /* We set ignorebody true here since the chunked
+                           decoder function will acknowledge that. Pay
+                           attention so that this is cleared again when this
+                           function returns! */
+                        k->ignorebody = TRUE;
+                        infof(data, "%zd bytes of chunk left\n", gotbytes-i);
+
+                        if(line_start[1] == '\n') {
+                          /* this can only be a LF if the letter at index 0
+                             was a CR */
+                          line_start++;
+                          i++;
+                        }
+
+                        /* now parse the chunked piece of data so that we can
+                           properly tell when the stream ends */
+                        r = Curl_httpchunk_read(conn, line_start+1,
+                                                  gotbytes -i, &gotbytes);
+                        if(r == CHUNKE_STOP) {
+                          /* we're done reading chunks! */
+                          infof(data, "chunk reading DONE\n");
+                          keepon = FALSE;
+                        }
+                        else
+                          infof(data, "Read %zd bytes of chunk, continue\n",
+                                gotbytes);
+                      }
+                      else {
+                        /* without content-length or chunked encoding, we
+                           can't keep the connection alive since the close is
+                           the end signal so we bail out at once instead */
+                        keepon=FALSE;
+                      }
+                    }
+                    else
+                      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(checkprefix("Content-Length:", line_start)) {
+                    cl = curlx_strtoofft(line_start +
+                                         strlen("Content-Length:"), NULL, 10);
+                  }
+                  else if(Curl_compareheader(line_start,
+                                             "Connection:", "close"))
+                    closeConnection = TRUE;
+                  else if(Curl_compareheader(line_start,
+                                             "Transfer-Encoding:",
+                                             "chunked")) {
+                    infof(data, "CONNECT responded chunked\n");
+                    chunked_encoding = TRUE;
+                    /* init our chunky engine */
+                    Curl_httpchunk_init(conn);
+                  }
+                  else if(Curl_compareheader(line_start,
+                                             "Proxy-Connection:", "close"))
+                    closeConnection = TRUE;
+                  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 */
+        if(Curl_pgrsUpdate(conn))
+          return CURLE_ABORTED_BY_CALLBACK;
+      } /* 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. */
+        result = Curl_http_auth_act(conn);
+        if(result)
+          return result;
+
+        if(conn->bits.close)
+          /* the connection has been marked for closure, most likely in the
+             Curl_http_auth_act() function and thus we can kill it at once
+             below
+          */
+          closeConnection = TRUE;
+      }
+
+      if(closeConnection && data->req.newurl) {
+        /* Connection closed by server. Don't use it anymore */
+        sclose(conn->sock[sockindex]);
+        conn->sock[sockindex] = CURL_SOCKET_BAD;
+        break;
+      }
+    } /* END NEGOTIATION PHASE */
+  } while(data->req.newurl);
+
+  if(200 != data->req.httpcode) {
+    failf(data, "Received HTTP code %d from proxy after CONNECT",
+          data->req.httpcode);
+
+    if(closeConnection && data->req.newurl)
+      conn->bits.proxy_connect_closed = TRUE;
+
+    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");
+  data->req.ignorebody = FALSE; /* put it (back) to non-ignore state */
+  return CURLE_OK;
+}
+#endif /* CURL_DISABLE_PROXY */
+
+/*
+ * Curl_http_connect() performs HTTP stuff to do at connect-time, called from
+ * the generic Curl_connect().
+ */
+CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
+{
+  struct SessionHandle *data;
+  CURLcode result;
+
+  data=conn->data;
+
+  /* We default to persistent connections. We set this already in this connect
+     function to make the re-use checks properly be able to check this bit. */
+  conn->bits.close = FALSE;
+
+#ifndef CURL_DISABLE_PROXY
+  /* 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 occurred, can we start talking SSL
+   */
+  if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
+
+    /* either SSL over proxy, or explicitly asked for */
+    result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
+                               conn->host.name,
+                               conn->remote_port);
+    if(CURLE_OK != result)
+      return result;
+  }
+
+  if(conn->bits.tunnel_connecting) {
+    /* nothing else to do except wait right now - we're not done here. */
+    return CURLE_OK;
+  }
+#endif /* CURL_DISABLE_PROXY */
+
+  if(conn->protocol & PROT_HTTPS) {
+    /* perform SSL initialization */
+    if(data->state.used_interface == Curl_if_multi) {
+      result = https_connecting(conn, done);
+      if(result)
+        return result;
+    }
+    else {
+      /* BLOCKING */
+      result = Curl_ssl_connect(conn, FIRSTSOCKET);
+      if(result)
+        return result;
+      *done = TRUE;
+    }
+  }
+  else {
+    *done = TRUE;
+  }
+
+  return CURLE_OK;
+}
+
+/* this returns the socket to wait for in the DO and DOING state for the multi
+   interface and then we're always _sending_ a request and thus we wait for
+   the single socket to become writable only */
+static int http_getsock_do(struct connectdata *conn,
+                           curl_socket_t *socks,
+                           int numsocks)
+{
+  /* write mode */
+  (void)numsocks; /* unused, we trust it to be at least 1 */
+  socks[0] = conn->sock[FIRSTSOCKET];
+  return GETSOCK_WRITESOCK(0);
+}
+
+#ifdef USE_SSL
+static CURLcode https_connecting(struct connectdata *conn, bool *done)
+{
+  CURLcode result;
+  DEBUGASSERT((conn) && (conn->protocol & PROT_HTTPS));
+
+  /* perform SSL initialization for this socket */
+  result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, done);
+  if(result)
+    conn->bits.close = TRUE; /* a failed connection is marked for closure
+                                to prevent (bad) re-use or similar */
+  return result;
+}
+#endif
+
+#ifdef USE_SSLEAY
+/* This function is OpenSSL-specific. It should be made to query the generic
+   SSL layer instead. */
+static int https_getsock(struct connectdata *conn,
+                         curl_socket_t *socks,
+                         int numsocks)
+{
+  if(conn->protocol & PROT_HTTPS) {
+    struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
+
+    if(!numsocks)
+      return GETSOCK_BLANK;
+
+    if(connssl->connecting_state == ssl_connect_2_writing) {
+      /* write mode */
+      socks[0] = conn->sock[FIRSTSOCKET];
+      return GETSOCK_WRITESOCK(0);
+    }
+    else if(connssl->connecting_state == ssl_connect_2_reading) {
+      /* read mode */
+      socks[0] = conn->sock[FIRSTSOCKET];
+      return GETSOCK_READSOCK(0);
+    }
+  }
+  return CURLE_OK;
+}
+#else
+#ifdef USE_GNUTLS
+static int https_getsock(struct connectdata *conn,
+                         curl_socket_t *socks,
+                         int numsocks)
+{
+  (void)conn;
+  (void)socks;
+  (void)numsocks;
+  return GETSOCK_BLANK;
+}
+#else
+#ifdef USE_NSS
+static int https_getsock(struct connectdata *conn,
+                         curl_socket_t *socks,
+                         int numsocks)
+{
+  (void)conn;
+  (void)socks;
+  (void)numsocks;
+  return GETSOCK_BLANK;
+}
+#else
+#ifdef USE_QSOSSL
+static int https_getsock(struct connectdata *conn,
+                         curl_socket_t *socks,
+                         int numsocks)
+{
+  (void)conn;
+  (void)socks;
+  (void)numsocks;
+  return GETSOCK_BLANK;
+}
+#endif
+#endif
+#endif
+#endif
+
+/*
+ * 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, bool premature)
+{
+  struct SessionHandle *data = conn->data;
+  struct HTTP *http =data->state.proto.http;
+  (void)premature; /* not used */
+
+  Curl_unencode_cleanup(conn);
+
+  /* set the proper values (possibly modified on POST) */
+  conn->fread_func = data->set.fread_func; /* restore */
+  conn->fread_in = data->set.in; /* restore */
+  conn->seek_func = data->set.seek_func; /* restore */
+  conn->seek_client = data->set.seek_client; /* restore */
+
+  if(http == NULL)
+    return CURLE_OK;
+
+  if(http->send_buffer) {
+    Curl_send_buffer *buff = http->send_buffer;
+
+    free(buff->buffer);
+    free(buff);
+    http->send_buffer = NULL; /* clear the pointer */
+  }
+
+  if(HTTPREQ_POST_FORM == data->set.httpreq) {
+    data->req.bytecount = http->readbytecount + http->writebytecount;
+
+    Curl_formclean(&http->sendit); /* Now free that whole lot */
+    if(http->form.fp) {
+      /* a file being uploaded was left opened, close it! */
+      fclose(http->form.fp);
+      http->form.fp = NULL;
+    }
+  }
+  else if(HTTPREQ_PUT == data->set.httpreq)
+    data->req.bytecount = http->readbytecount + http->writebytecount;
+
+  if(status != CURLE_OK)
+    return (status);
+
+  if(!premature && /* this check is pointless when DONE is called before the
+                      entire operation is complete */
+     !conn->bits.retry &&
+     ((http->readbytecount +
+       data->req.headerbytecount -
+       data->req.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;
+}
+
+
+/* Determine if we should use HTTP 1.1 for this request. Reasons to avoid it
+   are if the user specifically requested HTTP 1.0, if the server we are
+   connected to only supports 1.0, or if any server previously contacted to
+   handle this request only supports 1.0. */
+static bool use_http_1_1(const struct SessionHandle *data,
+                         const struct connectdata *conn)
+{
+  return (bool)((data->set.httpversion == CURL_HTTP_VERSION_1_1) ||
+         ((data->set.httpversion != CURL_HTTP_VERSION_1_0) &&
+          ((conn->httpversion == 11) ||
+           ((conn->httpversion != 10) &&
+            (data->state.httpversion != 10)))));
+}
+
+/* check and possibly add an Expect: header */
+static CURLcode expect100(struct SessionHandle *data,
+                          struct connectdata *conn,
+                          Curl_send_buffer *req_buffer)
+{
+  CURLcode result = CURLE_OK;
+  const char *ptr;
+  data->state.expect100header = FALSE; /* default to false unless it is set
+                                          to TRUE below */
+  if(use_http_1_1(data, conn)) {
+    /* if not doing HTTP 1.0 or 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) */
+    ptr = Curl_checkheaders(data, "Expect:");
+    if (ptr) {
+      data->state.expect100header =
+        Curl_compareheader(ptr, "Expect:", "100-continue");
+    }
+    else {
+      result = Curl_add_bufferf(req_buffer,
+                         "Expect: 100-continue\r\n");
+      if(result == CURLE_OK)
+        data->state.expect100header = TRUE;
+    }
+  }
+  return result;
+}
+
+CURLcode Curl_add_custom_headers(struct connectdata *conn,
+                                   Curl_send_buffer *req_buffer)
+{
+  char *ptr;
+  struct curl_slist *headers=conn->data->set.headers;
+
+  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(*ptr))
+        ptr++;
+
+      if(*ptr) {
+        /* only send this if the contents was non-blank */
+
+        if(conn->allocptr.host &&
+           /* a Host: header was sent already, don't pass on any custom Host:
+              header as that will produce *two* in the same request! */
+           checkprefix("Host:", headers->data))
+          ;
+        else if(conn->data->set.httpreq == HTTPREQ_POST_FORM &&
+                /* this header (extended by formdata.c) is sent later */
+                checkprefix("Content-Type:", headers->data))
+          ;
+        else if(conn->bits.authneg &&
+                /* while doing auth neg, don't allow the custom length since
+                   we will force length zero then */
+                checkprefix("Content-Length", headers->data))
+          ;
+        else {
+          CURLcode result = Curl_add_bufferf(req_buffer, "%s\r\n",
+                                             headers->data);
+          if(result)
+            return result;
+        }
+      }
+    }
+    headers = headers->next;
+  }
+  return CURLE_OK;
+}
+
+CURLcode Curl_add_timecondition(struct SessionHandle *data,
+                                Curl_send_buffer *req_buffer)
+{
+  struct tm *tm;
+  char *buf = data->state.buffer;
+  CURLcode result = CURLE_OK;
+
+  /* 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;
+  tm = (struct tm *)gmtime_r(&data->set.timevalue, &keeptime);
+#else
+  tm = gmtime(&data->set.timevalue);
+#endif
+
+  /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
+  snprintf(buf, BUFSIZE-1,
+           "%s, %02d %s %4d %02d:%02d:%02d GMT",
+           Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+           tm->tm_mday,
+           Curl_month[tm->tm_mon],
+           tm->tm_year + 1900,
+           tm->tm_hour,
+           tm->tm_min,
+           tm->tm_sec);
+
+  switch(data->set.timecondition) {
+  case CURL_TIMECOND_IFMODSINCE:
+  default:
+    result = Curl_add_bufferf(req_buffer,
+                              "If-Modified-Since: %s\r\n", buf);
+    break;
+  case CURL_TIMECOND_IFUNMODSINCE:
+    result = Curl_add_bufferf(req_buffer,
+                              "If-Unmodified-Since: %s\r\n", buf);
+    break;
+  case CURL_TIMECOND_LASTMOD:
+    result = Curl_add_bufferf(req_buffer,
+                              "Last-Modified: %s\r\n", buf);
+    break;
+  }
+
+  return result;
+}
+
+/*
+ * 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, bool *done)
+{
+  struct SessionHandle *data=conn->data;
+  CURLcode result=CURLE_OK;
+  struct HTTP *http;
+  const char *ppath = data->state.path;
+  bool paste_ftp_userpwd = FALSE;
+  char ftp_typecode[sizeof("/;type=?")] = "";
+  const char *host = conn->host.name;
+  const char *te = ""; /* transfer-encoding */
+  const char *ptr;
+  const char *request;
+  Curl_HttpReq httpreq = data->set.httpreq;
+  char *addcookies = NULL;
+  curl_off_t included_body = 0;
+  const char *httpstring;
+  Curl_send_buffer *req_buffer;
+  curl_off_t postsize; /* off_t type to be able to hold a large file size */
+  int seekerr = CURL_SEEKFUNC_OK;
+
+  /* Always consider the DO phase done after this function call, even if there
+     may be parts of the request that is not yet sent, since we can deal with
+     the rest of the request in the PERFORM phase. */
+  *done = TRUE;
+
+  /* If there already is a protocol-specific struct allocated for this
+     sessionhandle, deal with it */
+  Curl_reset_reqproto(conn);
+
+  if(!data->state.proto.http) {
+    /* Only allocate this struct if we don't already have it! */
+
+    http = calloc(1, sizeof(struct HTTP));
+    if(!http)
+      return CURLE_OUT_OF_MEMORY;
+    data->state.proto.http = http;
+  }
+  else
+    http = data->state.proto.http;
+
+  if(!data->state.this_is_a_follow) {
+    /* this is not a followed location, get the original host name */
+    if(data->state.first_host)
+      /* Free to avoid leaking memory on multiple requests*/
+      free(data->state.first_host);
+
+    data->state.first_host = strdup(conn->host.name);
+    if(!data->state.first_host)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  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.str[STRING_CUSTOMREQUEST])
+    request = data->set.str[STRING_CUSTOMREQUEST];
+  else {
+    if(data->set.opt_no_body)
+      request = "HEAD";
+    else {
+      DEBUGASSERT((httpreq > HTTPREQ_NONE) && (httpreq < HTTPREQ_LAST));
+      switch(httpreq) {
+      case HTTPREQ_POST:
+      case HTTPREQ_POST_FORM:
+        request = "POST";
+        break;
+      case HTTPREQ_PUT:
+        request = "PUT";
+        break;
+      default: /* this should never happen */
+      case HTTPREQ_GET:
+        request = "GET";
+        break;
+      case HTTPREQ_HEAD:
+        request = "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(Curl_checkheaders(data, "User-Agent:") && conn->allocptr.uagent) {
+    free(conn->allocptr.uagent);
+    conn->allocptr.uagent=NULL;
+  }
+
+  /* setup the authentication headers */
+  result = http_output_auth(conn, request, ppath, FALSE);
+  if(result)
+    return result;
+
+  if((data->state.authhost.multi || data->state.authproxy.multi) &&
+     (httpreq != HTTPREQ_GET) &&
+     (httpreq != HTTPREQ_HEAD)) {
+    /* Auth is required and we are not authenticated yet. Make a PUT or POST
+       with content-length zero as a "probe". */
+    conn->bits.authneg = TRUE;
+  }
+  else
+    conn->bits.authneg = FALSE;
+
+  Curl_safefree(conn->allocptr.ref);
+  if(data->change.referer && !Curl_checkheaders(data, "Referer:"))
+    conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
+  else
+    conn->allocptr.ref = NULL;
+
+  if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(data, "Cookie:"))
+    addcookies = data->set.str[STRING_COOKIE];
+
+  if(!Curl_checkheaders(data, "Accept-Encoding:") &&
+     data->set.str[STRING_ENCODING]) {
+    Curl_safefree(conn->allocptr.accept_encoding);
+    conn->allocptr.accept_encoding =
+      aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
+    if(!conn->allocptr.accept_encoding)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  ptr = Curl_checkheaders(data, "Transfer-Encoding:");
+  if(ptr) {
+    /* Some kind of TE is requested, check if 'chunked' is chosen */
+    data->req.upload_chunky =
+      Curl_compareheader(ptr, "Transfer-Encoding:", "chunked");
+  }
+  else {
+    if((conn->protocol&PROT_HTTP) &&
+        data->set.upload &&
+        (data->set.infilesize == -1)) {
+      if (use_http_1_1(data, conn)) {
+        /* HTTP, upload, unknown file size and not HTTP 1.0 */
+        data->req.upload_chunky = TRUE;
+      }
+      else {
+        failf(data, "Chunky upload is not supported by HTTP 1.0");
+        return CURLE_UPLOAD_FAILED;
+      }
+    }
+    else {
+      /* else, no chunky upload */
+      data->req.upload_chunky = FALSE;
+    }
+
+    if(data->req.upload_chunky)
+      te = "Transfer-Encoding: chunked\r\n";
+  }
+
+  Curl_safefree(conn->allocptr.host);
+
+  ptr = Curl_checkheaders(data, "Host:");
+  if(ptr && (!data->state.this_is_a_follow ||
+             Curl_raw_equal(data->state.first_host, conn->host.name))) {
+#if !defined(CURL_DISABLE_COOKIES)
+    /* 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. Except if the host name
+       is the same as the first one! */
+    char *cookiehost = Curl_copy_header_value(ptr);
+    if (!cookiehost)
+      return CURLE_OUT_OF_MEMORY;
+    if (!*cookiehost)
+      /* ignore empty data */
+      free(cookiehost);
+    else {
+      char *colon = strchr(cookiehost, ':');
+      if (colon)
+        *colon = 0; /* The host must not include an embedded port number */
+      Curl_safefree(conn->allocptr.cookiehost);
+      conn->allocptr.cookiehost = cookiehost;
+    }
+#endif
+
+    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:%hu\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;
+  }
+
+#ifndef CURL_DISABLE_PROXY
+  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;
+      ptr = strstr(url, conn->host.dispname);
+      if(ptr) {
+        /* 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, ptr - url);
+          /* append the new host name instead of the old */
+          memcpy(newurl + (ptr - url), conn->host.name, newlen);
+          /* append the piece after the host name */
+          memcpy(newurl + newlen + (ptr - url),
+                 ptr + currlen, /* copy the trailing zero byte too */
+                 urllen - (ptr-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(checkprefix("ftp://", ppath)) {
+      if (data->set.proxy_transfer_mode) {
+        /* when doing ftp, append ;type=<a|i> if not present */
+        char *type = strstr(ppath, ";type=");
+        if(type && type[6] && type[7] == 0) {
+          switch (Curl_raw_toupper(type[6])) {
+          case 'A':
+          case 'D':
+          case 'I':
+            break;
+          default:
+            type = NULL;
+          }
+        }
+        if(!type) {
+          char *p = ftp_typecode;
+          /* avoid sending invalid URLs like ftp://example.com;type=i if the
+           * user specified ftp://example.com without the slash */
+          if (!*data->state.path && ppath[strlen(ppath) - 1] != '/') {
+            *p++ = '/';
+          }
+          snprintf(p, sizeof(ftp_typecode) - 1, ";type=%c",
+                   data->set.prefer_ascii ? 'a' : 'i');
+        }
+      }
+      if (conn->bits.user_passwd && !conn->bits.userpwd_in_url)
+        paste_ftp_userpwd = TRUE;
+    }
+  }
+#endif /* CURL_DISABLE_PROXY */
+
+  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,
+                               Curl_checkheaders(data, "Content-Type:"),
+                               &http->postsize);
+     if(CURLE_OK != result) {
+       /* Curl_getFormData() doesn't use failf() */
+       failf(data, "failed creating formpost data");
+       return result;
+     }
+  }
+
+
+  http->p_accept = Curl_checkheaders(data, "Accept:")?NULL:"Accept: */*\r\n";
+
+  if(( (HTTPREQ_POST == httpreq) ||
+       (HTTPREQ_POST_FORM == httpreq) ||
+       (HTTPREQ_PUT == httpreq) ) &&
+     data->state.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(data->state.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!
+       */
+       data->state.resume_from = 0;
+    }
+
+    if(data->state.resume_from && !data->state.this_is_a_follow) {
+      /* do we still game? */
+
+      /* Now, let's read off the proper amount of bytes from the
+         input. */
+      if(conn->seek_func) {
+        seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
+                                  SEEK_SET);
+      }
+
+      if(seekerr != CURL_SEEKFUNC_OK) {
+        if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
+          failf(data, "Could not seek stream");
+          return CURLE_READ_ERROR;
+        }
+        /* when seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
+        else {
+          curl_off_t passed=0;
+
+          do {
+            size_t readthisamountnow = (size_t)(data->state.resume_from -
+                                                passed);
+            size_t actuallyread;
+
+            if(readthisamountnow > BUFSIZE)
+              readthisamountnow = BUFSIZE;
+
+            actuallyread = data->set.fread_func(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 != data->state.resume_from); /* loop until done */
+        }
+      }
+
+      /* now, decrease the size of the read */
+      if(data->set.infilesize>0) {
+        data->set.infilesize -= data->state.resume_from;
+
+        if(data->set.infilesize <= 0) {
+          failf(data, "File already completely uploaded");
+          return CURLE_PARTIAL_FILE;
+        }
+      }
+      /* we've passed, proceed as normal */
+    }
+  }
+  if(data->state.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) || (httpreq == HTTPREQ_HEAD)) &&
+       !Curl_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",
+                                         data->state.range);
+    }
+    else if((httpreq != HTTPREQ_GET) &&
+            !Curl_checkheaders(data, "Content-Range:")) {
+
+      /* if a line like this was already allocated, free the previous one */
+      if(conn->allocptr.rangeline)
+        free(conn->allocptr.rangeline);
+
+      if(data->set.set_resume_from < 0) {
+        /* Upload resume was asked for, but we don't know the size of the
+           remote part so we tell the server (and act accordingly) that we
+           upload the whole file (again) */
+        conn->allocptr.rangeline =
+          aprintf("Content-Range: bytes 0-%" FORMAT_OFF_T
+                  "/%" FORMAT_OFF_T "\r\n",
+                  data->set.infilesize - 1, data->set.infilesize);
+
+      }
+      else if(data->state.resume_from) {
+        /* This is because "resume" was selected */
+        curl_off_t total_expected_size=
+          data->state.resume_from + data->set.infilesize;
+        conn->allocptr.rangeline =
+            aprintf("Content-Range: bytes %s%" FORMAT_OFF_T
+                    "/%" FORMAT_OFF_T "\r\n",
+                    data->state.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",
+                    data->state.range, data->set.infilesize);
+      }
+      if(!conn->allocptr.rangeline)
+        return CURLE_OUT_OF_MEMORY;
+    }
+  }
+
+  /* Use 1.1 unless the user specifically asked for 1.0 or the server only
+     supports 1.0 */
+  httpstring= use_http_1_1(data, conn)?"1.1":"1.0";
+
+  /* initialize a dynamic send-buffer */
+  req_buffer = Curl_add_buffer_init();
+
+  if(!req_buffer)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* add the main request stuff */
+  /* GET/HEAD/POST/PUT */
+  result = Curl_add_bufferf(req_buffer, "%s ", request);
+  if (result)
+    return result;
+
+  /* url */
+  if (paste_ftp_userpwd)
+    result = Curl_add_bufferf(req_buffer, "ftp://%s:%s@%s",
+        conn->user, conn->passwd, ppath + sizeof("ftp://") - 1);
+  else
+    result = Curl_add_buffer(req_buffer, ppath, strlen(ppath));
+  if (result)
+    return result;
+
+  result = Curl_add_bufferf(req_buffer,
+                "%s" /* ftp typecode (;type=x) */
+                " HTTP/%s\r\n" /* HTTP version */
+                "%s" /* proxyuserpwd */
+                "%s" /* userpwd */
+                "%s" /* range */
+                "%s" /* user agent */
+                "%s" /* host */
+                "%s" /* accept */
+                "%s" /* accept-encoding */
+                "%s" /* referer */
+                "%s" /* Proxy-Connection */
+                "%s",/* transfer-encoding */
+
+                ftp_typecode,
+                httpstring,
+                conn->allocptr.proxyuserpwd?
+                conn->allocptr.proxyuserpwd:"",
+                conn->allocptr.userpwd?conn->allocptr.userpwd:"",
+                (data->state.use_range && conn->allocptr.rangeline)?
+                conn->allocptr.rangeline:"",
+                (data->set.str[STRING_USERAGENT] &&
+                 *data->set.str[STRING_USERAGENT] && conn->allocptr.uagent)?
+                conn->allocptr.uagent:"",
+                (conn->allocptr.host?conn->allocptr.host:""), /* Host: host */
+                http->p_accept?http->p_accept:"",
+                (data->set.str[STRING_ENCODING] &&
+                 *data->set.str[STRING_ENCODING] &&
+                 conn->allocptr.accept_encoding)?
+                conn->allocptr.accept_encoding:"",
+                (data->change.referer && conn->allocptr.ref)?
+                conn->allocptr.ref:"" /* Referer: <data> */,
+                (conn->bits.httpproxy &&
+                 !conn->bits.tunnel_proxy &&
+                 !Curl_checkheaders(data, "Proxy-Connection:"))?
+                "Proxy-Connection: Keep-Alive\r\n":"",
+                te
+      );
+
+  /*
+   * Free userpwd now --- cannot reuse this for Negotiate and possibly NTLM
+   * with basic and digest, it will be freed anyway by the next request
+   */
+
+  Curl_safefree (conn->allocptr.userpwd);
+  conn->allocptr.userpwd = NULL;
+
+  if(result)
+    return result;
+
+#if !defined(CURL_DISABLE_COOKIES)
+  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,
+                               data->state.path,
+                               (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 = Curl_add_bufferf(req_buffer, "Cookie: ");
+            if(result)
+              break;
+          }
+          result = Curl_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, FALSE); /* free the cookie list */
+    }
+    if(addcookies && (CURLE_OK == result)) {
+      if(!count)
+        result = Curl_add_bufferf(req_buffer, "Cookie: ");
+      if(CURLE_OK == result) {
+        result = Curl_add_bufferf(req_buffer, "%s%s",
+                             count?"; ":"",
+                             addcookies);
+        count++;
+      }
+    }
+    if(count && (CURLE_OK == result))
+      result = Curl_add_buffer(req_buffer, "\r\n", 2);
+
+    if(result)
+      return result;
+  }
+#endif
+
+  if(data->set.timecondition) {
+      result = Curl_add_timecondition(data, req_buffer);
+    if(result)
+      return result;
+  }
+
+  result = Curl_add_custom_headers(conn, req_buffer);
+  if(result)
+    return result;
+
+  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(!http->sendit || conn->bits.authneg) {
+      /* nothing to post! */
+      result = Curl_add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n");
+      if(result)
+        return result;
+
+      result = Curl_add_buffer_send(req_buffer, conn,
+                               &data->info.request_size, 0, FIRSTSOCKET);
+      if(result)
+        failf(data, "Failed sending POST request");
+      else
+        /* setup variables for the upcoming transfer */
+        result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
+                                     &http->readbytecount,
+                                     -1, NULL);
+      break;
+    }
+
+    if(Curl_FormInit(&http->form, http->sendit)) {
+      failf(data, "Internal HTTP POST error!");
+      return CURLE_HTTP_POST_ERROR;
+    }
+
+    /* Get the currently set callback function pointer and store that in the
+       form struct since we might want the actual user-provided callback later
+       on. The conn->fread_func pointer itself will be changed for the
+       multipart case to the function that returns a multipart formatted
+       stream. */
+    http->form.fread_func = conn->fread_func;
+
+    /* Set the read function to read from the generated form data */
+    conn->fread_func = (curl_read_callback)Curl_FormReader;
+    conn->fread_in = &http->form;
+
+    http->sending = HTTPSEND_BODY;
+
+    if(!data->req.upload_chunky) {
+      /* only add Content-Length if not uploading chunked */
+      result = Curl_add_bufferf(req_buffer,
+                           "Content-Length: %" FORMAT_OFF_T "\r\n",
+                           http->postsize);
+      if(result)
+        return result;
+    }
+
+    result = expect100(data, conn, req_buffer);
+    if(result)
+      return result;
+
+    {
+
+      /* Get Content-Type: line from Curl_formpostheader.
+       */
+      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 = Curl_add_buffer(req_buffer, contentType, linelength);
+      if(result)
+        return result;
+    }
+
+    /* make the request end in a true CRLF */
+    result = Curl_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 = Curl_add_buffer_send(req_buffer, conn,
+                             &data->info.request_size, 0, FIRSTSOCKET);
+    if(result)
+      failf(data, "Failed sending POST request");
+    else
+      /* setup variables for the upcoming transfer */
+      result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
+                                   &http->readbytecount,
+                                   FIRSTSOCKET,
+                                   &http->writebytecount);
+
+    if(result) {
+      Curl_formclean(&http->sendit); /* free that whole lot */
+      return result;
+    }
+#ifdef CURL_DOES_CONVERSIONS
+/* time to convert the form data... */
+    result = Curl_formconvert(data, http->sendit);
+    if(result) {
+      Curl_formclean(&http->sendit); /* free that whole lot */
+      return result;
+    }
+#endif /* CURL_DOES_CONVERSIONS */
+    break;
+
+  case HTTPREQ_PUT: /* Let's PUT the data to the server! */
+
+    if(conn->bits.authneg)
+      postsize = 0;
+    else
+      postsize = data->set.infilesize;
+
+    if((postsize != -1) && !data->req.upload_chunky) {
+      /* only add Content-Length if not uploading chunked */
+      result = Curl_add_bufferf(req_buffer,
+                           "Content-Length: %" FORMAT_OFF_T "\r\n",
+                           postsize );
+      if(result)
+        return result;
+    }
+
+    result = expect100(data, conn, req_buffer);
+    if(result)
+      return result;
+
+    result = Curl_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, postsize);
+
+    /* this sends the buffer and frees all the buffer resources */
+    result = Curl_add_buffer_send(req_buffer, conn,
+                             &data->info.request_size, 0, FIRSTSOCKET);
+    if(result)
+      failf(data, "Failed sending PUT request");
+    else
+      /* prepare for transfer */
+      result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
+                                   &http->readbytecount,
+                                   postsize?FIRSTSOCKET:-1,
+                                   postsize?&http->writebytecount:NULL);
+    if(result)
+      return result;
+    break;
+
+  case HTTPREQ_POST:
+    /* this is the simple POST, using x-www-form-urlencoded style */
+
+    if(conn->bits.authneg)
+      postsize = 0;
+    else {
+      /* figure out the size of the postfields */
+      postsize = (data->set.postfieldsize != -1)?
+        data->set.postfieldsize:
+        (data->set.postfields? (curl_off_t)strlen(data->set.postfields):-1);
+    }
+    if(!data->req.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(conn->bits.authneg || !Curl_checkheaders(data, "Content-Length:")) {
+        /* we allow replacing this header if not during auth negotiation,
+           although it isn't very wise to actually set your own */
+        result = Curl_add_bufferf(req_buffer,
+                             "Content-Length: %" FORMAT_OFF_T"\r\n",
+                             postsize);
+        if(result)
+          return result;
+      }
+    }
+
+    if(!Curl_checkheaders(data, "Content-Type:")) {
+      result = Curl_add_bufferf(req_buffer,
+                                "Content-Type: application/"
+                                "x-www-form-urlencoded\r\n");
+      if(result)
+        return result;
+    }
+
+    /* For really small posts we don't use Expect: headers at all, and for
+       the somewhat bigger ones we allow the app to disable it. Just make
+       sure that the expect100header is always set to the preferred value
+       here. */
+    ptr = Curl_checkheaders(data, "Expect:");
+    if(ptr) {
+      data->state.expect100header =
+        Curl_compareheader(ptr, "Expect:", "100-continue");
+    }
+    else if(postsize > TINY_INITIAL_POST_SIZE || postsize < 0) {
+      result = expect100(data, conn, req_buffer);
+      if(result)
+        return result;
+    }
+    else
+      data->state.expect100header = FALSE;
+
+    if(data->set.postfields) {
+
+      if(!data->state.expect100header &&
+         (postsize < MAX_INITIAL_POST_SIZE))  {
+        /* if we don't use expect: 100  AND
+           postsize is less than MAX_INITIAL_POST_SIZE
+
+           then append the post data to the HTTP request 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 = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
+        if(result)
+          return result;
+
+        if(!data->req.upload_chunky) {
+          /* We're not sending it 'chunked', append it to the request
+             already now to reduce the number if send() calls */
+          result = Curl_add_buffer(req_buffer, data->set.postfields,
+                              (size_t)postsize);
+          included_body = postsize;
+        }
+        else {
+          /* Append the POST data chunky-style */
+          result = Curl_add_bufferf(req_buffer, "%x\r\n", (int)postsize);
+          if(CURLE_OK == result)
+            result = Curl_add_buffer(req_buffer, data->set.postfields,
+                                (size_t)postsize);
+          if(CURLE_OK == result)
+            result = Curl_add_buffer(req_buffer,
+                                "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7);
+          /* CR  LF   0  CR  LF  CR  LF */
+          included_body = postsize + 7;
+        }
+        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_func = (curl_read_callback)readmoredata;
+        conn->fread_in = (void *)conn;
+
+        /* set the upload size to the progress meter */
+        Curl_pgrsSetUploadSize(data, http->postsize);
+
+        result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
+        if(result)
+          return result;
+      }
+    }
+    else {
+      result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
+      if(result)
+        return result;
+
+      if(data->req.upload_chunky && conn->bits.authneg) {
+        /* Chunky upload is selected and we're negotiating auth still, send
+           end-of-data only */
+        result = Curl_add_buffer(req_buffer,
+                            "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7);
+        /* CR  LF   0  CR  LF  CR  LF */
+        if(result)
+          return result;
+      }
+
+      else if(data->set.postfieldsize) {
+        /* set the upload size to the progress meter */
+        Curl_pgrsSetUploadSize(data, postsize?postsize:-1);
+
+        /* set the pointer to mark that we will send the post body using the
+           read callback, but only if we're not in authenticate
+           negotiation  */
+        if(!conn->bits.authneg) {
+          http->postdata = (char *)&http->postdata;
+          http->postsize = postsize;
+        }
+      }
+    }
+    /* issue the request */
+    result = Curl_add_buffer_send(req_buffer, conn, &data->info.request_size,
+                             (size_t)included_body, FIRSTSOCKET);
+
+    if(result)
+      failf(data, "Failed sending HTTP POST request");
+    else
+      result =
+        Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
+                            &http->readbytecount,
+                            http->postdata?FIRSTSOCKET:-1,
+                            http->postdata?&http->writebytecount:NULL);
+    break;
+
+  default:
+    result = Curl_add_buffer(req_buffer, "\r\n", 2);
+    if(result)
+      return result;
+
+    /* issue the request */
+    result = Curl_add_buffer_send(req_buffer, conn,
+                             &data->info.request_size, 0, FIRSTSOCKET);
+
+    if(result)
+      failf(data, "Failed sending HTTP request");
+    else
+      /* HTTP GET/HEAD download: */
+      result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
+                                   &http->readbytecount,
+                                   http->postdata?FIRSTSOCKET:-1,
+                                   http->postdata?&http->writebytecount:NULL);
+  }
+  if(result)
+    return result;
+
+  if(http->writebytecount) {
+    /* if a request-body has been sent off, we make sure this progress is noted
+       properly */
+    Curl_pgrsSetUploadCounter(data, http->writebytecount);
+    if(Curl_pgrsUpdate(conn))
+      result = CURLE_ABORTED_BY_CALLBACK;
+  }
+
+  return result;
+}
+
+/*
+ * 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;
+  bool rc = FALSE;
+#ifdef CURL_DOES_CONVERSIONS
+  /* convert from the network encoding using a scratch area */
+  char *scratch = strdup(s);
+  if(NULL == scratch) {
+     failf (data, "Failed to allocate memory for conversion!");
+     return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
+  }
+  if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) {
+    /* Curl_convert_from_network calls failf if unsuccessful */
+     free(scratch);
+     return FALSE; /* can't return CURLE_foobar so return FALSE */
+  }
+  s = scratch;
+#endif /* CURL_DOES_CONVERSIONS */
+
+  while(head) {
+    if(checkprefix(head->data, s)) {
+      rc = TRUE;
+      break;
+    }
+    head = head->next;
+  }
+
+  if((rc != TRUE) && (checkprefix("HTTP/", s))) {
+    rc = TRUE;
+  }
+
+#ifdef CURL_DOES_CONVERSIONS
+  free(scratch);
+#endif /* CURL_DOES_CONVERSIONS */
+  return rc;
+}
+
+#ifndef CURL_DISABLE_RTSP
+static bool
+checkrtspprefix(struct SessionHandle *data,
+                const char *s)
+{
+
+#ifdef CURL_DOES_CONVERSIONS
+  /* convert from the network encoding using a scratch area */
+  char *scratch = strdup(s);
+  if(NULL == scratch) {
+    failf (data, "Failed to allocate memory for conversion!");
+    return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
+  }
+  if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) {
+    /* Curl_convert_from_network calls failf if unsuccessful */
+    free(scratch);
+    return FALSE; /* can't return CURLE_foobar so return FALSE */
+  }
+  s = scratch;
+#else
+  (void)data; /* unused */
+#endif /* CURL_DOES_CONVERSIONS */
+  if(checkprefix("RTSP/", s))
+    return TRUE;
+  else
+    return FALSE;
+}
+#endif /* CURL_DISABLE_RTSP */
+
+static bool
+checkprotoprefix(struct SessionHandle *data, struct connectdata *conn,
+                 const char *s)
+{
+#ifndef CURL_DISABLE_RTSP
+  if(conn->protocol & PROT_RTSP)
+    return checkrtspprefix(data, s);
+#else
+  (void)conn;
+#endif /* CURL_DISABLE_RTSP */
+
+  return checkhttpprefix(data, s);
+}
+
+/*
+ * header_append() copies 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.
+ */
+static CURLcode header_append(struct SessionHandle *data,
+                              struct SingleRequest *k,
+                              size_t length)
+{
+  if(k->hbuflen + length >= data->state.headersize) {
+    /* We enlarge the header buffer as it is too small */
+    char *newbuff;
+    size_t hbufp_index;
+    size_t newsize;
+
+    if(k->hbuflen + length > CURL_MAX_HTTP_HEADER) {
+      /* The reason to have a max limit for this is to avoid the risk of a bad
+         server feeding libcurl with a never-ending header that will cause
+         reallocs infinitely */
+      failf (data, "Avoided giant realloc for header (max is %d)!",
+             CURL_MAX_HTTP_HEADER);
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    newsize=CURLMAX((k->hbuflen+ length)*3/2, data->state.headersize*2);
+    hbufp_index = k->hbufp - data->state.headerbuff;
+    newbuff = 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_start, length);
+  k->hbufp += length;
+  k->hbuflen += length;
+  *k->hbufp = 0;
+
+  return CURLE_OK;
+}
+
+
+/*
+ * Read any HTTP header lines from the server and pass them to the client app.
+ */
+CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
+                                       struct connectdata *conn,
+                                       ssize_t *nread,
+                                       bool *stop_reading)
+{
+  CURLcode result;
+  struct SingleRequest *k = &data->req;
+
+  /* header line within buffer loop */
+  do {
+    size_t rest_length;
+    size_t full_length;
+    int writetype;
+
+    /* str_start is start of line within buf */
+    k->str_start = k->str;
+
+    /* data is in network encoding so use 0x0a instead of '\n' */
+    k->end_ptr = memchr(k->str_start, 0x0a, *nread);
+
+    if(!k->end_ptr) {
+      /* Not a complete header line within buffer, append the data to
+         the end of the headerbuff. */
+      result = header_append(data, k, *nread);
+      if(result)
+        return result;
+
+      if(!k->headerline && (k->hbuflen>5)) {
+        /* make a first check that this looks like a protocol header */
+        if(!checkprotoprefix(data, conn, data->state.headerbuff)) {
+          /* this is not the beginning of a protocol 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 -= (ssize_t)rest_length;
+
+    k->str = k->end_ptr + 1; /* move past new line */
+
+    full_length = k->str - k->str_start;
+
+    result = header_append(data, k, full_length);
+    if(result)
+      return result;
+
+    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) &&
+         !checkprotoprefix(data, conn, data->state.headerbuff)) {
+        /* this is not the beginning of a protocol 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 it's all a bad header */
+          k->badheader = HEADER_ALLBAD;
+          *nread = (ssize_t)rest_length;
+        }
+        break;
+      }
+    }
+
+    /* headers are in network encoding so
+       use 0x0a and 0x0d instead of '\n' and '\r' */
+    if((0x0a == *k->p) || (0x0d == *k->p)) {
+      size_t headerlen;
+      /* Zero-length header line means end of headers! */
+
+#ifdef CURL_DOES_CONVERSIONS
+      if(0x0d == *k->p) {
+        *k->p = '\r'; /* replace with CR in host encoding */
+        k->p++;       /* pass the CR byte */
+      }
+      if(0x0a == *k->p) {
+        *k->p = '\n'; /* replace with LF in host encoding */
+        k->p++;       /* pass the LF byte */
+      }
+#else
+      if('\r' == *k->p)
+        k->p++; /* pass the \r byte */
+      if('\n' == *k->p)
+        k->p++; /* pass the \n byte */
+#endif /* CURL_DOES_CONVERSIONS */
+
+      if(100 <= k->httpcode && 199 >= 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->exp100) {
+          k->exp100 = EXP100_SEND_DATA;
+          k->keepon |= KEEP_SEND;
+        }
+      }
+      else {
+        k->header = FALSE; /* no more header to parse! */
+
+        if((k->size == -1) && !k->chunk && !conn->bits.close &&
+           (conn->httpversion >= 11) && !(conn->protocol & PROT_RTSP)) {
+          /* On HTTP 1.1, when connection is not to get closed, but no
+             Content-Length nor Content-Encoding chunked have been
+             received, according to RFC2616 section 4.4 point 5, we
+             assume that the server will close the connection to
+             signal the end of the document. */
+          infof(data, "no chunk, no close, no size. Assume close to "
+                "signal end\n");
+          conn->bits.close = TRUE;
+        }
+      }
+
+      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->exp100 = EXP100_FAILED;
+        k->keepon &= ~KEEP_SEND;
+      }
+
+      /*
+       * 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;
+      }
+
+      /* 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(conn, writetype,
+                                 data->state.headerbuff,
+                                 headerlen);
+      if(result)
+        return result;
+
+      data->info.header_size += (long)headerlen;
+      data->req.headerbytecount += (long)headerlen;
+
+      data->req.deductheadercount =
+        (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0;
+
+      if(data->state.resume_from &&
+         (data->set.httpreq==HTTPREQ_GET) &&
+         (k->httpcode == 416)) {
+        /* "Requested Range Not Satisfiable" */
+        *stop_reading = TRUE;
+      }
+
+      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 method was picked. */
+        result = Curl_http_auth_act(conn);
+
+        if(result)
+          return result;
+
+        if(conn->bits.rewindaftersend) {
+          /* We rewind after a complete send, so thus we continue
+             sending now */
+          infof(data, "Keep sending data to get tossed away!\n");
+          k->keepon |= KEEP_SEND;
+        }
+      }
+
+      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(data->set.opt_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(k->chunk)
+            k->maxdownload = k->size = -1;
+        }
+        if(-1 != k->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, k->size);
+          k->maxdownload = k->size;
+        }
+
+        /* If max download size is *zero* (nothing) we already
+           have nothing and can safely return ok now! */
+        if(0 == k->maxdownload)
+          *stop_reading = TRUE;
+
+        if(*stop_reading) {
+          /* we make sure that this socket isn't read more now */
+          k->keepon &= ~KEEP_RECV;
+        }
+
+        if(data->set.verbose)
+          Curl_debug(data, CURLINFO_HEADER_IN,
+                     k->str_start, headerlen, conn);
+        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 consider this to be the body right away! */
+      int httpversion_major;
+      int rtspversion_major;
+      int nc = 0;
+#ifdef CURL_DOES_CONVERSIONS
+#define HEADER1 scratch
+#define SCRATCHSIZE 21
+      CURLcode res;
+      char scratch[SCRATCHSIZE+1]; /* "HTTP/major.minor 123" */
+      /* We can't really convert this yet because we
+         don't know if it's the 1st header line or the body.
+         So we do a partial conversion into a scratch area,
+         leaving the data at k->p as-is.
+      */
+      strncpy(&scratch[0], k->p, SCRATCHSIZE);
+      scratch[SCRATCHSIZE] = 0; /* null terminate */
+      res = Curl_convert_from_network(data,
+                                      &scratch[0],
+                                      SCRATCHSIZE);
+      if(CURLE_OK != res) {
+        /* Curl_convert_from_network calls failf if unsuccessful */
+        return res;
+      }
+#else
+#define HEADER1 k->p /* no conversion needed, just use k->p */
+#endif /* CURL_DOES_CONVERSIONS */
+
+      if(conn->protocol & PROT_HTTP) {
+        nc = sscanf(HEADER1,
+            " HTTP/%d.%d %3d",
+            &httpversion_major,
+            &conn->httpversion,
+            &k->httpcode);
+        if(nc==3) {
+          conn->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(HEADER1, " HTTP %3d", &k->httpcode);
+          conn->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;
+              conn->httpversion = 10;
+            }
+          }
+        }
+      }
+      else if(conn->protocol & PROT_RTSP) {
+        nc = sscanf(HEADER1,
+                    " RTSP/%d.%d %3d",
+                    &rtspversion_major,
+                    &conn->rtspversion,
+                    &k->httpcode);
+        if(nc==3) {
+          conn->rtspversion += 10 * rtspversion_major;
+          conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */
+        }
+        else {
+          /* TODO: do we care about the other cases here? */
+          nc = 0;
+        }
+      }
+
+      if(nc) {
+        data->info.httpcode = k->httpcode;
+
+        data->info.httpversion = conn->httpversion;
+        if (!data->state.httpversion ||
+            data->state.httpversion > conn->httpversion)
+          /* store the lowest server version we encounter */
+          data->state.httpversion = conn->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) || !conn->bits.user_passwd) &&
+           ((k->httpcode != 407) || !conn->bits.proxy_user_passwd) ) {
+
+          if(data->state.resume_from &&
+             (data->set.httpreq==HTTPREQ_GET) &&
+             (k->httpcode == 416)) {
+            /* "Requested Range Not Satisfiable", just proceed and
+               pretend this is no error */
+          }
+          else {
+            /* serious error, go home! */
+            failf (data, "The requested URL returned error: %d",
+                   k->httpcode);
+            return CURLE_HTTP_RETURNED_ERROR;
+          }
+        }
+
+        if(conn->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! */
+          infof(data, "HTTP 1.0, assume close after body\n");
+          conn->bits.close = TRUE;
+        }
+        else if(conn->httpversion >= 11 &&
+                !conn->bits.close) {
+          /* If HTTP version is >= 1.1 and connection is persistent
+             server supports pipelining. */
+          DEBUGF(infof(data,
+                       "HTTP 1.1 or later with persistent connection, "
+                       "pipelining supported\n"));
+          conn->server_supports_pipelining = 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.  */
+          if(data->set.timecondition)
+            data->info.timecond = TRUE;
+          k->size=0;
+          k->maxdownload=0;
+          k->ignorecl = TRUE; /* ignore Content-Length headers */
+          break;
+        default:
+          /* nothing */
+          break;
+        }
+      }
+      else {
+        k->header = FALSE;   /* this is not a header line */
+        break;
+      }
+    }
+
+#ifdef CURL_DOES_CONVERSIONS
+    /* convert from the network encoding */
+    result = Curl_convert_from_network(data, k->p, strlen(k->p));
+    if(CURLE_OK != result) {
+      return(result);
+    }
+    /* Curl_convert_from_network calls failf if unsuccessful */
+#endif /* CURL_DOES_CONVERSIONS */
+
+    /* 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->ignorecl && !data->set.ignorecl &&
+       checkprefix("Content-Length:", k->p)) {
+      curl_off_t 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) {
+        k->size = contentlength;
+        k->maxdownload = k->size;
+        /* we set the progress download size already at this point
+           just to make it easier for apps/callbacks to extract this
+           info as soon as possible */
+        Curl_pgrsSetDownloadSize(data, k->size);
+      }
+      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 *contenttype = Curl_copy_header_value(k->p);
+      if (!contenttype)
+        return CURLE_OUT_OF_MEMORY;
+      if (!*contenttype)
+        /* ignore empty data */
+        free(contenttype);
+      else {
+        Curl_safefree(data->info.contenttype);
+        data->info.contenttype = contenttype;
+      }
+    }
+    else if((conn->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((conn->httpversion == 11) &&
+            conn->bits.httpproxy &&
+            Curl_compareheader(k->p,
+                               "Proxy-Connection:", "close")) {
+      /*
+       * We get a HTTP/1.1 response from a proxy and it says it'll
+       * close down after this transfer.
+       */
+      conn->bits.close = TRUE; /* close when done */
+      infof(data, "HTTP/1.1 proxy connection set close!\n");
+    }
+    else if((conn->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") &&
+            !(conn->protocol & PROT_RTSP)) {
+      /*
+       * [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. */
+      k->chunk = TRUE; /* chunks coming our way */
+
+      /* init our chunky engine */
+      Curl_httpchunk_init(conn);
+    }
+
+    else if(checkprefix("Trailer:", k->p) ||
+            checkprefix("Trailers:", k->p)) {
+      /*
+       * This test helps Curl_httpchunk_read() to determine to look
+       * for well formed trailers after the zero chunksize record. In
+       * this case a CRLF is required after the zero chunksize record
+       * when no trailers are sent, or after the last trailer record.
+       *
+       * It seems both Trailer: and Trailers: occur in the wild.
+       */
+      k->trailerhdrpresent = TRUE;
+    }
+
+    else if(checkprefix("Content-Encoding:", k->p) &&
+            data->set.str[STRING_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 */
+      start = k->p + 17;
+      while(*start && ISSPACE(*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(checkprefix("Content-Range:", k->p)) {
+      /* Content-Range: bytes [num]-
+         Content-Range: bytes: [num]-
+         Content-Range: [num]-
+
+         The second format was added since Sun's webserver
+         JavaWebServer/1.1.1 obviously sends the header this way!
+         The third added since some servers use that!
+      */
+
+      char *ptr = k->p + 14;
+
+      /* Move forward until first digit */
+      while(*ptr && !ISDIGIT(*ptr))
+        ptr++;
+
+      k->offset = curlx_strtoofft(ptr, NULL, 10);
+
+      if(data->state.resume_from == k->offset)
+        /* we asked for a resume and we got it */
+        k->content_range = TRUE;
+    }
+#if !defined(CURL_DISABLE_COOKIES)
+    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,
+                      data->state.path);
+      Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+    }
+#endif
+    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 = (long)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)) {
+      /* this is the URL that the server advises us to use instead */
+      char *location = Curl_copy_header_value(k->p);
+      if (!location)
+        return CURLE_OUT_OF_MEMORY;
+      if (!*location)
+        /* ignore empty data */
+        free(location);
+      else {
+        DEBUGASSERT(!data->req.location);
+        data->req.location = location;
+
+        if(data->set.http_follow_location) {
+          DEBUGASSERT(!data->req.newurl);
+          data->req.newurl = strdup(data->req.location); /* clone */
+          if(!data->req.newurl)
+            return CURLE_OUT_OF_MEMORY;
+
+          /* some cases of POST and PUT etc needs to rewind the data
+             stream at this point */
+          result = Curl_http_perhapsrewind(conn);
+          if(result)
+            return result;
+        }
+      }
+    }
+#ifndef CURL_DISABLE_RTSP
+    else if(conn->protocol & PROT_RTSP) {
+      result = Curl_rtsp_parseheader(conn, k->p);
+      if(result)
+        return result;
+    }
+#endif
+    /*
+     * 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, (size_t)k->hbuflen, conn);
+
+    result = Curl_client_write(conn, writetype, k->p, k->hbuflen);
+    if(result)
+      return result;
+
+    data->info.header_size += (long)k->hbuflen;
+    data->req.headerbytecount += (long)k->hbuflen;
+
+    /* reset hbufp pointer && hbuflen */
+    k->hbufp = data->state.headerbuff;
+    k->hbuflen = 0;
+  }
+  while(!*stop_reading && *k->str); /* header line within buffer */
+
+  /* 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. */
+
+  return CURLE_OK;
+}
+
+#endif /* CURL_DISABLE_HTTP */
diff --git a/lib/http.h b/lib/http.h
new file mode 100644
index 0000000..b7c1abf
--- /dev/null
+++ b/lib/http.h
@@ -0,0 +1,162 @@
+#ifndef __HTTP_H
+#define __HTTP_H
+
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+#ifndef CURL_DISABLE_HTTP
+
+extern const struct Curl_handler Curl_handler_http;
+
+#ifdef USE_SSL
+extern const struct Curl_handler Curl_handler_https;
+#endif
+
+bool Curl_compareheader(const char *headerline,  /* line to check */
+                        const char *header,   /* header keyword _with_ colon */
+                        const char *content); /* content string to find */
+
+char *Curl_checkheaders(struct SessionHandle *data, const char *thisheader);
+
+char *Curl_copy_header_value(const char *h);
+
+
+/* ------------------------------------------------------------------------- */
+/*
+ * 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 Curl_send_buffer {
+  char *buffer;
+  size_t size_max;
+  size_t size_used;
+};
+typedef struct Curl_send_buffer Curl_send_buffer;
+
+Curl_send_buffer *Curl_add_buffer_init(void);
+CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...);
+CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size);
+CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
+                         struct connectdata *conn,
+                         long *bytes_written,
+                         size_t included_body_bytes,
+                         int socketindex);
+
+
+CURLcode Curl_add_timecondition(struct SessionHandle *data,
+                                Curl_send_buffer *buf);
+CURLcode Curl_add_custom_headers(struct connectdata *conn,
+                                   Curl_send_buffer *req_buffer);
+
+
+/* ftp can use this as well */
+CURLcode Curl_proxyCONNECT(struct connectdata *conn,
+                           int tunnelsocket,
+                           const char *hostname, unsigned short remote_port);
+
+/* protocol-specific functions set up to be called by the main engine */
+CURLcode Curl_http(struct connectdata *conn, bool *done);
+CURLcode Curl_http_done(struct connectdata *, CURLcode, bool premature);
+CURLcode Curl_http_connect(struct connectdata *conn, bool *done);
+
+/* 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, const char *header);
+CURLcode Curl_http_auth_act(struct connectdata *conn);
+CURLcode Curl_http_perhapsrewind(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 */
+
+/* MAX_INITIAL_POST_SIZE indicates the number of bytes that will make the POST
+   data get included in the initial data chunk sent to the server. If the
+   data is larger than this, it will automatically get split up in multiple
+   system calls.
+
+   This value used to be fairly big (100K), but we must take into account that
+   if the server rejects the POST due for authentication reasons, this data
+   will always be uncondtionally sent and thus it may not be larger than can
+   always be afforded to send twice.
+
+   It must not be greater than 64K to work on VMS.
+*/
+#ifndef MAX_INITIAL_POST_SIZE
+#define MAX_INITIAL_POST_SIZE (64*1024)
+#endif
+
+#ifndef TINY_INITIAL_POST_SIZE
+#define TINY_INITIAL_POST_SIZE 1024
+#endif
+
+#endif /* CURL_DISABLE_HTTP */
+
+/****************************************************************************
+ * HTTP unique setup
+ ***************************************************************************/
+struct HTTP {
+  struct FormData *sendit;
+  curl_off_t postsize; /* off_t to handle large file sizes */
+  const 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 back {
+    curl_read_callback fread_func; /* backup storage for fread pointer */
+    void *fread_in;           /* backup storage for fread_in pointer */
+    const 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 */
+};
+
+CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
+                                     struct connectdata *conn,
+                                     ssize_t *nread,
+                                     bool *stop_reading);
+
+#endif
diff --git a/lib/http_chunks.c b/lib/http_chunks.c
new file mode 100644
index 0000000..a66f872
--- /dev/null
+++ b/lib/http_chunks.c
@@ -0,0 +1,422 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+#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"
+#include "easyif.h" /* for Curl_convert_to_network prototype */
+
+#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.
+
+ */
+
+/* Check for an ASCII hex digit.
+ We avoid the use of isxdigit to accommodate non-ASCII hosts. */
+static bool Curl_isxdigit(char digit)
+{
+  return (bool)( (digit >= 0x30 && digit <= 0x39)    /* 0-9 */
+              || (digit >= 0x41 && digit <= 0x46)    /* A-F */
+              || (digit >= 0x61 && digit <= 0x66) ); /* a-f */
+}
+
+void Curl_httpchunk_init(struct connectdata *conn)
+{
+  struct Curl_chunker *chunk = &conn->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.
+ *
+ * This function always uses ASCII hex values to accommodate non-ASCII hosts.
+ * For example, 0x0d and 0x0a are used instead of '\r' and '\n'.
+ */
+CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
+                              char *datap,
+                              ssize_t datalen,
+                              ssize_t *wrotep)
+{
+  CURLcode result=CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  struct Curl_chunker *ch = &conn->chunk;
+  struct SingleRequest *k = &data->req;
+  size_t piece;
+  size_t length = (size_t)datalen;
+  size_t *wrote = (size_t *)wrotep;
+
+  *wrote = 0; /* nothing's written yet */
+
+  /* the original data is written to the client, but we go on with the
+     chunk read process, to properly calculate the content length*/
+  if(data->set.http_te_skip && !k->ignorebody) {
+    result = Curl_client_write(conn, CLIENTWRITE_BODY, datap, datalen);
+    if(result)
+      return CHUNKE_WRITE_ERROR;
+  }
+
+  while(length) {
+    switch(ch->state) {
+    case CHUNK_HEX:
+      if(Curl_isxdigit(*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;
+#ifdef CURL_DOES_CONVERSIONS
+        /* convert to host encoding before calling strtoul */
+        result = Curl_convert_from_network(conn->data,
+                                           ch->hexbuffer,
+                                           ch->hexindex);
+        if(result != CURLE_OK) {
+          /* Curl_convert_from_network calls failf if unsuccessful */
+          /* Treat it as a bad hex character */
+          return(CHUNKE_ILLEGAL_HEX);
+        }
+#endif /* CURL_DOES_CONVERSIONS */
+        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 == 0x0d)
+        ch->state = CHUNK_CR;
+      length--;
+      datap++;
+      break;
+
+    case CHUNK_CR:
+      /* waiting for the LF */
+      if(*datap == 0x0a) {
+        /* we're now expecting data to come, unless size was zero! */
+        if(0 == ch->datasize) {
+          if(k->trailerhdrpresent!=TRUE) {
+            /* No Trailer: header found - revert to original Curl processing */
+            ch->state = CHUNK_STOPCR;
+
+            /* We need to increment the datap here since we bypass the
+               increment below with the immediate break */
+            length--;
+            datap++;
+
+            /* This is the final byte, continue to read the final CRLF */
+            break;
+          }
+          else {
+            ch->state = CHUNK_TRAILER; /* attempt to read trailers */
+            conn->trlPos=0;
+          }
+        }
+        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->data->set.http_ce_skip?
+              IDENTITY : data->req.content_encoding) {
+      case IDENTITY:
+#endif
+        if(!k->ignorebody) {
+          if( !data->set.http_te_skip )
+            result = Curl_client_write(conn, CLIENTWRITE_BODY, datap,
+                                       piece);
+          else
+            result = CURLE_OK;
+        }
+#ifdef HAVE_LIBZ
+        break;
+
+      case DEFLATE:
+        /* update data->req.keep.str to point to the chunk data. */
+        data->req.str = datap;
+        result = Curl_unencode_deflate_write(conn, &data->req,
+                                             (ssize_t)piece);
+        break;
+
+      case GZIP:
+        /* update data->req.keep.str to point to the chunk data. */
+        data->req.str = datap;
+        result = Curl_unencode_gzip_write(conn, &data->req,
+                                          (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 == 0x0d) {
+        ch->state = CHUNK_POSTLF;
+        datap++;
+        length--;
+      }
+      else {
+        return CHUNKE_BAD_CHUNK;
+      }
+      break;
+
+    case CHUNK_POSTLF:
+      if(*datap == 0x0a) {
+        /*
+         * 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_TRAILER:
+      /* conn->trailer is assumed to be freed in url.c on a
+         connection basis */
+      if(conn->trlPos >= conn->trlMax) {
+        /* in this logic we always allocate one byte more than trlMax
+           contains, just because CHUNK_TRAILER_POSTCR will append two bytes
+           so we need to make sure we have room for an extra byte */
+        char *ptr;
+        if(conn->trlMax) {
+          conn->trlMax *= 2;
+          ptr = realloc(conn->trailer, conn->trlMax + 1);
+        }
+        else {
+          conn->trlMax=128;
+          ptr = malloc(conn->trlMax + 1);
+        }
+        if(!ptr)
+          return CHUNKE_OUT_OF_MEMORY;
+        conn->trailer = ptr;
+      }
+      conn->trailer[conn->trlPos++]=*datap;
+
+      if(*datap == 0x0d)
+        ch->state = CHUNK_TRAILER_CR;
+      else {
+        datap++;
+        length--;
+      }
+      break;
+
+    case CHUNK_TRAILER_CR:
+      if(*datap == 0x0d) {
+        ch->state = CHUNK_TRAILER_POSTCR;
+        datap++;
+        length--;
+      }
+      else
+        return CHUNKE_BAD_CHUNK;
+      break;
+
+    case CHUNK_TRAILER_POSTCR:
+      if(*datap == 0x0a) {
+        conn->trailer[conn->trlPos++]=0x0a;
+        conn->trailer[conn->trlPos]=0;
+        if(conn->trlPos==2) {
+          ch->state = CHUNK_STOP;
+          length--;
+
+          /*
+           * Note that this case skips over the final STOP states since we've
+           * already read the final CRLF and need to return
+           */
+
+          ch->dataleft = length;
+
+          return CHUNKE_STOP; /* return stop */
+        }
+        else {
+#ifdef CURL_DOES_CONVERSIONS
+          /* Convert to host encoding before calling Curl_client_write */
+          result = Curl_convert_from_network(conn->data,
+                                             conn->trailer,
+                                             conn->trlPos);
+          if(result != CURLE_OK) {
+            /* Curl_convert_from_network calls failf if unsuccessful */
+            /* Treat it as a bad chunk */
+            return(CHUNKE_BAD_CHUNK);
+          }
+#endif /* CURL_DOES_CONVERSIONS */
+          if(!data->set.http_te_skip) {
+            result = Curl_client_write(conn, CLIENTWRITE_HEADER,
+                                       conn->trailer, conn->trlPos);
+            if(result)
+              return CHUNKE_WRITE_ERROR;
+          }
+        }
+        ch->state = CHUNK_TRAILER;
+        conn->trlPos=0;
+        datap++;
+        length--;
+      }
+      else
+        return CHUNKE_BAD_CHUNK;
+      break;
+
+    case CHUNK_STOPCR:
+      /* Read the final CRLF that ends all chunk bodies */
+
+      if(*datap == 0x0d) {
+        ch->state = CHUNK_STOP;
+        datap++;
+        length--;
+      }
+      else {
+        return CHUNKE_BAD_CHUNK;
+      }
+      break;
+
+    case CHUNK_STOP:
+      if(*datap == 0x0a) {
+        length--;
+
+        /* Record the length of any 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 */
+      }
+      else {
+        return CHUNKE_BAD_CHUNK;
+      }
+
+    default:
+      return CHUNKE_STATE_ERROR;
+    }
+  }
+  return CHUNKE_OK;
+}
+#endif /* CURL_DISABLE_HTTP */
diff --git a/lib/http_chunks.h b/lib/http_chunks.h
new file mode 100644
index 0000000..6056e18
--- /dev/null
+++ b/lib/http_chunks.h
@@ -0,0 +1,107 @@
+#ifndef __HTTP_CHUNKS_H
+#define __HTTP_CHUNKS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, 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.
+ *
+ ***************************************************************************/
+/*
+ * 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,
+
+  /* Each Chunk body should end with a CRLF.  Read a CR and nothing else,
+     then move to CHUNK_STOP */
+  CHUNK_STOPCR,
+
+  /* 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,
+
+  /* At this point optional trailer headers can be found, unless the next line
+     is CRLF */
+  CHUNK_TRAILER,
+
+  /* A trailer CR has been found - next state is CHUNK_TRAILER_POSTCR.
+     Next char must be a LF */
+  CHUNK_TRAILER_CR,
+
+  /* A trailer LF must be found now, otherwise CHUNKE_BAD_CHUNK will be
+     signalled If this is an empty trailer CHUNKE_STOP will be signalled.
+     Otherwise the trailer will be broadcasted via Curl_client_write() and the
+     next state will be CHUNK_TRAILER */
+  CHUNK_TRAILER_POSTCR,
+
+  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_OUT_OF_MEMORY,
+  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/lib/http_digest.c b/lib/http_digest.c
new file mode 100644
index 0000000..ff3871c
--- /dev/null
+++ b/lib/http_digest.c
@@ -0,0 +1,585 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "urldata.h"
+#include "sendf.h"
+#include "rawstr.h"
+#include "curl_base64.h"
+#include "curl_md5.h"
+#include "http_digest.h"
+#include "strtok.h"
+#include "url.h" /* for Curl_safefree() */
+#include "curl_memory.h"
+#include "easyif.h" /* included for Curl_convert_... prototypes */
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#define MAX_VALUE_LENGTH 256
+#define MAX_CONTENT_LENGTH 1024
+
+/*
+ * Return 0 on success and then the buffers are filled in fine.
+ *
+ * Non-zero means failure to parse.
+ */
+static int get_pair(const char *str, char *value, char *content,
+                    const char **endptr)
+{
+  int c;
+  bool starts_with_quote = FALSE;
+  bool escape = FALSE;
+
+  for(c=MAX_VALUE_LENGTH-1; (*str && (*str != '=') && c--); )
+    *value++ = *str++;
+  *value=0;
+
+  if('=' != *str++)
+    /* eek, no match */
+    return 1;
+
+  if('\"' == *str) {
+    /* this starts with a quote so it must end with one as well! */
+    str++;
+    starts_with_quote = TRUE;
+  }
+
+  for(c=MAX_CONTENT_LENGTH-1; *str && c--; str++) {
+    switch(*str) {
+    case '\\':
+      if(!escape) {
+        /* possibly the start of an escaped quote */
+        escape = TRUE;
+        *content++ = '\\'; /* even though this is an escape character, we still
+                              store it as-is in the target buffer */
+        continue;
+      }
+      break;
+    case ',':
+      if(!starts_with_quote) {
+        /* this signals the end of the content if we didn't get a starting quote
+           and then we do "sloppy" parsing */
+        c=0; /* the end */
+        continue;
+      }
+      break;
+    case '\r':
+    case '\n':
+      /* end of string */
+      c=0;
+      continue;
+    case '\"':
+      if(!escape && starts_with_quote) {
+        /* end of string */
+        c=0;
+        continue;
+      }
+      break;
+    }
+    escape = FALSE;
+    *content++ = *str;
+  }
+  *content=0;
+
+  *endptr = str;
+
+  return 0; /* all is fine! */
+}
+
+/* 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,
+                             const char *header) /* rest of the *-authenticate:
+                                                    header */
+{
+  bool more = TRUE;
+  char *token = NULL;
+  char *tmp = NULL;
+  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(*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[MAX_VALUE_LENGTH];
+      char content[MAX_CONTENT_LENGTH];
+
+      while(*header && ISSPACE(*header))
+        header++;
+
+      /* extract a value=content pair */
+      if(!get_pair(header, value, content, &header)) {
+        if(Curl_raw_equal(value, "nonce")) {
+          d->nonce = strdup(content);
+          if(!d->nonce)
+            return CURLDIGEST_NOMEM;
+        }
+        else if(Curl_raw_equal(value, "stale")) {
+          if(Curl_raw_equal(content, "true")) {
+            d->stale = TRUE;
+            d->nc = 1; /* we make a new nonce now */
+          }
+        }
+        else if(Curl_raw_equal(value, "realm")) {
+          d->realm = strdup(content);
+          if(!d->realm)
+            return CURLDIGEST_NOMEM;
+        }
+        else if(Curl_raw_equal(value, "opaque")) {
+          d->opaque = strdup(content);
+          if(!d->opaque)
+            return CURLDIGEST_NOMEM;
+        }
+        else if(Curl_raw_equal(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(Curl_raw_equal(token, "auth")) {
+              foundAuth = TRUE;
+            }
+            else if(Curl_raw_equal(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(Curl_raw_equal(value, "algorithm")) {
+          d->algorithm = strdup(content);
+          if(!d->algorithm)
+            return CURLDIGEST_NOMEM;
+          if(Curl_raw_equal(content, "MD5-sess"))
+            d->algo = CURLDIGESTALGO_MD5SESS;
+          else if(Curl_raw_equal(content, "MD5"))
+            d->algo = CURLDIGESTALGO_MD5;
+          else
+            return CURLDIGEST_BADALGO;
+        }
+        else {
+          /* unknown specifier, ignore it! */
+        }
+      }
+      else
+        break; /* we're done here */
+
+      /* pass all additional spaces here */
+      while(*header && ISSPACE(*header))
+        header++;
+      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,
+                            const unsigned char *request,
+                            const 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 = NULL;
+  struct timeval now;
+
+  char **allocuserpwd;
+  const char *userp;
+  const char *passwdp;
+  struct auth *authp;
+
+  struct SessionHandle *data = conn->data;
+  struct digestdata *d;
+#ifdef CURL_DOES_CONVERSIONS
+  CURLcode rc;
+/* The CURL_OUTPUT_DIGEST_CONV macro below is for non-ASCII machines.
+   It converts digest text to ASCII so the MD5 will be correct for
+   what ultimately goes over the network.
+*/
+#define CURL_OUTPUT_DIGEST_CONV(a, b) \
+  rc = Curl_convert_to_network(a, (char *)b, strlen((const char*)b)); \
+  if(rc != CURLE_OK) { \
+    free(b); \
+    return rc; \
+  }
+#else
+#define CURL_OUTPUT_DIGEST_CONV(a, b)
+#endif /* CURL_DOES_CONVERSIONS */
+
+  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;
+  }
+
+  if(*allocuserpwd) {
+    Curl_safefree(*allocuserpwd);
+    *allocuserpwd = NULL;
+  }
+
+  /* not set means empty */
+  if(!userp)
+    userp="";
+
+  if(!passwdp)
+    passwdp="";
+
+  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", (long)now.tv_sec);
+    if(Curl_base64_encode(data, 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_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
+  Curl_md5it(md5buf, md5this);
+  free(md5this); /* free this again */
+
+  ha1 = 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);
+    if(!tmp)
+      return CURLE_OUT_OF_MEMORY;
+    CURL_OUTPUT_DIGEST_CONV(data, tmp); /* convert on non-ASCII machines */
+    Curl_md5it(md5buf, (unsigned char *)tmp);
+    free(tmp); /* free this again */
+    md5_to_ascii(md5buf, ha1);
+  }
+
+  /*
+    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)
+  */
+
+  /* So IE browsers < v7 cut off the URI part at the query part when they
+     evaluate the MD5 and some (IIS?) servers work with them so we may need to
+     do the Digest IE-style. Note that the different ways cause different MD5
+     sums to get sent.
+
+     Apache servers can be set to do the Digest IE-style automatically using
+     the BrowserMatch feature:
+     http://httpd.apache.org/docs/2.2/mod/mod_auth_digest.html#msie
+
+     Further details on Digest implementation differences:
+     http://www.fngtps.com/2006/09/http-authentication
+  */
+  if(authp->iestyle && ((tmp = strchr((char *)uripath, '?')) != NULL)) {
+    md5this = (unsigned char *)aprintf("%s:%.*s", request,
+                                       (int)(tmp - (char *)uripath), uripath);
+  }
+  else
+    md5this = (unsigned char *)aprintf("%s:%s", request, uripath);
+
+  if(!md5this) {
+    free(ha1);
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(d->qop && Curl_raw_equal(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_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
+  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_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
+  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"
+  */
+
+  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(Curl_raw_equal(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 + zero (3 bytes) to the userpwd header */
+  tmp = realloc(*allocuserpwd, strlen(*allocuserpwd) + 3);
+  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/lib/http_digest.h b/lib/http_digest.h
new file mode 100644
index 0000000..8c96378
--- /dev/null
+++ b/lib/http_digest.h
@@ -0,0 +1,57 @@
+#ifndef __HTTP_DIGEST_H
+#define __HTTP_DIGEST_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * 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.
+ *
+ ***************************************************************************/
+
+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, const char *header);
+
+/* this is for creating digest header output */
+CURLcode Curl_output_digest(struct connectdata *conn,
+                            bool proxy,
+                            const unsigned char *request,
+                            const unsigned char *uripath);
+void Curl_digest_cleanup_one(struct digestdata *dig);
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+void Curl_digest_cleanup(struct SessionHandle *data);
+#else
+#define Curl_digest_cleanup(x) do {} while(0)
+#endif
+
+#endif
diff --git a/lib/http_negotiate.c b/lib/http_negotiate.c
new file mode 100644
index 0000000..956f734
--- /dev/null
+++ b/lib/http_negotiate.c
@@ -0,0 +1,358 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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"
+
+#ifdef HAVE_GSSAPI
+#ifdef HAVE_OLD_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 "urldata.h"
+#include "sendf.h"
+#include "rawstr.h"
+#include "curl_base64.h"
+#include "http_negotiate.h"
+#include "curl_memory.h"
+
+#ifdef HAVE_SPNEGO
+#  include <spnegohelp.h>
+#  ifdef USE_SSLEAY
+#    ifdef USE_OPENSSL
+#      include <openssl/objects.h>
+#    else
+#      include <objects.h>
+#    endif
+#  else
+#    error "Can't compile SPNEGO support without OpenSSL."
+#  endif
+#endif
+
+#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, bool proxy, gss_name_t *server)
+{
+  struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg:
+    &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(proxy ? conn->proxy.name :
+                                              conn->host.name) + 1;
+  if(token.length + 1 > sizeof(name))
+    return EMSGSIZE;
+
+  snprintf(name, sizeof(name), "%s@%s", service, proxy ? conn->proxy.name :
+           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, const 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, "%s", buf);
+}
+
+/* returning zero (0) means success, everything else is treated as "failure"
+   with no care exactly what the failure was */
+int Curl_input_negotiate(struct connectdata *conn, bool proxy,
+                         const char *header)
+{
+  struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg:
+    &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, rawlen;
+  bool gss;
+  const char* protocol;
+
+  while(*header && ISSPACE(*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, proxy, &neg_ctx->server_name)))
+    return ret;
+
+  header += strlen(neg_ctx->protocol);
+  while(*header && ISSPACE(*header))
+    header++;
+
+  len = strlen(header);
+  if(len > 0) {
+    rawlen = Curl_base64_decode(header,
+                                (unsigned char **)&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;
+
+        if(input_token.value == NULL)
+          return CURLE_OUT_OF_MEMORY;
+
+        spnegoToken = malloc(input_token.length);
+        if(spnegoToken == NULL)
+          return CURLE_OUT_OF_MEMORY;
+
+        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 = malloc(mechTokenLength);
+          if (input_token.value == NULL)
+            return CURLE_OUT_OF_MEMORY;
+
+          memcpy(input_token.value, mechToken,mechTokenLength);
+          input_token.length = mechTokenLength;
+          free(mechToken);
+          mechToken = NULL;
+          infof(conn->data, "Parse SPNEGO Target Token succeeded\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,
+                  "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, bool proxy)
+{
+  struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg:
+    &conn->data->state.negotiate;
+  char *encoded = NULL;
+  size_t 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 succeeded\n");
+    }
+  }
+#endif
+  len = Curl_base64_encode(conn->data,
+                           neg_ctx->output_token.value,
+                           neg_ctx->output_token.length,
+                           &encoded);
+
+  if(len == 0)
+    return CURLE_OUT_OF_MEMORY;
+
+  conn->allocptr.userpwd =
+    aprintf("%sAuthorization: %s %s\r\n", proxy ? "Proxy-" : "",
+            neg_ctx->protocol, encoded);
+  free(encoded);
+  Curl_cleanup_negotiate (conn->data);
+  return (conn->allocptr.userpwd == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK;
+}
+
+static void cleanup(struct negotiatedata *neg_ctx)
+{
+  OM_uint32 minor_status;
+  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));
+}
+
+void Curl_cleanup_negotiate(struct SessionHandle *data)
+{
+  cleanup(&data->state.negotiate);
+  cleanup(&data->state.proxyneg);
+}
+
+
+#endif
+#endif
diff --git a/lib/http_negotiate.h b/lib/http_negotiate.h
new file mode 100644
index 0000000..35501f0
--- /dev/null
+++ b/lib/http_negotiate.h
@@ -0,0 +1,38 @@
+#ifndef HEADER_CURL_HTTP_NEGOTIATE_H
+#define HEADER_CURL_HTTP_NEGOTIATE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+#ifdef HAVE_GSSAPI
+
+/* this is for Negotiate header input */
+int Curl_input_negotiate(struct connectdata *conn, bool proxy,
+                         const char *header);
+
+/* this is for creating Negotiate header output */
+CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy);
+
+void Curl_cleanup_negotiate(struct SessionHandle *data);
+
+#endif /* HAVE_GSSAPI */
+
+#endif /* HEADER_CURL_HTTP_NEGOTIATE_H */
diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c
new file mode 100644
index 0000000..36e538e
--- /dev/null
+++ b/lib/http_ntlm.c
@@ -0,0 +1,1194 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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"
+
+/* NTLM details:
+
+   http://davenport.sourceforge.net/ntlm.html
+   http://www.innovation.ch/java/ntlm.html
+
+   Another implementation:
+   http://lxr.mozilla.org/mozilla/source/security/manager/ssl/src/nsNTLMAuthModule.cpp
+
+*/
+
+#ifndef CURL_DISABLE_HTTP
+#ifdef USE_NTLM
+
+#define DEBUG_ME 0
+
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
+#include <netdb.h>
+#endif
+
+#include "urldata.h"
+#include "easyif.h"  /* for Curl_convert_... prototypes */
+#include "sendf.h"
+#include "rawstr.h"
+#include "curl_base64.h"
+#include "http_ntlm.h"
+#include "url.h"
+#include "curl_memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* "NTLMSSP" signature is always in ASCII regardless of the platform */
+#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
+
+#ifdef USE_SSLEAY
+#include "ssluse.h"
+#    ifdef USE_OPENSSL
+#      include <openssl/des.h>
+#      ifndef OPENSSL_NO_MD4
+#        include <openssl/md4.h>
+#      endif
+#      include <openssl/md5.h>
+#      include <openssl/ssl.h>
+#      include <openssl/rand.h>
+#    else
+#      include <des.h>
+#      ifndef OPENSSL_NO_MD4
+#        include <md4.h>
+#      endif
+#      include <md5.h>
+#      include <ssl.h>
+#      include <rand.h>
+#    endif
+
+#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
+
+#ifdef OPENSSL_NO_MD4
+/* This requires MD4, but OpenSSL was compiled without it */
+#define USE_NTRESPONSES 0
+#define USE_NTLM2SESSION 0
+#endif
+
+#elif defined(USE_GNUTLS)
+
+#include "gtls.h"
+#include <gcrypt.h>
+
+#define MD5_DIGEST_LENGTH 16
+#define MD4_DIGEST_LENGTH 16
+
+#elif defined(USE_WINDOWS_SSPI)
+
+#include "curl_sspi.h"
+
+#else
+#    error "Can't compile NTLM support without a crypto library."
+#endif
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifndef USE_NTRESPONSES 
+/* Define this to make the type-3 message include the NT response message */
+#define USE_NTRESPONSES 1
+
+/* Define this to make the type-3 message include the NTLM2Session response
+   message, requires USE_NTRESPONSES. */
+#define USE_NTLM2SESSION 1
+#endif
+
+#ifndef USE_WINDOWS_SSPI
+/* this function converts from the little endian format used in the incoming
+   package to whatever endian format we're using natively */
+static unsigned int readint_le(unsigned char *buf) /* must point to a
+                                                      4 bytes buffer*/
+{
+  return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) |
+    ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24);
+}
+#endif
+
+#if DEBUG_ME
+# define DEBUG_OUT(x) x
+static void print_flags(FILE *handle, unsigned long flags)
+{
+  if(flags & NTLMFLAG_NEGOTIATE_UNICODE)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE ");
+  if(flags & NTLMFLAG_NEGOTIATE_OEM)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM ");
+  if(flags & NTLMFLAG_REQUEST_TARGET)
+    fprintf(handle, "NTLMFLAG_REQUEST_TARGET ");
+  if(flags & (1<<3))
+    fprintf(handle, "NTLMFLAG_UNKNOWN_3 ");
+  if(flags & NTLMFLAG_NEGOTIATE_SIGN)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN ");
+  if(flags & NTLMFLAG_NEGOTIATE_SEAL)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL ");
+  if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
+  if(flags & NTLMFLAG_NEGOTIATE_LM_KEY)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY ");
+  if(flags & NTLMFLAG_NEGOTIATE_NETWARE)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE ");
+  if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
+  if(flags & (1<<10))
+    fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
+  if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS ");
+  if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
+  if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
+  if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
+  if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
+  if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN)
+    fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
+  if(flags & NTLMFLAG_TARGET_TYPE_SERVER)
+    fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER ");
+  if(flags & NTLMFLAG_TARGET_TYPE_SHARE)
+    fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE ");
+  if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
+  if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE)
+    fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
+  if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE)
+    fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
+  if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY)
+    fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
+  if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
+  if(flags & (1<<24))
+    fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
+  if(flags & (1<<25))
+    fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
+  if(flags & (1<<26))
+    fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
+  if(flags & (1<<27))
+    fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
+  if(flags & (1<<28))
+    fprintf(handle, "NTLMFLAG_UNKNOWN_28 ");
+  if(flags & NTLMFLAG_NEGOTIATE_128)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_128 ");
+  if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
+  if(flags & NTLMFLAG_NEGOTIATE_56)
+    fprintf(handle, "NTLMFLAG_NEGOTIATE_56 ");
+}
+
+static void print_hex(FILE *handle, const char *buf, size_t len)
+{
+  const char *p = buf;
+  fprintf(stderr, "0x");
+  while(len-- > 0)
+    fprintf(stderr, "%02.2x", (unsigned int)*p++);
+}
+#else
+# define DEBUG_OUT(x)
+#endif
+
+/*
+  (*) = 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 */
+                         const char *header) /* rest of the www-authenticate:
+                                                header */
+{
+  /* point to the correct struct with this */
+  struct ntlmdata *ntlm;
+#ifndef USE_WINDOWS_SSPI
+  static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
+#endif
+
+  ntlm = proxy?&conn->proxyntlm:&conn->ntlm;
+
+  /* skip initial whitespaces */
+  while(*header && ISSPACE(*header))
+    header++;
+
+  if(checkprefix("NTLM", header)) {
+    header += strlen("NTLM");
+
+    while(*header && ISSPACE(*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;
+      unsigned char *buffer;
+      size = Curl_base64_decode(header, &buffer);
+      if(!buffer)
+        return CURLNTLM_BAD;
+
+      ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */
+
+#ifdef USE_WINDOWS_SSPI
+      ntlm->type_2 = malloc(size+1);
+      if(ntlm->type_2 == NULL) {
+        free(buffer);
+        return CURLE_OUT_OF_MEMORY;
+      }
+      ntlm->n_type_2 = size;
+      memcpy(ntlm->type_2, buffer, size);
+#else
+      ntlm->flags = 0;
+
+      if((size < 32) ||
+         (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) ||
+         (memcmp(buffer+8, type2_marker, sizeof(type2_marker)) != 0)) {
+        /* This was not a good enough type-2 message */
+        free(buffer);
+        return CURLNTLM_BAD;
+      }
+
+      ntlm->flags = readint_le(&buffer[20]);
+      memcpy(ntlm->nonce, &buffer[24], 8);
+
+      DEBUG_OUT({
+        fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
+        print_flags(stderr, ntlm->flags);
+        fprintf(stderr, "\n                  nonce=");
+        print_hex(stderr, (char *)ntlm->nonce, 8);
+        fprintf(stderr, "\n****\n");
+        fprintf(stderr, "**** Header %s\n ", header);
+      });
+#endif
+      free(buffer);
+    }
+    else {
+      if(ntlm->state >= NTLMSTATE_TYPE1)
+        return CURLNTLM_BAD;
+
+      ntlm->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */
+    }
+  }
+  return CURLNTLM_FINE;
+}
+
+#ifndef USE_WINDOWS_SSPI
+
+#ifdef USE_SSLEAY
+/*
+ * 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(const unsigned char *key_56,
+                          DES_key_schedule DESKEYARG(ks))
+{
+  DES_cblock key;
+
+  key[0] = key_56[0];
+  key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
+  key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
+  key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
+  key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
+  key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
+  key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
+  key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
+
+  DES_set_odd_parity(&key);
+  DES_set_key(&key, ks);
+}
+#elif defined(USE_GNUTLS)
+
+/*
+ * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.
+ */
+static void setup_des_key(const unsigned char *key_56,
+                          gcry_cipher_hd_t *des)
+{
+  char key[8];
+
+  key[0] = key_56[0];
+  key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
+  key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
+  key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
+  key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
+  key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
+  key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
+  key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
+
+  gcry_cipher_setkey(*des, key, 8);
+}
+#endif
+
+ /*
+  * 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 lm_resp(const unsigned char *keys,
+                    const unsigned char *plaintext,
+                    unsigned char *results)
+{
+#ifdef USE_SSLEAY
+  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);
+#elif defined(USE_GNUTLS)
+  gcry_cipher_hd_t des;
+
+  gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+  setup_des_key(keys, &des);
+  gcry_cipher_encrypt(des, results, 8, plaintext, 8);
+  gcry_cipher_close(des);
+
+  gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+  setup_des_key(keys+7, &des);
+  gcry_cipher_encrypt(des, results+8, 8, plaintext, 8);
+  gcry_cipher_close(des);
+
+  gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+  setup_des_key(keys+14, &des);
+  gcry_cipher_encrypt(des, results+16, 8, plaintext, 8);
+  gcry_cipher_close(des);
+#endif
+}
+
+
+/*
+ * Set up lanmanager hashed password
+ */
+static void mk_lm_hash(struct SessionHandle *data,
+                       const char *password,
+                       unsigned char *lmbuffer /* 21 bytes */)
+{
+  unsigned char pw[14];
+  static const unsigned char magic[] = {
+    0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */
+  };
+  size_t len = CURLMIN(strlen(password), 14);
+
+  Curl_strntoupper((char *)pw, password, len);
+  memset(&pw[len], 0, 14-len);
+
+#ifdef CURL_DOES_CONVERSIONS
+  /*
+   * The LanManager hashed password needs to be created using the
+   * password in the network encoding not the host encoding.
+   */
+  if(data)
+    Curl_convert_to_network(data, (char *)pw, 14);
+#else
+  (void)data;
+#endif
+
+  {
+    /* Create LanManager hashed password. */
+
+#ifdef USE_SSLEAY
+    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);
+#elif defined(USE_GNUTLS)
+    gcry_cipher_hd_t des;
+
+    gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+    setup_des_key(pw, &des);
+    gcry_cipher_encrypt(des, lmbuffer, 8, magic, 8);
+    gcry_cipher_close(des);
+
+    gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+    setup_des_key(pw+7, &des);
+    gcry_cipher_encrypt(des, lmbuffer+8, 8, magic, 8);
+    gcry_cipher_close(des);
+#endif
+
+    memset(lmbuffer + 16, 0, 21 - 16);
+  }
+  }
+
+#if USE_NTRESPONSES
+static void ascii_to_unicode_le(unsigned char *dest, const char *src,
+                               size_t srclen)
+{
+  size_t i;
+  for (i=0; i<srclen; i++) {
+    dest[2*i]   = (unsigned char)src[i];
+    dest[2*i+1] =   '\0';
+  }
+}
+
+/*
+ * Set up nt hashed passwords
+ */
+static CURLcode mk_nt_hash(struct SessionHandle *data,
+                           const char *password,
+                           unsigned char *ntbuffer /* 21 bytes */)
+{
+  size_t len = strlen(password);
+  unsigned char *pw = malloc(len*2);
+  if(!pw)
+    return CURLE_OUT_OF_MEMORY;
+
+  ascii_to_unicode_le(pw, password, len);
+
+#ifdef CURL_DOES_CONVERSIONS
+  /*
+   * The NT hashed password needs to be created using the
+   * password in the network encoding not the host encoding.
+   */
+  if(data)
+    Curl_convert_to_network(data, (char *)pw, len*2);
+#else
+  (void)data;
+#endif
+
+  {
+    /* Create NT hashed password. */
+#ifdef USE_SSLEAY
+    MD4_CTX MD4pw;
+    MD4_Init(&MD4pw);
+    MD4_Update(&MD4pw, pw, 2*len);
+    MD4_Final(ntbuffer, &MD4pw);
+#elif defined(USE_GNUTLS)
+    gcry_md_hd_t MD4pw;
+    gcry_md_open(&MD4pw, GCRY_MD_MD4, 0);
+    gcry_md_write(MD4pw, pw, 2*len);
+    memcpy (ntbuffer, gcry_md_read (MD4pw, 0), MD4_DIGEST_LENGTH);
+    gcry_md_close(MD4pw);
+#endif
+
+    memset(ntbuffer + 16, 0, 21 - 16);
+  }
+
+  free(pw);
+  return CURLE_OK;
+}
+#endif
+
+
+#endif
+
+#ifdef USE_WINDOWS_SSPI
+
+static void
+ntlm_sspi_cleanup(struct ntlmdata *ntlm)
+{
+  if(ntlm->type_2) {
+    free(ntlm->type_2);
+    ntlm->type_2 = NULL;
+  }
+  if(ntlm->has_handles) {
+    s_pSecFn->DeleteSecurityContext(&ntlm->c_handle);
+    s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
+    ntlm->has_handles = 0;
+  }
+  if(ntlm->p_identity) {
+    if(ntlm->identity.User) free(ntlm->identity.User);
+    if(ntlm->identity.Password) free(ntlm->identity.Password);
+    if(ntlm->identity.Domain) free(ntlm->identity.Domain);
+    ntlm->p_identity = NULL;
+  }
+}
+
+#endif
+
+#define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff)
+#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
+  (((x) >>16)&0xff), (((x)>>24) & 0xff)
+
+#define HOSTNAME_MAX 1024
+
+/* this is for creating ntlm header output */
+CURLcode Curl_output_ntlm(struct connectdata *conn,
+                          bool proxy)
+{
+  const char *domain=""; /* empty */
+  char host [HOSTNAME_MAX+ 1] = ""; /* empty */
+#ifndef USE_WINDOWS_SSPI
+  size_t domlen = strlen(domain);
+  size_t hostlen = strlen(host);
+  size_t hostoff; /* host name offset */
+  size_t domoff;  /* domain name offset */
+#endif
+  size_t size;
+  char *base64=NULL;
+  unsigned char ntlmbuf[1024]; /* enough, unless the user+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 */
+  const char *userp;
+  const char *passwdp;
+  /* point to the correct struct with this */
+  struct ntlmdata *ntlm;
+  struct auth *authp;
+
+  DEBUGASSERT(conn);
+  DEBUGASSERT(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="";
+
+  if(!passwdp)
+    passwdp="";
+
+#ifdef USE_WINDOWS_SSPI
+  if (s_hSecDll == NULL) {
+    /* not thread safe and leaks - use curl_global_init() to avoid */
+    CURLcode err = Curl_sspi_global_init();
+    if (s_hSecDll == NULL)
+      return err;
+  }
+#endif
+
+  switch(ntlm->state) {
+  case NTLMSTATE_TYPE1:
+  default: /* for the weird cases we (re)start here */
+#ifdef USE_WINDOWS_SSPI
+  {
+    SecBuffer buf;
+    SecBufferDesc desc;
+    SECURITY_STATUS status;
+    ULONG attrs;
+    const char *user;
+    int domlen;
+    TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */
+
+    ntlm_sspi_cleanup(ntlm);
+
+    user = strchr(userp, '\\');
+    if(!user)
+      user = strchr(userp, '/');
+
+    if(user) {
+      domain = userp;
+      domlen = user - userp;
+      user++;
+    }
+    else {
+      user = userp;
+      domain = "";
+      domlen = 0;
+    }
+
+    if(user && *user) {
+      /* note: initialize all of this before doing the mallocs so that
+       * it can be cleaned up later without leaking memory.
+       */
+      ntlm->p_identity = &ntlm->identity;
+      memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity));
+      if((ntlm->identity.User = (unsigned char *)strdup(user)) == NULL)
+        return CURLE_OUT_OF_MEMORY;
+      ntlm->identity.UserLength = strlen(user);
+      if((ntlm->identity.Password = (unsigned char *)strdup(passwdp)) == NULL)
+        return CURLE_OUT_OF_MEMORY;
+      ntlm->identity.PasswordLength = strlen(passwdp);
+      if((ntlm->identity.Domain = malloc(domlen+1)) == NULL)
+        return CURLE_OUT_OF_MEMORY;
+      strncpy((char *)ntlm->identity.Domain, domain, domlen);
+      ntlm->identity.Domain[domlen] = '\0';
+      ntlm->identity.DomainLength = domlen;
+      ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
+    }
+    else {
+      ntlm->p_identity = NULL;
+    }
+
+    if(s_pSecFn->AcquireCredentialsHandleA(
+          NULL, (char *)"NTLM", SECPKG_CRED_OUTBOUND, NULL, ntlm->p_identity,
+          NULL, NULL, &ntlm->handle, &tsDummy
+          ) != SEC_E_OK) {
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    desc.ulVersion = SECBUFFER_VERSION;
+    desc.cBuffers  = 1;
+    desc.pBuffers  = &buf;
+    buf.cbBuffer   = sizeof(ntlmbuf);
+    buf.BufferType = SECBUFFER_TOKEN;
+    buf.pvBuffer   = ntlmbuf;
+
+    status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, NULL,
+                                                 (char *) host,
+                                                 ISC_REQ_CONFIDENTIALITY |
+                                                 ISC_REQ_REPLAY_DETECT |
+                                                 ISC_REQ_CONNECTION,
+                                                 0, SECURITY_NETWORK_DREP,
+                                                 NULL, 0,
+                                                 &ntlm->c_handle, &desc,
+                                                 &attrs, &tsDummy);
+
+    if(status == SEC_I_COMPLETE_AND_CONTINUE ||
+        status == SEC_I_CONTINUE_NEEDED) {
+      s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc);
+    }
+    else if(status != SEC_E_OK) {
+      s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
+      return CURLE_RECV_ERROR;
+    }
+
+    ntlm->has_handles = 1;
+    size = buf.cbBuffer;
+  }
+#else
+    hostoff = 0;
+    domoff = hostoff + hostlen; /* This is 0: remember that host and domain
+                                   are empty */
+
+    /* 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
+
+    */
+#if USE_NTLM2SESSION
+#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
+#else
+#define NTLM2FLAG 0
+#endif
+    snprintf((char *)ntlmbuf, sizeof(ntlmbuf), NTLMSSP_SIGNATURE "%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|
+               NTLMFLAG_REQUEST_TARGET|
+               NTLMFLAG_NEGOTIATE_NTLM_KEY|
+               NTLM2FLAG|
+               NTLMFLAG_NEGOTIATE_ALWAYS_SIGN
+               ),
+             SHORTPAIR(domlen),
+             SHORTPAIR(domlen),
+             SHORTPAIR(domoff),
+             0,0,
+             SHORTPAIR(hostlen),
+             SHORTPAIR(hostlen),
+             SHORTPAIR(hostoff),
+             0,0,
+             host /* this is empty */, domain /* this is empty */);
+
+    /* initial packet length */
+    size = 32 + hostlen + domlen;
+#endif
+
+    DEBUG_OUT({
+      fprintf(stderr, "**** TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
+              LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM|
+                          NTLMFLAG_REQUEST_TARGET|
+                          NTLMFLAG_NEGOTIATE_NTLM_KEY|
+                          NTLM2FLAG|
+                          NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
+              NTLMFLAG_NEGOTIATE_OEM|
+              NTLMFLAG_REQUEST_TARGET|
+              NTLMFLAG_NEGOTIATE_NTLM_KEY|
+              NTLM2FLAG|
+              NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
+      print_flags(stderr,
+                  NTLMFLAG_NEGOTIATE_OEM|
+                  NTLMFLAG_REQUEST_TARGET|
+                  NTLMFLAG_NEGOTIATE_NTLM_KEY|
+                  NTLM2FLAG|
+                  NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
+      fprintf(stderr, "\n****\n");
+    });
+
+    /* now size is the size of the base64 encoded package size */
+    size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64);
+
+    if(size >0 ) {
+      Curl_safefree(*allocuserpwd);
+      *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+                              proxy?"Proxy-":"",
+                              base64);
+      DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
+      free(base64);
+    }
+    else
+      return CURLE_OUT_OF_MEMORY; /* FIX TODO */
+
+    break;
+
+  case NTLMSTATE_TYPE2:
+    /* We received the type-2 message 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
+
+    */
+
+  {
+#ifdef USE_WINDOWS_SSPI
+    SecBuffer type_2, type_3;
+    SecBufferDesc type_2_desc, type_3_desc;
+    SECURITY_STATUS status;
+    ULONG attrs;
+    TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */
+
+    type_2_desc.ulVersion  = type_3_desc.ulVersion  = SECBUFFER_VERSION;
+    type_2_desc.cBuffers   = type_3_desc.cBuffers   = 1;
+    type_2_desc.pBuffers   = &type_2;
+    type_3_desc.pBuffers   = &type_3;
+
+    type_2.BufferType = SECBUFFER_TOKEN;
+    type_2.pvBuffer   = ntlm->type_2;
+    type_2.cbBuffer   = ntlm->n_type_2;
+    type_3.BufferType = SECBUFFER_TOKEN;
+    type_3.pvBuffer   = ntlmbuf;
+    type_3.cbBuffer   = sizeof(ntlmbuf);
+
+    status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, &ntlm->c_handle,
+                                       (char *) host,
+                                       ISC_REQ_CONFIDENTIALITY |
+                                       ISC_REQ_REPLAY_DETECT |
+                                       ISC_REQ_CONNECTION,
+                                       0, SECURITY_NETWORK_DREP, &type_2_desc,
+                                       0, &ntlm->c_handle, &type_3_desc,
+                                       &attrs, &tsDummy);
+
+    if(status != SEC_E_OK)
+      return CURLE_RECV_ERROR;
+
+    size = type_3.cbBuffer;
+
+    ntlm_sspi_cleanup(ntlm);
+
+#else
+    int lmrespoff;
+    unsigned char lmresp[24]; /* fixed-size */
+#if USE_NTRESPONSES
+    int ntrespoff;
+    unsigned char ntresp[24]; /* fixed-size */
+#endif
+    size_t useroff;
+    const char *user;
+    size_t userlen;
+
+    user = strchr(userp, '\\');
+    if(!user)
+      user = strchr(userp, '/');
+
+    if(user) {
+      domain = userp;
+      domlen = (user - domain);
+      user++;
+    }
+    else
+      user = userp;
+    userlen = strlen(user);
+
+    if(gethostname(host, HOSTNAME_MAX)) {
+      infof(conn->data, "gethostname() failed, continuing without!");
+      hostlen = 0;
+    }
+    else {
+      /* If the workstation if configured with a full DNS name (i.e.
+       * workstation.somewhere.net) gethostname() returns the fully qualified
+       * name, which NTLM doesn't like.
+       */
+      char *dot = strchr(host, '.');
+      if(dot)
+        *dot = '\0';
+      hostlen = strlen(host);
+    }
+
+#if USE_NTLM2SESSION
+    /* We don't support NTLM2 if we don't have USE_NTRESPONSES */
+    if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
+      unsigned char ntbuffer[0x18];
+      unsigned char tmp[0x18];
+      unsigned char md5sum[MD5_DIGEST_LENGTH];
+      unsigned char entropy[8];
+
+      /* Need to create 8 bytes random data */
+#ifdef USE_SSLEAY
+      MD5_CTX MD5pw;
+      Curl_ossl_seed(conn->data); /* Initiate the seed if not already done */
+      RAND_bytes(entropy,8);
+#elif defined(USE_GNUTLS)
+      gcry_md_hd_t MD5pw;
+      Curl_gtls_seed(conn->data); /* Initiate the seed if not already done */
+      gcry_randomize(entropy, 8, GCRY_STRONG_RANDOM);
+#endif
+
+      /* 8 bytes random data as challenge in lmresp */
+      memcpy(lmresp,entropy,8);
+      /* Pad with zeros */
+      memset(lmresp+8,0,0x10);
+
+      /* Fill tmp with challenge(nonce?) + entropy */
+      memcpy(tmp,&ntlm->nonce[0],8);
+      memcpy(tmp+8,entropy,8);
+
+#ifdef USE_SSLEAY
+      MD5_Init(&MD5pw);
+      MD5_Update(&MD5pw, tmp, 16);
+      MD5_Final(md5sum, &MD5pw);
+#elif defined(USE_GNUTLS)
+      gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
+      gcry_md_write(MD5pw, tmp, MD5_DIGEST_LENGTH);
+      memcpy(md5sum, gcry_md_read (MD5pw, 0), MD5_DIGEST_LENGTH);
+      gcry_md_close(MD5pw);
+#endif
+
+      /* We shall only use the first 8 bytes of md5sum,
+         but the des code in lm_resp only encrypt the first 8 bytes */
+      if(mk_nt_hash(conn->data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY)
+        return CURLE_OUT_OF_MEMORY;
+      lm_resp(ntbuffer, md5sum, ntresp);
+
+      /* End of NTLM2 Session code */
+    }
+    else
+#endif
+	{
+
+#if USE_NTRESPONSES
+      unsigned char ntbuffer[0x18];
+#endif
+      unsigned char lmbuffer[0x18];
+
+#if USE_NTRESPONSES
+      if(mk_nt_hash(conn->data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY)
+        return CURLE_OUT_OF_MEMORY;
+      lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
+#endif
+
+      mk_lm_hash(conn->data, passwdp, lmbuffer);
+      lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
+      /* A safer but less compatible alternative is:
+       *   lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
+       * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */
+    }
+
+    lmrespoff = 64; /* size of the message header */
+#if USE_NTRESPONSES
+    ntrespoff = lmrespoff + 0x18;
+    domoff = ntrespoff + 0x18;
+#else
+    domoff = lmrespoff + 0x18;
+#endif
+    useroff = domoff + domlen;
+    hostoff = useroff + userlen;
+
+    /*
+     * In the case the server sets the flag NTLMFLAG_NEGOTIATE_UNICODE, we
+     * need to filter it off because libcurl doesn't UNICODE encode the
+     * strings it packs into the NTLM authenticate packet.
+     */
+    ntlm->flags &= ~NTLMFLAG_NEGOTIATE_UNICODE;
+
+    /* Create the big type-3 message binary blob */
+    size = snprintf((char *)ntlmbuf, sizeof(ntlmbuf),
+                    NTLMSSP_SIGNATURE "%c"
+                    "\x03%c%c%c" /* type-3, 32 bits */
+
+                    "%c%c" /* LanManager length */
+                    "%c%c" /* LanManager 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"  /* 2 zeroes */
+
+                    "%c%c"  /* session key length (unknown purpose) */
+                    "%c%c"  /* session key allocated space (unknown purpose) */
+                    "%c%c"  /* session key offset (unknown purpose) */
+                    "%c%c"  /* 2 zeroes */
+
+                    "%c%c%c%c" /* flags */
+
+                    /* 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,
+
+#if USE_NTRESPONSES
+                    SHORTPAIR(0x18),  /* NT-response length, twice */
+                    SHORTPAIR(0x18),
+                    SHORTPAIR(ntrespoff),
+                    0x0, 0x0,
+#else
+                    0x0, 0x0,
+                    0x0, 0x0,
+                    0x0, 0x0,
+                    0x0, 0x0,
+#endif
+                    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,
+
+                    LONGQUARTET(ntlm->flags));
+    DEBUGASSERT(size==64);
+
+    DEBUGASSERT(size == (size_t)lmrespoff);
+    /* We append the binary hashes */
+    if(size < (sizeof(ntlmbuf) - 0x18)) {
+      memcpy(&ntlmbuf[size], lmresp, 0x18);
+      size += 0x18;
+    }
+
+    DEBUG_OUT({
+        fprintf(stderr, "**** TYPE3 header lmresp=");
+        print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
+    });
+
+#if USE_NTRESPONSES
+    if(size < (sizeof(ntlmbuf) - 0x18)) {
+      DEBUGASSERT(size == (size_t)ntrespoff);
+      memcpy(&ntlmbuf[size], ntresp, 0x18);
+      size += 0x18;
+    }
+
+    DEBUG_OUT({
+        fprintf(stderr, "\n                  ntresp=");
+        print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18);
+    });
+
+#endif
+
+    DEBUG_OUT({
+        fprintf(stderr, "\n                  flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
+                LONGQUARTET(ntlm->flags), ntlm->flags);
+        print_flags(stderr, ntlm->flags);
+        fprintf(stderr, "\n****\n");
+    });
+
+
+    /* Make sure that the domain, user and host strings fit in the target
+       buffer before we copy them there. */
+    if(size + userlen + domlen + hostlen >= sizeof(ntlmbuf)) {
+      failf(conn->data, "user + domain + host name too big");
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    DEBUGASSERT(size == domoff);
+    memcpy(&ntlmbuf[size], domain, domlen);
+    size += domlen;
+
+    DEBUGASSERT(size == useroff);
+    memcpy(&ntlmbuf[size], user, userlen);
+    size += userlen;
+
+    DEBUGASSERT(size == hostoff);
+    memcpy(&ntlmbuf[size], host, hostlen);
+    size += hostlen;
+
+#ifdef CURL_DOES_CONVERSIONS
+    /* convert domain, user, and host to ASCII but leave the rest as-is */
+    if(CURLE_OK != Curl_convert_to_network(conn->data,
+                                           (char *)&ntlmbuf[domoff],
+                                           size-domoff)) {
+      return CURLE_CONV_FAILED;
+    }
+#endif /* CURL_DOES_CONVERSIONS */
+
+#endif
+
+    /* convert the binary blob into base64 */
+    size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64);
+
+    if(size >0 ) {
+      Curl_safefree(*allocuserpwd);
+      *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+                              proxy?"Proxy-":"",
+                              base64);
+      DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
+      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;
+}
+
+
+void
+Curl_ntlm_cleanup(struct connectdata *conn)
+{
+#ifdef USE_WINDOWS_SSPI
+  ntlm_sspi_cleanup(&conn->ntlm);
+  ntlm_sspi_cleanup(&conn->proxyntlm);
+#else
+  (void)conn;
+#endif
+}
+
+
+#endif /* USE_NTLM */
+#endif /* !CURL_DISABLE_HTTP */
diff --git a/lib/http_ntlm.h b/lib/http_ntlm.h
new file mode 100644
index 0000000..c7422d7
--- /dev/null
+++ b/lib/http_ntlm.h
@@ -0,0 +1,149 @@
+#ifndef __HTTP_NTLM_H
+#define __HTTP_NTLM_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+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,
+                         const char *header);
+
+/* this is for creating ntlm header output */
+CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy);
+
+void Curl_ntlm_cleanup(struct connectdata *conn);
+#ifndef USE_NTLM
+#define Curl_ntlm_cleanup(x)
+#endif
+
+/* 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)
+/* Indicates that datagram authentication is being used. */
+
+#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) */
+
+#define NTLMFLAG_NEGOTIATE_ANONYMOUS             (1<<11)
+/* Sent by the client in the Type 3 message to indicate that an anonymous
+   context has been established. This also affects the response fields. */
+
+#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)
+/* Indicates that the client will provide an encrypted master key in
+   the "Session Key" field of the Type 3 message. */
+
+#define NTLMFLAG_NEGOTIATE_56                    (1<<31)
+/* Indicates that 56-bit encryption is supported. */
+#endif
diff --git a/lib/if2ip.c b/lib/if2ip.c
new file mode 100644
index 0000000..19504d1
--- /dev/null
+++ b/lib/if2ip.c
@@ -0,0 +1,160 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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"
+
+#ifdef HAVE_UNISTD_H
+#  include <unistd.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
+#ifdef HAVE_NET_IF_H
+#  include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#  include <sys/ioctl.h>
+#endif
+#ifdef HAVE_NETDB_H
+#  include <netdb.h>
+#endif
+#ifdef HAVE_SYS_SOCKIO_H
+#  include <sys/sockio.h>
+#endif
+#ifdef HAVE_IFADDRS_H
+#  include <ifaddrs.h>
+#endif
+#ifdef HAVE_STROPTS_H
+#  include <stropts.h>
+#endif
+#ifdef __VMS
+#  include <inet.h>
+#endif
+
+#include "inet_ntop.h"
+#include "strequal.h"
+#include "if2ip.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* ------------------------------------------------------------------ */
+
+#if defined(HAVE_GETIFADDRS)
+
+char *Curl_if2ip(int af, const char *interface, char *buf, int buf_size)
+{
+  struct ifaddrs *iface, *head;
+  char *ip=NULL;
+
+  if (getifaddrs(&head) >= 0) {
+    for (iface=head; iface != NULL; iface=iface->ifa_next) {
+      if ((iface->ifa_addr != NULL) &&
+          (iface->ifa_addr->sa_family == af) &&
+          curl_strequal(iface->ifa_name, interface)) {
+        void *addr;
+        char scope[12]="";
+#ifdef ENABLE_IPV6
+        if (af == AF_INET6) {
+          unsigned int scopeid = 0;
+          addr = &((struct sockaddr_in6 *)iface->ifa_addr)->sin6_addr;
+#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
+          /* Include the scope of this interface as part of the address */
+          scopeid = ((struct sockaddr_in6 *)iface->ifa_addr)->sin6_scope_id;
+#endif
+          if (scopeid)
+            snprintf(scope, sizeof(scope), "%%%u", scopeid);
+        }
+        else
+#endif
+          addr = &((struct sockaddr_in *)iface->ifa_addr)->sin_addr;
+        ip = (char *) Curl_inet_ntop(af, addr, buf, buf_size);
+        strlcat(buf, scope, buf_size);
+        break;
+      }
+    }
+    freeifaddrs(head);
+  }
+  return ip;
+}
+
+#elif defined(HAVE_IOCTL_SIOCGIFADDR)
+
+char *Curl_if2ip(int af, const char *interface, char *buf, int buf_size)
+{
+  struct ifreq req;
+  struct in_addr in;
+  struct sockaddr_in *s;
+  curl_socket_t dummy;
+  size_t len;
+  char *ip;
+
+  if(!interface || (af != AF_INET))
+    return NULL;
+
+  len = strlen(interface);
+  if(len >= sizeof(req.ifr_name))
+    return NULL;
+
+  dummy = socket(AF_INET, SOCK_STREAM, 0);
+  if(CURL_SOCKET_BAD == dummy)
+    return NULL;
+
+  memset(&req, 0, sizeof(req));
+  memcpy(req.ifr_name, interface, len+1);
+  req.ifr_addr.sa_family = AF_INET;
+
+  if(ioctl(dummy, SIOCGIFADDR, &req) < 0) {
+    sclose(dummy);
+    return NULL;
+  }
+
+  s = (struct sockaddr_in *)&req.ifr_addr;
+  memcpy(&in, &s->sin_addr, sizeof(in));
+  ip = (char *) Curl_inet_ntop(s->sin_family, &in, buf, buf_size);
+
+  sclose(dummy);
+  return ip;
+}
+
+#else
+
+char *Curl_if2ip(int af, const char *interf, char *buf, int buf_size)
+{
+    (void) af;
+    (void) interf;
+    (void) buf;
+    (void) buf_size;
+    return NULL;
+}
+
+#endif
diff --git a/lib/if2ip.h b/lib/if2ip.h
new file mode 100644
index 0000000..cdf2638
--- /dev/null
+++ b/lib/if2ip.h
@@ -0,0 +1,65 @@
+#ifndef __IF2IP_H
+#define __IF2IP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2005, 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"
+
+extern char *Curl_if2ip(int af, const char *interf, char *buf, int buf_size);
+
+#ifdef __INTERIX
+#include <sys/socket.h>
+
+/* 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_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/lib/imap.c b/lib/imap.c
new file mode 100644
index 0000000..f7b895d
--- /dev/null
+++ b/lib/imap.c
@@ -0,0 +1,1030 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ * RFC3501 IMAPv4 protocol
+ * RFC5092 IMAP URL Scheme
+ *
+ ***************************************************************************/
+
+#include "setup.h"
+
+#ifndef CURL_DISABLE_IMAP
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.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
+#ifdef HAVE_UTSNAME_H
+#include <sys/utsname.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.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 "easyif.h" /* for Curl_convert_... prototypes */
+
+#include "if2ip.h"
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "socks.h"
+#include "imap.h"
+
+#include "strtoofft.h"
+#include "strequal.h"
+#include "sslgen.h"
+#include "connect.h"
+#include "strerror.h"
+#include "select.h"
+#include "multiif.h"
+#include "url.h"
+#include "rawstr.h"
+#include "strtoofft.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* Local API functions */
+static CURLcode imap_parse_url_path(struct connectdata *conn);
+static CURLcode imap_regular_transfer(struct connectdata *conn, bool *done);
+static CURLcode imap_do(struct connectdata *conn, bool *done);
+static CURLcode imap_done(struct connectdata *conn,
+                          CURLcode, bool premature);
+static CURLcode imap_connect(struct connectdata *conn, bool *done);
+static CURLcode imap_disconnect(struct connectdata *conn);
+static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done);
+static int imap_getsock(struct connectdata *conn,
+                        curl_socket_t *socks,
+                        int numsocks);
+static CURLcode imap_doing(struct connectdata *conn,
+                           bool *dophase_done);
+static CURLcode imap_setup_connection(struct connectdata * conn);
+
+/*
+ * IMAP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_imap = {
+  "IMAP",                           /* scheme */
+  imap_setup_connection,            /* setup_connection */
+  imap_do,                          /* do_it */
+  imap_done,                        /* done */
+  ZERO_NULL,                        /* do_more */
+  imap_connect,                     /* connect_it */
+  imap_multi_statemach,             /* connecting */
+  imap_doing,                       /* doing */
+  imap_getsock,                     /* proto_getsock */
+  imap_getsock,                     /* doing_getsock */
+  ZERO_NULL,                        /* perform_getsock */
+  imap_disconnect,                  /* disconnect */
+  PORT_IMAP,                        /* defport */
+  PROT_IMAP                         /* protocol */
+};
+
+
+#ifdef USE_SSL
+/*
+ * IMAPS protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_imaps = {
+  "IMAPS",                          /* scheme */
+  imap_setup_connection,            /* setup_connection */
+  imap_do,                          /* do_it */
+  imap_done,                        /* done */
+  ZERO_NULL,                        /* do_more */
+  imap_connect,                     /* connect_it */
+  imap_multi_statemach,             /* connecting */
+  imap_doing,                       /* doing */
+  imap_getsock,                     /* proto_getsock */
+  imap_getsock,                     /* doing_getsock */
+  ZERO_NULL,                        /* perform_getsock */
+  imap_disconnect,                  /* disconnect */
+  PORT_IMAPS,                       /* defport */
+  PROT_IMAP | PROT_IMAPS | PROT_SSL  /* protocol */
+};
+#endif
+
+#ifndef CURL_DISABLE_HTTP
+/*
+ * HTTP-proxyed IMAP protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_imap_proxy = {
+  "IMAP",                               /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  Curl_http,                            /* do_it */
+  Curl_http_done,                       /* done */
+  ZERO_NULL,                            /* do_more */
+  ZERO_NULL,                            /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  PORT_IMAP,                            /* defport */
+  PROT_HTTP                             /* protocol */
+};
+
+
+#ifdef USE_SSL
+/*
+ * HTTP-proxyed IMAPS protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_imaps_proxy = {
+  "IMAPS",                              /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  Curl_http,                            /* do_it */
+  Curl_http_done,                       /* done */
+  ZERO_NULL,                            /* do_more */
+  ZERO_NULL,                            /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  PORT_IMAPS,                           /* defport */
+  PROT_HTTP                             /* protocol */
+};
+#endif
+#endif
+
+/***********************************************************************
+ *
+ * imapsendf()
+ *
+ * Sends the formated string as an IMAP command to a server
+ *
+ * NOTE: we build the command in a fixed-length buffer, which sets length
+ * restrictions on the command!
+ *
+ * Designed to never block.
+ */
+static CURLcode imapsendf(struct connectdata *conn,
+                          const char *idstr, /* id to wait for at the
+                                                completion of this command */
+                          const char *fmt, ...)
+{
+  CURLcode res;
+  struct imap_conn *imapc = &conn->proto.imapc;
+  va_list ap;
+  va_start(ap, fmt);
+
+  imapc->idstr = idstr; /* this is the thing */
+
+  res = Curl_pp_vsendf(&imapc->pp, fmt, ap);
+
+  va_end(ap);
+
+  return res;
+}
+
+static const char *getcmdid(struct connectdata *conn)
+{
+  static const char * const ids[]= {
+    "A",
+    "B",
+    "C",
+    "D"
+  };
+
+  struct imap_conn *imapc = &conn->proto.imapc;
+
+  /* get the next id, but wrap at end of table */
+  imapc->cmdid = (int)((imapc->cmdid+1) % (sizeof(ids)/sizeof(ids[0])));
+
+  return ids[imapc->cmdid];
+}
+
+/* For the IMAP "protocol connect" and "doing" phases only */
+static int imap_getsock(struct connectdata *conn,
+                        curl_socket_t *socks,
+                        int numsocks)
+{
+  return Curl_pp_getsock(&conn->proto.imapc.pp, socks, numsocks);
+}
+
+/* fucntion that checks for an imap status code at the start of the
+   given string */
+static int imap_endofresp(struct pingpong *pp, int *resp)
+{
+  char *line = pp->linestart_resp;
+  size_t len = pp->nread_resp;
+  struct imap_conn *imapc = &pp->conn->proto.imapc;
+  const char *id = imapc->idstr;
+  size_t id_len = strlen(id);
+
+  if(len >= id_len + 3) {
+    if(!memcmp(id, line, id_len) && (line[id_len] == ' ') ) {
+      /* end of response */
+      *resp = line[id_len+1]; /* O, N or B */
+      return TRUE;
+    }
+    else if((imapc->state == IMAP_FETCH) &&
+            !memcmp("* ", line, 2) ) {
+      /* FETCH response we're interested in */
+      *resp = '*';
+      return TRUE;
+    }
+  }
+  return FALSE; /* nothing for us */
+}
+
+/* This is the ONLY way to change IMAP state! */
+static void state(struct connectdata *conn,
+                  imapstate newstate)
+{
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  /* for debug purposes */
+  static const char * const names[]={
+    "STOP",
+    "SERVERGREET",
+    "LOGIN",
+    "STARTTLS",
+    "SELECT",
+    "FETCH",
+    "LOGOUT",
+    /* LAST */
+  };
+#endif
+  struct imap_conn *imapc = &conn->proto.imapc;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  if(imapc->state != newstate)
+    infof(conn->data, "IMAP %p state change from %s to %s\n",
+          imapc, names[imapc->state], names[newstate]);
+#endif
+  imapc->state = newstate;
+}
+
+static CURLcode imap_state_login(struct connectdata *conn)
+{
+  CURLcode result;
+  struct FTP *imap = conn->data->state.proto.imap;
+  const char *str;
+
+  str = getcmdid(conn);
+
+  /* send USER and password */
+  result = imapsendf(conn, str, "%s LOGIN %s %s", str,
+                     imap->user?imap->user:"",
+                     imap->passwd?imap->passwd:"");
+  if(result)
+    return result;
+
+  state(conn, IMAP_LOGIN);
+
+  return CURLE_OK;
+}
+
+/* for STARTTLS responses */
+static CURLcode imap_state_starttls_resp(struct connectdata *conn,
+                                         int imapcode,
+                                         imapstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  (void)instate; /* no use for this yet */
+
+  if(imapcode != 'O') {
+    failf(data, "STARTTLS denied. %c", imapcode);
+    result = CURLE_LOGIN_DENIED;
+  }
+  else {
+    /* Curl_ssl_connect is BLOCKING */
+    result = Curl_ssl_connect(conn, FIRSTSOCKET);
+    if(CURLE_OK == result) {
+      conn->protocol |= PROT_IMAPS;
+      result = imap_state_login(conn);
+    }
+  }
+  state(conn, IMAP_STOP);
+  return result;
+}
+
+/* for LOGIN responses */
+static CURLcode imap_state_login_resp(struct connectdata *conn,
+                                      int imapcode,
+                                      imapstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  (void)instate; /* no use for this yet */
+
+  if(imapcode != 'O') {
+    failf(data, "Access denied. %c", imapcode);
+    result = CURLE_LOGIN_DENIED;
+  }
+
+  state(conn, IMAP_STOP);
+  return result;
+}
+
+/* for the (first line of) FETCH BODY[TEXT] response */
+static CURLcode imap_state_fetch_resp(struct connectdata *conn,
+                                      int imapcode,
+                                      imapstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  struct imap_conn *imapc = &conn->proto.imapc;
+  struct FTP *imap = data->state.proto.imap;
+  struct pingpong *pp = &imapc->pp;
+  const char *ptr = data->state.buffer;
+  (void)instate; /* no use for this yet */
+
+  if('*' != imapcode) {
+    Curl_pgrsSetDownloadSize(data, 0);
+    state(conn, IMAP_STOP);
+    return CURLE_OK;
+  }
+
+  /* Something like this comes "* 1 FETCH (BODY[TEXT] {2021}\r" */
+  while(*ptr && (*ptr != '{'))
+    ptr++;
+
+  if(*ptr == '{') {
+    curl_off_t filesize = curlx_strtoofft(ptr+1, NULL, 10);
+    if(filesize)
+      Curl_pgrsSetDownloadSize(data, filesize);
+
+    infof(data, "Found %" FORMAT_OFF_TU " bytes to download\n", filesize);
+
+    if(pp->cache) {
+      /* At this point there is a bunch of data in the header "cache" that is
+         actually body content, send it as body and then skip it. Do note
+         that there may even be additional "headers" after the body. */
+      size_t chunk = pp->cache_size;
+
+      if(chunk > (size_t)filesize)
+        /* the conversion from curl_off_t to size_t is always fine here */
+        chunk = (size_t)filesize;
+
+      result = Curl_client_write(conn, CLIENTWRITE_BODY, pp->cache, chunk);
+      if(result)
+        return result;
+
+      filesize -= chunk;
+
+      /* we've now used parts of or the entire cache */
+      if(pp->cache_size > chunk) {
+        /* part of, move the trailing data to the start and reduce the size */
+        memmove(pp->cache, pp->cache+chunk,
+                pp->cache_size - chunk);
+        pp->cache_size -= chunk;
+      }
+      else {
+        /* cache is drained */
+        free(pp->cache);
+        pp->cache = NULL;
+        pp->cache_size = 0;
+      }
+    }
+
+    infof(data, "Filesize left: %" FORMAT_OFF_T "\n", filesize);
+
+    if(!filesize)
+      /* the entire data is already transfered! */
+      result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+    else
+      /* IMAP download */
+      result=Curl_setup_transfer(conn, FIRSTSOCKET, filesize, FALSE,
+                                 imap->bytecountp,
+                                 -1, NULL); /* no upload here */
+
+    data->req.maxdownload = filesize;
+  }
+  else
+    /* We don't know how to parse this line */
+    result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: fix this code */
+
+  state(conn, IMAP_STOP);
+  return result;
+}
+
+/* start the DO phase */
+static CURLcode imap_select(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct imap_conn *imapc = &conn->proto.imapc;
+  const char *str;
+
+  str = getcmdid(conn);
+
+  result = imapsendf(conn, str, "%s SELECT %s", str,
+                     imapc->mailbox?imapc->mailbox:"");
+  if(result)
+    return result;
+
+  state(conn, IMAP_SELECT);
+  return result;
+}
+
+static CURLcode imap_fetch(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  const char *str;
+
+  str = getcmdid(conn);
+
+  /* TODO: make this select the correct mail
+   * Use "1 body[text]" to get the full mail body of mail 1
+   */
+  result = imapsendf(conn, str, "%s FETCH 1 BODY[TEXT]", str);
+  if(result)
+    return result;
+
+  /*
+   * When issued, the server will respond with a single line similar to
+   * '* 1 FETCH (BODY[TEXT] {2021}'
+   *
+   * Identifying the fetch and how many bytes of contents we can expect. We
+   * must extract that number before continuing to "download as usual".
+   */
+
+  state(conn, IMAP_FETCH);
+  return result;
+}
+
+/* for SELECT responses */
+static CURLcode imap_state_select_resp(struct connectdata *conn,
+                                       int imapcode,
+                                       imapstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  (void)instate; /* no use for this yet */
+
+  if(imapcode != 'O') {
+    failf(data, "Select failed");
+    result = CURLE_LOGIN_DENIED;
+  }
+  else
+    result = imap_fetch(conn);
+  return result;
+}
+
+static CURLcode imap_statemach_act(struct connectdata *conn)
+{
+  CURLcode result;
+  curl_socket_t sock = conn->sock[FIRSTSOCKET];
+  struct SessionHandle *data=conn->data;
+  int imapcode;
+  struct imap_conn *imapc = &conn->proto.imapc;
+  struct pingpong *pp = &imapc->pp;
+  size_t nread = 0;
+
+  if(pp->sendleft)
+    return Curl_pp_flushsend(pp);
+
+  /* we read a piece of response */
+  result = Curl_pp_readresp(sock, pp, &imapcode, &nread);
+  if(result)
+    return result;
+
+  if(imapcode)
+  /* we have now received a full IMAP server response */
+  switch(imapc->state) {
+  case IMAP_SERVERGREET:
+    if(imapcode != 'O') {
+      failf(data, "Got unexpected imap-server response");
+      return CURLE_FTP_WEIRD_SERVER_REPLY;
+    }
+
+    if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
+      /* We don't have a SSL/TLS connection yet, but SSL is requested. Switch
+         to TLS connection now */
+      const char *str;
+
+      str = getcmdid(conn);
+      result = imapsendf(conn, str, "%s STARTTLS", str);
+      state(conn, IMAP_STARTTLS);
+    }
+    else
+      result = imap_state_login(conn);
+    if(result)
+      return result;
+    break;
+
+  case IMAP_LOGIN:
+    result = imap_state_login_resp(conn, imapcode, imapc->state);
+    break;
+
+  case IMAP_STARTTLS:
+    result = imap_state_starttls_resp(conn, imapcode, imapc->state);
+    break;
+
+  case IMAP_FETCH:
+    result = imap_state_fetch_resp(conn, imapcode, imapc->state);
+    break;
+
+  case IMAP_SELECT:
+    result = imap_state_select_resp(conn, imapcode, imapc->state);
+    break;
+
+  case IMAP_LOGOUT:
+    /* fallthrough, just stop! */
+  default:
+    /* internal error */
+    state(conn, IMAP_STOP);
+    break;
+  }
+
+  return result;
+}
+
+/* called repeatedly until done from multi.c */
+static CURLcode imap_multi_statemach(struct connectdata *conn,
+                                         bool *done)
+{
+  struct imap_conn *imapc = &conn->proto.imapc;
+  CURLcode result = Curl_pp_multi_statemach(&imapc->pp);
+
+  *done = (bool)(imapc->state == IMAP_STOP);
+
+  return result;
+}
+
+static CURLcode imap_easy_statemach(struct connectdata *conn)
+{
+  struct imap_conn *imapc = &conn->proto.imapc;
+  struct pingpong *pp = &imapc->pp;
+  CURLcode result = CURLE_OK;
+
+  while(imapc->state != IMAP_STOP) {
+    result = Curl_pp_easy_statemach(pp);
+    if(result)
+      break;
+  }
+
+  return result;
+}
+
+/*
+ * Allocate and initialize the struct IMAP for the current SessionHandle.  If
+ * need be.
+ */
+static CURLcode imap_init(struct connectdata *conn)
+{
+  struct SessionHandle *data = conn->data;
+  struct FTP *imap = data->state.proto.imap;
+  if(!imap) {
+    imap = data->state.proto.imap = calloc(sizeof(struct FTP), 1);
+    if(!imap)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* get some initial data into the imap struct */
+  imap->bytecountp = &data->req.bytecount;
+
+  /* No need to duplicate user+password, the connectdata struct won't change
+     during a session, but we re-init them here since on subsequent inits
+     since the conn struct may have changed or been replaced.
+  */
+  imap->user = conn->user;
+  imap->passwd = conn->passwd;
+
+  return CURLE_OK;
+}
+
+/*
+ * imap_connect() should do everything that is to be considered a part of
+ * the connection phase.
+ *
+ * The variable 'done' points to will be TRUE if the protocol-layer connect
+ * phase is done when this function returns, or FALSE is not. When called as
+ * a part of the easy interface, it will always be TRUE.
+ */
+static CURLcode imap_connect(struct connectdata *conn,
+                                 bool *done) /* see description above */
+{
+  CURLcode result;
+  struct imap_conn *imapc = &conn->proto.imapc;
+  struct SessionHandle *data=conn->data;
+  struct pingpong *pp = &imapc->pp;
+
+  *done = FALSE; /* default to not done yet */
+
+  /* If there already is a protocol-specific struct allocated for this
+     sessionhandle, deal with it */
+  Curl_reset_reqproto(conn);
+
+  result = imap_init(conn);
+  if(CURLE_OK != result)
+    return result;
+
+  /* We always support persistant connections on imap */
+  conn->bits.close = FALSE;
+
+  pp->response_time = RESP_TIMEOUT; /* set default response time-out */
+  pp->statemach_act = imap_statemach_act;
+  pp->endofresp = imap_endofresp;
+  pp->conn = conn;
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY)
+  if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
+    /* for IMAP over HTTP proxy */
+    struct HTTP http_proxy;
+    struct FTP *imap_save;
+
+    /* BLOCKING */
+    /* We want "seamless" IMAP operations through HTTP proxy tunnel */
+
+    /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
+     * conn->proto.http; we want IMAP through HTTP and we have to change the
+     * member temporarily for connecting to the HTTP proxy. After
+     * Curl_proxyCONNECT we have to set back the member to the original struct
+     * IMAP pointer
+     */
+    imap_save = data->state.proto.imap;
+    memset(&http_proxy, 0, sizeof(http_proxy));
+    data->state.proto.http = &http_proxy;
+
+    result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
+                               conn->host.name, conn->remote_port);
+
+    data->state.proto.imap = imap_save;
+
+    if(CURLE_OK != result)
+      return result;
+  }
+#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */
+
+  if(conn->protocol & PROT_IMAPS) {
+    /* BLOCKING */
+    /* IMAPS is simply imap with SSL for the control channel */
+    /* now, perform the SSL initialization for this socket */
+    result = Curl_ssl_connect(conn, FIRSTSOCKET);
+    if(result)
+      return result;
+  }
+
+  Curl_pp_init(pp); /* init generic pingpong data */
+
+  /* When we connect, we start in the state where we await the server greeting
+     response */
+  state(conn, IMAP_SERVERGREET);
+  imapc->idstr = "*"; /* we start off waiting for a '*' response */
+
+  if(data->state.used_interface == Curl_if_multi)
+    result = imap_multi_statemach(conn, done);
+  else {
+    result = imap_easy_statemach(conn);
+    if(!result)
+      *done = TRUE;
+  }
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_done()
+ *
+ * The DONE function. This does what needs to be done after a single DO has
+ * performed.
+ *
+ * Input argument is already checked for validity.
+ */
+static CURLcode imap_done(struct connectdata *conn, CURLcode status,
+                          bool premature)
+{
+  struct SessionHandle *data = conn->data;
+  struct FTP *imap = data->state.proto.imap;
+  CURLcode result=CURLE_OK;
+  (void)premature;
+
+  if(!imap)
+    /* When the easy handle is removed from the multi while libcurl is still
+     * trying to resolve the host name, it seems that the imap struct is not
+     * yet initialized, but the removal action calls Curl_done() which calls
+     * this function. So we simply return success if no imap pointer is set.
+     */
+    return CURLE_OK;
+
+  if(status) {
+    conn->bits.close = TRUE; /* marked for closure */
+    result = status;      /* use the already set error code */
+  }
+
+  /* clear these for next connection */
+  imap->transfer = FTPTRANSFER_BODY;
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform()
+ *
+ * This is the actual DO function for IMAP. Get a file/directory according to
+ * the options previously setup.
+ */
+
+static
+CURLcode imap_perform(struct connectdata *conn,
+                     bool *connected,  /* connect status after PASV / PORT */
+                     bool *dophase_done)
+{
+  /* this is IMAP and no proxy */
+  CURLcode result=CURLE_OK;
+
+  DEBUGF(infof(conn->data, "DO phase starts\n"));
+
+  if(conn->data->set.opt_no_body) {
+    /* requested no body means no transfer... */
+    struct FTP *imap = conn->data->state.proto.imap;
+    imap->transfer = FTPTRANSFER_INFO;
+  }
+
+  *dophase_done = FALSE; /* not done yet */
+
+  /* start the first command in the DO phase */
+  result = imap_select(conn);
+  if(result)
+    return result;
+
+  /* run the state-machine */
+  if(conn->data->state.used_interface == Curl_if_multi)
+    result = imap_multi_statemach(conn, dophase_done);
+  else {
+    result = imap_easy_statemach(conn);
+    *dophase_done = TRUE; /* with the easy interface we are done here */
+  }
+  *connected = conn->bits.tcpconnect;
+
+  if(*dophase_done)
+    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_do()
+ *
+ * This function is registered as 'curl_do' function. It decodes the path
+ * parts etc as a wrapper to the actual DO function (imap_perform).
+ *
+ * The input argument is already checked for validity.
+ */
+static CURLcode imap_do(struct connectdata *conn, bool *done)
+{
+  CURLcode retcode = CURLE_OK;
+
+  *done = FALSE; /* default to false */
+
+  /*
+    Since connections can be re-used between SessionHandles, this might be a
+    connection already existing but on a fresh SessionHandle struct so we must
+    make sure we have a good 'struct IMAP' to play with. For new connections,
+    the struct IMAP is allocated and setup in the imap_connect() function.
+  */
+  Curl_reset_reqproto(conn);
+  retcode = imap_init(conn);
+  if(retcode)
+    return retcode;
+
+  retcode = imap_parse_url_path(conn);
+  if(retcode)
+    return retcode;
+
+  retcode = imap_regular_transfer(conn, done);
+
+  return retcode;
+}
+
+/***********************************************************************
+ *
+ * imap_logout()
+ *
+ * This should be called before calling sclose().  We should then wait for the
+ * response from the server before returning. The calling code should then try
+ * to close the connection.
+ *
+ */
+static CURLcode imap_logout(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  const char *str;
+
+  str = getcmdid(conn);
+
+  result = imapsendf(conn, str, "%s LOGOUT", str, NULL);
+  if(result)
+    return result;
+  state(conn, IMAP_LOGOUT);
+
+  result = imap_easy_statemach(conn);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_disconnect()
+ *
+ * Disconnect from an IMAP server. Cleanup protocol-specific per-connection
+ * resources. BLOCKING.
+ */
+static CURLcode imap_disconnect(struct connectdata *conn)
+{
+  struct imap_conn *imapc= &conn->proto.imapc;
+
+  /* The IMAP session may or may not have been allocated/setup at this
+     point! */
+  if (imapc->pp.conn)
+    (void)imap_logout(conn); /* ignore errors on the LOGOUT */
+
+  Curl_pp_disconnect(&imapc->pp);
+
+  Curl_safefree(imapc->mailbox);
+
+  return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * imap_parse_url_path()
+ *
+ * Parse the URL path into separate path components.
+ *
+ */
+static CURLcode imap_parse_url_path(struct connectdata *conn)
+{
+  /* the imap struct is already inited in imap_connect() */
+  struct imap_conn *imapc = &conn->proto.imapc;
+  struct SessionHandle *data = conn->data;
+  const char *path = data->state.path;
+  int len;
+
+  if(!*path)
+    path = "INBOX";
+
+  /* url decode the path and use this mailbox */
+  imapc->mailbox = curl_easy_unescape(data, path, 0, &len);
+  if(!imapc->mailbox)
+    return CURLE_OUT_OF_MEMORY;
+
+  return CURLE_OK;
+}
+
+/* call this when the DO phase has completed */
+static CURLcode imap_dophase_done(struct connectdata *conn,
+                                  bool connected)
+{
+  CURLcode result = CURLE_OK;
+  struct FTP *imap = conn->data->state.proto.imap;
+  (void)connected;
+
+  if(imap->transfer != FTPTRANSFER_BODY)
+    /* no data to transfer */
+    result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+
+  return result;
+}
+
+/* called from multi.c while DOing */
+static CURLcode imap_doing(struct connectdata *conn,
+                               bool *dophase_done)
+{
+  CURLcode result;
+  result = imap_multi_statemach(conn, dophase_done);
+
+  if(*dophase_done) {
+    result = imap_dophase_done(conn, FALSE /* not connected */);
+
+    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+  }
+  return result;
+}
+
+/***********************************************************************
+ *
+ * imap_regular_transfer()
+ *
+ * The input argument is already checked for validity.
+ *
+ * Performs all commands done before a regular transfer between a local and a
+ * remote host.
+ *
+ */
+static
+CURLcode imap_regular_transfer(struct connectdata *conn,
+                              bool *dophase_done)
+{
+  CURLcode result=CURLE_OK;
+  bool connected=FALSE;
+  struct SessionHandle *data = conn->data;
+  data->req.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);
+
+  result = imap_perform(conn,
+                        &connected, /* have we connected after PASV/PORT */
+                        dophase_done); /* all commands in the DO-phase done? */
+
+  if(CURLE_OK == result) {
+
+    if(!*dophase_done)
+      /* the DO phase has not completed yet */
+      return CURLE_OK;
+
+    result = imap_dophase_done(conn, connected);
+    if(result)
+      return result;
+  }
+
+  return result;
+}
+
+static CURLcode imap_setup_connection(struct connectdata * conn)
+{
+  struct SessionHandle *data = conn->data;
+
+  if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
+    /* Unless we have asked to tunnel imap operations through the proxy, we
+       switch and use HTTP operations only */
+#ifndef CURL_DISABLE_HTTP
+    if(conn->handler == &Curl_handler_imap)
+      conn->handler = &Curl_handler_imap_proxy;
+    else {
+#ifdef USE_SSL
+      conn->handler = &Curl_handler_imaps_proxy;
+#else
+      failf(data, "IMAPS not supported!");
+      return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+    }
+    /*
+     * We explicitly mark this connection as persistent here as we're doing
+     * IMAP over HTTP and thus we accidentally avoid setting this value
+     * otherwise.
+     */
+    conn->bits.close = FALSE;
+#else
+    failf(data, "IMAP over http proxy requires HTTP support built-in!");
+    return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+  }
+
+  data->state.path++;   /* don't include the initial slash */
+
+  return CURLE_OK;
+}
+
+#endif /* CURL_DISABLE_IMAP */
diff --git a/lib/imap.h b/lib/imap.h
new file mode 100644
index 0000000..2f0b62a
--- /dev/null
+++ b/lib/imap.h
@@ -0,0 +1,55 @@
+#ifndef __IMAP_H
+#define __IMAP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2009, 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 "pingpong.h"
+
+/****************************************************************************
+ * IMAP unique setup
+ ***************************************************************************/
+typedef enum {
+  IMAP_STOP,    /* do nothing state, stops the state machine */
+  IMAP_SERVERGREET, /* waiting for the initial greeting immediately after
+                       a connect */
+  IMAP_LOGIN,
+  IMAP_STARTTLS,
+  IMAP_SELECT,
+  IMAP_FETCH,
+  IMAP_LOGOUT,
+  IMAP_LAST  /* never used */
+} imapstate;
+
+/* imap_conn is used for struct connection-oriented data in the connectdata
+   struct */
+struct imap_conn {
+  struct pingpong pp;
+  char *mailbox;     /* what to FETCH */
+  imapstate state; /* always use imap.c:state() to change state! */
+  int cmdid;       /* id number/index */
+  const char *idstr; /* pointer to a string for which to wait for as id */
+};
+
+extern const struct Curl_handler Curl_handler_imap;
+extern const struct Curl_handler Curl_handler_imaps;
+
+#endif /* __IMAP_H */
diff --git a/lib/inet_ntop.c b/lib/inet_ntop.c
new file mode 100644
index 0000000..26867f4
--- /dev/null
+++ b/lib/inet_ntop.c
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 1996-2001  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.
+ */
+/*
+ * 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_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"
+
+#define IN6ADDRSZ       16
+#define INADDRSZ         4
+#define INT16SZ          2
+
+/*
+ * Format an IPv4 address, more or less like inet_ntoa().
+ *
+ * Returns `dst' (as a const)
+ * Note:
+ *  - uses no statics
+ *  - takes a unsigned char* not an in_addr as input
+ */
+static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size)
+{
+  char tmp[sizeof "255.255.255.255"];
+  size_t len;
+
+  DEBUGASSERT(size >= 16);
+
+  tmp[0] = '\0';
+  (void)snprintf(tmp, sizeof(tmp), "%d.%d.%d.%d",
+          ((int)((unsigned char)src[0])) & 0xff,
+          ((int)((unsigned char)src[1])) & 0xff,
+          ((int)((unsigned char)src[2])) & 0xff,
+          ((int)((unsigned char)src[3])) & 0xff);
+
+  len = strlen(tmp);
+  if(len == 0 || len >= size)
+  {
+    SET_ERRNO(ENOSPC);
+    return (NULL);
+  }
+  strcpy(dst, tmp);
+  return dst;
+}
+
+#ifdef ENABLE_IPV6
+/*
+ * Convert IPv6 binary address into presentation (printable) format.
+ */
+static char *inet_ntop6 (const unsigned 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;
+  unsigned 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;
+  best.len = 0;
+  cur.len = 0;
+
+  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);
+  }
+  strcpy(dst, tmp);
+  return dst;
+}
+#endif  /* ENABLE_IPV6 */
+
+/*
+ * Convert a network format address to presentation format.
+ *
+ * Returns pointer to presentation format address (`buf').
+ * Returns NULL on error and errno set with the specific
+ * error, EAFNOSUPPORT or ENOSPC.
+ *
+ * On Windows we store the error in the thread errno, not
+ * in the winsock error code. This is to avoid loosing the
+ * actual last winsock error. So use macro ERRNO to fetch the
+ * errno this funtion sets when returning NULL, not SOCKERRNO.
+ */
+char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
+{
+  switch (af) {
+  case AF_INET:
+    return inet_ntop4((const unsigned char*)src, buf, size);
+#ifdef ENABLE_IPV6
+  case AF_INET6:
+    return inet_ntop6((const unsigned char*)src, buf, size);
+#endif
+  default:
+    SET_ERRNO(EAFNOSUPPORT);
+    return NULL;
+  }
+}
+#endif  /* HAVE_INET_NTOP */
diff --git a/lib/inet_ntop.h b/lib/inet_ntop.h
new file mode 100644
index 0000000..8db9775
--- /dev/null
+++ b/lib/inet_ntop.h
@@ -0,0 +1,37 @@
+#ifndef __INET_NTOP_H
+#define __INET_NTOP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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"
+
+char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size);
+
+#ifdef HAVE_INET_NTOP
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#define Curl_inet_ntop(af,addr,buf,size) \
+        inet_ntop(af,addr,buf,(curl_socklen_t)size)
+#endif
+
+#endif /* __INET_NTOP_H */
diff --git a/lib/inet_pton.c b/lib/inet_pton.c
new file mode 100644
index 0000000..9189ce6
--- /dev/null
+++ b/lib/inet_pton.c
@@ -0,0 +1,239 @@
+/* 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_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
+
+/*
+ * 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)
+ * notice:
+ *      On Windows we store the error in the thread errno, not
+ *      in the winsock error code. This is to avoid loosing the
+ *      actual last winsock error. So use macro ERRNO to fetch the
+ *      errno this funtion sets when returning (-1), not SOCKERRNO.
+ * author:
+ *      Paul Vixie, 1996.
+ */
+int
+Curl_inet_pton(int af, const char *src, void *dst)
+{
+  switch (af) {
+  case AF_INET:
+    return (inet_pton4(src, (unsigned char *)dst));
+#ifdef ENABLE_IPV6
+  case AF_INET6:
+    return (inet_pton6(src, (unsigned char *)dst));
+#endif
+  default:
+    SET_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;
+  *tp = 0;
+  while((ch = *src++) != '\0') {
+    const char *pch;
+
+    if((pch = strchr(digits, ch)) != NULL) {
+      unsigned int val = *tp * 10 + (unsigned int)(pch - digits);
+
+      if(saw_digit && *tp == 0)
+        return (0);
+      if(val > 255)
+        return (0);
+      *tp = (unsigned char)val;
+      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);
+  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;
+  unsigned 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(++saw_xdigit > 4)
+        return (0);
+      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 long n = tp - colonp;
+    long i;
+
+    if(tp == endp)
+      return (0);
+    for (i = 1; i <= n; i++) {
+      endp[- i] = colonp[n - i];
+      colonp[n - i] = 0;
+    }
+    tp = endp;
+  }
+  if(tp != endp)
+    return (0);
+  memcpy(dst, tmp, IN6ADDRSZ);
+  return (1);
+}
+#endif /* ENABLE_IPV6 */
+
+#endif /* HAVE_INET_PTON */
diff --git a/lib/inet_pton.h b/lib/inet_pton.h
new file mode 100644
index 0000000..d53fddf
--- /dev/null
+++ b/lib/inet_pton.h
@@ -0,0 +1,36 @@
+#ifndef __INET_PTON_H
+#define __INET_PTON_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2005, 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"
+
+int Curl_inet_pton(int, const char *, void *);
+
+#ifdef HAVE_INET_PTON
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#define Curl_inet_pton(x,y,z) inet_pton(x,y,z)
+#endif
+
+#endif /* __INET_PTON_H */
diff --git a/lib/krb4.c b/lib/krb4.c
new file mode 100644
index 0000000..2b59fec
--- /dev/null
+++ b/lib/krb4.c
@@ -0,0 +1,422 @@
+/* This source code was modified by Martin Hedenfalk <mhe@stacken.kth.se> for
+ * use in Curl. Martin's latest changes were done 2000-09-18.
+ *
+ * It has since been patched away like a madman by Daniel Stenberg to make it
+ * better applied to curl conditions, and to make it not use globals, pollute
+ * name space and more.
+ *
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * Copyright (c) 2004 - 2009 Daniel Stenberg
+ * 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 <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 "urldata.h"
+#include "curl_base64.h"
+#include "ftp.h"
+#include "sendf.h"
+#include "krb4.h"
+#include "inet_ntop.h"
+#include "curl_memory.h"
+
+/* 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, const void *from, int length, int level, void **to,
+            struct connectdata *conn)
+{
+  struct krb4_data *d = app_data;
+  *to = malloc(length + 31);
+  if(!*to)
+    return -1;
+  if(level == prot_safe)
+    /* NOTE that the void* cast is safe, krb_mk_safe/priv don't modify the
+     * input buffer
+     */
+    return krb_mk_safe((void*)from, *to, length, &d->key,
+                       (struct sockaddr_in *)LOCAL_ADDR,
+                       (struct sockaddr_in *)REMOTE_ADDR);
+  else if(level == prot_private)
+    return krb_mk_priv((void*)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;
+  unsigned char *ptr;
+  size_t 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) {
+    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)
+      infof(data, "Can't get address for realm %s\n",
+                 krb_realmofhost(host));
+    else {
+      if(natAddr.s_addr != localaddr->sin_addr.s_addr) {
+        char addr_buf[128];
+        if(Curl_inet_ntop(AF_INET, natAddr, addr_buf, sizeof(addr_buf)))
+          infof(data, "Using NAT IP address (%s) for kerberos 4\n", addr_buf);
+        localaddr->sin_addr = natAddr;
+      }
+    }
+  }
+#endif
+
+  if(Curl_base64_encode(conn->data, (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, &ptr);
+  if(len > sizeof(adat.dat)-1) {
+    free(ptr);
+    len=0;
+  }
+  if(!len || !ptr) {
+    Curl_failf(data, "Failed to decode base64 from server");
+    return AUTH_ERROR;
+  }
+  memcpy((char *)adat.dat, ptr, len);
+  free(ptr);
+  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];
+  size_t tmp;
+  ssize_t nread;
+  int save;
+  CURLcode result;
+  unsigned char *ptr;
+
+  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, &ptr);
+  if(tmp >= sizeof(tkt.dat)) {
+    free(ptr);
+    tmp=0;
+  }
+  if(!tmp || !ptr) {
+    Curl_failf(conn->data, "Failed to decode base64 in reply");
+    Curl_set_command_prot(conn, save);
+    return CURLE_FTP_WEIRD_SERVER_REPLY;
+  }
+  memcpy((char *)tkt.dat, ptr, tmp);
+  free(ptr);
+  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(conn->data, (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/lib/krb4.h b/lib/krb4.h
new file mode 100644
index 0000000..81998b5
--- /dev/null
+++ b/lib/krb4.h
@@ -0,0 +1,74 @@
+#ifndef __KRB4_H
+#define __KRB4_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * 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.
+ *
+ ***************************************************************************/
+
+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 *, const 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
+
+#ifdef HAVE_KRB4
+extern struct Curl_sec_client_mech Curl_krb4_client_mech;
+#endif
+#ifdef HAVE_GSSAPI
+extern struct Curl_sec_client_mech Curl_krb5_client_mech;
+#endif
+
+CURLcode Curl_krb_kauth(struct connectdata *conn);
+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);
+ssize_t Curl_sec_send(struct connectdata *conn, int, const char *, int);
+int Curl_sec_write(struct connectdata *conn, int, const 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/lib/krb5.c b/lib/krb5.c
new file mode 100644
index 0000000..36afc3c
--- /dev/null
+++ b/lib/krb5.c
@@ -0,0 +1,325 @@
+/* GSSAPI/krb5 support for FTP - loosely based on old krb4.c
+ *
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * Copyright (c) 2004 - 2009 Daniel Stenberg
+ * 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_GSSAPI
+
+#ifdef HAVE_OLD_GSSMIT
+#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
+#endif
+
+#include <stdlib.h>
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#include <string.h>
+
+#ifdef HAVE_GSSGNU
+#  include <gss.h>
+#elif defined HAVE_GSSMIT
+   /* MIT style */
+#  include <gssapi/gssapi.h>
+#  include <gssapi/gssapi_generic.h>
+#  include <gssapi/gssapi_krb5.h>
+#else
+   /* Heimdal-style */
+#  include <gssapi.h>
+#endif
+
+#include "urldata.h"
+#include "curl_base64.h"
+#include "ftp.h"
+#include "sendf.h"
+#include "krb4.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 LOCAL_ADDR (&conn->local_addr)
+#define REMOTE_ADDR conn->ip_addr->ai_addr
+
+static int
+krb5_check_prot(void *app_data, int level)
+{
+  app_data = NULL; /* prevent compiler warning */
+  if(level == prot_confidential)
+    return -1;
+  return 0;
+}
+
+static int
+krb5_decode(void *app_data, void *buf, int len, int level,
+            struct connectdata *conn)
+{
+  gss_ctx_id_t *context = app_data;
+  OM_uint32 maj, min;
+  gss_buffer_desc enc, dec;
+
+  /* shut gcc up */
+  level = 0;
+  conn = NULL;
+
+  enc.value = buf;
+  enc.length = len;
+  maj = gss_unseal(&min, *context, &enc, &dec, NULL, NULL);
+  if(maj != GSS_S_COMPLETE) {
+    if(len >= 4)
+      strcpy(buf, "599 ");
+    return -1;
+  }
+
+  memcpy(buf, dec.value, dec.length);
+  len = dec.length;
+  gss_release_buffer(&min, &dec);
+
+  return len;
+}
+
+static int
+krb5_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 0;
+}
+
+static int
+krb5_encode(void *app_data, const void *from, int length, int level, void **to,
+            struct connectdata *conn)
+{
+  gss_ctx_id_t *context = app_data;
+  gss_buffer_desc dec, enc;
+  OM_uint32 maj, min;
+  int state;
+  int len;
+
+  /* shut gcc up */
+  conn = NULL;
+
+  /* NOTE that the cast is safe, neither of the krb5, gnu gss and heimdal
+   * libraries modify the input buffer in gss_seal()
+   */
+  dec.value = (void*)from;
+  dec.length = length;
+  maj = gss_seal(&min, *context,
+                 level == prot_private,
+                 GSS_C_QOP_DEFAULT,
+                 &dec, &state, &enc);
+
+  if(maj != GSS_S_COMPLETE)
+    return -1;
+
+  /* malloc a new buffer, in case gss_release_buffer doesn't work as expected */
+  *to = malloc(enc.length);
+  if(!*to)
+    return -1;
+  memcpy(*to, enc.value, enc.length);
+  len = enc.length;
+  gss_release_buffer(&min, &enc);
+  return len;
+}
+
+static int
+krb5_auth(void *app_data, struct connectdata *conn)
+{
+  int ret;
+  char *p;
+  const char *host = conn->dns_entry->addr->ai_canonname;
+  ssize_t nread;
+  curl_socklen_t l = sizeof(conn->local_addr);
+  struct SessionHandle *data = conn->data;
+  CURLcode result;
+  const char *service = "ftp", *srv_host = "host";
+  gss_buffer_desc gssbuf, _gssresp, *gssresp;
+  OM_uint32 maj, min;
+  gss_name_t gssname;
+  gss_ctx_id_t *context = app_data;
+  struct gss_channel_bindings_struct chan;
+
+  if(getsockname(conn->sock[FIRSTSOCKET],
+                 (struct sockaddr *)LOCAL_ADDR, &l) < 0)
+    perror("getsockname()");
+
+  chan.initiator_addrtype = GSS_C_AF_INET;
+  chan.initiator_address.length = l - 4;
+  chan.initiator_address.value =
+    &((struct sockaddr_in *)LOCAL_ADDR)->sin_addr.s_addr;
+  chan.acceptor_addrtype = GSS_C_AF_INET;
+  chan.acceptor_address.length = l - 4;
+  chan.acceptor_address.value =
+    &((struct sockaddr_in *)REMOTE_ADDR)->sin_addr.s_addr;
+  chan.application_data.length = 0;
+  chan.application_data.value = NULL;
+
+  /* this loop will execute twice (once for service, once for host) */
+  while(1) {
+    /* this really shouldn't be repeated here, but can't help it */
+    if(service == srv_host) {
+      result = Curl_ftpsendf(conn, "AUTH GSSAPI");
+
+      if(result)
+        return -2;
+      if(Curl_GetFTPResponse(&nread, conn, NULL))
+        return -1;
+
+      if(data->state.buffer[0] != '3')
+        return -1;
+    }
+
+    gssbuf.value = data->state.buffer;
+    gssbuf.length = snprintf(gssbuf.value, BUFSIZE, "%s@%s", service, host);
+    maj = gss_import_name(&min, &gssbuf, GSS_C_NT_HOSTBASED_SERVICE, &gssname);
+    if(maj != GSS_S_COMPLETE) {
+      gss_release_name(&min, &gssname);
+      if(service == srv_host) {
+        Curl_failf(data, "Error importing service name %s", gssbuf.value);
+        return AUTH_ERROR;
+      }
+      service = srv_host;
+      continue;
+    }
+    {
+      gss_OID t;
+      gss_display_name(&min, gssname, &gssbuf, &t);
+      Curl_infof(data, "Trying against %s\n", gssbuf.value);
+      gss_release_buffer(&min, &gssbuf);
+    }
+    gssresp = GSS_C_NO_BUFFER;
+    *context = GSS_C_NO_CONTEXT;
+
+    do {
+      ret = AUTH_OK;
+      maj = gss_init_sec_context(&min,
+                                 GSS_C_NO_CREDENTIAL,
+                                 context,
+                                 gssname,
+                                 GSS_C_NO_OID,
+                                 GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,
+                                 0,
+                                 &chan,
+                                 gssresp,
+                                 NULL,
+                                 &gssbuf,
+                                 NULL,
+                                 NULL);
+
+      if(gssresp) {
+        free(_gssresp.value);
+        gssresp = NULL;
+      }
+
+      if(maj != GSS_S_COMPLETE && maj != GSS_S_CONTINUE_NEEDED) {
+        Curl_infof(data, "Error creating security context");
+        ret = AUTH_ERROR;
+        break;
+      }
+
+      if(gssbuf.length != 0) {
+        if(Curl_base64_encode(data, (char *)gssbuf.value, gssbuf.length, &p)
+           < 1) {
+          Curl_infof(data, "Out of memory base64-encoding");
+          ret = AUTH_CONTINUE;
+          break;
+        }
+
+        result = Curl_ftpsendf(conn, "ADAT %s", p);
+
+        free(p);
+
+        if(result) {
+          ret = -2;
+          break;
+        }
+
+        if(Curl_GetFTPResponse(&nread, conn, NULL)) {
+          ret = -1;
+          break;
+        }
+
+        if(data->state.buffer[0] != '2' && data->state.buffer[0] != '3'){
+          Curl_infof(data, "Server didn't accept auth data\n");
+          ret = AUTH_ERROR;
+          break;
+        }
+
+        p = data->state.buffer + 4;
+        p = strstr(p, "ADAT=");
+        if(p) {
+          _gssresp.length = Curl_base64_decode(p + 5, (unsigned char **)
+                                               &_gssresp.value);
+          if(_gssresp.length < 1) {
+            Curl_failf(data, "Out of memory base64-encoding");
+            ret = AUTH_CONTINUE;
+            break;
+          }
+        }
+
+        gssresp = &_gssresp;
+      }
+    } while(maj == GSS_S_CONTINUE_NEEDED);
+
+    gss_release_name(&min, &gssname);
+
+    if(gssresp)
+      free(_gssresp.value);
+
+    if(ret == AUTH_OK || service == srv_host)
+      return ret;
+
+    service = srv_host;
+  }
+}
+
+struct Curl_sec_client_mech Curl_krb5_client_mech = {
+    "GSSAPI",
+    sizeof(gss_ctx_id_t),
+    NULL, /* init */
+    krb5_auth,
+    NULL, /* end */
+    krb5_check_prot,
+    krb5_overhead,
+    krb5_encode,
+    krb5_decode
+};
+
+#endif /* HAVE_GSSAPI */
+#endif /* CURL_DISABLE_FTP */
diff --git a/lib/ldap.c b/lib/ldap.c
new file mode 100644
index 0000000..07ec5b0
--- /dev/null
+++ b/lib/ldap.c
@@ -0,0 +1,718 @@
+/***************************************************************************
+ *                      _   _ ____  _
+ *  Project         ___| | | |  _ \| |
+ *                 / __| | | | |_) | |
+ *                | (__| |_| |  _ <| |___
+ *                 \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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"
+
+#ifndef CURL_DISABLE_LDAP
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+#ifdef CURL_LDAP_HYBRID         /* If W$ definitions are needed. */
+# include <windows.h>
+  /* Remember we are NOT in a W$ compiler! */
+# undef WIN32
+# undef _WIN32
+# undef __WIN32__
+#endif
+
+#ifdef CURL_LDAP_WIN            /* Use W$ LDAP implementation. */
+# include <winldap.h>
+# ifndef LDAP_VENDOR_NAME
+#  error Your Platform SDK is NOT sufficient for LDAP support! Update your Platform SDK, or disable LDAP support!
+# else
+#  include <winber.h>
+# endif
+#else
+#define LDAP_DEPRECATED 1       /* Be sure ldap_init() is defined. */
+#ifdef HAVE_LBER_H
+# include <lber.h>
+#endif
+# include <ldap.h>
+#if (defined(HAVE_LDAP_SSL) && defined(HAVE_LDAP_SSL_H))
+# include <ldap_ssl.h>
+#endif /* HAVE_LDAP_SSL && HAVE_LDAP_SSL_H */
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "sendf.h"
+#include "escape.h"
+#include "progress.h"
+#include "transfer.h"
+#include "strequal.h"
+#include "strtok.h"
+#include "curl_ldap.h"
+#include "curl_memory.h"
+#include "curl_base64.h"
+#include "rawstr.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "memdebug.h"
+
+#ifndef HAVE_LDAP_URL_PARSE
+
+/* Use our own implementation. */
+
+typedef struct {
+    char   *lud_host;
+    int     lud_port;
+    char   *lud_dn;
+    char  **lud_attrs;
+    int     lud_scope;
+    char   *lud_filter;
+    char  **lud_exts;
+} CURL_LDAPURLDesc;
+
+#undef LDAPURLDesc
+#define LDAPURLDesc             CURL_LDAPURLDesc
+
+static int  _ldap_url_parse (const struct connectdata *conn,
+                             LDAPURLDesc **ludp);
+static void _ldap_free_urldesc (LDAPURLDesc *ludp);
+
+#undef ldap_free_urldesc
+#define ldap_free_urldesc       _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
+
+
+static CURLcode Curl_ldap(struct connectdata *conn, bool *done);
+
+/*
+ * LDAP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ldap = {
+  "LDAP",                               /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  Curl_ldap,                            /* do_it */
+  ZERO_NULL,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  ZERO_NULL,                            /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  PORT_LDAP,                            /* defport */
+  PROT_LDAP                             /* protocol */
+};
+
+#ifdef HAVE_LDAP_SSL
+/*
+ * LDAPS protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ldaps = {
+  "LDAPS",                              /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  Curl_ldap,                            /* do_it */
+  ZERO_NULL,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  ZERO_NULL,                            /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  PORT_LDAPS,                           /* defport */
+  PROT_LDAP | PROT_SSL                  /* protocol */
+};
+#endif
+
+
+static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
+{
+  CURLcode status = CURLE_OK;
+  int rc = 0;
+  LDAP *server = NULL;
+  LDAPURLDesc *ludp = NULL;
+  LDAPMessage *result = NULL;
+  LDAPMessage *entryIterator;
+  int num = 0;
+  struct SessionHandle *data=conn->data;
+  int ldap_proto = LDAP_VERSION3;
+  int ldap_ssl = 0;
+  char *val_b64;
+  size_t val_b64_sz;
+  curl_off_t dlsize=0;
+#ifdef LDAP_OPT_NETWORK_TIMEOUT
+  struct timeval ldap_timeout = {10,0}; /* 10 sec connection/search timeout */
+#endif
+
+  *done = TRUE; /* unconditionally */
+  infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d\n",
+          LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION);
+  infof(data, "LDAP local: %s\n", data->change.url);
+
+#ifdef HAVE_LDAP_URL_PARSE
+  rc = ldap_url_parse(data->change.url, &ludp);
+#else
+  rc = _ldap_url_parse(conn, &ludp);
+#endif
+  if(rc != 0) {
+    failf(data, "LDAP local: %s", ldap_err2string(rc));
+    status = CURLE_LDAP_INVALID_URL;
+    goto quit;
+  }
+
+  /* Get the URL scheme ( either ldap or ldaps ) */
+  if(conn->protocol & PROT_SSL)
+    ldap_ssl = 1;
+  infof(data, "LDAP local: trying to establish %s connection\n",
+          ldap_ssl ? "encrypted" : "cleartext");
+
+#ifdef LDAP_OPT_NETWORK_TIMEOUT
+  ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout);
+#endif
+  ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
+
+  if(ldap_ssl) {
+#ifdef HAVE_LDAP_SSL
+#ifdef CURL_LDAP_WIN
+    /* Win32 LDAP SDK doesnt support insecure mode without CA! */
+    server = ldap_sslinit(conn->host.name, (int)conn->port, 1);
+    ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON);
+#else
+    int ldap_option;
+    char* ldap_ca = data->set.str[STRING_SSL_CAFILE];
+#if defined(CURL_HAS_NOVELL_LDAPSDK)
+    rc = ldapssl_client_init(NULL, NULL);
+    if(rc != LDAP_SUCCESS) {
+      failf(data, "LDAP local: ldapssl_client_init %s", ldap_err2string(rc));
+      status = CURLE_SSL_CERTPROBLEM;
+      goto quit;
+    }
+    if(data->set.ssl.verifypeer) {
+      /* Novell SDK supports DER or BASE64 files. */
+      int cert_type = LDAPSSL_CERT_FILETYPE_B64;
+      if((data->set.str[STRING_CERT_TYPE]) &&
+         (Curl_raw_equal(data->set.str[STRING_CERT_TYPE], "DER")))
+        cert_type = LDAPSSL_CERT_FILETYPE_DER;
+      if(!ldap_ca) {
+        failf(data, "LDAP local: ERROR %s CA cert not set!",
+              (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"));
+        status = CURLE_SSL_CERTPROBLEM;
+        goto quit;
+      }
+      infof(data, "LDAP local: using %s CA cert '%s'\n",
+              (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
+              ldap_ca);
+      rc = ldapssl_add_trusted_cert(ldap_ca, cert_type);
+      if(rc != LDAP_SUCCESS) {
+        failf(data, "LDAP local: ERROR setting %s CA cert: %s",
+                (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
+                ldap_err2string(rc));
+        status = CURLE_SSL_CERTPROBLEM;
+        goto quit;
+      }
+      ldap_option = LDAPSSL_VERIFY_SERVER;
+    } else {
+      ldap_option = LDAPSSL_VERIFY_NONE;
+    }
+    rc = ldapssl_set_verify_mode(ldap_option);
+    if(rc != LDAP_SUCCESS) {
+      failf(data, "LDAP local: ERROR setting cert verify mode: %s",
+              ldap_err2string(rc));
+      status = CURLE_SSL_CERTPROBLEM;
+      goto quit;
+    }
+    server = ldapssl_init(conn->host.name, (int)conn->port, 1);
+    if(server == NULL) {
+      failf(data, "LDAP local: Cannot connect to %s:%hu",
+              conn->host.name, conn->port);
+      status = CURLE_COULDNT_CONNECT;
+      goto quit;
+    }
+#elif defined(LDAP_OPT_X_TLS)
+    if(data->set.ssl.verifypeer) {
+      /* OpenLDAP SDK supports BASE64 files. */
+      if((data->set.str[STRING_CERT_TYPE]) &&
+         (!Curl_raw_equal(data->set.str[STRING_CERT_TYPE], "PEM"))) {
+        failf(data, "LDAP local: ERROR OpenLDAP does only support PEM cert-type!");
+        status = CURLE_SSL_CERTPROBLEM;
+        goto quit;
+      }
+      if(!ldap_ca) {
+        failf(data, "LDAP local: ERROR PEM CA cert not set!");
+        status = CURLE_SSL_CERTPROBLEM;
+        goto quit;
+      }
+      infof(data, "LDAP local: using PEM CA cert: %s\n", ldap_ca);
+      rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ldap_ca);
+      if(rc != LDAP_SUCCESS) {
+        failf(data, "LDAP local: ERROR setting PEM CA cert: %s",
+                ldap_err2string(rc));
+        status = CURLE_SSL_CERTPROBLEM;
+        goto quit;
+      }
+      ldap_option = LDAP_OPT_X_TLS_DEMAND;
+    } else {
+      ldap_option = LDAP_OPT_X_TLS_NEVER;
+    }
+    rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_option);
+    if(rc != LDAP_SUCCESS) {
+      failf(data, "LDAP local: ERROR setting cert verify mode: %s",
+              ldap_err2string(rc));
+      status = CURLE_SSL_CERTPROBLEM;
+      goto quit;
+    }
+    server = ldap_init(conn->host.name, (int)conn->port);
+    if(server == NULL) {
+      failf(data, "LDAP local: Cannot connect to %s:%hu",
+              conn->host.name, conn->port);
+      status = CURLE_COULDNT_CONNECT;
+      goto quit;
+    }
+    ldap_option = LDAP_OPT_X_TLS_HARD;
+    rc = ldap_set_option(server, LDAP_OPT_X_TLS, &ldap_option);
+    if(rc != LDAP_SUCCESS) {
+      failf(data, "LDAP local: ERROR setting SSL/TLS mode: %s",
+              ldap_err2string(rc));
+      status = CURLE_SSL_CERTPROBLEM;
+      goto quit;
+    }
+/*
+    rc = ldap_start_tls_s(server, NULL, NULL);
+    if(rc != LDAP_SUCCESS) {
+      failf(data, "LDAP local: ERROR starting SSL/TLS mode: %s",
+              ldap_err2string(rc));
+      status = CURLE_SSL_CERTPROBLEM;
+      goto quit;
+    }
+*/
+#else
+    /* we should probably never come up to here since configure
+       should check in first place if we can support LDAP SSL/TLS */
+    failf(data, "LDAP local: SSL/TLS not supported with this version "
+            "of the OpenLDAP toolkit\n");
+    status = CURLE_SSL_CERTPROBLEM;
+    goto quit;
+#endif
+#endif
+#endif /* CURL_LDAP_USE_SSL */
+  } else {
+    server = ldap_init(conn->host.name, (int)conn->port);
+    if(server == NULL) {
+      failf(data, "LDAP local: Cannot connect to %s:%hu",
+              conn->host.name, conn->port);
+      status = CURLE_COULDNT_CONNECT;
+      goto quit;
+    }
+  }
+#ifdef CURL_LDAP_WIN
+  ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
+#endif
+
+  rc = ldap_simple_bind_s(server,
+                          conn->bits.user_passwd ? conn->user : NULL,
+                          conn->bits.user_passwd ? conn->passwd : NULL);
+  if(!ldap_ssl && rc != 0) {
+    ldap_proto = LDAP_VERSION2;
+    ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
+    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: ldap_simple_bind_s %s", ldap_err2string(rc));
+     status = CURLE_LDAP_CANNOT_BIND;
+     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++)
+  {
+    BerElement *ber = NULL;
+    char  *attribute;       /*! suspicious that this isn't 'const' */
+    char  *dn = ldap_get_dn(server, entryIterator);
+    int i;
+
+    Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
+    Curl_client_write(conn, CLIENTWRITE_BODY, (char *)dn, 0);
+    Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
+
+    dlsize += strlen(dn)+5;
+
+    for (attribute = ldap_first_attribute(server, entryIterator, &ber);
+         attribute;
+         attribute = ldap_next_attribute(server, entryIterator, ber))
+    {
+      BerValue **vals = ldap_get_values_len(server, entryIterator, attribute);
+
+      if(vals != NULL)
+      {
+        for (i = 0; (vals[i] != NULL); i++)
+        {
+          Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
+          Curl_client_write(conn, CLIENTWRITE_BODY, (char *) attribute, 0);
+          Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2);
+          dlsize += strlen(attribute)+3;
+
+          if((strlen(attribute) > 7) &&
+              (strcmp(";binary",
+                      (char *)attribute +
+                      (strlen((char *)attribute) - 7)) == 0)) {
+            /* Binary attribute, encode to base64. */
+            val_b64_sz = Curl_base64_encode(data,
+                                            vals[i]->bv_val,
+                                            vals[i]->bv_len,
+                                            &val_b64);
+            if(val_b64_sz > 0) {
+              Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, val_b64_sz);
+              free(val_b64);
+              dlsize += val_b64_sz;
+            }
+          }
+          else {
+            Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val,
+                              vals[i]->bv_len);
+            dlsize += vals[i]->bv_len;
+          }
+          Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
+          dlsize++;
+        }
+
+        /* Free memory used to store values */
+        ldap_value_free_len(vals);
+      }
+      Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
+      dlsize++;
+      Curl_pgrsSetDownloadCounter(data, dlsize);
+      ldap_memfree(attribute);
+    }
+    ldap_memfree(dn);
+    if(ber)
+       ber_free(ber, 0);
+  }
+
+quit:
+  if(result) {
+    ldap_msgfree(result);
+    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);
+#if defined(HAVE_LDAP_SSL) && defined(CURL_HAS_NOVELL_LDAPSDK)
+  if(ldap_ssl)
+    ldapssl_client_deinit();
+#endif /* HAVE_LDAP_SSL && CURL_HAS_NOVELL_LDAPSDK */
+
+  /* no data to transfer */
+  Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+  conn->bits.close = TRUE;
+
+  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
+
+#ifndef HAVE_LDAP_URL_PARSE
+
+/*
+ * Return scope-value for a scope-string.
+ */
+static int str2scope (const char *p)
+{
+  if(strequal(p, "one"))
+     return LDAP_SCOPE_ONELEVEL;
+  if(strequal(p, "onetree"))
+     return LDAP_SCOPE_ONELEVEL;
+  if(strequal(p, "base"))
+     return LDAP_SCOPE_BASE;
+  if(strequal(p, "sub"))
+     return LDAP_SCOPE_SUBTREE;
+  if(strequal( 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 (void *data, LDAPURLDesc *ludp)
+{
+  int i;
+
+  if(ludp->lud_filter) {
+    ludp->lud_filter = curl_easy_unescape(data, ludp->lud_filter, 0, NULL);
+    if(!ludp->lud_filter)
+       return (FALSE);
+  }
+
+  for (i = 0; ludp->lud_attrs && ludp->lud_attrs[i]; i++) {
+    ludp->lud_attrs[i] = curl_easy_unescape(data, ludp->lud_attrs[i], 0, NULL);
+    if(!ludp->lud_attrs[i])
+       return (FALSE);
+  }
+
+  for (i = 0; ludp->lud_exts && ludp->lud_exts[i]; i++) {
+    ludp->lud_exts[i] = curl_easy_unescape(data, ludp->lud_exts[i], 0, NULL);
+    if(!ludp->lud_exts[i])
+       return (FALSE);
+  }
+
+  if(ludp->lud_dn) {
+    char *dn = ludp->lud_dn;
+    char *new_dn = curl_easy_unescape(data, dn, 0, NULL);
+
+    free(dn);
+    ludp->lud_dn = new_dn;
+    if(!new_dn)
+       return (FALSE);
+  }
+  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->data->state.path+1'. All fields are optional.
+ * e.g.
+ *   ldap://<hostname>:<port>/?<attributes>?<scope>?<filter>
+ * yields ludp->lud_dn = "".
+ *
+ * Defined in RFC4516 section 2.
+ */
+static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp)
+{
+  char *p, *q;
+  int i;
+
+  if(!conn->data ||
+      !conn->data->state.path ||
+      conn->data->state.path[0] != '/' ||
+      !checkprefix("LDAP", 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->data->state.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(conn->data, ludp))
+    return LDAP_NO_MEMORY;
+  return LDAP_SUCCESS;
+}
+
+static int _ldap_url_parse (const struct connectdata *conn,
+                            LDAPURLDesc **ludpp)
+{
+  LDAPURLDesc *ludp = calloc(1, sizeof(*ludp));
+  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  /* !HAVE_LDAP_URL_PARSE */
+#endif  /* CURL_DISABLE_LDAP */
diff --git a/lib/llist.c b/lib/llist.c
new file mode 100644
index 0000000..a121c60
--- /dev/null
+++ b/lib/llist.c
@@ -0,0 +1,186 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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 <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(struct curl_llist *l, curl_llist_dtor dtor)
+{
+  l->size = 0;
+  l->dtor = dtor;
+  l->head = NULL;
+  l->tail = NULL;
+}
+
+struct curl_llist *
+Curl_llist_alloc(curl_llist_dtor dtor)
+{
+  struct curl_llist *list;
+
+  list = malloc(sizeof(struct 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(struct curl_llist *list, struct curl_llist_element *e,
+                       const void *p)
+{
+  struct curl_llist_element *ne = malloc(sizeof(struct 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(struct curl_llist *list, struct 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(struct curl_llist *list, void *user)
+{
+  if(list) {
+    while(list->size > 0)
+      Curl_llist_remove(list, list->tail, user);
+
+    free(list);
+  }
+}
+
+size_t
+Curl_llist_count(struct curl_llist *list)
+{
+  return list->size;
+}
+
+int Curl_llist_move(struct curl_llist *list, struct curl_llist_element *e,
+                    struct curl_llist *to_list, struct curl_llist_element *to_e)
+{
+  /* Remove element from list */
+  if(e == NULL || list->size == 0)
+    return 0;
+
+  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->size;
+
+  /* Add element to to_list after to_e */
+  if(to_list->size == 0) {
+    to_list->head = e;
+    to_list->head->prev = NULL;
+    to_list->head->next = NULL;
+    to_list->tail = e;
+  }
+  else {
+    e->next = to_e->next;
+    e->prev = to_e;
+    if(to_e->next) {
+      to_e->next->prev = e;
+    }
+    else {
+      to_list->tail = e;
+    }
+    to_e->next = e;
+  }
+
+  ++to_list->size;
+
+  return 1;
+}
diff --git a/lib/llist.h b/lib/llist.h
new file mode 100644
index 0000000..358d3d6
--- /dev/null
+++ b/lib/llist.h
@@ -0,0 +1,61 @@
+#ifndef __LLIST_H
+#define __LLIST_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2008, 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 <stddef.h>
+
+typedef void (*curl_llist_dtor)(void *, void *);
+
+struct curl_llist_element {
+  void *ptr;
+
+  struct curl_llist_element *prev;
+  struct curl_llist_element *next;
+};
+
+struct curl_llist {
+  struct curl_llist_element *head;
+  struct curl_llist_element *tail;
+
+  curl_llist_dtor dtor;
+
+  size_t size;
+};
+
+void Curl_llist_init(struct curl_llist *, curl_llist_dtor);
+struct curl_llist *Curl_llist_alloc(curl_llist_dtor);
+int Curl_llist_insert_next(struct curl_llist *, struct curl_llist_element *,
+                           const void *);
+int Curl_llist_insert_prev(struct curl_llist *, struct curl_llist_element *,
+                           const void *);
+int Curl_llist_remove(struct curl_llist *, struct curl_llist_element *,
+                      void *);
+int Curl_llist_remove_next(struct curl_llist *, struct curl_llist_element *,
+                           void *);
+size_t Curl_llist_count(struct curl_llist *);
+void Curl_llist_destroy(struct curl_llist *, void *);
+int Curl_llist_move(struct curl_llist *, struct curl_llist_element *,
+                    struct curl_llist *, struct curl_llist_element *);
+
+#endif
diff --git a/lib/md5.c b/lib/md5.c
new file mode 100644
index 0000000..32d0634
--- /dev/null
+++ b/lib/md5.c
@@ -0,0 +1,372 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2008, 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"
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+
+#include <string.h>
+
+#include "curl_md5.h"
+
+#ifdef USE_GNUTLS
+
+#include <gcrypt.h>
+
+void Curl_md5it(unsigned char *outbuffer, /* 16 bytes */
+                const unsigned char *input)
+{
+  gcry_md_hd_t ctx;
+  gcry_md_open(&ctx, GCRY_MD_MD5, 0);
+  gcry_md_write(ctx, input, (unsigned int)strlen((char *)input));
+  memcpy (outbuffer, gcry_md_read (ctx, 0), 16);
+  gcry_md_close(ctx);
+}
+
+#else
+
+#ifdef USE_SSLEAY
+/* When OpenSSL is available we use the MD5-function from OpenSSL */
+
+#  ifdef USE_OPENSSL
+#    include <openssl/md5.h>
+#  else
+#    include <md5.h>
+#  endif
+
+#else /* USE_SSLEAY */
+/* When OpenSSL is not available we use this code segment */
+
+/* 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.
+ */
+
+/* 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 *, const 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], const unsigned char [64]);
+static void Encode(unsigned char *, UINT4 *, unsigned int);
+static void Decode(UINT4 *, const unsigned char *, unsigned int);
+
+static const 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 */
+                        const 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],
+                         const 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,
+                    const 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);
+}
+
+#endif /* USE_SSLEAY */
+
+void Curl_md5it(unsigned char *outbuffer, /* 16 bytes */
+                const unsigned char *input)
+{
+  MD5_CTX ctx;
+  MD5_Init(&ctx);
+  MD5_Update(&ctx, input, (unsigned int)strlen((char *)input));
+  MD5_Final(outbuffer, &ctx);
+}
+
+#endif /* USE_GNUTLS */
+
+#endif /* CURL_DISABLE_CRYPTO_AUTH */
diff --git a/lib/memdebug.c b/lib/memdebug.c
new file mode 100644
index 0000000..69e204b
--- /dev/null
+++ b/lib/memdebug.c
@@ -0,0 +1,394 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+#ifdef CURLDEBUG
+#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>
+#include <stdarg.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"
+
+#ifndef HAVE_ASSERT_H
+#  define assert(x) do { } while (0)
+#endif
+
+struct memdebug {
+  size_t size;
+  union {
+    double d;
+    void * p;
+  } 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 = NULL;
+static bool memlimit = FALSE; /* enable memory limit */
+static long memsize = 0;  /* set number of mallocs allowed */
+
+/* this sets the log file name */
+void curl_memdebug(const char *logname)
+{
+  if(!logfile) {
+    if(logname)
+      logfile = fopen(logname, "w");
+    else
+      logfile = stderr;
+#ifdef MEMDEBUG_LOG_SYNC
+    /* Flush the log file after every line so the log isn't lost in a crash */
+    setvbuf(logfile, (char *)NULL, _IOLBF, 0);
+#endif
+  }
+}
+
+/* This function sets the number of malloc() calls that should return
+   successfully! */
+void curl_memlimit(long limit)
+{
+  if(!memlimit) {
+    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(source) {
+        /* log to file */
+        curl_memlog("LIMIT %s:%d %s reached memlimit\n",
+                    source, line, func);
+        /* log to stderr also */
+        fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
+                source, line, func);
+      }
+      SET_ERRNO(ENOMEM);
+      return TRUE; /* RETURN ERROR! */
+    }
+    else
+      memsize--; /* countdown */
+
+    /* log the countdown */
+    if(source)
+      curl_memlog("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;
+
+  assert(wantedsize != 0);
+
+  if(countcheck("malloc", line, source))
+    return NULL;
+
+  /* alloc at least 64 bytes */
+  size = sizeof(struct memdebug)+wantedsize;
+
+  mem = (Curl_cmalloc)(size);
+  if(mem) {
+    /* fill memory with junk */
+    memset(mem->mem, 0xA5, wantedsize);
+    mem->size = wantedsize;
+  }
+
+  if(source)
+    curl_memlog("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;
+
+  assert(wanted_elements != 0);
+  assert(wanted_size != 0);
+
+  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 = (Curl_cmalloc)(size);
+  if(mem) {
+    /* fill memory with zeroes */
+    memset(mem->mem, 0, user_size);
+    mem->size = user_size;
+  }
+
+  if(source)
+    curl_memlog("MEM %s:%d calloc(%zu,%zu) = %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;
+
+  assert(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(source)
+    curl_memlog("MEM %s:%d strdup(%p) (%zu) = %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;
+
+  assert(wantedsize != 0);
+
+  if(countcheck("realloc", line, source))
+    return NULL;
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:1684)
+   /* 1684: conversion from pointer to same-sized integral type */
+#endif
+
+  if(ptr)
+    mem = (void *)((char *)ptr - offsetof(struct memdebug, mem));
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+
+  mem = (Curl_crealloc)(mem, size);
+  if(source)
+    curl_memlog("MEM %s:%d realloc(%p, %zu) = %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;
+
+  assert(ptr != NULL);
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:1684)
+   /* 1684: conversion from pointer to same-sized integral type */
+#endif
+
+  mem = (void *)((char *)ptr - offsetof(struct memdebug, mem));
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+
+  /* destroy  */
+  memset(mem->mem, 0x13, mem->size);
+
+  /* free for real */
+  (Curl_cfree)(mem);
+
+  if(source)
+    curl_memlog("MEM %s:%d free(%p)\n", source, line, ptr);
+}
+
+curl_socket_t curl_socket(int domain, int type, int protocol,
+                          int line, const char *source)
+{
+  const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
+                    "FD %s:%d socket() = %d\n" :
+                    (sizeof(curl_socket_t) == sizeof(long)) ?
+                    "FD %s:%d socket() = %ld\n" :
+                    "FD %s:%d socket() = %zd\n" ;
+
+  curl_socket_t sockfd = socket(domain, type, protocol);
+  if(source && (sockfd != CURL_SOCKET_BAD))
+    curl_memlog(fmt, source, line, sockfd);
+  return sockfd;
+}
+
+curl_socket_t curl_accept(curl_socket_t s, void *saddr, void *saddrlen,
+                          int line, const char *source)
+{
+  const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
+                    "FD %s:%d accept() = %d\n" :
+                    (sizeof(curl_socket_t) == sizeof(long)) ?
+                    "FD %s:%d accept() = %ld\n" :
+                    "FD %s:%d accept() = %zd\n" ;
+
+  struct sockaddr *addr = (struct sockaddr *)saddr;
+  curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen;
+  curl_socket_t sockfd = accept(s, addr, addrlen);
+  if(source && (sockfd != CURL_SOCKET_BAD))
+    curl_memlog(fmt, source, line, sockfd);
+  return sockfd;
+}
+
+/* separate function to allow libcurl to mark a "faked" close */
+void curl_mark_sclose(curl_socket_t sockfd, int line, const char *source)
+{
+  const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
+                    "FD %s:%d sclose(%d)\n" :
+                    (sizeof(curl_socket_t) == sizeof(long)) ?
+                    "FD %s:%d sclose(%ld)\n" :
+                    "FD %s:%d sclose(%zd)\n" ;
+
+  if(source)
+    curl_memlog(fmt, source, line, sockfd);
+}
+
+/* this is our own defined way to close sockets on *ALL* platforms */
+int curl_sclose(curl_socket_t sockfd, int line, const char *source)
+{
+  int res=sclose(sockfd);
+  curl_mark_sclose(sockfd, line, source);
+  return res;
+}
+
+FILE *curl_fopen(const char *file, const char *mode,
+                 int line, const char *source)
+{
+  FILE *res=fopen(file, mode);
+  if(source)
+    curl_memlog("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
+                source, line, file, mode, res);
+  return res;
+}
+
+#ifdef HAVE_FDOPEN
+FILE *curl_fdopen(int filedes, const char *mode,
+                  int line, const char *source)
+{
+  FILE *res=fdopen(filedes, mode);
+  if(source)
+    curl_memlog("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n",
+                source, line, filedes, mode, res);
+  return res;
+}
+#endif
+
+int curl_fclose(FILE *file, int line, const char *source)
+{
+  int res;
+
+  assert(file != NULL);
+
+  res=fclose(file);
+  if(source)
+    curl_memlog("FILE %s:%d fclose(%p)\n",
+                source, line, file);
+  return res;
+}
+
+#define LOGLINE_BUFSIZE  1024
+
+/* this does the writting to the memory tracking log file */
+void curl_memlog(const char *format, ...)
+{
+  char *buf;
+  int nchars;
+  va_list ap;
+
+  if(!logfile)
+    return;
+
+  buf = (Curl_cmalloc)(LOGLINE_BUFSIZE);
+  if(!buf)
+    return;
+
+  va_start(ap, format);
+  nchars = vsnprintf(buf, LOGLINE_BUFSIZE, format, ap);
+  va_end(ap);
+
+  if(nchars > LOGLINE_BUFSIZE - 1)
+    nchars = LOGLINE_BUFSIZE - 1;
+
+  if(nchars > 0)
+    fwrite(buf, 1, nchars, logfile);
+
+  (Curl_cfree)(buf);
+}
+
+#endif /* CURLDEBUG */
diff --git a/lib/memdebug.h b/lib/memdebug.h
new file mode 100644
index 0000000..56b9f12
--- /dev/null
+++ b/lib/memdebug.h
@@ -0,0 +1,139 @@
+#ifdef CURLDEBUG
+#ifndef _CURL_MEMDEBUG_H
+#define _CURL_MEMDEBUG_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+/*
+ * 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 <curl/curl.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#include <stdio.h>
+
+#define logfile curl_debuglogfile
+
+extern FILE *logfile;
+
+/* memory functions */
+CURL_EXTERN void *curl_domalloc(size_t size, int line, const char *source);
+CURL_EXTERN void *curl_docalloc(size_t elements, size_t size, int line, const char *source);
+CURL_EXTERN void *curl_dorealloc(void *ptr, size_t size, int line, const char *source);
+CURL_EXTERN void curl_dofree(void *ptr, int line, const char *source);
+CURL_EXTERN char *curl_dostrdup(const char *str, int line, const char *source);
+CURL_EXTERN void curl_memdebug(const char *logname);
+CURL_EXTERN void curl_memlimit(long limit);
+CURL_EXTERN void curl_memlog(const char *format, ...);
+
+/* file descriptor manipulators */
+CURL_EXTERN curl_socket_t curl_socket(int domain, int type, int protocol,
+                                      int line , const char *source);
+CURL_EXTERN void curl_mark_sclose(curl_socket_t sockfd,
+                                  int line , const char *source);
+CURL_EXTERN int curl_sclose(curl_socket_t sockfd,
+                            int line , const char *source);
+CURL_EXTERN curl_socket_t curl_accept(curl_socket_t s, void *a, void *alen,
+                                      int line, const char *source);
+
+/* FILE functions */
+CURL_EXTERN FILE *curl_fopen(const char *file, const char *mode, int line,
+                             const char *source);
+#ifdef HAVE_FDOPEN
+CURL_EXTERN FILE *curl_fdopen(int filedes, const char *mode, int line,
+                              const char *source);
+#endif
+CURL_EXTERN 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__)
+
+#ifdef HAVE_GETADDRINFO
+#if defined(getaddrinfo) && defined(__osf__)
+/* OSF/1 and Tru64 have getaddrinfo as a define already, so we cannot define
+   our macro as for other platforms. Instead, we redefine the new name they
+   define getaddrinfo to become! */
+#define ogetaddrinfo(host,serv,hint,res) \
+  curl_dogetaddrinfo(host,serv,hint,res,__LINE__,__FILE__)
+#else
+#undef getaddrinfo
+#define getaddrinfo(host,serv,hint,res) \
+  curl_dogetaddrinfo(host,serv,hint,res,__LINE__,__FILE__)
+#endif
+#endif /* HAVE_GETADDRINFO */
+
+#ifdef HAVE_GETNAMEINFO
+#undef getnameinfo
+#define getnameinfo(sa,salen,host,hostlen,serv,servlen,flags) \
+  curl_dogetnameinfo(sa,salen,host,hostlen,serv,servlen,flags, __LINE__, \
+  __FILE__)
+#endif /* HAVE_GETNAMEINFO */
+
+#ifdef HAVE_FREEADDRINFO
+#undef freeaddrinfo
+#define freeaddrinfo(data) \
+  curl_dofreeaddrinfo(data,__LINE__,__FILE__)
+#endif /* HAVE_FREEADDRINFO */
+
+/* sclose is probably already defined, redefine it! */
+#undef sclose
+#define sclose(sockfd) curl_sclose(sockfd,__LINE__,__FILE__)
+
+#define fake_sclose(sockfd) curl_mark_sclose(sockfd,__LINE__,__FILE__)
+
+#undef fopen
+#define fopen(file,mode) curl_fopen(file,mode,__LINE__,__FILE__)
+#undef fdopen
+#define fdopen(file,mode) curl_fdopen(file,mode,__LINE__,__FILE__)
+#define fclose(file) curl_fclose(file,__LINE__,__FILE__)
+
+#endif /* MEMDEBUG_NODEFINES */
+
+#endif /* _CURL_MEMDEBUG_H */
+#endif /* CURLDEBUG */
+
+#ifndef fake_sclose
+#define fake_sclose(x)
+#endif
diff --git a/lib/mk-ca-bundle.pl b/lib/mk-ca-bundle.pl
new file mode 100755
index 0000000..8d461d0
--- /dev/null
+++ b/lib/mk-ca-bundle.pl
@@ -0,0 +1,186 @@
+#!/usr/bin/perl -w
+# ***************************************************************************
+# *                                  _   _ ____  _
+# *  Project                     ___| | | |  _ \| |
+# *                             / __| | | | |_) | |
+# *                            | (__| |_| |  _ <| |___
+# *                             \___|\___/|_| \_\_____|
+# *
+# * Copyright (C) 1998 - 2010, 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.
+# *
+# ***************************************************************************
+# This Perl script creates a fresh ca-bundle.crt file for use with libcurl.
+# It downloads certdata.txt from Mozilla's source tree (see URL below),
+# then parses certdata.txt and extracts CA Root Certificates into PEM format.
+# These are then processed with the OpenSSL commandline tool to produce the
+# final ca-bundle.crt file.
+# The script is based on the parse-certs script written by Roland Krikava.
+# This Perl script works on almost any platform since its only external
+# dependency is the OpenSSL commandline tool for optional text listing.
+# Hacked by Guenter Knauf.
+#
+use Getopt::Std;
+use MIME::Base64;
+use LWP::UserAgent;
+use strict;
+use vars qw($opt_b $opt_h $opt_i $opt_l $opt_n $opt_q $opt_t $opt_u $opt_v);
+
+my $url = 'http://mxr.mozilla.org/seamonkey/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1';
+# If the OpenSSL commandline is not in search path you can configure it here!
+my $openssl = 'openssl';
+
+my $version = $1 if ('$Revision$' =~ /\s(\d+\.\d+)\s/);
+
+getopts('bhilnqtuv');
+
+if ($opt_i) {
+  print ("=" x 78 . "\n");
+  print "Script Version            : $version\n";
+  print "Perl Version              : $]\n";
+  print "Operating System Name     : $^O\n";
+  print "Getopt::Std.pm Version    : ${Getopt::Std::VERSION}\n";
+  print "MIME::Base64.pm Version   : ${MIME::Base64::VERSION}\n";
+  print "LWP::UserAgent.pm Version : ${LWP::UserAgent::VERSION}\n";
+  print "LWP.pm Version            : ${LWP::VERSION}\n";
+  print ("=" x 78 . "\n");
+}
+
+$0 =~ s/\\/\//g;
+$0 = substr($0, rindex($0, '/') + 1);
+if ($opt_h) {
+  printf("Usage:\t%s [-b] [-i] [-l] [-n] [-q] [-t] [-u] [-v] [<outputfile>]\n", $0);
+  print "\t-b\tbackup an existing version of ca-bundle.crt\n";
+  print "\t-i\tprint version info about used modules\n";
+  print "\t-l\tprint license info about certdata.txt\n";
+  print "\t-n\tno download of certdata.txt (to use existing)\n";
+  print "\t-q\tbe really quiet (no progress output at all)\n";
+  print "\t-t\tinclude plain text listing of certificates\n";
+  print "\t-u\tunlink (remove) certdata.txt after processing\n";
+  print "\t-v\tbe verbose and print out processed CAs\n";
+  exit;
+}
+
+my $crt = $ARGV[0] || 'ca-bundle.crt';
+my $txt = substr($url, rindex($url, '/') + 1);
+$txt =~ s/\?.*//;
+
+if (!$opt_n || !-e $txt) {
+  print "Downloading '$txt' ...\n" if (!$opt_q);
+  my $ua  = new LWP::UserAgent(agent => "$0/$version");
+  my $req = new HTTP::Request('GET', $url);
+  my $res = $ua->request($req);
+  if ($res->is_success) {
+    open(TXT,">$txt") or die "Couldn't open $txt: $!";
+    print TXT $res->content . "\n";
+    close(TXT) or die "Couldn't close $txt: $!";
+  } else {
+    die $res->status_line;
+  }
+}
+
+if ($opt_b && -e $crt) {
+  my $bk = 1;
+  while (-e "$crt.~${bk}~") {
+    $bk++;
+  }
+  rename $crt, "$crt.~${bk}~";
+}
+
+my $format = $opt_t ? "plain text and " : "";
+my $currentdate = scalar gmtime() . " UTC";
+open(CRT,">$crt") or die "Couldn't open $crt: $!";
+print CRT <<EOT;
+##
+## $crt -- Bundle of CA Root Certificates
+##
+## Converted at: ${currentdate}
+##
+## This is a bundle of X.509 certificates of public Certificate Authorities
+## (CA). These were automatically extracted from Mozilla's root certificates
+## file (certdata.txt).  This file can be found in the mozilla source tree:
+## '/mozilla/security/nss/lib/ckfw/builtins/certdata.txt'
+##
+## It contains the certificates in ${format}PEM format and therefore
+## can be directly used with curl / libcurl / php_curl, or with
+## an Apache+mod_ssl webserver for SSL client authentication.
+## Just configure this file as the SSLCACertificateFile.
+##
+
+EOT
+
+close(CRT) or die "Couldn't close $crt: $!";
+
+print "Processing  '$txt' ...\n" if (!$opt_q);
+my $caname;
+my $certnum = 0;
+open(TXT,"$txt") or die "Couldn't open $txt: $!";
+while (<TXT>) {
+  if (/\*\*\*\*\* BEGIN LICENSE BLOCK \*\*\*\*\*/) {
+    open(CRT, ">>$crt") or die "Couldn't open $crt: $!";
+    print CRT;
+    print if ($opt_l);
+    while (<TXT>) {
+      print CRT;
+      print if ($opt_l);
+      last if (/\*\*\*\*\* END LICENSE BLOCK \*\*\*\*\*/);
+    }
+    close(CRT) or die "Couldn't close $crt: $!";
+  }
+  next if /^#|^\s*$/;
+  chomp;
+  if (/^CVS_ID\s+\"(.*)\"/) {
+    open(CRT, ">>$crt") or die "Couldn't open $crt: $!";
+    print CRT "# $1\n";
+    close(CRT) or die "Couldn't close $crt: $!";
+  }
+  if (/^CKA_LABEL\s+[A-Z0-9]+\s+\"(.*)\"/) {
+    $caname = $1;
+  }
+  if (/^CKA_VALUE MULTILINE_OCTAL/) {
+    my $data;
+    while (<TXT>) {
+      last if (/^END/);
+      chomp;
+      my @octets = split(/\\/);
+      shift @octets;
+      for (@octets) {
+        $data .= chr(oct);
+      }
+    }
+    my $pem = "-----BEGIN CERTIFICATE-----\n"
+            . MIME::Base64::encode($data)
+            . "-----END CERTIFICATE-----\n";
+    open(CRT, ">>$crt") or die "Couldn't open $crt: $!";
+    print CRT "\n$caname\n";
+    print CRT ("=" x length($caname) . "\n");
+    if (!$opt_t) {
+      print CRT $pem;
+    }
+    close(CRT) or die "Couldn't close $crt: $!";
+    if ($opt_t) {
+      open(TMP, "|$openssl x509 -md5 -fingerprint -text -inform PEM >> $crt") or die "Couldn't open openssl pipe: $!";
+      print TMP $pem;
+      close(TMP) or die "Couldn't close openssl pipe: $!";
+    }
+    print "Parsing: $caname\n" if ($opt_v);
+    $certnum ++;
+  }
+}
+close(TXT) or die "Couldn't close $txt: $!";
+unlink $txt if ($opt_u);
+print "Done ($certnum CA certs processed).\n" if (!$opt_q);
+
+exit;
+
+
diff --git a/lib/mprintf.c b/lib/mprintf.c
new file mode 100644
index 0000000..1d93c58
--- /dev/null
+++ b/lib/mprintf.c
@@ -0,0 +1,1247 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1999 - 2010, 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.
+ *
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <string.h>
+
+#if defined(DJGPP) && (DJGPP_MINOR < 4)
+#undef _MPRINTF_REPLACE /* don't use x_was_used() here */
+#endif
+
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifndef SIZEOF_LONG_DOUBLE
+#define SIZEOF_LONG_DOUBLE 0
+#endif
+
+/*
+ * If SIZEOF_SIZE_T has not been defined, default to the size of long.
+ */
+
+#ifndef SIZEOF_SIZE_T
+#  define SIZEOF_SIZE_T CURL_SIZEOF_LONG
+#endif
+
+#ifdef HAVE_LONGLONG
+#  define LONG_LONG_TYPE long long
+#  define HAVE_LONG_LONG_TYPE
+#else
+#  if defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
+#    define LONG_LONG_TYPE __int64
+#    define HAVE_LONG_LONG_TYPE
+#  else
+#    undef LONG_LONG_TYPE
+#    undef HAVE_LONG_LONG_TYPE
+#  endif
+#endif
+
+/*
+ * Max integer data types that mprintf.c is capable
+ */
+
+#ifdef HAVE_LONG_LONG_TYPE
+#  define mp_intmax_t LONG_LONG_TYPE
+#  define mp_uintmax_t unsigned LONG_LONG_TYPE
+#else
+#  define mp_intmax_t long
+#  define mp_uintmax_t unsigned long
+#endif
+
+#define BUFFSIZE 256 /* buffer for long-to-str and float-to-str calcs */
+#define MAX_PARAMETERS 128 /* lame static limit */
+
+#ifdef __AMIGA__
+# undef FORMAT_INT
+#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;
+    union {
+      mp_intmax_t as_signed;
+      mp_uintmax_t as_unsigned;
+    } num;
+    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 */
+  int fail;     /* (!= 0) if an alloc has failed and thus
+                   the output is not the complete data */
+};
+
+static long dprintf_DollarString(char *input, char **end)
+{
+  int number=0;
+  while(ISDIGIT(*input)) {
+    number *= 10;
+    number += *input-'0';
+    input++;
+  }
+  if(number && ('$'==*input++)) {
+    *end = input;
+    return number;
+  }
+  return 0;
+}
+
+static int 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 1; /* true */
+  default:
+    return 0; /* false */
+  }
+}
+
+#ifdef DPRINTF_DEBUG2
+static void dprintf_Pass1Report(va_stack_t *vto, int max)
+{
+  int i;
+  char buffer[256];
+  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_INTPTR:
+      type = "intptr";
+      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(const char *format, va_stack_t *vto, char **endpos,
+                          va_list arglist)
+{
+  char *fmt = (char *)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 > CURL_SIZEOF_LONG)
+          flags |= FLAGS_LONGLONG;
+#else
+          flags |= FLAGS_LONG;
+#endif
+          break;
+        case 'O':
+#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
+          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.as_signed = (mp_intmax_t)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 HAVE_LONG_LONG_TYPE
+        if((vto[i].flags & FLAGS_LONGLONG) && (vto[i].flags & FLAGS_UNSIGNED))
+          vto[i].data.num.as_unsigned =
+            (mp_uintmax_t)va_arg(arglist, mp_uintmax_t);
+        else if(vto[i].flags & FLAGS_LONGLONG)
+          vto[i].data.num.as_signed =
+            (mp_intmax_t)va_arg(arglist, mp_intmax_t);
+        else
+#endif
+        {
+          if((vto[i].flags & FLAGS_LONG) && (vto[i].flags & FLAGS_UNSIGNED))
+            vto[i].data.num.as_unsigned =
+              (mp_uintmax_t)va_arg(arglist, unsigned long);
+          else if(vto[i].flags & FLAGS_LONG)
+            vto[i].data.num.as_signed =
+              (mp_intmax_t)va_arg(arglist, long);
+          else if(vto[i].flags & FLAGS_UNSIGNED)
+            vto[i].data.num.as_unsigned =
+              (mp_uintmax_t)va_arg(arglist, unsigned int);
+          else
+            vto[i].data.num.as_signed =
+              (mp_intmax_t)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(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.  */
+    int is_alt;
+
+    /* Width of a field.  */
+    long width;
+
+    /* Precision of a field.  */
+    long prec;
+
+    /* Decimal integer is negative.  */
+    int is_neg;
+
+    /* Base of a number to be written.  */
+    long base;
+
+    /* Integral values to be written.  */
+    mp_uintmax_t num;
+
+    /* Used to convert negative in positive.  */
+    mp_intmax_t 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 = (long)vto[p->width].data.num.as_signed;
+    else
+      width = p->width;
+
+    /* pick up the specified precision */
+    if(p->flags & FLAGS_PRECPARAM) {
+      prec = (long)vto[p->precision].data.num.as_signed;
+      param_num++; /* since the precision is extraced from a parameter, we
+                      must skip that to get to the next one properly */
+    }
+    else if(p->flags & FLAGS_PREC)
+      prec = p->precision;
+    else
+      prec = -1;
+
+    is_alt = (p->flags & FLAGS_ALT) ? 1 : 0;
+
+    switch (p->type) {
+    case FORMAT_INT:
+      num = p->data.num.as_unsigned;
+      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;
+
+      is_neg = (p->data.num.as_signed < (mp_intmax_t)0) ? 1 : 0;
+      if(is_neg) {
+        /* signed_num might fail to hold absolute negative minimum by 1 */
+        signed_num = p->data.num.as_signed + (mp_intmax_t)1;
+        signed_num = -signed_num;
+        num = (mp_uintmax_t)signed_num;
+        num += (mp_uintmax_t)1;
+      }
+
+      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 -= (long)(workend - w);
+        prec -= (long)(workend - w);
+
+        if(is_alt && base == 8 && prec <= 0) {
+          *w-- = '0';
+          --width;
+        }
+
+        if(prec > 0) {
+          width -= prec;
+          while(prec-- > 0)
+            *w-- = '0';
+        }
+
+        if(is_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(is_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 const char null[] = "(nil)";
+        const 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 = "";
+            len = 0;
+          }
+        }
+        else
+          len = strlen(str);
+
+        if(prec != -1 && (size_t) prec < len)
+          len = (size_t)prec;
+        width -= (long)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;
+          is_alt = 1;
+          num = (size_t) ptr;
+          is_neg = 0;
+          goto number;
+        }
+        else {
+          /* Write "(nil)" for a nil pointer.  */
+          static const char strnil[] = "(nil)";
+          const char *point;
+
+          width -= (long)(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 = (long)vto[p->width].data.num.as_signed;
+
+        prec = -1;
+        if(p->flags & FLAGS_PREC)
+          prec = p->precision;
+        else if(p->flags & FLAGS_PRECPARAM)
+          prec = (long)vto[p->precision].data.num.as_signed;
+
+        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;
+        }
+        if(p->flags & FLAGS_LONG)
+          *fptr++ = 'l';
+
+        if(p->flags & FLAGS_FLOATE)
+          *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'E':'e');
+        else if(p->flags & FLAGS_FLOATG)
+          *fptr++ = (char)((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 HAVE_LONG_LONG_TYPE
+      if(p->flags & FLAGS_LONGLONG)
+        *(LONG_LONG_TYPE *) p->data.ptr = (LONG_LONG_TYPE)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 = malloc(32);
+    if(!infop->buffer) {
+      infop->fail = 1;
+      return -1; /* fail */
+    }
+    infop->alloc = 32;
+    infop->len =0;
+  }
+  else if(infop->len+1 >= infop->alloc) {
+    char *newptr;
+
+    newptr = realloc(infop->buffer, infop->alloc*2);
+
+    if(!newptr) {
+      infop->fail = 1;
+      return -1; /* fail */
+    }
+    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 = 0;
+
+  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 = 0;
+
+  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;
+}
+
+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 HAVE_LONG_LONG_TYPE
+  LONG_LONG_TYPE one=99;
+  LONG_LONG_TYPE two=100;
+  LONG_LONG_TYPE 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 kiss 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/lib/msvcproj.foot b/lib/msvcproj.foot
new file mode 100644
index 0000000..8ce4ca0
--- /dev/null
+++ b/lib/msvcproj.foot
@@ -0,0 +1,11 @@
+
+# Begin Group "Resource Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\libcurl.rc
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/lib/msvcproj.head b/lib/msvcproj.head
new file mode 100644
index 0000000..5714ef7
--- /dev/null
+++ b/lib/msvcproj.head
@@ -0,0 +1,147 @@
+# Microsoft Developer Studio Project File - Name="libcurl" - Package Owner=<4>

+# Microsoft Developer Studio Generated Build File, Format Version 6.00

+# ** DO NOT EDIT **

+

+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102

+# TARGTYPE "Win32 (x86) Static Library" 0x0104

+

+CFG=libcurl - Win32 LIB Debug

+!MESSAGE This is not a valid makefile. To build this project using NMAKE,

+!MESSAGE use the Export Makefile command and run

+!MESSAGE 

+!MESSAGE NMAKE /f "libcurl.mak".

+!MESSAGE 

+!MESSAGE You can specify a configuration when running NMAKE

+!MESSAGE by defining the macro CFG on the command line. For example:

+!MESSAGE 

+!MESSAGE NMAKE /f "libcurl.mak" CFG="libcurl - Win32 LIB Debug"

+!MESSAGE 

+!MESSAGE Possible choices for configuration are:

+!MESSAGE 

+!MESSAGE "libcurl - Win32 DLL Debug" (based on "Win32 (x86) Dynamic-Link Library")

+!MESSAGE "libcurl - Win32 DLL Release" (based on "Win32 (x86) Dynamic-Link Library")

+!MESSAGE "libcurl - Win32 LIB Debug" (based on "Win32 (x86) Static Library")

+!MESSAGE "libcurl - Win32 LIB Release" (based on "Win32 (x86) Static Library")

+!MESSAGE 

+

+# Begin Project

+# PROP AllowPerConfigDependencies 0

+# PROP Scc_ProjName ""

+# PROP Scc_LocalPath ""

+

+!IF  "$(CFG)" == "libcurl - Win32 DLL Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir "DLL-Debug"

+# PROP BASE Intermediate_Dir "DLL-Debug"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir "DLL-Debug"

+# PROP Intermediate_Dir "DLL-Debug"

+# PROP Ignore_Export_Lib 0

+# PROP Target_Dir ""

+CPP=cl.exe

+# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "." /I "..\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "BUILDING_LIBCURL" /FD /GZ /c

+# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "." /I "..\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "BUILDING_LIBCURL" /FD /GZ /c

+MTL=midl.exe

+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32

+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32

+RSC=rc.exe

+# ADD BASE RSC /l 0x409 /d "_DEBUG"

+# ADD RSC /l 0x409 /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib ws2_32.lib wldap32.lib /nologo /dll /incremental:no /map /debug /machine:I386 /out:"DLL-Debug/libcurld.dll" /implib:"DLL-Debug/libcurld_imp.lib" /pdbtype:sept

+# ADD LINK32 kernel32.lib ws2_32.lib wldap32.lib /nologo /dll /incremental:no /map /debug /machine:I386 /out:"DLL-Debug/libcurld.dll" /implib:"DLL-Debug/libcurld_imp.lib" /pdbtype:sept

+

+!ELSEIF  "$(CFG)" == "libcurl - Win32 DLL Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir "DLL-Release"

+# PROP BASE Intermediate_Dir "DLL-Release"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir "DLL-Release"

+# PROP Intermediate_Dir "DLL-Release"

+# PROP Ignore_Export_Lib 0

+# PROP Target_Dir ""

+CPP=cl.exe

+# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "..\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "BUILDING_LIBCURL" /FD /c

+# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "..\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "BUILDING_LIBCURL" /FD /c

+MTL=midl.exe

+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32

+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32

+RSC=rc.exe

+# ADD BASE RSC /l 0x409 /d "NDEBUG"

+# ADD RSC /l 0x409 /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LINK32=link.exe

+# ADD BASE LINK32 kernel32.lib ws2_32.lib wldap32.lib /nologo /dll /pdb:none /machine:I386 /out:"DLL-Release/libcurl.dll" /implib:"DLL-Release/libcurl_imp.lib"

+# ADD LINK32 kernel32.lib ws2_32.lib wldap32.lib /nologo /dll /pdb:none /machine:I386 /out:"DLL-Release/libcurl.dll" /implib:"DLL-Release/libcurl_imp.lib"

+

+!ELSEIF  "$(CFG)" == "libcurl - Win32 LIB Debug"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 1

+# PROP BASE Output_Dir "LIB-Debug"

+# PROP BASE Intermediate_Dir "LIB-Debug"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 1

+# PROP Output_Dir "LIB-Debug"

+# PROP Intermediate_Dir "LIB-Debug"

+# PROP Target_Dir ""

+CPP=cl.exe

+# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "." /I "..\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "BUILDING_LIBCURL" /D "CURL_STATICLIB" /FD /GZ /c

+# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "." /I "..\include" /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "BUILDING_LIBCURL" /D "CURL_STATICLIB" /FD /GZ /c

+RSC=rc.exe

+# ADD BASE RSC /l 0x409 /d "_DEBUG"

+# ADD RSC /l 0x409 /d "_DEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LIB32=link.exe -lib

+# ADD BASE LIB32 /nologo /out:"LIB-Debug/libcurld.lib" /machine:I386

+# ADD LIB32 /nologo /out:"LIB-Debug/libcurld.lib" /machine:I386

+

+!ELSEIF  "$(CFG)" == "libcurl - Win32 LIB Release"

+

+# PROP BASE Use_MFC 0

+# PROP BASE Use_Debug_Libraries 0

+# PROP BASE Output_Dir "LIB-Release"

+# PROP BASE Intermediate_Dir "LIB-Release"

+# PROP BASE Target_Dir ""

+# PROP Use_MFC 0

+# PROP Use_Debug_Libraries 0

+# PROP Output_Dir "LIB-Release"

+# PROP Intermediate_Dir "LIB-Release"

+# PROP Target_Dir ""

+CPP=cl.exe

+# ADD BASE CPP /nologo /MD /W3 /GX /O2 /I "." /I "..\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "BUILDING_LIBCURL" /D "CURL_STATICLIB" /FD /c

+# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /I "..\include" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "BUILDING_LIBCURL" /D "CURL_STATICLIB" /FD /c

+RSC=rc.exe

+# ADD BASE RSC /l 0x409 /d "NDEBUG"

+# ADD RSC /l 0x409 /d "NDEBUG"

+BSC32=bscmake.exe

+# ADD BASE BSC32 /nologo

+# ADD BSC32 /nologo

+LIB32=link.exe -lib

+# ADD BASE LIB32 /nologo /out:"LIB-Release/libcurl.lib" /machine:I386

+# ADD LIB32 /nologo /out:"LIB-Release/libcurl.lib" /machine:I386

+

+!ENDIF 

+

+# Begin Target

+

+# Name "libcurl - Win32 DLL Debug"

+# Name "libcurl - Win32 DLL Release"

+# Name "libcurl - Win32 LIB Debug"

+# Name "libcurl - Win32 LIB Release"

diff --git a/lib/multi.c b/lib/multi.c
new file mode 100644
index 0000000..476cb81
--- /dev/null
+++ b/lib/multi.c
@@ -0,0 +1,2489 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+#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 "easyif.h"
+#include "multiif.h"
+#include "sendf.h"
+#include "timeval.h"
+#include "http.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+  CURL_SOCKET_HASH_TABLE_SIZE should be a prime number. Increasing it from 97
+  to 911 takes on a 32-bit machine 4 x 804 = 3211 more bytes.  Still, every
+  CURL handle takes 45-50 K memory, therefore this 3K are not significant.
+*/
+#ifndef CURL_SOCKET_HASH_TABLE_SIZE
+#define CURL_SOCKET_HASH_TABLE_SIZE 911
+#endif
+
+struct Curl_message {
+  /* the 'CURLMsg' is the part that is visible to the external user */
+  struct CURLMsg extmsg;
+  struct Curl_message *next;
+};
+
+/* NOTE: if you add a state here, add the name to the statename[] array as
+   well!
+*/
+typedef enum {
+  CURLM_STATE_INIT,        /* start in this state */
+  CURLM_STATE_CONNECT,     /* resolve/connect has been sent off */
+  CURLM_STATE_WAITRESOLVE, /* awaiting the resolve to finalize */
+  CURLM_STATE_WAITCONNECT, /* awaiting the connect to finalize */
+  CURLM_STATE_WAITPROXYCONNECT, /* awaiting proxy CONNECT to finalize */
+  CURLM_STATE_PROTOCONNECT, /* completing the protocol-specific connect phase */
+  CURLM_STATE_WAITDO,      /* wait for our turn to send the request */
+  CURLM_STATE_DO,          /* start send off the request (part 1) */
+  CURLM_STATE_DOING,       /* sending off the request (part 1) */
+  CURLM_STATE_DO_MORE,     /* send off the request (part 2) */
+  CURLM_STATE_DO_DONE,     /* done sending off request */
+  CURLM_STATE_WAITPERFORM, /* wait for our turn to read the response */
+  CURLM_STATE_PERFORM,     /* transfer data */
+  CURLM_STATE_TOOFAST,     /* wait because limit-rate exceeded */
+  CURLM_STATE_DONE,        /* post data transfer operation */
+  CURLM_STATE_COMPLETED,   /* operation complete */
+
+  CURLM_STATE_LAST /* not a true state, never use this */
+} CURLMstate;
+
+/* we support N sockets per easy handle. Set the corresponding bit to what
+   action we should wait for */
+#define MAX_SOCKSPEREASYHANDLE 5
+#define GETSOCK_READABLE (0x00ff)
+#define GETSOCK_WRITABLE (0xff00)
+
+struct closure {
+  struct closure *next; /* a simple one-way list of structs */
+  struct SessionHandle *easy_handle;
+};
+
+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 */
+
+  /* Array with the plain socket numbers this handle takes care of, in no
+     particular order. Note that all sockets are added to the sockhash, where
+     the state etc are also kept. This array is mostly used to detect when a
+     socket is to be removed from the hash. See singlesocket(). */
+  curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE];
+  int numsocks;
+};
+
+#define CURL_MULTI_HANDLE 0x000bab1e
+
+#define GOOD_MULTI_HANDLE(x) \
+  ((x)&&(((struct Curl_multi *)(x))->type == CURL_MULTI_HANDLE))
+#define GOOD_EASY_HANDLE(x) \
+ (((struct SessionHandle *)(x))->magic == CURLEASY_MAGIC_NUMBER)
+
+/* 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;
+
+  int num_easy; /* amount of entries in the linked list above. */
+  int num_msgs; /* amount of messages in the easy handles */
+  int num_alive; /* amount of easy handles that are added but have not yet
+                    reached COMPLETE state */
+
+  /* callback function and user data pointer for the *socket() API */
+  curl_socket_callback socket_cb;
+  void *socket_userp;
+
+  /* Hostname cache */
+  struct curl_hash *hostcache;
+
+  /* timetree points to the splay-tree of time nodes to figure out expire
+     times of all currently set timers */
+  struct Curl_tree *timetree;
+
+  /* 'sockhash' is the lookup hash for socket descriptor => easy handles (note
+     the pluralis form, there can be more than one easy handle waiting on the
+     same actual socket) */
+  struct curl_hash *sockhash;
+
+  /* Whether pipelining is enabled for this multi handle */
+  bool pipelining_enabled;
+
+  /* shared connection cache */
+  struct conncache *connc;
+  long maxconnects; /* if >0, a fixed limit of the maximum number of entries
+                       we're allowed to grow the connection cache to */
+
+  /* list of easy handles kept around for doing nice connection closures */
+  struct closure *closure;
+
+  /* timer callback and user data pointer for the *socket() API */
+  curl_multi_timer_callback timer_cb;
+  void *timer_userp;
+  struct timeval timer_lastcall; /* the fixed time for the timeout for the
+                                    previous callback */
+};
+
+static void multi_connc_remove_handle(struct Curl_multi *multi,
+                                      struct SessionHandle *data);
+static void singlesocket(struct Curl_multi *multi,
+                         struct Curl_one_easy *easy);
+static CURLMcode add_closure(struct Curl_multi *multi,
+                             struct SessionHandle *data);
+static int update_timer(struct Curl_multi *multi);
+
+static CURLcode addHandleToSendOrPendPipeline(struct SessionHandle *handle,
+                                              struct connectdata *conn);
+static int checkPendPipeline(struct connectdata *conn);
+static void moveHandleFromSendToRecvPipeline(struct SessionHandle *handle,
+                                             struct connectdata *conn);
+static void moveHandleFromRecvToDonePipeline(struct SessionHandle *handle,
+                                             struct connectdata *conn);
+static bool isHandleAtHead(struct SessionHandle *handle,
+                           struct curl_llist *pipeline);
+
+#ifdef DEBUGBUILD
+static const char * const statename[]={
+  "INIT",
+  "CONNECT",
+  "WAITRESOLVE",
+  "WAITCONNECT",
+  "WAITPROXYCONNECT",
+  "PROTOCONNECT",
+  "WAITDO",
+  "DO",
+  "DOING",
+  "DO_MORE",
+  "DO_DONE",
+  "WAITPERFORM",
+  "PERFORM",
+  "TOOFAST",
+  "DONE",
+  "COMPLETED",
+};
+#endif
+
+/* always use this function to change state, to make debugging easier */
+static void multistate(struct Curl_one_easy *easy, CURLMstate state)
+{
+#ifdef DEBUGBUILD
+  long connectindex = -5000;
+#endif
+  CURLMstate oldstate = easy->state;
+
+  if(oldstate == state)
+    /* don't bother when the new state is the same as the old state */
+    return;
+
+  easy->state = state;
+
+#ifdef DEBUGBUILD
+  if(easy->easy_conn) {
+    if(easy->state > CURLM_STATE_CONNECT &&
+       easy->state < CURLM_STATE_COMPLETED)
+      connectindex = easy->easy_conn->connectindex;
+
+    infof(easy->easy_handle,
+          "STATE: %s => %s handle %p; (connection #%ld) \n",
+          statename[oldstate], statename[easy->state],
+          (char *)easy, connectindex);
+  }
+#endif
+  if(state == CURLM_STATE_COMPLETED)
+    /* changing to COMPLETED means there's one less easy handle 'alive' */
+    easy->easy_handle->multi->num_alive--;
+}
+
+/*
+ * We add one of these structs to the sockhash for a particular socket
+ */
+
+struct Curl_sh_entry {
+  struct SessionHandle *easy;
+  time_t timestamp;
+  int action;  /* what action READ/WRITE this socket waits for */
+  curl_socket_t socket; /* mainly to ease debugging */
+  void *socketp; /* settable by users with curl_multi_assign() */
+};
+/* bits for 'action' having no bits means this socket is not expecting any
+   action */
+#define SH_READ  1
+#define SH_WRITE 2
+
+/* make sure this socket is present in the hash for this handle */
+static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh,
+                                         curl_socket_t s,
+                                         struct SessionHandle *data)
+{
+  struct Curl_sh_entry *there =
+    Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
+  struct Curl_sh_entry *check;
+
+  if(there)
+    /* it is present, return fine */
+    return there;
+
+  /* not present, add it */
+  check = calloc(1, sizeof(struct Curl_sh_entry));
+  if(!check)
+    return NULL; /* major failure */
+  check->easy = data;
+  check->socket = s;
+
+  /* make/add new hash entry */
+  if(NULL == Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) {
+    free(check);
+    return NULL; /* major failure */
+  }
+
+  return check; /* things are good in sockhash land */
+}
+
+
+/* delete the given socket + handle from the hash */
+static void sh_delentry(struct curl_hash *sh, curl_socket_t s)
+{
+  struct Curl_sh_entry *there =
+    Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
+
+  if(there) {
+    /* this socket is in the hash */
+    /* We remove the hash entry. (This'll end up in a call to
+       sh_freeentry().) */
+    Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t));
+  }
+}
+
+/*
+ * free a sockhash entry
+ */
+static void sh_freeentry(void *freethis)
+{
+  struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis;
+
+  if(p)
+    free(p);
+}
+
+static size_t fd_key_compare(void*k1, size_t k1_len, void*k2, size_t k2_len)
+{
+  (void) k1_len; (void) k2_len;
+
+  return (*((int* ) k1)) == (*((int* ) k2));
+}
+
+static size_t hash_fd(void* key, size_t key_length, size_t slots_num)
+{
+  int fd = * ((int* ) key);
+  (void) key_length;
+
+  return (fd % (int)slots_num);
+}
+
+/*
+ * sh_init() creates a new socket hash and returns the handle for it.
+ *
+ * Quote from README.multi_socket:
+ *
+ * "Some tests at 7000 and 9000 connections showed that the socket hash lookup
+ * is somewhat of a bottle neck. Its current implementation may be a bit too
+ * limiting. It simply has a fixed-size array, and on each entry in the array
+ * it has a linked list with entries. So the hash only checks which list to
+ * scan through. The code I had used so for used a list with merely 7 slots
+ * (as that is what the DNS hash uses) but with 7000 connections that would
+ * make an average of 1000 nodes in each list to run through. I upped that to
+ * 97 slots (I believe a prime is suitable) and noticed a significant speed
+ * increase.  I need to reconsider the hash implementation or use a rather
+ * large default value like this. At 9000 connections I was still below 10us
+ * per call."
+ *
+ */
+static struct curl_hash *sh_init(void)
+{
+  return Curl_hash_alloc(CURL_SOCKET_HASH_TABLE_SIZE, hash_fd, fd_key_compare,
+                         sh_freeentry);
+}
+
+CURLM *curl_multi_init(void)
+{
+  struct Curl_multi *multi = calloc(1, sizeof(struct Curl_multi));
+
+  if(!multi)
+    return NULL;
+
+  multi->type = CURL_MULTI_HANDLE;
+
+  multi->hostcache = Curl_mk_dnscache();
+  if(!multi->hostcache) {
+    /* failure, free mem and bail out */
+    free(multi);
+    return NULL;
+  }
+
+  multi->sockhash = sh_init();
+  if(!multi->sockhash) {
+    /* failure, free mem and bail out */
+    Curl_hash_destroy(multi->hostcache);
+    free(multi);
+    return NULL;
+  }
+
+  multi->connc = Curl_mk_connc(CONNCACHE_MULTI, -1L);
+  if(!multi->connc) {
+    Curl_hash_destroy(multi->sockhash);
+    Curl_hash_destroy(multi->hostcache);
+    free(multi);
+    return NULL;
+  }
+
+  /* Let's make the doubly-linked list a circular list.  This makes
+     the linked list code simpler and allows inserting at the end
+     with less work (we didn't keep a tail pointer before). */
+  multi->easy.next = &multi->easy;
+  multi->easy.prev = &multi->easy;
+
+  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;
+  struct closure *cl;
+  struct closure *prev=NULL;
+
+  /* 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;
+
+  /* Prevent users to add the same handle more than once! */
+  if(((struct SessionHandle *)easy_handle)->multi)
+    /* possibly we should create a new unique error code for this condition */
+    return CURLM_BAD_EASY_HANDLE;
+
+  /* Now, time to add an easy handle to the multi stack */
+  easy = calloc(1, sizeof(struct Curl_one_easy));
+  if(!easy)
+    return CURLM_OUT_OF_MEMORY;
+
+  cl = multi->closure;
+  while(cl) {
+    struct closure *next = cl->next;
+    if(cl->easy_handle == (struct SessionHandle *)easy_handle) {
+      /* remove this handle from the closure list */
+      free(cl);
+      if(prev)
+        prev->next = next;
+      else
+        multi->closure = next;
+      break; /* no need to continue since this handle can only be present once
+                in the list */
+    }
+    prev = cl;
+    cl = next;
+  }
+
+  /* set the easy handle */
+  easy->easy_handle = easy_handle;
+  multistate(easy, CURLM_STATE_INIT);
+
+  /* set the back pointer to one_easy to assist in removal */
+  easy->easy_handle->multi_pos =  easy;
+
+  /* for multi interface connections, we share DNS cache automatically if the
+     easy handle's one is currently private. */
+  if(easy->easy_handle->dns.hostcache &&
+     (easy->easy_handle->dns.hostcachetype == HCACHE_PRIVATE)) {
+    Curl_hash_destroy(easy->easy_handle->dns.hostcache);
+    easy->easy_handle->dns.hostcache = NULL;
+    easy->easy_handle->dns.hostcachetype = HCACHE_NONE;
+  }
+
+  if(!easy->easy_handle->dns.hostcache ||
+     (easy->easy_handle->dns.hostcachetype == HCACHE_NONE)) {
+    easy->easy_handle->dns.hostcache = multi->hostcache;
+    easy->easy_handle->dns.hostcachetype = HCACHE_MULTI;
+  }
+
+  if(easy->easy_handle->state.connc) {
+    if(easy->easy_handle->state.connc->type == CONNCACHE_PRIVATE) {
+      /* kill old private version */
+      Curl_rm_connc(easy->easy_handle->state.connc);
+      /* point out our shared one instead */
+      easy->easy_handle->state.connc = multi->connc;
+    }
+    /* else it is already using multi? */
+  }
+  else
+    /* point out our shared one */
+    easy->easy_handle->state.connc = multi->connc;
+
+  /* Make sure the type is setup correctly */
+  easy->easy_handle->state.connc->type = CONNCACHE_MULTI;
+
+  /* This adds the new entry at the back of the list
+     to try and maintain a FIFO queue so the pipelined
+     requests are in order. */
+
+  /* We add this new entry last in the list. We make our 'next' point to the
+     'first' struct and our 'prev' point to the previous 'prev' */
+  easy->next = &multi->easy;
+  easy->prev = multi->easy.prev;
+
+  /* make 'easy' the last node in the chain */
+  multi->easy.prev = easy;
+
+  /* if there was a prev node, make sure its 'next' pointer links to
+     the new node */
+  easy->prev->next = easy;
+
+  Curl_easy_addmulti(easy_handle, multi_handle);
+
+  /* make the SessionHandle struct refer back to this struct */
+  easy->easy_handle->set.one_easy = easy;
+
+  /* Set the timeout for this handle to expire really soon so that it will
+     be taken care of even when this handle is added in the midst of operation
+     when only the curl_multi_socket() API is used. During that flow, only
+     sockets that time-out or have actions will be dealt with. Since this
+     handle has no action yet, we make sure it times out to get things to
+     happen. */
+  Curl_expire(easy->easy_handle, 1);
+
+  /* increase the node-counter */
+  multi->num_easy++;
+
+  if((multi->num_easy * 4) > multi->connc->num) {
+    /* We want the connection cache to have plenty room. Before we supported
+       the shared cache every single easy handle had 5 entries in their cache
+       by default. */
+    long newmax = multi->num_easy * 4;
+
+    if(multi->maxconnects && (multi->maxconnects < newmax))
+      /* don't grow beyond the allowed size */
+      newmax = multi->maxconnects;
+
+    if(newmax > multi->connc->num) {
+      /* we only do this is we can in fact grow the cache */
+      CURLcode res = Curl_ch_connc(easy_handle, multi->connc, newmax);
+      if(res != CURLE_OK) {
+        /* FIXME: may need to do more cleanup here */
+        curl_multi_remove_handle(multi_handle, easy_handle);
+        return CURLM_OUT_OF_MEMORY;
+      }
+    }
+  }
+
+  /* increase the alive-counter */
+  multi->num_alive++;
+
+  /* A somewhat crude work-around for a little glitch in update_timer() that
+     happens if the lastcall time is set to the same time when the handle is
+     removed as when the next handle is added, as then the check in
+     update_timer() that prevents calling the application multiple times with
+     the same timer infor will not trigger and then the new handle's timeout
+     will not be notified to the app.
+
+     The work-around is thus simply to clear the 'lastcall' variable to force
+     update_timer() to always trigger a callback to the app when a new easy
+     handle is added */
+  memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
+
+  update_timer(multi);
+  return CURLM_OK;
+}
+
+#if 0
+/* Debug-function, used like this:
+ *
+ * Curl_hash_print(multi->sockhash, debug_print_sock_hash);
+ *
+ * Enable the hash print function first by editing hash.c
+ */
+static void debug_print_sock_hash(void *p)
+{
+  struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p;
+
+  fprintf(stderr, " [easy %p/magic %x/socket %d]",
+          (void *)sh->easy, sh->easy->magic, (int)sh->socket);
+}
+#endif
+
+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;
+
+  /* pick-up from the 'curl_handle' the kept position in the list */
+  easy = ((struct SessionHandle *)curl_handle)->multi_pos;
+
+  if(easy) {
+    bool premature = (bool)(easy->state != CURLM_STATE_COMPLETED);
+    bool easy_owns_conn = (bool)(easy->easy_conn &&
+                                 (easy->easy_conn->data == easy->easy_handle));
+
+    /* 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. */
+    if(premature)
+      /* this handle is "alive" so we need to count down the total number of
+         alive connections when this is removed */
+      multi->num_alive--;
+
+    if(easy->easy_conn &&
+       (easy->easy_conn->send_pipe->size +
+        easy->easy_conn->recv_pipe->size > 1) &&
+       easy->state > CURLM_STATE_WAITDO &&
+       easy->state < CURLM_STATE_COMPLETED) {
+      /* If the handle is in a pipeline and has started sending off its
+         request but not received its reponse yet, we need to close
+         connection. */
+      easy->easy_conn->bits.close = TRUE;
+      /* Set connection owner so that Curl_done() closes it.
+         We can sefely do this here since connection is killed. */
+      easy->easy_conn->data = easy->easy_handle;
+    }
+
+    /* The timer must be shut down before easy->multi is set to NULL,
+       else the timenode will remain in the splay tree after
+       curl_easy_cleanup is called. */
+    Curl_expire(easy->easy_handle, 0);
+
+    if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) {
+      /* clear out the usage of the shared DNS cache */
+      easy->easy_handle->dns.hostcache = NULL;
+      easy->easy_handle->dns.hostcachetype = HCACHE_NONE;
+    }
+
+    if(easy->easy_conn) {
+
+      /* we must call Curl_done() here (if we still "own it") so that we don't
+         leave a half-baked one around */
+      if (easy_owns_conn) {
+
+        /* Curl_done() clears the conn->data field to lose the association
+           between the easy handle and the connection
+
+           Note that this ignores the return code simply because there's
+           nothing really useful to do with it anyway! */
+        (void)Curl_done(&easy->easy_conn, easy->result, premature);
+
+        if(easy->easy_conn)
+          /* the connection is still alive, set back the association to enable
+             the check below to trigger TRUE */
+          easy->easy_conn->data = easy->easy_handle;
+      }
+      else
+        /* Clear connection pipelines, if Curl_done above was not called */
+        Curl_getoff_all_pipelines(easy->easy_handle, easy->easy_conn);
+    }
+
+    /* figure out if the easy handle is used by one or more connections in the
+       cache */
+    multi_connc_remove_handle(multi, easy->easy_handle);
+
+    if(easy->easy_handle->state.connc->type == CONNCACHE_MULTI) {
+      /* if this was using the shared connection cache we clear the pointer
+         to that since we're not part of that handle anymore */
+      easy->easy_handle->state.connc = NULL;
+
+      /* Modify the connectindex since this handle can't point to the
+         connection cache anymore.
+
+         TODO: consider if this is really what we want. The connection cache
+         is within the multi handle and that owns the connections so we should
+         not need to touch connections like this when we just remove an easy
+         handle...
+      */
+      if(easy->easy_conn && easy_owns_conn &&
+         (easy->easy_conn->send_pipe->size +
+          easy->easy_conn->recv_pipe->size == 0))
+        easy->easy_conn->connectindex = -1;
+    }
+
+    /* change state without using multistate(), only to make singlesocket() do
+       what we want */
+    easy->state = CURLM_STATE_COMPLETED;
+    singlesocket(multi, easy); /* to let the application know what sockets
+                                  that vanish with this handle */
+
+    Curl_easy_addmulti(easy->easy_handle, NULL); /* clear the association
+                                                    to this multi handle */
+
+    /* 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;
+
+    easy->easy_handle->set.one_easy = NULL; /* detached */
+
+    /* Null the position in the controlling structure */
+    easy->easy_handle->multi_pos = NULL;
+
+    /* 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 */
+
+    update_timer(multi);
+    return CURLM_OK;
+  }
+  else
+    return CURLM_BAD_EASY_HANDLE; /* twasn't found */
+}
+
+bool Curl_multi_canPipeline(const struct Curl_multi* multi)
+{
+  return multi->pipelining_enabled;
+}
+
+void Curl_multi_handlePipeBreak(struct SessionHandle *data)
+{
+  struct Curl_one_easy *one_easy = data->set.one_easy;
+
+  if(one_easy)
+    one_easy->easy_conn = NULL;
+}
+
+static int waitconnect_getsock(struct connectdata *conn,
+                               curl_socket_t *sock,
+                               int numsocks)
+{
+  if(!numsocks)
+    return GETSOCK_BLANK;
+
+  sock[0] = conn->sock[FIRSTSOCKET];
+
+  /* when we've sent a CONNECT to a proxy, we should rather wait for the
+     socket to become readable to be able to get the response headers */
+  if(conn->bits.tunnel_connecting)
+    return GETSOCK_READSOCK(0);
+
+  return GETSOCK_WRITESOCK(0);
+}
+
+static int domore_getsock(struct connectdata *conn,
+                          curl_socket_t *sock,
+                          int numsocks)
+{
+  if(!numsocks)
+    return GETSOCK_BLANK;
+
+  /* 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 */
+  sock[0] = conn->sock[SECONDARYSOCKET];
+
+  return GETSOCK_WRITESOCK(0);
+}
+
+/* returns bitmapped flags for this handle and its sockets */
+static int multi_getsock(struct Curl_one_easy *easy,
+                         curl_socket_t *socks, /* points to numsocks number
+                                                  of sockets */
+                         int numsocks)
+{
+  /* If the pipe broke, or if there's no connection left for this easy handle,
+     then we MUST bail out now with no bitmask set. The no connection case can
+     happen when this is called from curl_multi_remove_handle() =>
+     singlesocket() => multi_getsock().
+  */
+  if(easy->easy_handle->state.pipe_broke || !easy->easy_conn)
+    return 0;
+
+  if(easy->state > CURLM_STATE_CONNECT &&
+     easy->state < CURLM_STATE_COMPLETED) {
+    /* Set up ownership correctly */
+    easy->easy_conn->data = easy->easy_handle;
+  }
+
+  switch(easy->state) {
+  default:
+#if 0 /* switch back on these cases to get the compiler to check for all enums
+         to be present */
+  case CURLM_STATE_TOOFAST:  /* returns 0, so will not select. */
+  case CURLM_STATE_COMPLETED:
+  case CURLM_STATE_INIT:
+  case CURLM_STATE_CONNECT:
+  case CURLM_STATE_WAITDO:
+  case CURLM_STATE_DONE:
+  case CURLM_STATE_LAST:
+    /* this will get called with CURLM_STATE_COMPLETED when a handle is
+       removed */
+#endif
+    return 0;
+
+  case CURLM_STATE_WAITRESOLVE:
+    return Curl_resolv_getsock(easy->easy_conn, socks, numsocks);
+
+  case CURLM_STATE_PROTOCONNECT:
+    return Curl_protocol_getsock(easy->easy_conn, socks, numsocks);
+
+  case CURLM_STATE_DO:
+  case CURLM_STATE_DOING:
+    return Curl_doing_getsock(easy->easy_conn, socks, numsocks);
+
+  case CURLM_STATE_WAITPROXYCONNECT:
+  case CURLM_STATE_WAITCONNECT:
+    return waitconnect_getsock(easy->easy_conn, socks, numsocks);
+
+  case CURLM_STATE_DO_MORE:
+    return domore_getsock(easy->easy_conn, socks, numsocks);
+
+  case CURLM_STATE_DO_DONE: /* since is set after DO is completed, we switch
+                               to waiting for the same as the *PERFORM states */
+  case CURLM_STATE_PERFORM:
+  case CURLM_STATE_WAITPERFORM:
+    return Curl_single_getsock(easy->easy_conn, socks, numsocks);
+  }
+
+}
+
+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;
+  curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
+  int bitmap;
+  int i;
+  (void)exc_fd_set; /* not used */
+
+  if(!GOOD_MULTI_HANDLE(multi))
+    return CURLM_BAD_HANDLE;
+
+  easy=multi->easy.next;
+  while(easy != &multi->easy) {
+    bitmap = multi_getsock(easy, sockbunch, MAX_SOCKSPEREASYHANDLE);
+
+    for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
+      curl_socket_t s = CURL_SOCKET_BAD;
+
+      if(bitmap & GETSOCK_READSOCK(i)) {
+        FD_SET(sockbunch[i], read_fd_set);
+        s = sockbunch[i];
+      }
+      if(bitmap & GETSOCK_WRITESOCK(i)) {
+        FD_SET(sockbunch[i], write_fd_set);
+        s = sockbunch[i];
+      }
+      if(s == CURL_SOCKET_BAD)
+        /* this socket is unused, break out of loop */
+        break;
+      else {
+        if((int)s > this_max_fd)
+          this_max_fd = (int)s;
+      }
+    }
+
+    easy = easy->next; /* check next handle */
+  }
+
+  *max_fd = this_max_fd;
+
+  return CURLM_OK;
+}
+
+static CURLMcode multi_runsingle(struct Curl_multi *multi,
+                                 struct Curl_one_easy *easy)
+{
+  struct Curl_message *msg = NULL;
+  bool connected;
+  bool async;
+  bool protocol_connect = FALSE;
+  bool dophase_done;
+  bool done = FALSE;
+  CURLMcode result = CURLM_OK;
+  struct SingleRequest *k;
+
+  if(!GOOD_EASY_HANDLE(easy->easy_handle))
+    return CURLM_BAD_EASY_HANDLE;
+
+  do {
+    /* this is a do-while loop just to allow a break to skip to the end
+       of it */
+    bool disconnect_conn = FALSE;
+
+    /* Handle the case when the pipe breaks, i.e., the connection
+       we're using gets cleaned up and we're left with nothing. */
+    if(easy->easy_handle->state.pipe_broke) {
+      infof(easy->easy_handle, "Pipe broke: handle 0x%p, url = %s\n",
+            easy, easy->easy_handle->state.path);
+
+      if(easy->state != CURLM_STATE_COMPLETED) {
+        /* Head back to the CONNECT state */
+        multistate(easy, CURLM_STATE_CONNECT);
+        result = CURLM_CALL_MULTI_PERFORM;
+        easy->result = CURLE_OK;
+      }
+
+      easy->easy_handle->state.pipe_broke = FALSE;
+      easy->easy_conn = NULL;
+      break;
+    }
+
+    if(easy->easy_conn && easy->state > CURLM_STATE_CONNECT &&
+       easy->state < CURLM_STATE_COMPLETED)
+      /* Make sure we set the connection's current owner */
+      easy->easy_conn->data = easy->easy_handle;
+
+    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 */
+        multistate(easy, 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, &protocol_connect);
+
+      if(CURLE_OK == easy->result) {
+        /* Add this handle to the send or pend pipeline */
+        easy->result = addHandleToSendOrPendPipeline(easy->easy_handle,
+                                                     easy->easy_conn);
+        if(CURLE_OK == easy->result) {
+          if(async)
+            /* We're now waiting for an asynchronous name lookup */
+            multistate(easy, CURLM_STATE_WAITRESOLVE);
+          else {
+            /* after the connect has been sent off, go WAITCONNECT unless the
+               protocol connect is already done and we can go directly to
+               WAITDO or DO! */
+            result = CURLM_CALL_MULTI_PERFORM;
+
+            if(protocol_connect)
+              multistate(easy, multi->pipelining_enabled?
+                         CURLM_STATE_WAITDO:CURLM_STATE_DO);
+            else {
+#ifndef CURL_DISABLE_HTTP
+              if(easy->easy_conn->bits.tunnel_connecting)
+                multistate(easy, CURLM_STATE_WAITPROXYCONNECT);
+              else
+#endif
+                multistate(easy, CURLM_STATE_WAITCONNECT);
+            }
+          }
+        }
+      }
+      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) {
+        /* Update sockets here. Mainly because the socket(s) may have been
+           closed and the application thus needs to be told, even if it is
+           likely that the same socket(s) will again be used further down. */
+        singlesocket(multi, easy);
+
+        /* Perform the next step in the connection phase, and then move on
+           to the WAITCONNECT state */
+        easy->result = Curl_async_resolved(easy->easy_conn,
+                                           &protocol_connect);
+
+        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 */
+        else {
+          /* call again please so that we get the next socket setup */
+          result = CURLM_CALL_MULTI_PERFORM;
+          if(protocol_connect)
+            multistate(easy, multi->pipelining_enabled?
+                       CURLM_STATE_WAITDO:CURLM_STATE_DO);
+          else {
+#ifndef CURL_DISABLE_HTTP
+            if(easy->easy_conn->bits.tunnel_connecting)
+              multistate(easy, CURLM_STATE_WAITPROXYCONNECT);
+            else
+#endif
+              multistate(easy, CURLM_STATE_WAITCONNECT);
+          }
+        }
+      }
+
+      if(CURLE_OK != easy->result) {
+        /* failure detected */
+        disconnect_conn = TRUE;
+        break;
+      }
+    }
+    break;
+
+#ifndef CURL_DISABLE_HTTP
+    case CURLM_STATE_WAITPROXYCONNECT:
+      /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
+      easy->result = Curl_http_connect(easy->easy_conn, &protocol_connect);
+
+      if(easy->easy_conn->bits.proxy_connect_closed) {
+        /* reset the error buffer */
+        if(easy->easy_handle->set.errorbuffer)
+          easy->easy_handle->set.errorbuffer[0] = '\0';
+        easy->easy_handle->state.errorbuf = FALSE;
+
+        easy->result = CURLE_OK;
+        result = CURLM_CALL_MULTI_PERFORM;
+        multistate(easy, CURLM_STATE_CONNECT);
+      }
+      else if (CURLE_OK == easy->result) {
+        if(!easy->easy_conn->bits.tunnel_connecting)
+          multistate(easy, CURLM_STATE_WAITCONNECT);
+      }
+      break;
+#endif
+
+    case CURLM_STATE_WAITCONNECT:
+      /* awaiting a completion of an asynch connect */
+      easy->result = Curl_is_connected(easy->easy_conn,
+                                       FIRSTSOCKET,
+                                       &connected);
+      if(connected) {
+        /* see if we need to do any proxy magic first once we connected */
+        easy->result = Curl_connected_proxy(easy->easy_conn);
+
+        if(!easy->result)
+          /* if everything is still fine we do the protocol-specific connect
+             setup */
+          easy->result = Curl_protocol_connect(easy->easy_conn,
+                                               &protocol_connect);
+      }
+
+      if(CURLE_OK != easy->result) {
+        /* failure detected */
+        /* Just break, the cleaning up is handled all in one place */
+        disconnect_conn = TRUE;
+        break;
+      }
+
+      if(connected) {
+        if(!protocol_connect) {
+          /* We have a TCP connection, but 'protocol_connect' may be false
+             and then we continue to 'STATE_PROTOCONNECT'. If protocol
+             connect is TRUE, we move on to STATE_DO.
+             BUT if we are using a proxy we must change to WAITPROXYCONNECT
+          */
+#ifndef CURL_DISABLE_HTTP
+          if(easy->easy_conn->bits.tunnel_connecting)
+            multistate(easy, CURLM_STATE_WAITPROXYCONNECT);
+          else
+#endif
+            multistate(easy, CURLM_STATE_PROTOCONNECT);
+
+        }
+        else
+          /* after the connect has completed, go WAITDO or DO */
+          multistate(easy, multi->pipelining_enabled?
+                     CURLM_STATE_WAITDO:CURLM_STATE_DO);
+
+        result = CURLM_CALL_MULTI_PERFORM;
+      }
+      break;
+
+    case CURLM_STATE_PROTOCONNECT:
+      /* protocol-specific connect phase */
+      easy->result = Curl_protocol_connecting(easy->easy_conn,
+                                              &protocol_connect);
+      if((easy->result == CURLE_OK) && protocol_connect) {
+        /* after the connect has completed, go WAITDO or DO */
+        multistate(easy, multi->pipelining_enabled?
+                   CURLM_STATE_WAITDO:CURLM_STATE_DO);
+        result = CURLM_CALL_MULTI_PERFORM;
+      }
+      else if(easy->result) {
+        /* failure detected */
+        Curl_posttransfer(easy->easy_handle);
+        Curl_done(&easy->easy_conn, easy->result, FALSE);
+        disconnect_conn = TRUE;
+      }
+      break;
+
+    case CURLM_STATE_WAITDO:
+      /* Wait for our turn to DO when we're pipelining requests */
+#ifdef DEBUGBUILD
+      infof(easy->easy_handle, "Conn %ld send pipe %zu inuse %d athead %d\n",
+            easy->easy_conn->connectindex,
+            easy->easy_conn->send_pipe->size,
+            easy->easy_conn->writechannel_inuse?1:0,
+            isHandleAtHead(easy->easy_handle,
+                           easy->easy_conn->send_pipe)?1:0);
+#endif
+      if(!easy->easy_conn->writechannel_inuse &&
+         isHandleAtHead(easy->easy_handle,
+                        easy->easy_conn->send_pipe)) {
+        /* Grab the channel */
+        easy->easy_conn->writechannel_inuse = TRUE;
+        multistate(easy, CURLM_STATE_DO);
+        result = CURLM_CALL_MULTI_PERFORM;
+      }
+      break;
+
+    case CURLM_STATE_DO:
+      if(easy->easy_handle->set.connect_only) {
+        /* keep connection open for application to use the socket */
+        easy->easy_conn->bits.close = FALSE;
+        multistate(easy, CURLM_STATE_DONE);
+        easy->result = CURLE_OK;
+        result = CURLM_OK;
+      }
+      else {
+        /* Perform the protocol's DO action */
+        easy->result = Curl_do(&easy->easy_conn,
+                               &dophase_done);
+
+        if(CURLE_OK == easy->result) {
+          if(!dophase_done) {
+            /* DO was not completed in one function call, we must continue
+               DOING... */
+            multistate(easy, CURLM_STATE_DOING);
+            result = CURLM_OK;
+          }
+
+          /* after DO, go DO_DONE... or DO_MORE */
+          else if(easy->easy_conn->bits.do_more) {
+            /* we're supposed to do more, but we need to sit down, relax
+               and wait a little while first */
+            multistate(easy, CURLM_STATE_DO_MORE);
+            result = CURLM_OK;
+          }
+          else {
+            /* we're done with the DO, now DO_DONE */
+            multistate(easy, CURLM_STATE_DO_DONE);
+            result = CURLM_CALL_MULTI_PERFORM;
+          }
+        }
+        else if ((CURLE_SEND_ERROR == easy->result) &&
+                 easy->easy_conn->bits.reuse) {
+          /*
+           * In this situation, a connection that we were trying to use
+           * may have unexpectedly died.  If possible, send the connection
+           * back to the CONNECT phase so we can try again.
+           */
+          char *newurl = NULL;
+          followtype follow=FOLLOW_NONE;
+          CURLcode drc;
+          bool retry = FALSE;
+
+          drc = Curl_retry_request(easy->easy_conn, &newurl);
+          if(drc) {
+            /* a failure here pretty much implies an out of memory */
+            easy->result = drc;
+            disconnect_conn = TRUE;
+          }
+          else
+            retry = (bool)(newurl?TRUE:FALSE);
+
+          Curl_posttransfer(easy->easy_handle);
+          drc = Curl_done(&easy->easy_conn, easy->result, FALSE);
+
+          /* When set to retry the connection, we must to go back to
+           * the CONNECT state */
+          if(retry) {
+            if ((drc == CURLE_OK) || (drc == CURLE_SEND_ERROR)) {
+              follow = FOLLOW_RETRY;
+              drc = Curl_follow(easy->easy_handle, newurl, follow);
+              if(drc == CURLE_OK) {
+                multistate(easy, CURLM_STATE_CONNECT);
+                result = CURLM_CALL_MULTI_PERFORM;
+                easy->result = CURLE_OK;
+              }
+              else {
+                /* Follow failed */
+                easy->result = drc;
+                free(newurl);
+              }
+            }
+            else {
+              /* done didn't return OK or SEND_ERROR */
+              easy->result = drc;
+              free(newurl);
+            }
+          }
+          else {
+            /* Have error handler disconnect conn if we can't retry */
+            disconnect_conn = TRUE;
+          }
+        }
+        else {
+          /* failure detected */
+          Curl_posttransfer(easy->easy_handle);
+          Curl_done(&easy->easy_conn, easy->result, FALSE);
+          disconnect_conn = TRUE;
+        }
+      }
+      break;
+
+    case CURLM_STATE_DOING:
+      /* we continue DOING until the DO phase is complete */
+      easy->result = Curl_protocol_doing(easy->easy_conn,
+                                         &dophase_done);
+      if(CURLE_OK == easy->result) {
+        if(dophase_done) {
+          /* 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 */
+            multistate(easy, CURLM_STATE_DO_MORE);
+            result = CURLM_OK;
+          }
+          else {
+            /* we're done with the DO, now DO_DONE */
+            multistate(easy, CURLM_STATE_DO_DONE);
+            result = CURLM_CALL_MULTI_PERFORM;
+          }
+        } /* dophase_done */
+      }
+      else {
+        /* failure detected */
+        Curl_posttransfer(easy->easy_handle);
+        Curl_done(&easy->easy_conn, easy->result, FALSE);
+        disconnect_conn = TRUE;
+      }
+      break;
+
+    case CURLM_STATE_DO_MORE:
+      /* 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 DO_DONE
+         */
+        easy->result = Curl_do_more(easy->easy_conn);
+
+        /* No need to remove ourselves from the send pipeline here since that
+           is done for us in Curl_done() */
+
+        if(CURLE_OK == easy->result) {
+          multistate(easy, CURLM_STATE_DO_DONE);
+          result = CURLM_CALL_MULTI_PERFORM;
+        }
+        else {
+          /* failure detected */
+          Curl_posttransfer(easy->easy_handle);
+          Curl_done(&easy->easy_conn, easy->result, FALSE);
+          disconnect_conn = TRUE;
+        }
+      }
+      break;
+
+    case CURLM_STATE_DO_DONE:
+      /* Move ourselves from the send to recv pipeline */
+      moveHandleFromSendToRecvPipeline(easy->easy_handle, easy->easy_conn);
+      /* Check if we can move pending requests to send pipe */
+      checkPendPipeline(easy->easy_conn);
+      multistate(easy, CURLM_STATE_WAITPERFORM);
+      result = CURLM_CALL_MULTI_PERFORM;
+      break;
+
+    case CURLM_STATE_WAITPERFORM:
+      /* Wait for our turn to PERFORM */
+      if(!easy->easy_conn->readchannel_inuse &&
+         isHandleAtHead(easy->easy_handle,
+                        easy->easy_conn->recv_pipe)) {
+        /* Grab the channel */
+        easy->easy_conn->readchannel_inuse = TRUE;
+        multistate(easy, CURLM_STATE_PERFORM);
+        result = CURLM_CALL_MULTI_PERFORM;
+      }
+#ifdef DEBUGBUILD
+      else {
+        infof(easy->easy_handle, "Conn %ld recv pipe %zu inuse %d athead %d\n",
+              easy->easy_conn->connectindex,
+              easy->easy_conn->recv_pipe->size,
+              easy->easy_conn->readchannel_inuse?1:0,
+              isHandleAtHead(easy->easy_handle,
+                             easy->easy_conn->recv_pipe)?1:0);
+      }
+#endif
+      break;
+
+    case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */
+      /* if both rates are within spec, resume transfer */
+      Curl_pgrsUpdate(easy->easy_conn);
+      if( ( ( easy->easy_handle->set.max_send_speed == 0 ) ||
+            ( easy->easy_handle->progress.ulspeed <
+              easy->easy_handle->set.max_send_speed ) )  &&
+          ( ( easy->easy_handle->set.max_recv_speed == 0 ) ||
+            ( easy->easy_handle->progress.dlspeed <
+              easy->easy_handle->set.max_recv_speed ) )
+        )
+        multistate(easy, CURLM_STATE_PERFORM);
+      break;
+
+    case CURLM_STATE_PERFORM:
+      /* check if over speed */
+      if( (  ( easy->easy_handle->set.max_send_speed > 0 ) &&
+             ( easy->easy_handle->progress.ulspeed >
+               easy->easy_handle->set.max_send_speed ) )  ||
+          (  ( easy->easy_handle->set.max_recv_speed > 0 ) &&
+             ( easy->easy_handle->progress.dlspeed >
+               easy->easy_handle->set.max_recv_speed ) )
+        ) {
+        /* Transfer is over the speed limit. Change state.  TODO: Call
+         * Curl_expire() with the time left until we're targeted to be below
+         * the speed limit again. */
+        multistate(easy, CURLM_STATE_TOOFAST );
+        break;
+      }
+
+      /* read/write data if it is ready to do so */
+      easy->result = Curl_readwrite(easy->easy_conn, &done);
+
+      k = &easy->easy_handle->req;
+
+      if(!(k->keepon & KEEP_RECV)) {
+        /* We're done receiving */
+        easy->easy_conn->readchannel_inuse = FALSE;
+      }
+
+      if(!(k->keepon & KEEP_SEND)) {
+        /* We're done sending */
+        easy->easy_conn->writechannel_inuse = FALSE;
+      }
+
+      if(easy->result)  {
+        /* The transfer phase returned error, we mark the connection to get
+         * closed to prevent being re-used. This is because we can't possibly
+         * know if the connection is in a good shape or not now.  Unless it is
+         * a protocol which uses two "channels" like FTP, as then the error
+         * happened in the data connection.
+         */
+        if(!(easy->easy_conn->protocol & PROT_DUALCHANNEL))
+          easy->easy_conn->bits.close = TRUE;
+
+        Curl_posttransfer(easy->easy_handle);
+        Curl_done(&easy->easy_conn, easy->result, FALSE);
+      }
+      else if(TRUE == done) {
+        char *newurl = NULL;
+        bool retry = FALSE;
+        followtype follow=FOLLOW_NONE;
+
+        easy->result = Curl_retry_request(easy->easy_conn, &newurl);
+        if(!easy->result)
+          retry = (bool)(newurl?TRUE:FALSE);
+
+        /* call this even if the readwrite function returned error */
+        Curl_posttransfer(easy->easy_handle);
+
+        /* we're no longer receving */
+        moveHandleFromRecvToDonePipeline(easy->easy_handle,
+                                         easy->easy_conn);
+
+        /* expire the new receiving pipeline head */
+        if(easy->easy_conn->recv_pipe->head)
+          Curl_expire(easy->easy_conn->recv_pipe->head->ptr, 1);
+
+        /* Check if we can move pending requests to send pipe */
+        checkPendPipeline(easy->easy_conn);
+
+        /* When we follow redirects or is set to retry the connection, we must
+           to go back to the CONNECT state */
+        if(easy->easy_handle->req.newurl || retry) {
+          if(!retry) {
+            /* if the URL is a follow-location and not just a retried request
+               then figure out the URL here */
+            newurl = easy->easy_handle->req.newurl;
+            easy->easy_handle->req.newurl = NULL;
+            follow = FOLLOW_REDIR;
+          }
+          else
+            follow = FOLLOW_RETRY;
+          easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE);
+          if(easy->result == CURLE_OK)
+            easy->result = Curl_follow(easy->easy_handle, newurl, follow);
+          if(CURLE_OK == easy->result) {
+            multistate(easy, CURLM_STATE_CONNECT);
+            result = CURLM_CALL_MULTI_PERFORM;
+          }
+          else if(newurl)
+            /* Since we "took it", we are in charge of freeing this on
+               failure */
+            free(newurl);
+        }
+        else {
+          /* after the transfer is done, go DONE */
+
+          /* but first check to see if we got a location info even though we're
+             not following redirects */
+          if (easy->easy_handle->req.location) {
+            newurl = easy->easy_handle->req.location;
+            easy->easy_handle->req.location = NULL;
+            easy->result = Curl_follow(easy->easy_handle, newurl, FOLLOW_FAKE);
+            if (easy->result)
+              free(newurl);
+          }
+
+          multistate(easy, CURLM_STATE_DONE);
+          result = CURLM_CALL_MULTI_PERFORM;
+        }
+      }
+
+      break;
+
+    case CURLM_STATE_DONE:
+
+      if(easy->easy_conn) {
+        /* Remove ourselves from the receive and done pipelines. Handle
+           should be on one of these lists, depending upon how we got here. */
+        Curl_removeHandleFromPipeline(easy->easy_handle,
+                                      easy->easy_conn->recv_pipe);
+        Curl_removeHandleFromPipeline(easy->easy_handle,
+                                      easy->easy_conn->done_pipe);
+        /* Check if we can move pending requests to send pipe */
+        checkPendPipeline(easy->easy_conn);
+
+        if(easy->easy_conn->bits.stream_was_rewound) {
+          /* This request read past its response boundary so we quickly let
+             the other requests consume those bytes since there is no
+             guarantee that the socket will become active again */
+          result = CURLM_CALL_MULTI_PERFORM;
+        }
+
+        /* post-transfer command */
+        easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE);
+        /*
+         * If there are other handles on the pipeline, Curl_done won't set
+         * easy_conn to NULL.  In such a case, curl_multi_remove_handle() can
+         * access free'd data, if the connection is free'd and the handle
+         * removed before we perform the processing in CURLM_STATE_COMPLETED
+         */
+        if (easy->easy_conn)
+          easy->easy_conn = NULL;
+      }
+
+      /* after we have DONE what we're supposed to do, go COMPLETED, and
+         it doesn't matter what the Curl_done() returned! */
+      multistate(easy, 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. */
+
+      /* Important: reset the conn pointer so that we don't point to memory
+         that could be freed anytime */
+      easy->easy_conn = NULL;
+      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.
+         */
+
+        /* NOTE: no attempt to disconnect connections must be made
+           in the case blocks above - cleanup happens only here */
+
+        easy->easy_handle->state.pipe_broke = FALSE;
+
+        if(easy->easy_conn) {
+          /* if this has a connection, unsubscribe from the pipelines */
+          easy->easy_conn->writechannel_inuse = FALSE;
+          easy->easy_conn->readchannel_inuse = FALSE;
+          Curl_removeHandleFromPipeline(easy->easy_handle,
+                                        easy->easy_conn->send_pipe);
+          Curl_removeHandleFromPipeline(easy->easy_handle,
+                                        easy->easy_conn->recv_pipe);
+          Curl_removeHandleFromPipeline(easy->easy_handle,
+                                        easy->easy_conn->done_pipe);
+          /* Check if we can move pending requests to send pipe */
+          checkPendPipeline(easy->easy_conn);
+        }
+
+        if(disconnect_conn) {
+          Curl_disconnect(easy->easy_conn); /* disconnect properly */
+
+          /* This is where we make sure that the easy_conn pointer is reset.
+             We don't have to do this in every case block above where a
+             failure is detected */
+          easy->easy_conn = NULL;
+        }
+
+        multistate(easy, CURLM_STATE_COMPLETED);
+      }
+    }
+  } while(0);
+  if((CURLM_STATE_COMPLETED == easy->state) && !easy->msg) {
+    if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) {
+      /* clear out the usage of the shared DNS cache */
+      easy->easy_handle->dns.hostcache = NULL;
+      easy->easy_handle->dns.hostcachetype = HCACHE_NONE;
+    }
+
+    /* now add a node to the Curl_message linked list with this info */
+    msg = 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 */
+  }
+
+  return result;
+}
+
+
+CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
+{
+  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+  struct Curl_one_easy *easy;
+  CURLMcode returncode=CURLM_OK;
+  struct Curl_tree *t;
+
+  if(!GOOD_MULTI_HANDLE(multi))
+    return CURLM_BAD_HANDLE;
+
+  easy=multi->easy.next;
+  while(easy != &multi->easy) {
+    CURLMcode result;
+
+    do
+      result = multi_runsingle(multi, easy);
+    while (CURLM_CALL_MULTI_PERFORM == result);
+
+    if(result)
+      returncode = result;
+
+    easy = easy->next; /* operate on next handle */
+  }
+
+  /*
+   * Simply remove all expired timers from the splay since handles are dealt
+   * with unconditionally by this function and curl_multi_timeout() requires
+   * that already passed/handled expire times are removed from the splay.
+   */
+  do {
+    struct timeval now = Curl_tvnow();
+
+    multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
+    if(t) {
+      struct SessionHandle *d = t->payload;
+      struct timeval* tv = &d->state.expiretime;
+
+      /* clear the expire times within the handles that we remove from the
+         splay tree */
+      tv->tv_sec = 0;
+      tv->tv_usec = 0;
+    }
+
+  } while(t);
+
+  *running_handles = multi->num_alive;
+
+  if( CURLM_OK >= returncode )
+    update_timer(multi);
+
+  return returncode;
+}
+
+/* This is called when an easy handle is cleanup'ed that is part of a multi
+   handle */
+void Curl_multi_rmeasy(void *multi_handle, CURL *easy_handle)
+{
+  curl_multi_remove_handle(multi_handle, easy_handle);
+}
+
+
+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;
+  int i;
+  struct closure *cl;
+  struct closure *n;
+
+  if(GOOD_MULTI_HANDLE(multi)) {
+    multi->type = 0; /* not good anymore */
+    Curl_hash_destroy(multi->hostcache);
+    Curl_hash_destroy(multi->sockhash);
+    multi->hostcache = NULL;
+    multi->sockhash = NULL;
+
+    /* go over all connections that have close actions */
+    for(i=0; i< multi->connc->num; i++) {
+      if(multi->connc->connects[i] &&
+         multi->connc->connects[i]->protocol & PROT_CLOSEACTION) {
+        Curl_disconnect(multi->connc->connects[i]);
+        multi->connc->connects[i] = NULL;
+      }
+    }
+    /* now walk through the list of handles we kept around only to be
+       able to close connections "properly" */
+    cl = multi->closure;
+    while(cl) {
+      cl->easy_handle->state.shared_conn = NULL; /* no more shared */
+      if(cl->easy_handle->state.closed)
+        /* close handle only if curl_easy_cleanup() already has been called
+           for this easy handle */
+        Curl_close(cl->easy_handle);
+      n = cl->next;
+      free(cl);
+      cl= n;
+    }
+
+    Curl_rm_connc(multi->connc);
+
+    /* remove all easy handles */
+    easy = multi->easy.next;
+    while(easy != &multi->easy) {
+      nexteasy=easy->next;
+      if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) {
+        /* clear out the usage of the shared DNS cache */
+        easy->easy_handle->dns.hostcache = NULL;
+        easy->easy_handle->dns.hostcachetype = HCACHE_NONE;
+      }
+
+      /* Clear the pointer to the connection cache */
+      easy->easy_handle->state.connc = NULL;
+
+      Curl_easy_addmulti(easy->easy_handle, NULL); /* clear the association */
+
+      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 != &multi->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;
+}
+
+/*
+ * singlesocket() checks what sockets we deal with and their "action state"
+ * and if we have a different state in any of those sockets from last time we
+ * call the callback accordingly.
+ */
+static void singlesocket(struct Curl_multi *multi,
+                         struct Curl_one_easy *easy)
+{
+  curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
+  int i;
+  struct Curl_sh_entry *entry;
+  curl_socket_t s;
+  int num;
+  unsigned int curraction;
+  struct Curl_one_easy *easy_by_hash;
+  bool remove_sock_from_hash;
+
+  for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++)
+    socks[i] = CURL_SOCKET_BAD;
+
+  /* Fill in the 'current' struct with the state as it is now: what sockets to
+     supervise and for what actions */
+  curraction = multi_getsock(easy, socks, MAX_SOCKSPEREASYHANDLE);
+
+  /* We have 0 .. N sockets already and we get to know about the 0 .. M
+     sockets we should have from now on. Detect the differences, remove no
+     longer supervised ones and add new ones */
+
+  /* walk over the sockets we got right now */
+  for(i=0; (i< MAX_SOCKSPEREASYHANDLE) &&
+        (curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i)));
+      i++) {
+    int action = CURL_POLL_NONE;
+
+    s = socks[i];
+
+    /* get it from the hash */
+    entry = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
+
+    if(curraction & GETSOCK_READSOCK(i))
+      action |= CURL_POLL_IN;
+    if(curraction & GETSOCK_WRITESOCK(i))
+      action |= CURL_POLL_OUT;
+
+    if(entry) {
+      /* yeps, already present so check if it has the same action set */
+      if(entry->action == action)
+        /* same, continue */
+        continue;
+    }
+    else {
+      /* this is a socket we didn't have before, add it! */
+      entry = sh_addentry(multi->sockhash, s, easy->easy_handle);
+      if(!entry)
+        /* fatal */
+        return;
+    }
+
+    multi->socket_cb(easy->easy_handle,
+                     s,
+                     action,
+                     multi->socket_userp,
+                     entry ? entry->socketp : NULL);
+
+    entry->action = action; /* store the current action state */
+  }
+
+  num = i; /* number of sockets */
+
+  /* when we've walked over all the sockets we should have right now, we must
+     make sure to detect sockets that are removed */
+  for(i=0; i< easy->numsocks; i++) {
+    int j;
+    s = easy->sockets[i];
+    for(j=0; j<num; j++) {
+      if(s == socks[j]) {
+        /* this is still supervised */
+        s = CURL_SOCKET_BAD;
+        break;
+      }
+    }
+    if(s != CURL_SOCKET_BAD) {
+
+      /* this socket has been removed. Tell the app to remove it */
+      remove_sock_from_hash = TRUE;
+
+      entry = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
+      if(entry) {
+        /* check if the socket to be removed serves a connection which has
+           other easy-s in a pipeline. In this case the socket should not be
+           removed. */
+        struct connectdata *easy_conn;
+
+        easy_by_hash = entry->easy->multi_pos;
+        easy_conn = easy_by_hash->easy_conn;
+        if(easy_conn) {
+          if (easy_conn->recv_pipe && easy_conn->recv_pipe->size > 1) {
+            /* the handle should not be removed from the pipe yet */
+            remove_sock_from_hash = FALSE;
+
+            /* Update the sockhash entry to instead point to the next in line
+               for the recv_pipe, or the first (in case this particular easy
+               isn't already) */
+            if (entry->easy == easy->easy_handle) {
+              if (isHandleAtHead(easy->easy_handle, easy_conn->recv_pipe))
+                entry->easy = easy_conn->recv_pipe->head->next->ptr;
+              else
+                entry->easy = easy_conn->recv_pipe->head->ptr;
+            }
+          }
+          if (easy_conn->send_pipe  && easy_conn->send_pipe->size > 1) {
+            /* the handle should not be removed from the pipe yet */
+            remove_sock_from_hash = FALSE;
+
+            /* Update the sockhash entry to instead point to the next in line
+               for the send_pipe, or the first (in case this particular easy
+               isn't already) */
+            if (entry->easy == easy->easy_handle) {
+              if (isHandleAtHead(easy->easy_handle, easy_conn->send_pipe))
+                entry->easy = easy_conn->send_pipe->head->next->ptr;
+              else
+                entry->easy = easy_conn->send_pipe->head->ptr;
+            }
+          }
+          /* Don't worry about overwriting recv_pipe head with send_pipe_head,
+             when action will be asked on the socket (see multi_socket()), the
+             head of the correct pipe will be taken according to the
+             action. */
+        }
+      }
+      else
+        /* just a precaution, this socket really SHOULD be in the hash already
+           but in case it isn't, we don't have to tell the app to remove it
+           either since it never got to know about it */
+        remove_sock_from_hash = FALSE;
+
+      if (remove_sock_from_hash) {
+        multi->socket_cb(easy->easy_handle,
+                         s,
+                         CURL_POLL_REMOVE,
+                         multi->socket_userp,
+                         entry ? entry->socketp : NULL);
+        sh_delentry(multi->sockhash, s);
+      }
+
+    }
+  }
+
+  memcpy(easy->sockets, socks, num*sizeof(curl_socket_t));
+  easy->numsocks = num;
+}
+
+static CURLMcode multi_socket(struct Curl_multi *multi,
+                              bool checkall,
+                              curl_socket_t s,
+                              int ev_bitmask,
+                              int *running_handles)
+{
+  CURLMcode result = CURLM_OK;
+  struct SessionHandle *data = NULL;
+  struct Curl_tree *t;
+
+  if(checkall) {
+    struct Curl_one_easy *easyp;
+    /* *perform() deals with running_handles on its own */
+    result = curl_multi_perform(multi, running_handles);
+
+    /* walk through each easy handle and do the socket state change magic
+       and callbacks */
+    easyp=multi->easy.next;
+    while(easyp != &multi->easy) {
+      singlesocket(multi, easyp);
+      easyp = easyp->next;
+    }
+
+    /* or should we fall-through and do the timer-based stuff? */
+    return result;
+  }
+  else if(s != CURL_SOCKET_TIMEOUT) {
+
+    struct Curl_sh_entry *entry =
+      Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
+
+    if(!entry)
+      /* Unmatched socket, we can't act on it but we ignore this fact.  In
+         real-world tests it has been proved that libevent can in fact give
+         the application actions even though the socket was just previously
+         asked to get removed, so thus we better survive stray socket actions
+         and just move on. */
+      ;
+    else {
+      data = entry->easy;
+
+      if(data->magic != CURLEASY_MAGIC_NUMBER)
+        /* bad bad bad bad bad bad bad */
+        return CURLM_INTERNAL_ERROR;
+
+      /* If the pipeline is enabled, take the handle which is in the head of
+         the pipeline. If we should write into the socket, take the send_pipe
+         head.  If we should read from the socket, take the recv_pipe head. */
+      if(data->set.one_easy->easy_conn) {
+        if ((ev_bitmask & CURL_POLL_OUT) &&
+            data->set.one_easy->easy_conn->send_pipe &&
+            data->set.one_easy->easy_conn->send_pipe->head)
+          data = data->set.one_easy->easy_conn->send_pipe->head->ptr;
+        else if ((ev_bitmask & CURL_POLL_IN) &&
+                 data->set.one_easy->easy_conn->recv_pipe &&
+                 data->set.one_easy->easy_conn->recv_pipe->head)
+          data = data->set.one_easy->easy_conn->recv_pipe->head->ptr;
+      }
+
+      if(data->set.one_easy->easy_conn)  /* set socket event bitmask */
+        data->set.one_easy->easy_conn->cselect_bits = ev_bitmask;
+
+      do
+        result = multi_runsingle(multi, data->set.one_easy);
+      while (CURLM_CALL_MULTI_PERFORM == result);
+
+      if(data->set.one_easy->easy_conn)
+        data->set.one_easy->easy_conn->cselect_bits = 0;
+
+      if(CURLM_OK >= result)
+        /* get the socket(s) and check if the state has been changed since
+           last */
+        singlesocket(multi, data->set.one_easy);
+
+      /* Now we fall-through and do the timer-based stuff, since we don't want
+         to force the user to have to deal with timeouts as long as at least
+         one connection in fact has traffic. */
+
+      data = NULL; /* set data to NULL again to avoid calling
+                      multi_runsingle() in case there's no need to */
+    }
+  }
+
+  /*
+   * The loop following here will go on as long as there are expire-times left
+   * to process in the splay and 'data' will be re-assigned for every expired
+   * handle we deal with.
+   */
+  do {
+    struct timeval now;
+
+    /* the first loop lap 'data' can be NULL */
+    if(data) {
+      do
+        result = multi_runsingle(multi, data->set.one_easy);
+      while (CURLM_CALL_MULTI_PERFORM == result);
+
+      if(CURLM_OK >= result)
+        /* get the socket(s) and check if the state has been changed since
+           last */
+        singlesocket(multi, data->set.one_easy);
+    }
+
+    /* Check if there's one (more) expired timer to deal with! This function
+       extracts a matching node if there is one */
+
+    now = Curl_tvnow();
+    now.tv_usec += 1000; /* to compensate for the truncating of 999us to 0ms,
+                            we always add time here to make the comparison
+                            below better */
+
+    multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
+    if(t) {
+      /* assign 'data' to be the easy handle we just removed from the splay
+         tree */
+      data = t->payload;
+      /* clear the expire time within the handle we removed from the
+         splay tree */
+      data->state.expiretime.tv_sec = 0;
+      data->state.expiretime.tv_usec = 0;
+    }
+
+  } while(t);
+
+  *running_handles = multi->num_alive;
+  return result;
+}
+
+#undef curl_multi_setopt
+CURLMcode curl_multi_setopt(CURLM *multi_handle,
+                            CURLMoption option, ...)
+{
+  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+  CURLMcode res = CURLM_OK;
+  va_list param;
+
+  if(!GOOD_MULTI_HANDLE(multi))
+    return CURLM_BAD_HANDLE;
+
+  va_start(param, option);
+
+  switch(option) {
+  case CURLMOPT_SOCKETFUNCTION:
+    multi->socket_cb = va_arg(param, curl_socket_callback);
+    break;
+  case CURLMOPT_SOCKETDATA:
+    multi->socket_userp = va_arg(param, void *);
+    break;
+  case CURLMOPT_PIPELINING:
+    multi->pipelining_enabled = (bool)(0 != va_arg(param, long));
+    break;
+  case CURLMOPT_TIMERFUNCTION:
+    multi->timer_cb = va_arg(param, curl_multi_timer_callback);
+    break;
+  case CURLMOPT_TIMERDATA:
+    multi->timer_userp = va_arg(param, void *);
+    break;
+  case CURLMOPT_MAXCONNECTS:
+    multi->maxconnects = va_arg(param, long);
+    break;
+  default:
+    res = CURLM_UNKNOWN_OPTION;
+    break;
+  }
+  va_end(param);
+  return res;
+}
+
+/* we define curl_multi_socket() in the public multi.h header */
+#undef curl_multi_socket
+
+CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
+                            int *running_handles)
+{
+  CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s,
+                                  0, running_handles);
+  if(CURLM_OK >= result)
+    update_timer((struct Curl_multi *)multi_handle);
+  return result;
+}
+
+CURLMcode curl_multi_socket_action(CURLM *multi_handle, curl_socket_t s,
+                                   int ev_bitmask, int *running_handles)
+{
+  CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s,
+                                  ev_bitmask, running_handles);
+  if(CURLM_OK >= result)
+    update_timer((struct Curl_multi *)multi_handle);
+  return result;
+}
+
+CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles)
+
+{
+  CURLMcode result = multi_socket((struct Curl_multi *)multi_handle,
+                                  TRUE, CURL_SOCKET_BAD, 0, running_handles);
+  if(CURLM_OK >= result)
+    update_timer((struct Curl_multi *)multi_handle);
+  return result;
+}
+
+static CURLMcode multi_timeout(struct Curl_multi *multi,
+                               long *timeout_ms)
+{
+  static struct timeval tv_zero = {0,0};
+
+  if(multi->timetree) {
+    /* we have a tree of expire times */
+    struct timeval now = Curl_tvnow();
+
+    /* splay the lowest to the bottom */
+    multi->timetree = Curl_splay(tv_zero, multi->timetree);
+
+    if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) {
+      /* some time left before expiration */
+      *timeout_ms = curlx_tvdiff(multi->timetree->key, now);
+      if(!*timeout_ms)
+        /*
+         * Since we only provide millisecond resolution on the returned value
+         * and the diff might be less than one millisecond here, we don't
+         * return zero as that may cause short bursts of busyloops on fast
+         * processors while the diff is still present but less than one
+         * millisecond! instead we return 1 until the time is ripe.
+         */
+        *timeout_ms=1;
+    }
+    else
+      /* 0 means immediately */
+      *timeout_ms = 0;
+  }
+  else
+    *timeout_ms = -1;
+
+  return CURLM_OK;
+}
+
+CURLMcode curl_multi_timeout(CURLM *multi_handle,
+                             long *timeout_ms)
+{
+  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+
+  /* First, make some basic checks that the CURLM handle is a good handle */
+  if(!GOOD_MULTI_HANDLE(multi))
+    return CURLM_BAD_HANDLE;
+
+  return multi_timeout(multi, timeout_ms);
+}
+
+/*
+ * Tell the application it should update its timers, if it subscribes to the
+ * update timer callback.
+ */
+static int update_timer(struct Curl_multi *multi)
+{
+  long timeout_ms;
+  if(!multi->timer_cb)
+    return 0;
+  if( multi_timeout(multi, &timeout_ms) != CURLM_OK )
+    return -1;
+  if( timeout_ms < 0 )
+    return 0;
+
+  /* When multi_timeout() is done, multi->timetree points to the node with the
+   * timeout we got the (relative) time-out time for. We can thus easily check
+   * if this is the same (fixed) time as we got in a previous call and then
+   * avoid calling the callback again. */
+  if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0)
+    return 0;
+
+  multi->timer_lastcall = multi->timetree->key;
+
+  return multi->timer_cb((CURLM*)multi, timeout_ms, multi->timer_userp);
+}
+
+static CURLcode addHandleToSendOrPendPipeline(struct SessionHandle *handle,
+                                              struct connectdata *conn)
+{
+  size_t pipeLen = conn->send_pipe->size + conn->recv_pipe->size;
+  struct curl_llist *pipeline;
+
+  if(!Curl_isPipeliningEnabled(handle) ||
+     pipeLen == 0)
+    pipeline = conn->send_pipe;
+  else {
+    if(conn->server_supports_pipelining &&
+       pipeLen < MAX_PIPELINE_LENGTH)
+      pipeline = conn->send_pipe;
+    else
+      pipeline = conn->pend_pipe;
+  }
+
+  return Curl_addHandleToPipeline(handle, pipeline);
+}
+
+static int checkPendPipeline(struct connectdata *conn)
+{
+  int result = 0;
+  struct curl_llist_element *sendhead = conn->send_pipe->head;
+
+  size_t pipeLen = conn->send_pipe->size + conn->recv_pipe->size;
+  if (conn->server_supports_pipelining || pipeLen == 0) {
+    struct curl_llist_element *curr = conn->pend_pipe->head;
+    const size_t maxPipeLen =
+      conn->server_supports_pipelining ? MAX_PIPELINE_LENGTH : 1;
+
+    while(pipeLen < maxPipeLen && curr) {
+      Curl_llist_move(conn->pend_pipe, curr,
+                      conn->send_pipe, conn->send_pipe->tail);
+      Curl_pgrsTime(curr->ptr, TIMER_PRETRANSFER);
+      ++result; /* count how many handles we moved */
+      curr = conn->pend_pipe->head;
+      ++pipeLen;
+    }
+  }
+
+  if (result) {
+    conn->now = Curl_tvnow();
+    /* something moved, check for a new send pipeline leader */
+    if(sendhead != conn->send_pipe->head) {
+      /* this is a new one as head, expire it */
+      conn->writechannel_inuse = FALSE; /* not in use yet */
+      infof(conn->data, "%p is at send pipe head!\n",
+            conn->send_pipe->head->ptr);
+      Curl_expire(conn->send_pipe->head->ptr, 1);
+    }
+  }
+
+  return result;
+}
+
+/* Move this transfer from the sending list to the receiving list.
+
+   Pay special attention to the new sending list "leader" as it needs to get
+   checked to update what sockets it acts on.
+
+*/
+static void moveHandleFromSendToRecvPipeline(struct SessionHandle *handle,
+                                             struct connectdata *conn)
+{
+  struct curl_llist_element *curr;
+
+  curr = conn->send_pipe->head;
+  while(curr) {
+    if(curr->ptr == handle) {
+      Curl_llist_move(conn->send_pipe, curr,
+                      conn->recv_pipe, conn->recv_pipe->tail);
+
+      if(conn->send_pipe->head) {
+        /* Since there's a new easy handle at the start of the send pipeline,
+           set its timeout value to 1ms to make it trigger instantly */
+        conn->writechannel_inuse = FALSE; /* not used now */
+        infof(conn->data, "%p is at send pipe head B!\n",
+              conn->send_pipe->head->ptr);
+        Curl_expire(conn->send_pipe->head->ptr, 1);
+      }
+
+      /* The receiver's list is not really interesting here since either this
+         handle is now first in the list and we'll deal with it soon, or
+         another handle is already first and thus is already taken care of */
+
+      break; /* we're done! */
+    }
+    curr = curr->next;
+  }
+}
+
+static void moveHandleFromRecvToDonePipeline(struct SessionHandle *handle,
+                                            struct connectdata *conn)
+{
+  struct curl_llist_element *curr;
+
+  curr = conn->recv_pipe->head;
+  while(curr) {
+    if(curr->ptr == handle) {
+      Curl_llist_move(conn->recv_pipe, curr,
+                      conn->done_pipe, conn->done_pipe->tail);
+      break;
+    }
+    curr = curr->next;
+  }
+}
+static bool isHandleAtHead(struct SessionHandle *handle,
+                           struct curl_llist *pipeline)
+{
+  struct curl_llist_element *curr = pipeline->head;
+  if(curr)
+    return (bool)(curr->ptr == handle);
+
+  return FALSE;
+}
+
+/* given a number of milliseconds from now to use to set the 'act before
+   this'-time for the transfer, to be extracted by curl_multi_timeout()
+
+   Pass zero to clear the timeout value for this handle.
+*/
+void Curl_expire(struct SessionHandle *data, long milli)
+{
+  struct Curl_multi *multi = data->multi;
+  struct timeval *nowp = &data->state.expiretime;
+  int rc;
+
+  /* this is only interesting for multi-interface using libcurl, and only
+     while there is still a multi interface struct remaining! */
+  if(!multi)
+    return;
+
+  if(!milli) {
+    /* No timeout, clear the time data. */
+    if(nowp->tv_sec || nowp->tv_usec) {
+      /* Since this is an cleared time, we must remove the previous entry from
+         the splay tree */
+      rc = Curl_splayremovebyaddr(multi->timetree,
+                                  &data->state.timenode,
+                                  &multi->timetree);
+      if(rc)
+        infof(data, "Internal error clearing splay node = %d\n", rc);
+      infof(data, "Expire cleared\n");
+      nowp->tv_sec = 0;
+      nowp->tv_usec = 0;
+    }
+  }
+  else {
+    struct timeval set;
+    int rest;
+
+    set = Curl_tvnow();
+    set.tv_sec += milli/1000;
+    set.tv_usec += (milli%1000)*1000;
+
+    rest = (int)(set.tv_usec - 1000000);
+    if(rest > 0) {
+      /* bigger than a full microsec */
+      set.tv_sec++;
+      set.tv_usec -= 1000000;
+    }
+
+    if(nowp->tv_sec || nowp->tv_usec) {
+      /* This means that the struct is added as a node in the splay tree.
+         Compare if the new time is earlier, and only remove-old/add-new if it
+         is. */
+      long diff = curlx_tvdiff(set, *nowp);
+      if(diff > 0)
+        /* the new expire time was later so we don't change this */
+        return;
+
+      /* Since this is an updated time, we must remove the previous entry from
+         the splay tree first and then re-add the new value */
+      rc = Curl_splayremovebyaddr(multi->timetree,
+                                  &data->state.timenode,
+                                  &multi->timetree);
+      if(rc)
+        infof(data, "Internal error removing splay node = %d\n", rc);
+    }
+
+    *nowp = set;
+#if 0
+    infof(data, "Expire at %ld / %ld (%ldms) %p\n",
+          (long)nowp->tv_sec, (long)nowp->tv_usec, milli, data);
+#endif
+    data->state.timenode.payload = data;
+    multi->timetree = Curl_splayinsert(*nowp,
+                                       multi->timetree,
+                                       &data->state.timenode);
+  }
+#if 0
+  Curl_splayprint(multi->timetree, 0, TRUE);
+#endif
+}
+
+CURLMcode curl_multi_assign(CURLM *multi_handle,
+                            curl_socket_t s, void *hashp)
+{
+  struct Curl_sh_entry *there = NULL;
+  struct Curl_multi *multi = (struct Curl_multi *)multi_handle;
+
+  if(s != CURL_SOCKET_BAD)
+    there = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(curl_socket_t));
+
+  if(!there)
+    return CURLM_BAD_SOCKET;
+
+  there->socketp = hashp;
+
+  return CURLM_OK;
+}
+
+static void multi_connc_remove_handle(struct Curl_multi *multi,
+                                      struct SessionHandle *data)
+{
+  /* a connection in the connection cache pointing to the given 'data' ? */
+  int i;
+
+  for(i=0; i< multi->connc->num; i++) {
+    struct connectdata * conn = multi->connc->connects[i];
+
+    if(conn && conn->data == data) {
+      /* If this easy_handle was the last one in charge for one or more
+         connections in the shared connection cache, we might need to keep
+         this handle around until either A) the connection is closed and
+         killed properly, or B) another easy_handle uses the connection.
+
+         The reason why we need to have a easy_handle associated with a live
+         connection is simply that some connections will need a handle to get
+         closed down properly. Currently, the only connections that need to
+         keep a easy_handle handle around are using FTP(S). Such connections
+         have the PROT_CLOSEACTION bit set.
+
+         Thus, we need to check for all connections in the shared cache that
+         points to this handle and are using PROT_CLOSEACTION. If there's any,
+         we need to add this handle to the list of "easy handles kept around
+         for nice connection closures".
+      */
+
+      if(conn->protocol & PROT_CLOSEACTION) {
+        /* this handle is still being used by a shared connection and
+           thus we leave it around for now */
+        if(add_closure(multi, data) == CURLM_OK)
+          data->state.shared_conn = multi;
+        else {
+          /* out of memory - so much for graceful shutdown */
+          Curl_disconnect(conn);
+          multi->connc->connects[i] = NULL;
+        }
+      }
+      else
+        /* disconect the easy handle from the connection since the connection
+           will now remain but this easy handle is going */
+        conn->data = NULL;
+    }
+  }
+}
+
+/* Add the given data pointer to the list of 'closure handles' that are kept
+   around only to be able to close some connections nicely - just make sure
+   that this handle isn't already added, like for the cases when an easy
+   handle is removed, added and removed again... */
+static CURLMcode add_closure(struct Curl_multi *multi,
+                             struct SessionHandle *data)
+{
+  struct closure *cl = multi->closure;
+  struct closure *p = NULL;
+  bool add = TRUE;
+
+  /* Before adding, scan through all the other currently kept handles and see
+     if there are any connections still referring to them and kill them if
+     not. */
+  while(cl) {
+    struct closure *n;
+    bool inuse = FALSE;
+    int i;
+
+    for(i=0; i< multi->connc->num; i++) {
+      if(multi->connc->connects[i] &&
+         (multi->connc->connects[i]->data == cl->easy_handle)) {
+        inuse = TRUE;
+        break;
+      }
+    }
+
+    n = cl->next;
+
+    if(!inuse) {
+      /* cl->easy_handle is now killable */
+
+      /* unmark it as not having a connection around that uses it anymore */
+      cl->easy_handle->state.shared_conn= NULL;
+
+      if(cl->easy_handle->state.closed) {
+        infof(data, "Delayed kill of easy handle %p\n", cl->easy_handle);
+        /* close handle only if curl_easy_cleanup() already has been called
+           for this easy handle */
+        Curl_close(cl->easy_handle);
+      }
+      if(p)
+        p->next = n;
+      else
+        multi->closure = n;
+      free(cl);
+    } else {
+      if(cl->easy_handle == data)
+        add = FALSE;
+
+      p = cl;
+    }
+
+    cl = n;
+  }
+
+  if (add) {
+    cl = calloc(1, sizeof(struct closure));
+    if(!cl)
+      return CURLM_OUT_OF_MEMORY;
+
+    cl->easy_handle = data;
+    cl->next = multi->closure;
+    multi->closure = cl;
+  }
+
+  return CURLM_OK;
+}
+
+#ifdef DEBUGBUILD
+void Curl_multi_dump(const struct Curl_multi *multi_handle)
+{
+  struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+  struct Curl_one_easy *easy;
+  int i;
+  fprintf(stderr, "* Multi status: %d handles, %d alive\n",
+          multi->num_easy, multi->num_alive);
+  for(easy=multi->easy.next; easy != &multi->easy; easy = easy->next) {
+    if(easy->state != CURLM_STATE_COMPLETED) {
+      /* only display handles that are not completed */
+      fprintf(stderr, "handle %p, state %s, %d sockets\n",
+              (void *)easy->easy_handle,
+              statename[easy->state], easy->numsocks);
+      for(i=0; i < easy->numsocks; i++) {
+        curl_socket_t s = easy->sockets[i];
+        struct Curl_sh_entry *entry =
+          Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
+
+        fprintf(stderr, "%d ", (int)s);
+        if(!entry) {
+          fprintf(stderr, "INTERNAL CONFUSION\n");
+          continue;
+        }
+        fprintf(stderr, "[%s %s] ",
+                entry->action&CURL_POLL_IN?"RECVING":"",
+                entry->action&CURL_POLL_OUT?"SENDING":"");
+      }
+      if(easy->numsocks)
+        fprintf(stderr, "\n");
+    }
+  }
+}
+#endif
diff --git a/lib/multiif.h b/lib/multiif.h
new file mode 100644
index 0000000..798544e
--- /dev/null
+++ b/lib/multiif.h
@@ -0,0 +1,55 @@
+#ifndef __MULTIIF_H
+#define __MULTIIF_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+/*
+ * Prototypes for library-wide functions provided by multi.c
+ */
+void Curl_expire(struct SessionHandle *data, long milli);
+
+void Curl_multi_rmeasy(void *multi, CURL *data);
+
+bool Curl_multi_canPipeline(const struct Curl_multi* multi);
+void Curl_multi_handlePipeBreak(struct SessionHandle *data);
+
+/* the write bits start at bit 16 for the *getsock() bitmap */
+#define GETSOCK_WRITEBITSTART 16
+
+#define GETSOCK_BLANK 0 /* no bits set */
+
+/* set the bit for the given sock number to make the bitmap for writable */
+#define GETSOCK_WRITESOCK(x) (1 << (GETSOCK_WRITEBITSTART + (x)))
+
+/* set the bit for the given sock number to make the bitmap for readable */
+#define GETSOCK_READSOCK(x) (1 << (x))
+
+#ifdef DEBUGBUILD
+ /*
+  * Curl_multi_dump is not a stable public function, this is only meant to
+  * allow easier tracking of the internal handle's state and what sockets
+  * they use. Only for research and development DEBUGBUILD enabled builds.
+  */
+void Curl_multi_dump(const struct Curl_multi *multi_handle);
+#endif
+
+#endif /* __MULTIIF_H */
diff --git a/lib/netrc.c b/lib/netrc.c
new file mode 100644
index 0000000..e944325
--- /dev/null
+++ b/lib/netrc.c
@@ -0,0 +1,245 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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"
+#include "rawstr.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(const 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 DEBUGBUILD
+  {
+    /* 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) {
+      fprintf(stderr, "NETRC: overridden " NETRC " file: %s\n", override);
+      netrcfile = override;
+      netrc_alloc = TRUE;
+    }
+  }
+#endif /* DEBUGBUILD */
+  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];
+    int  netrcbuffsize = (int)sizeof(netrcbuffer);
+
+    while(!done && fgets(netrcbuffer, netrcbuffsize, 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(Curl_raw_equal("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(Curl_raw_equal(host, tok)) {
+            /* and yes, this is our host! */
+            state=HOSTVALID;
+#ifdef _NETRC_DEBUG
+            fprintf(stderr, "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 = Curl_raw_equal(login, tok);
+            }
+            else {
+              strncpy(login, tok, LOGINSIZE-1);
+#ifdef _NETRC_DEBUG
+              fprintf(stderr, "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
+              fprintf(stderr, "PASSWORD: %s\n", password);
+#endif
+            }
+            state_password=0;
+          }
+          else if(Curl_raw_equal("login", tok))
+            state_login=1;
+          else if(Curl_raw_equal("password", tok))
+            state_password=1;
+          else if(Curl_raw_equal("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, argv_item_t 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/lib/netrc.h b/lib/netrc.h
new file mode 100644
index 0000000..5406d4c
--- /dev/null
+++ b/lib/netrc.h
@@ -0,0 +1,34 @@
+#ifndef HEADER_CURL_NETRC_H
+#define HEADER_CURL_NETRC_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+int Curl_parsenetrc(const 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 /* HEADER_CURL_NETRC_H */
diff --git a/lib/nonblock.c b/lib/nonblock.c
new file mode 100644
index 0000000..cd81950
--- /dev/null
+++ b/lib/nonblock.c
@@ -0,0 +1,101 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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"
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
+#include <sys/filio.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#include "nonblock.h"
+
+/*
+ * curlx_nonblock() set the given socket to either blocking or non-blocking
+ * mode based on the 'nonblock' boolean argument. This function is highly
+ * portable.
+ */
+int curlx_nonblock(curl_socket_t sockfd,    /* operate on this */
+                   int nonblock   /* TRUE or FALSE */)
+{
+#if defined(USE_BLOCKING_SOCKETS)
+
+  return 0; /* returns success */
+
+#elif defined(HAVE_FCNTL_O_NONBLOCK)
+
+  /* most recent unix versions */
+  int flags;
+  flags = fcntl(sockfd, F_GETFL, 0);
+  if(FALSE != nonblock)
+    return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
+  else
+    return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
+
+#elif defined(HAVE_IOCTL_FIONBIO)
+
+  /* older unix versions */
+  int flags;
+  flags = nonblock;
+  return ioctl(sockfd, FIONBIO, &flags);
+
+#elif defined(HAVE_IOCTLSOCKET_FIONBIO)
+
+  /* Windows */
+  unsigned long flags;
+  flags = nonblock;
+  return ioctlsocket(sockfd, FIONBIO, &flags);
+
+#elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO)
+
+  /* Amiga */
+  return IoctlSocket(sockfd, FIONBIO, (long)nonblock);
+
+#elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK)
+
+  /* BeOS */
+  long b = nonblock ? 1 : 0;
+  return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
+
+#else
+#  error "no non-blocking method was found/used/set"
+#endif
+}
diff --git a/lib/nonblock.h b/lib/nonblock.h
new file mode 100644
index 0000000..adcd2c1
--- /dev/null
+++ b/lib/nonblock.h
@@ -0,0 +1,30 @@
+#ifndef __NONBLOCK_H
+#define __NONBLOCK_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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 <curl/curl.h> /* for curl_socket_t */
+
+int curlx_nonblock(curl_socket_t sockfd,    /* operate on this */
+                   int nonblock   /* TRUE or FALSE */);
+
+#endif
diff --git a/lib/nss.c b/lib/nss.c
new file mode 100644
index 0000000..0f8ebd5
--- /dev/null
+++ b/lib/nss.c
@@ -0,0 +1,1425 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all NSS-specific code for the TLS/SSL layer. No code
+ * but sslgen.c should ever call or use these functions.
+ */
+
+#include "setup.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#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 "connect.h"
+#include "strequal.h"
+#include "select.h"
+#include "sslgen.h"
+
+#define _MPRINTF_REPLACE /* use the internal *printf() functions */
+#include <curl/mprintf.h>
+
+#ifdef USE_NSS
+
+#include "nssg.h"
+#include <nspr.h>
+#include <nss.h>
+#include <ssl.h>
+#include <sslerr.h>
+#include <secerr.h>
+#include <secmod.h>
+#include <sslproto.h>
+#include <prtypes.h>
+#include <pk11pub.h>
+#include <prio.h>
+#include <secitem.h>
+#include <secport.h>
+#include <certdb.h>
+#include <base64.h>
+
+#include "curl_memory.h"
+#include "rawstr.h"
+#include "easyif.h" /* for Curl_convert_from_utf8 prototype */
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#define SSL_DIR "/etc/pki/nssdb"
+
+/* enough to fit the string "PEM Token #[0|1]" */
+#define SLOTSIZE 13
+
+PRFileDesc *PR_ImportTCPSocket(PRInt32 osfd);
+
+PRLock * nss_initlock = NULL;
+
+volatile int initialized = 0;
+
+typedef struct {
+  const char *name;
+  int num;
+  PRInt32 version; /* protocol version valid for this cipher */
+} cipher_s;
+
+#define PK11_SETATTRS(x,id,v,l) (x)->type = (id);       \
+  (x)->pValue=(v); (x)->ulValueLen = (l)
+
+#define CERT_NewTempCertificate __CERT_NewTempCertificate
+
+enum sslversion { SSL2 = 1, SSL3 = 2, TLS = 4 };
+
+#define NUM_OF_CIPHERS sizeof(cipherlist)/sizeof(cipherlist[0])
+static const cipher_s cipherlist[] = {
+  /* SSL2 cipher suites */
+  {"rc4", SSL_EN_RC4_128_WITH_MD5, SSL2},
+  {"rc4-md5", SSL_EN_RC4_128_WITH_MD5, SSL2},
+  {"rc4export", SSL_EN_RC4_128_EXPORT40_WITH_MD5, SSL2},
+  {"rc2", SSL_EN_RC2_128_CBC_WITH_MD5, SSL2},
+  {"rc2export", SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, SSL2},
+  {"des", SSL_EN_DES_64_CBC_WITH_MD5, SSL2},
+  {"desede3", SSL_EN_DES_192_EDE3_CBC_WITH_MD5, SSL2},
+  /* SSL3/TLS cipher suites */
+  {"rsa_rc4_128_md5", SSL_RSA_WITH_RC4_128_MD5, SSL3 | TLS},
+  {"rsa_rc4_128_sha", SSL_RSA_WITH_RC4_128_SHA, SSL3 | TLS},
+  {"rsa_3des_sha", SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL3 | TLS},
+  {"rsa_des_sha", SSL_RSA_WITH_DES_CBC_SHA, SSL3 | TLS},
+  {"rsa_rc4_40_md5", SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL3 | TLS},
+  {"rsa_rc2_40_md5", SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, SSL3 | TLS},
+  {"rsa_null_md5", SSL_RSA_WITH_NULL_MD5, SSL3 | TLS},
+  {"rsa_null_sha", SSL_RSA_WITH_NULL_SHA, SSL3 | TLS},
+  {"fips_3des_sha", SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, SSL3 | TLS},
+  {"fips_des_sha", SSL_RSA_FIPS_WITH_DES_CBC_SHA, SSL3 | TLS},
+  {"fortezza", SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, SSL3 | TLS},
+  {"fortezza_rc4_128_sha", SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, SSL3 | TLS},
+  {"fortezza_null", SSL_FORTEZZA_DMS_WITH_NULL_SHA, SSL3 | TLS},
+  /* TLS 1.0: Exportable 56-bit Cipher Suites. */
+  {"rsa_des_56_sha", TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, SSL3 | TLS},
+  {"rsa_rc4_56_sha", TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, SSL3 | TLS},
+  /* AES ciphers. */
+  {"rsa_aes_128_sha", TLS_RSA_WITH_AES_128_CBC_SHA, SSL3 | TLS},
+  {"rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA, SSL3 | TLS},
+#ifdef NSS_ENABLE_ECC
+  /* ECC ciphers. */
+  {"ecdh_ecdsa_null_sha", TLS_ECDH_ECDSA_WITH_NULL_SHA, TLS},
+  {"ecdh_ecdsa_rc4_128_sha", TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS},
+  {"ecdh_ecdsa_3des_sha", TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS},
+  {"ecdh_ecdsa_aes_128_sha", TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, TLS},
+  {"ecdh_ecdsa_aes_256_sha", TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, TLS},
+  {"ecdhe_ecdsa_null_sha", TLS_ECDHE_ECDSA_WITH_NULL_SHA, TLS},
+  {"ecdhe_ecdsa_rc4_128_sha", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS},
+  {"ecdhe_ecdsa_3des_sha", TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS},
+  {"ecdhe_ecdsa_aes_128_sha", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS},
+  {"ecdhe_ecdsa_aes_256_sha", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS},
+  {"ecdh_rsa_null_sha", TLS_ECDH_RSA_WITH_NULL_SHA, TLS},
+  {"ecdh_rsa_128_sha", TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS},
+  {"ecdh_rsa_3des_sha", TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, TLS},
+  {"ecdh_rsa_aes_128_sha", TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS},
+  {"ecdh_rsa_aes_256_sha", TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, TLS},
+  {"echde_rsa_null", TLS_ECDHE_RSA_WITH_NULL_SHA, TLS},
+  {"ecdhe_rsa_rc4_128_sha", TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS},
+  {"ecdhe_rsa_3des_sha", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, TLS},
+  {"ecdhe_rsa_aes_128_sha", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS},
+  {"ecdhe_rsa_aes_256_sha", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS},
+  {"ecdh_anon_null_sha", TLS_ECDH_anon_WITH_NULL_SHA, TLS},
+  {"ecdh_anon_rc4_128sha", TLS_ECDH_anon_WITH_RC4_128_SHA, TLS},
+  {"ecdh_anon_3des_sha", TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, TLS},
+  {"ecdh_anon_aes_128_sha", TLS_ECDH_anon_WITH_AES_128_CBC_SHA, TLS},
+  {"ecdh_anon_aes_256_sha", TLS_ECDH_anon_WITH_AES_256_CBC_SHA, TLS},
+#endif
+};
+
+/* following ciphers are new in NSS 3.4 and not enabled by default, therefore
+   they are enabled explicitly */
+static const int enable_ciphers_by_default[] = {
+  TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+  TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+  TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+  TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+  TLS_RSA_WITH_AES_128_CBC_SHA,
+  TLS_RSA_WITH_AES_256_CBC_SHA,
+  SSL_NULL_WITH_NULL_NULL
+};
+
+#ifdef HAVE_PK11_CREATEGENERICOBJECT
+static const char* pem_library = "libnsspem.so";
+#endif
+SECMODModule* mod = NULL;
+
+static SECStatus set_ciphers(struct SessionHandle *data, PRFileDesc * model,
+                             char *cipher_list)
+{
+  unsigned int i;
+  PRBool cipher_state[NUM_OF_CIPHERS];
+  PRBool found;
+  char *cipher;
+  SECStatus rv;
+
+  /* First disable all ciphers. This uses a different max value in case
+   * NSS adds more ciphers later we don't want them available by
+   * accident
+   */
+  for(i=0; i<SSL_NumImplementedCiphers; i++) {
+    SSL_CipherPrefSet(model, SSL_ImplementedCiphers[i], SSL_NOT_ALLOWED);
+  }
+
+  /* Set every entry in our list to false */
+  for(i=0; i<NUM_OF_CIPHERS; i++) {
+    cipher_state[i] = PR_FALSE;
+  }
+
+  cipher = cipher_list;
+
+  while(cipher_list && (cipher_list[0])) {
+    while((*cipher) && (ISSPACE(*cipher)))
+      ++cipher;
+
+    if((cipher_list = strchr(cipher, ','))) {
+      *cipher_list++ = '\0';
+    }
+
+    found = PR_FALSE;
+
+    for(i=0; i<NUM_OF_CIPHERS; i++) {
+      if(Curl_raw_equal(cipher, cipherlist[i].name)) {
+        cipher_state[i] = PR_TRUE;
+        found = PR_TRUE;
+        break;
+      }
+    }
+
+    if(found == PR_FALSE) {
+      failf(data, "Unknown cipher in list: %s", cipher);
+      return SECFailure;
+    }
+
+    if(cipher_list) {
+      cipher = cipher_list;
+    }
+  }
+
+  /* Finally actually enable the selected ciphers */
+  for(i=0; i<NUM_OF_CIPHERS; i++) {
+    rv = SSL_CipherPrefSet(model, cipherlist[i].num, cipher_state[i]);
+    if(rv != SECSuccess) {
+      failf(data, "Unknown cipher in cipher list");
+      return SECFailure;
+    }
+  }
+
+  return SECSuccess;
+}
+
+/*
+ * Get the number of ciphers that are enabled. We use this to determine
+ * if we need to call NSS_SetDomesticPolicy() to enable the default ciphers.
+ */
+static int num_enabled_ciphers(void)
+{
+  PRInt32 policy = 0;
+  int count = 0;
+  unsigned int i;
+
+  for(i=0; i<NUM_OF_CIPHERS; i++) {
+    SSL_CipherPolicyGet(cipherlist[i].num, &policy);
+    if(policy)
+      count++;
+  }
+  return count;
+}
+
+/*
+ * Determine whether the nickname passed in is a filename that needs to
+ * be loaded as a PEM or a regular NSS nickname.
+ *
+ * returns 1 for a file
+ * returns 0 for not a file (NSS nickname)
+ */
+static int is_file(const char *filename)
+{
+  struct_stat st;
+
+  if(filename == NULL)
+    return 0;
+
+  if(stat(filename, &st) == 0)
+    if(S_ISREG(st.st_mode))
+      return 1;
+
+  return 0;
+}
+
+static char *fmt_nickname(char *str, bool *nickname_alloc)
+{
+  char *nickname = NULL;
+  *nickname_alloc = FALSE;
+
+  if(is_file(str)) {
+    char *n = strrchr(str, '/');
+    if(n) {
+      *nickname_alloc = TRUE;
+      n++; /* skip last slash */
+      nickname = aprintf("PEM Token #%d:%s", 1, n);
+    }
+    return nickname;
+  }
+
+  return str;
+}
+
+static int nss_load_cert(struct ssl_connect_data *ssl,
+                         const char *filename, PRBool cacert)
+{
+#ifdef HAVE_PK11_CREATEGENERICOBJECT
+  CK_SLOT_ID slotID;
+  PK11SlotInfo * slot = NULL;
+  CK_ATTRIBUTE *attrs;
+  CK_ATTRIBUTE theTemplate[20];
+  CK_BBOOL cktrue = CK_TRUE;
+  CK_BBOOL ckfalse = CK_FALSE;
+  CK_OBJECT_CLASS objClass = CKO_CERTIFICATE;
+  char slotname[SLOTSIZE];
+#endif
+  CERTCertificate *cert;
+  char *nickname = NULL;
+  char *n = NULL;
+
+  /* If there is no slash in the filename it is assumed to be a regular
+   * NSS nickname.
+   */
+  if(is_file(filename)) {
+    n = strrchr(filename, '/');
+    if(n)
+      n++;
+    if(!mod)
+      return 1;
+  }
+  else {
+    /* A nickname from the NSS internal database */
+    if(cacert)
+      return 0; /* You can't specify an NSS CA nickname this way */
+    nickname = strdup(filename);
+    if(!nickname)
+      return 0;
+    goto done;
+  }
+
+#ifdef HAVE_PK11_CREATEGENERICOBJECT
+  attrs = theTemplate;
+
+  /* All CA and trust objects go into slot 0. Other slots are used
+   * for storing certificates. With each new user certificate we increment
+   * the slot count. We only support 1 user certificate right now.
+   */
+  if(cacert)
+    slotID = 0;
+  else
+    slotID = 1;
+
+  snprintf(slotname, SLOTSIZE, "PEM Token #%ld", slotID);
+
+  nickname = aprintf("PEM Token #%ld:%s", slotID, n);
+  if(!nickname)
+    return 0;
+
+  slot = PK11_FindSlotByName(slotname);
+
+  if(!slot) {
+    free(nickname);
+    return 0;
+  }
+
+  PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) );
+  attrs++;
+  PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) );
+  attrs++;
+  PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)filename,
+                strlen(filename)+1);
+  attrs++;
+  if(cacert) {
+    PK11_SETATTRS(attrs, CKA_TRUST, &cktrue, sizeof(CK_BBOOL) );
+  }
+  else {
+    PK11_SETATTRS(attrs, CKA_TRUST, &ckfalse, sizeof(CK_BBOOL) );
+  }
+  attrs++;
+
+  /* This load the certificate in our PEM module into the appropriate
+   * slot.
+   */
+  ssl->cacert[slotID] = PK11_CreateGenericObject(slot, theTemplate, 4,
+                                                 PR_FALSE /* isPerm */);
+
+  PK11_FreeSlot(slot);
+
+  if(ssl->cacert[slotID] == NULL) {
+    free(nickname);
+    return 0;
+  }
+#else
+  /* We don't have PK11_CreateGenericObject but a file-based cert was passed
+   * in. We need to fail.
+   */
+  return 0;
+#endif
+
+  done:
+  /* Double-check that the certificate or nickname requested exists in
+   * either the token or the NSS certificate database.
+   */
+  if(!cacert) {
+    cert = PK11_FindCertFromNickname((char *)nickname, NULL);
+
+    /* An invalid nickname was passed in */
+    if(cert == NULL) {
+      free(nickname);
+      PR_SetError(SEC_ERROR_UNKNOWN_CERT, 0);
+      return 0;
+    }
+
+    CERT_DestroyCertificate(cert);
+  }
+
+  free(nickname);
+
+  return 1;
+}
+
+static int nss_load_crl(const char* crlfilename, PRBool ascii)
+{
+  PRFileDesc *infile;
+  PRStatus    prstat;
+  PRFileInfo  info;
+  PRInt32     nb;
+  int rv;
+  SECItem crlDER;
+  CERTSignedCrl *crl=NULL;
+  PK11SlotInfo *slot=NULL;
+
+  infile = PR_Open(crlfilename,PR_RDONLY,0);
+  if (!infile) {
+    return 0;
+  }
+  crlDER.data = NULL;
+  prstat = PR_GetOpenFileInfo(infile,&info);
+  if (prstat!=PR_SUCCESS)
+    return 0;
+  if (ascii) {
+    SECItem filedata;
+    char *asc,*body;
+    filedata.data = NULL;
+    if (!SECITEM_AllocItem(NULL,&filedata,info.size))
+      return 0;
+    nb = PR_Read(infile,filedata.data,info.size);
+    if (nb!=info.size)
+      return 0;
+    asc = (char*)filedata.data;
+    if (!asc)
+      return 0;
+
+    body=strstr(asc,"-----BEGIN");
+    if (body != NULL) {
+      char *trailer=NULL;
+      asc = body;
+      body = PORT_Strchr(asc,'\n');
+      if (!body)
+        body = PORT_Strchr(asc,'\r');
+      if (body)
+        trailer = strstr(++body,"-----END");
+      if (trailer!=NULL)
+        *trailer='\0';
+      else
+        return 0;
+    }
+    else {
+      body = asc;
+    }
+    rv = ATOB_ConvertAsciiToItem(&crlDER,body);
+    PORT_Free(filedata.data);
+    if (rv)
+      return 0;
+  }
+  else {
+    if (!SECITEM_AllocItem(NULL,&crlDER,info.size))
+      return 0;
+    nb = PR_Read(infile,crlDER.data,info.size);
+    if (nb!=info.size)
+      return 0;
+  }
+
+  slot = PK11_GetInternalKeySlot();
+  crl  = PK11_ImportCRL(slot,&crlDER,
+                        NULL,SEC_CRL_TYPE,
+                        NULL,CRL_IMPORT_DEFAULT_OPTIONS,
+                        NULL,(CRL_DECODE_DEFAULT_OPTIONS|
+                              CRL_DECODE_DONT_COPY_DER));
+  if (slot) PK11_FreeSlot(slot);
+  if (!crl) return 0;
+  SEC_DestroyCrl(crl);
+  return 1;
+}
+
+static int nss_load_key(struct connectdata *conn, int sockindex,
+                        char *key_file)
+{
+#ifdef HAVE_PK11_CREATEGENERICOBJECT
+  PK11SlotInfo * slot = NULL;
+  CK_ATTRIBUTE *attrs;
+  CK_ATTRIBUTE theTemplate[20];
+  CK_BBOOL cktrue = CK_TRUE;
+  CK_OBJECT_CLASS objClass = CKO_PRIVATE_KEY;
+  CK_SLOT_ID slotID;
+  char slotname[SLOTSIZE];
+  struct ssl_connect_data *sslconn = &conn->ssl[sockindex];
+
+  attrs = theTemplate;
+
+  /* FIXME: grok the various file types */
+
+  slotID = 1; /* hardcoded for now */
+
+  snprintf(slotname, sizeof(slotname), "PEM Token #%ld", slotID);
+  slot = PK11_FindSlotByName(slotname);
+
+  if(!slot)
+    return 0;
+
+  PK11_SETATTRS(attrs, CKA_CLASS, &objClass, sizeof(objClass) ); attrs++;
+  PK11_SETATTRS(attrs, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL) ); attrs++;
+  PK11_SETATTRS(attrs, CKA_LABEL, (unsigned char *)key_file,
+                strlen(key_file)+1); attrs++;
+
+  /* When adding an encrypted key the PKCS#11 will be set as removed */
+  sslconn->key = PK11_CreateGenericObject(slot, theTemplate, 3,
+                                          PR_FALSE /* isPerm */);
+  if(sslconn->key == NULL) {
+    PR_SetError(SEC_ERROR_BAD_KEY, 0);
+    return 0;
+  }
+
+  /* This will force the token to be seen as re-inserted */
+  SECMOD_WaitForAnyTokenEvent(mod, 0, 0);
+  PK11_IsPresent(slot);
+
+  /* parg is initialized in nss_Init_Tokens() */
+  if(PK11_Authenticate(slot, PR_TRUE,
+                       conn->data->set.str[STRING_KEY_PASSWD]) != SECSuccess) {
+
+    PK11_FreeSlot(slot);
+    return 0;
+  }
+  PK11_FreeSlot(slot);
+
+  return 1;
+#else
+  /* If we don't have PK11_CreateGenericObject then we can't load a file-based
+   * key.
+   */
+  (void)conn; /* unused */
+  (void)key_file; /* unused */
+  return 0;
+#endif
+}
+
+static int display_error(struct connectdata *conn, PRInt32 err,
+                         const char *filename)
+{
+  switch(err) {
+  case SEC_ERROR_BAD_PASSWORD:
+    failf(conn->data, "Unable to load client key: Incorrect password");
+    return 1;
+  case SEC_ERROR_UNKNOWN_CERT:
+    failf(conn->data, "Unable to load certificate %s", filename);
+    return 1;
+  default:
+    break;
+  }
+  return 0; /* The caller will print a generic error */
+}
+
+static int cert_stuff(struct connectdata *conn,
+                      int sockindex, char *cert_file, char *key_file)
+{
+  struct SessionHandle *data = conn->data;
+  int rv = 0;
+
+  if(cert_file) {
+    rv = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE);
+    if(!rv) {
+      if(!display_error(conn, PR_GetError(), cert_file))
+        failf(data, "Unable to load client cert %d.", PR_GetError());
+      return 0;
+    }
+  }
+  if(key_file || (is_file(cert_file))) {
+    if(key_file)
+      rv = nss_load_key(conn, sockindex, key_file);
+    else
+      /* In case the cert file also has the key */
+      rv = nss_load_key(conn, sockindex, cert_file);
+    if(!rv) {
+      if(!display_error(conn, PR_GetError(), key_file))
+        failf(data, "Unable to load client key %d.", PR_GetError());
+
+      return 0;
+    }
+  }
+  return 1;
+}
+
+static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg)
+{
+  (void)slot; /* unused */
+  if(retry || NULL == arg)
+    return NULL;
+  else
+    return (char *)PORT_Strdup((char *)arg);
+}
+
+static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
+{
+  SECStatus success = SECSuccess;
+  struct connectdata *conn = (struct connectdata *)arg;
+  PRErrorCode err = PR_GetError();
+  CERTCertificate *cert = NULL;
+  char *subject, *subject_cn, *issuer;
+
+  if(conn->data->set.ssl.certverifyresult!=0)
+    return success;
+
+  conn->data->set.ssl.certverifyresult=err;
+  cert = SSL_PeerCertificate(sock);
+  subject = CERT_NameToAscii(&cert->subject);
+  subject_cn = CERT_GetCommonName(&cert->subject);
+  issuer = CERT_NameToAscii(&cert->issuer);
+  CERT_DestroyCertificate(cert);
+
+  switch(err) {
+  case SEC_ERROR_CA_CERT_INVALID:
+    infof(conn->data, "Issuer certificate is invalid: '%s'\n", issuer);
+    if(conn->data->set.ssl.verifypeer)
+      success = SECFailure;
+    break;
+  case SEC_ERROR_UNTRUSTED_ISSUER:
+    if(conn->data->set.ssl.verifypeer)
+      success = SECFailure;
+    infof(conn->data, "Certificate is signed by an untrusted issuer: '%s'\n",
+          issuer);
+    break;
+  case SSL_ERROR_BAD_CERT_DOMAIN:
+    if(conn->data->set.ssl.verifyhost) {
+      failf(conn->data, "SSL: certificate subject name '%s' does not match "
+            "target host name '%s'", subject_cn, conn->host.dispname);
+      success = SECFailure;
+    } else {
+      infof(conn->data, "warning: SSL: certificate subject name '%s' does not "
+            "match target host name '%s'\n", subject_cn, conn->host.dispname);
+    }
+    break;
+  case SEC_ERROR_EXPIRED_CERTIFICATE:
+    if(conn->data->set.ssl.verifypeer)
+      success = SECFailure;
+    infof(conn->data, "Remote Certificate has expired.\n");
+    break;
+  case SEC_ERROR_UNKNOWN_ISSUER:
+    if(conn->data->set.ssl.verifypeer)
+      success = SECFailure;
+    infof(conn->data, "Peer's certificate issuer is not recognized: '%s'\n",
+          issuer);
+    break;
+  default:
+    if(conn->data->set.ssl.verifypeer)
+      success = SECFailure;
+    infof(conn->data, "Bad certificate received. Subject = '%s', "
+          "Issuer = '%s'\n", subject, issuer);
+    break;
+  }
+  if(success == SECSuccess)
+    infof(conn->data, "SSL certificate verify ok.\n");
+  PR_Free(subject);
+  PR_Free(subject_cn);
+  PR_Free(issuer);
+
+  return success;
+}
+
+/**
+ * Inform the application that the handshake is complete.
+ */
+static SECStatus HandshakeCallback(PRFileDesc *sock, void *arg)
+{
+  (void)sock;
+  (void)arg;
+  return SECSuccess;
+}
+
+static void display_cert_info(struct SessionHandle *data,
+                              CERTCertificate *cert)
+{
+  char *subject, *issuer, *common_name;
+  PRExplodedTime printableTime;
+  char timeString[256];
+  PRTime notBefore, notAfter;
+
+  subject = CERT_NameToAscii(&cert->subject);
+  issuer = CERT_NameToAscii(&cert->issuer);
+  common_name = CERT_GetCommonName(&cert->subject);
+  infof(data, "\tsubject: %s\n", subject);
+
+  CERT_GetCertTimes(cert, &notBefore, &notAfter);
+  PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
+  PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
+  infof(data, "\tstart date: %s\n", timeString);
+  PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime);
+  PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
+  infof(data, "\texpire date: %s\n", timeString);
+  infof(data, "\tcommon name: %s\n", common_name);
+  infof(data, "\tissuer: %s\n", issuer);
+
+  PR_Free(subject);
+  PR_Free(issuer);
+  PR_Free(common_name);
+}
+
+static void display_conn_info(struct connectdata *conn, PRFileDesc *sock)
+{
+  SSLChannelInfo channel;
+  SSLCipherSuiteInfo suite;
+  CERTCertificate *cert;
+
+  if(SSL_GetChannelInfo(sock, &channel, sizeof channel) ==
+     SECSuccess && channel.length == sizeof channel &&
+     channel.cipherSuite) {
+    if(SSL_GetCipherSuiteInfo(channel.cipherSuite,
+                              &suite, sizeof suite) == SECSuccess) {
+      infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName);
+    }
+  }
+
+  infof(conn->data, "Server certificate:\n");
+
+  cert = SSL_PeerCertificate(sock);
+  display_cert_info(conn->data, cert);
+  CERT_DestroyCertificate(cert);
+
+  return;
+}
+
+/**
+ *
+ * Check that the Peer certificate's issuer certificate matches the one found
+ * by issuer_nickname.  This is not exactly the way OpenSSL and GNU TLS do the
+ * issuer check, so we provide comments that mimic the OpenSSL
+ * X509_check_issued function (in x509v3/v3_purp.c)
+ */
+static SECStatus check_issuer_cert(PRFileDesc *sock,
+                                   char *issuer_nickname)
+{
+  CERTCertificate *cert,*cert_issuer,*issuer;
+  SECStatus res=SECSuccess;
+  void *proto_win = NULL;
+
+  /*
+    PRArenaPool   *tmpArena = NULL;
+    CERTAuthKeyID *authorityKeyID = NULL;
+    SECITEM       *caname = NULL;
+  */
+
+  cert = SSL_PeerCertificate(sock);
+  cert_issuer = CERT_FindCertIssuer(cert,PR_Now(),certUsageObjectSigner);
+
+  proto_win = SSL_RevealPinArg(sock);
+  issuer = NULL;
+  issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win);
+
+  if ((!cert_issuer) || (!issuer))
+    res = SECFailure;
+  else if (SECITEM_CompareItem(&cert_issuer->derCert,
+                               &issuer->derCert)!=SECEqual)
+    res = SECFailure;
+
+  CERT_DestroyCertificate(cert);
+  CERT_DestroyCertificate(issuer);
+  CERT_DestroyCertificate(cert_issuer);
+  return res;
+}
+
+/**
+ *
+ * Callback to pick the SSL client certificate.
+ */
+static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
+                                  struct CERTDistNamesStr *caNames,
+                                  struct CERTCertificateStr **pRetCert,
+                                  struct SECKEYPrivateKeyStr **pRetKey)
+{
+  static const char pem_nickname[] = "PEM Token #1";
+  const char *pem_slotname = pem_nickname;
+
+  struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg;
+  struct SessionHandle *data = connssl->data;
+  const char *nickname = connssl->client_nickname;
+
+  if (mod && nickname &&
+      0 == strncmp(nickname, pem_nickname, /* length of "PEM Token" */ 9)) {
+
+    /* use the cert/key provided by PEM reader */
+    PK11SlotInfo *slot;
+    void *proto_win = SSL_RevealPinArg(sock);
+    *pRetKey = NULL;
+
+    *pRetCert = PK11_FindCertFromNickname(nickname, proto_win);
+    if (NULL == *pRetCert) {
+      failf(data, "NSS: client certificate not found: %s", nickname);
+      return SECFailure;
+    }
+
+    slot = PK11_FindSlotByName(pem_slotname);
+    if (NULL == slot) {
+      failf(data, "NSS: PK11 slot not found: %s", pem_slotname);
+      return SECFailure;
+    }
+
+    *pRetKey = PK11_FindPrivateKeyFromCert(slot, *pRetCert, NULL);
+    PK11_FreeSlot(slot);
+    if (NULL == *pRetKey) {
+      failf(data, "NSS: private key not found for certificate: %s", nickname);
+      return SECFailure;
+    }
+
+    infof(data, "NSS: client certificate: %s\n", nickname);
+    display_cert_info(data, *pRetCert);
+    return SECSuccess;
+  }
+
+  /* use the default NSS hook */
+  if (SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames,
+                                          pRetCert, pRetKey)
+      || NULL == *pRetCert) {
+
+    if (NULL == nickname)
+      failf(data, "NSS: client certificate not found (nickname not "
+            "specified)");
+    else
+      failf(data, "NSS: client certificate not found: %s", nickname);
+
+    return SECFailure;
+  }
+
+  /* get certificate nickname if any */
+  nickname = (*pRetCert)->nickname;
+  if (NULL == nickname)
+    nickname = "[unknown]";
+
+  if (NULL == *pRetKey) {
+    failf(data, "NSS: private key not found for certificate: %s", nickname);
+    return SECFailure;
+  }
+
+  infof(data, "NSS: using client certificate: %s\n", nickname);
+  display_cert_info(data, *pRetCert);
+  return SECSuccess;
+}
+
+/* This function is supposed to decide, which error codes should be used
+ * to conclude server is TLS intolerant.
+ *
+ * taken from xulrunner - nsNSSIOLayer.cpp
+ */
+static PRBool
+isTLSIntoleranceError(PRInt32 err)
+{
+  switch (err) {
+  case SSL_ERROR_BAD_MAC_ALERT:
+  case SSL_ERROR_BAD_MAC_READ:
+  case SSL_ERROR_HANDSHAKE_FAILURE_ALERT:
+  case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT:
+  case SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE:
+  case SSL_ERROR_ILLEGAL_PARAMETER_ALERT:
+  case SSL_ERROR_NO_CYPHER_OVERLAP:
+  case SSL_ERROR_BAD_SERVER:
+  case SSL_ERROR_BAD_BLOCK_PADDING:
+  case SSL_ERROR_UNSUPPORTED_VERSION:
+  case SSL_ERROR_PROTOCOL_VERSION_ALERT:
+  case SSL_ERROR_RX_MALFORMED_FINISHED:
+  case SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE:
+  case SSL_ERROR_DECODE_ERROR_ALERT:
+  case SSL_ERROR_RX_UNKNOWN_ALERT:
+    return PR_TRUE;
+  default:
+    return PR_FALSE;
+  }
+}
+
+/**
+ * Global SSL init
+ *
+ * @retval 0 error initializing SSL
+ * @retval 1 SSL initialized successfully
+ */
+int Curl_nss_init(void)
+{
+  /* curl_global_init() is not thread-safe so this test is ok */
+  if (nss_initlock == NULL) {
+    PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 256);
+    nss_initlock = PR_NewLock();
+  }
+
+  /* We will actually initialize NSS later */
+
+  return 1;
+}
+
+/* Global cleanup */
+void Curl_nss_cleanup(void)
+{
+  /* This function isn't required to be threadsafe and this is only done
+   * as a safety feature.
+   */
+  PR_Lock(nss_initlock);
+  if (initialized) {
+    /* Free references to client certificates held in the SSL session cache.
+     * Omitting this hampers destruction of the security module owning
+     * the certificates. */
+    SSL_ClearSessionCache();
+
+    if(mod && SECSuccess == SECMOD_UnloadUserModule(mod)) {
+      SECMOD_DestroyModule(mod);
+      mod = NULL;
+    }
+    NSS_Shutdown();
+  }
+  PR_Unlock(nss_initlock);
+
+  PR_DestroyLock(nss_initlock);
+  nss_initlock = NULL;
+
+  initialized = 0;
+}
+
+/*
+ * This function uses SSL_peek to determine connection status.
+ *
+ * Return codes:
+ *     1 means the connection is still in place
+ *     0 means the connection has been closed
+ *    -1 means the connection status is unknown
+ */
+int
+Curl_nss_check_cxn(struct connectdata *conn)
+{
+  int rc;
+  char buf;
+
+  rc =
+    PR_Recv(conn->ssl[FIRSTSOCKET].handle, (void *)&buf, 1, PR_MSG_PEEK,
+            PR_SecondsToInterval(1));
+  if(rc > 0)
+    return 1; /* connection still in place */
+
+  if(rc == 0)
+    return 0; /* connection has been closed */
+
+  return -1;  /* connection status unknown */
+}
+
+/*
+ * This function is called when an SSL connection is closed.
+ */
+void Curl_nss_close(struct connectdata *conn, int sockindex)
+{
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+  if(connssl->handle) {
+    PR_Close(connssl->handle);
+
+    /* NSS closes the socket we previously handed to it, so we must mark it
+       as closed to avoid double close */
+    fake_sclose(conn->sock[sockindex]);
+    conn->sock[sockindex] = CURL_SOCKET_BAD;
+    if(connssl->client_nickname != NULL) {
+      free(connssl->client_nickname);
+      connssl->client_nickname = NULL;
+    }
+#ifdef HAVE_PK11_CREATEGENERICOBJECT
+    if(connssl->key)
+      (void)PK11_DestroyGenericObject(connssl->key);
+    if(connssl->cacert[1])
+      (void)PK11_DestroyGenericObject(connssl->cacert[1]);
+    if(connssl->cacert[0])
+      (void)PK11_DestroyGenericObject(connssl->cacert[0]);
+#endif
+    connssl->handle = NULL;
+  }
+}
+
+/*
+ * This function is called when the 'data' struct is going away. Close
+ * down everything and free all resources!
+ */
+int Curl_nss_close_all(struct SessionHandle *data)
+{
+  (void)data;
+  return 0;
+}
+
+/* handle client certificate related errors if any; return false otherwise */
+static bool handle_cc_error(PRInt32 err, struct SessionHandle *data)
+{
+  switch(err) {
+  case SSL_ERROR_BAD_CERT_ALERT:
+    failf(data, "SSL error: SSL_ERROR_BAD_CERT_ALERT");
+    return true;
+
+  case SSL_ERROR_REVOKED_CERT_ALERT:
+    failf(data, "SSL error: SSL_ERROR_REVOKED_CERT_ALERT");
+    return true;
+
+  case SSL_ERROR_EXPIRED_CERT_ALERT:
+    failf(data, "SSL error: SSL_ERROR_EXPIRED_CERT_ALERT");
+    return true;
+
+  default:
+    return false;
+  }
+}
+
+CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
+{
+  PRInt32 err;
+  PRFileDesc *model = NULL;
+  PRBool ssl2 = PR_FALSE;
+  PRBool ssl3 = PR_FALSE;
+  PRBool tlsv1 = PR_FALSE;
+  struct SessionHandle *data = conn->data;
+  curl_socket_t sockfd = conn->sock[sockindex];
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+  SECStatus rv;
+  char *certDir = NULL;
+  int curlerr;
+  const int *cipher_to_enable;
+  PRSocketOptionData sock_opt;
+  PRUint32 timeout;
+
+  curlerr = CURLE_SSL_CONNECT_ERROR;
+
+  if (connssl->state == ssl_connection_complete)
+    return CURLE_OK;
+
+  connssl->data = data;
+
+#ifdef HAVE_PK11_CREATEGENERICOBJECT
+  connssl->cacert[0] = NULL;
+  connssl->cacert[1] = NULL;
+  connssl->key = NULL;
+#endif
+
+  /* FIXME. NSS doesn't support multiple databases open at the same time. */
+  PR_Lock(nss_initlock);
+  if(!initialized) {
+    struct_stat st;
+
+    /* First we check if $SSL_DIR points to a valid dir */
+    certDir = getenv("SSL_DIR");
+    if(certDir) {
+      if((stat(certDir, &st) != 0) ||
+         (!S_ISDIR(st.st_mode))) {
+        certDir = NULL;
+      }
+    }
+
+    /* Now we check if the default location is a valid dir */
+    if(!certDir) {
+      if((stat(SSL_DIR, &st) == 0) &&
+         (S_ISDIR(st.st_mode))) {
+        certDir = (char *)SSL_DIR;
+      }
+    }
+
+    if (!NSS_IsInitialized()) {
+      initialized = 1;
+      infof(conn->data, "Initializing NSS with certpath: %s\n",
+            certDir ? certDir : "none");
+      if(!certDir) {
+        rv = NSS_NoDB_Init(NULL);
+      }
+      else {
+        char *certpath = PR_smprintf("%s%s",
+                                     NSS_VersionCheck("3.12.0") ? "sql:" : "",
+                                     certDir);
+        rv = NSS_Initialize(certpath, "", "", "", NSS_INIT_READONLY);
+        PR_smprintf_free(certpath);
+      }
+      if(rv != SECSuccess) {
+        infof(conn->data, "Unable to initialize NSS database\n");
+        curlerr = CURLE_SSL_CACERT_BADFILE;
+        initialized = 0;
+        PR_Unlock(nss_initlock);
+        goto error;
+      }
+    }
+
+    if(num_enabled_ciphers() == 0)
+      NSS_SetDomesticPolicy();
+
+#ifdef HAVE_PK11_CREATEGENERICOBJECT
+    if(!mod) {
+      char *configstring = aprintf("library=%s name=PEM", pem_library);
+      if(!configstring) {
+        PR_Unlock(nss_initlock);
+        goto error;
+      }
+      mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE);
+      free(configstring);
+
+      if(!mod || !mod->loaded) {
+        if(mod) {
+          SECMOD_DestroyModule(mod);
+          mod = NULL;
+        }
+        infof(data, "WARNING: failed to load NSS PEM library %s. Using "
+              "OpenSSL PEM certificates will not work.\n", pem_library);
+      }
+    }
+#endif
+
+    PK11_SetPasswordFunc(nss_get_password);
+
+  }
+  PR_Unlock(nss_initlock);
+
+  model = PR_NewTCPSocket();
+  if(!model)
+    goto error;
+  model = SSL_ImportFD(NULL, model);
+
+  /* make the socket nonblocking */
+  sock_opt.option = PR_SockOpt_Nonblocking;
+  sock_opt.value.non_blocking = PR_TRUE;
+  if(PR_SetSocketOption(model, &sock_opt) != SECSuccess)
+    goto error;
+
+  if(SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) != SECSuccess)
+    goto error;
+  if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess)
+    goto error;
+  if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess)
+    goto error;
+
+  switch (data->set.ssl.version) {
+  default:
+  case CURL_SSLVERSION_DEFAULT:
+    ssl3 = PR_TRUE;
+    if (data->state.ssl_connect_retry)
+      infof(data, "TLS disabled due to previous handshake failure\n");
+    else
+      tlsv1 = PR_TRUE;
+    break;
+  case CURL_SSLVERSION_TLSv1:
+    tlsv1 = PR_TRUE;
+    break;
+  case CURL_SSLVERSION_SSLv2:
+    ssl2 = PR_TRUE;
+    break;
+  case CURL_SSLVERSION_SSLv3:
+    ssl3 = PR_TRUE;
+    break;
+  }
+
+  if(SSL_OptionSet(model, SSL_ENABLE_SSL2, ssl2) != SECSuccess)
+    goto error;
+  if(SSL_OptionSet(model, SSL_ENABLE_SSL3, ssl3) != SECSuccess)
+    goto error;
+  if(SSL_OptionSet(model, SSL_ENABLE_TLS, tlsv1) != SECSuccess)
+    goto error;
+
+  if(SSL_OptionSet(model, SSL_V2_COMPATIBLE_HELLO, ssl2) != SECSuccess)
+    goto error;
+
+  /* reset the flag to avoid an infinite loop */
+  data->state.ssl_connect_retry = FALSE;
+
+  /* enable all ciphers from enable_ciphers_by_default */
+  cipher_to_enable = enable_ciphers_by_default;
+  while (SSL_NULL_WITH_NULL_NULL != *cipher_to_enable) {
+    if (SSL_CipherPrefSet(model, *cipher_to_enable, PR_TRUE) != SECSuccess) {
+      curlerr = CURLE_SSL_CIPHER;
+      goto error;
+    }
+    cipher_to_enable++;
+  }
+
+  if(data->set.ssl.cipher_list) {
+    if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess) {
+      curlerr = CURLE_SSL_CIPHER;
+      goto error;
+    }
+  }
+
+  if(data->set.ssl.verifyhost == 1)
+    infof(data, "warning: ignoring unsupported value (1) of ssl.verifyhost\n");
+
+  data->set.ssl.certverifyresult=0; /* not checked yet */
+  if(SSL_BadCertHook(model, (SSLBadCertHandler) BadCertHandler, conn)
+     != SECSuccess) {
+    goto error;
+  }
+  if(SSL_HandshakeCallback(model, (SSLHandshakeCallback) HandshakeCallback,
+                           NULL) != SECSuccess)
+    goto error;
+
+  if(!data->set.ssl.verifypeer)
+    /* skip the verifying of the peer */
+    ;
+  else if(data->set.ssl.CAfile) {
+    int rc = nss_load_cert(&conn->ssl[sockindex], data->set.ssl.CAfile,
+                           PR_TRUE);
+    if(!rc) {
+      curlerr = CURLE_SSL_CACERT_BADFILE;
+      goto error;
+    }
+  }
+  else if(data->set.ssl.CApath) {
+    struct_stat st;
+    PRDir      *dir;
+    PRDirEntry *entry;
+
+    if(stat(data->set.ssl.CApath, &st) == -1) {
+      curlerr = CURLE_SSL_CACERT_BADFILE;
+      goto error;
+    }
+
+    if(S_ISDIR(st.st_mode)) {
+      int rc;
+
+      dir = PR_OpenDir(data->set.ssl.CApath);
+      do {
+        entry = PR_ReadDir(dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN);
+
+        if(entry) {
+          char fullpath[PATH_MAX];
+
+          snprintf(fullpath, sizeof(fullpath), "%s/%s", data->set.ssl.CApath,
+                   entry->name);
+          rc = nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE);
+          /* FIXME: check this return value! */
+        }
+        /* This is purposefully tolerant of errors so non-PEM files
+         * can be in the same directory */
+      } while(entry != NULL);
+      PR_CloseDir(dir);
+    }
+  }
+  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");
+
+  if (data->set.ssl.CRLfile) {
+    int rc = nss_load_crl(data->set.ssl.CRLfile, PR_FALSE);
+    if (!rc) {
+      curlerr = CURLE_SSL_CRL_BADFILE;
+      goto error;
+    }
+    infof(data,
+          "  CRLfile: %s\n",
+          data->set.ssl.CRLfile ? data->set.ssl.CRLfile : "none");
+  }
+
+  if(data->set.str[STRING_CERT]) {
+    bool nickname_alloc = FALSE;
+    char *nickname = fmt_nickname(data->set.str[STRING_CERT], &nickname_alloc);
+    if(!nickname)
+      return CURLE_OUT_OF_MEMORY;
+
+    if(!cert_stuff(conn, sockindex, data->set.str[STRING_CERT],
+                   data->set.str[STRING_KEY])) {
+      /* failf() is already done in cert_stuff() */
+      if(nickname_alloc)
+        free(nickname);
+      return CURLE_SSL_CERTPROBLEM;
+    }
+
+    /* this "takes over" the pointer to the allocated name or makes a
+       dup of it */
+    connssl->client_nickname = nickname_alloc?nickname:strdup(nickname);
+    if(!connssl->client_nickname)
+      return CURLE_OUT_OF_MEMORY;
+
+  }
+  else
+    connssl->client_nickname = NULL;
+
+  if(SSL_GetClientAuthDataHook(model, SelectClientCert,
+                               (void *)connssl) != SECSuccess) {
+    curlerr = CURLE_SSL_CERTPROBLEM;
+    goto error;
+  }
+
+  /* Import our model socket  onto the existing file descriptor */
+  connssl->handle = PR_ImportTCPSocket(sockfd);
+  connssl->handle = SSL_ImportFD(model, connssl->handle);
+  if(!connssl->handle)
+    goto error;
+
+  PR_Close(model); /* We don't need this any more */
+  model = NULL;
+
+  /* This is the password associated with the cert that we're using */
+  if (data->set.str[STRING_KEY_PASSWD]) {
+    SSL_SetPKCS11PinArg(connssl->handle, data->set.str[STRING_KEY_PASSWD]);
+  }
+
+  /* Force handshake on next I/O */
+  SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE);
+
+  SSL_SetURL(connssl->handle, conn->host.name);
+
+  /* Force the handshake now */
+  timeout = PR_MillisecondsToInterval((PRUint32)Curl_timeleft(conn, NULL, TRUE));
+  if(SSL_ForceHandshakeWithTimeout(connssl->handle, timeout) != SECSuccess) {
+    if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
+      curlerr = CURLE_PEER_FAILED_VERIFICATION;
+    else if(conn->data->set.ssl.certverifyresult!=0)
+      curlerr = CURLE_SSL_CACERT;
+    goto error;
+  }
+
+  connssl->state = ssl_connection_complete;
+
+  display_conn_info(conn, connssl->handle);
+
+  if (data->set.str[STRING_SSL_ISSUERCERT]) {
+    SECStatus ret;
+    bool nickname_alloc = FALSE;
+    char *nickname = fmt_nickname(data->set.str[STRING_SSL_ISSUERCERT],
+                                  &nickname_alloc);
+
+    if(!nickname)
+      return CURLE_OUT_OF_MEMORY;
+
+    ret = check_issuer_cert(connssl->handle, nickname);
+
+    if(nickname_alloc)
+      free(nickname);
+
+    if(SECFailure == ret) {
+      infof(data,"SSL certificate issuer check failed\n");
+      curlerr = CURLE_SSL_ISSUER_ERROR;
+      goto error;
+    }
+    else {
+      infof(data, "SSL certificate issuer check ok\n");
+    }
+  }
+
+  return CURLE_OK;
+
+  error:
+  /* reset the flag to avoid an infinite loop */
+  data->state.ssl_connect_retry = FALSE;
+
+  err = PR_GetError();
+  if(handle_cc_error(err, data))
+    curlerr = CURLE_SSL_CERTPROBLEM;
+  else
+    infof(data, "NSS error %d\n", err);
+
+  if(model)
+    PR_Close(model);
+
+  if (ssl3 && tlsv1 && isTLSIntoleranceError(err)) {
+    /* schedule reconnect through Curl_retry_request() */
+    data->state.ssl_connect_retry = TRUE;
+    infof(data, "Error in TLS handshake, trying SSLv3...\n");
+    return CURLE_OK;
+  }
+
+  return curlerr;
+}
+
+/* for documentation see Curl_ssl_send() in sslgen.h */
+int Curl_nss_send(struct connectdata *conn,  /* connection data */
+                  int sockindex,             /* socketindex */
+                  const void *mem,           /* send this data */
+                  size_t len,                /* amount to write */
+                  int *curlcode)
+{
+  int rc;
+
+  rc = PR_Send(conn->ssl[sockindex].handle, mem, (int)len, 0, -1);
+
+  if(rc < 0) {
+    PRInt32 err = PR_GetError();
+    if(err == PR_WOULD_BLOCK_ERROR)
+      *curlcode = -1; /* EWOULDBLOCK */
+    else if(handle_cc_error(err, conn->data))
+      *curlcode = CURLE_SSL_CERTPROBLEM;
+    else {
+      failf(conn->data, "SSL write: error %d", err);
+      *curlcode = CURLE_SEND_ERROR;
+    }
+    return -1;
+  }
+  return rc; /* number of bytes */
+}
+
+/* for documentation see Curl_ssl_recv() in sslgen.h */
+ssize_t Curl_nss_recv(struct connectdata * conn, /* connection data */
+                      int num,                   /* socketindex */
+                      char *buf,                 /* store read data here */
+                      size_t buffersize,         /* max amount to read */
+                      int *curlcode)
+{
+  ssize_t nread;
+
+  nread = PR_Recv(conn->ssl[num].handle, buf, (int)buffersize, 0, -1);
+  if(nread < 0) {
+    /* failed SSL read */
+    PRInt32 err = PR_GetError();
+
+    if(err == PR_WOULD_BLOCK_ERROR)
+      *curlcode = -1; /* EWOULDBLOCK */
+    else if(handle_cc_error(err, conn->data))
+      *curlcode = CURLE_SSL_CERTPROBLEM;
+    else {
+      failf(conn->data, "SSL read: errno %d", err);
+      *curlcode = CURLE_RECV_ERROR;
+    }
+    return -1;
+  }
+  return nread;
+}
+
+size_t Curl_nss_version(char *buffer, size_t size)
+{
+  return snprintf(buffer, size, "NSS/%s", NSS_VERSION);
+}
+#endif /* USE_NSS */
diff --git a/lib/nssg.h b/lib/nssg.h
new file mode 100644
index 0000000..309c3d6
--- /dev/null
+++ b/lib/nssg.h
@@ -0,0 +1,84 @@
+#ifndef __NSSG_H
+#define __NSSG_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+#ifdef USE_NSS
+/*
+ * This header should only be needed to get included by sslgen.c and nss.c
+ */
+
+#include "urldata.h"
+CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex);
+CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn,
+                                      int sockindex,
+                                      bool *done);
+/* close a SSL connection */
+void Curl_nss_close(struct connectdata *conn, int sockindex);
+
+/* tell NSS to close down all open information regarding connections (and
+   thus session ID caching etc) */
+int Curl_nss_close_all(struct SessionHandle *data);
+
+int Curl_nss_init(void);
+void Curl_nss_cleanup(void);
+
+/* for documentation see Curl_ssl_send() in sslgen.h */
+int Curl_nss_send(struct connectdata *conn,
+                  int sockindex,
+                  const void *mem,
+                  size_t len,
+                  int *curlcode);
+
+/* for documentation see Curl_ssl_recv() in sslgen.h */
+ssize_t Curl_nss_recv(struct connectdata *conn, /* connection data */
+                      int num,                  /* socketindex */
+                      char *buf,                /* store read data here */
+                      size_t buffersize,        /* max amount to read */
+                      int *curlcode);
+
+size_t Curl_nss_version(char *buffer, size_t size);
+int Curl_nss_check_cxn(struct connectdata *cxn);
+int Curl_nss_seed(struct SessionHandle *data);
+
+/* API setup for NSS */
+#define curlssl_init Curl_nss_init
+#define curlssl_cleanup Curl_nss_cleanup
+#define curlssl_connect Curl_nss_connect
+
+/* NSS has its own session ID cache */
+#define curlssl_session_free(x)
+#define curlssl_close_all Curl_nss_close_all
+#define curlssl_close Curl_nss_close
+/* NSS has no shutdown function provided and thus always fail */
+#define curlssl_shutdown(x,y) (x=x, y=y, 1)
+#define curlssl_set_engine(x,y) (x=x, y=y, CURLE_FAILED_INIT)
+#define curlssl_set_engine_default(x) (x=x, CURLE_FAILED_INIT)
+#define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL)
+#define curlssl_send Curl_nss_send
+#define curlssl_recv Curl_nss_recv
+#define curlssl_version Curl_nss_version
+#define curlssl_check_cxn(x) Curl_nss_check_cxn(x)
+#define curlssl_data_pending(x,y) (x=x, y=y, 0)
+
+#endif /* USE_NSS */
+#endif
diff --git a/lib/nwlib.c b/lib/nwlib.c
new file mode 100644
index 0000000..f9c8a42
--- /dev/null
+++ b/lib/nwlib.c
@@ -0,0 +1,327 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+#ifdef NETWARE /* Novell NetWare */
+
+#include <stdlib.h>
+
+#ifdef __NOVELL_LIBC__
+/* For native LibC-based NLM we need to register as a real lib. */
+#include <errno.h>
+#include <string.h>
+#include <library.h>
+#include <netware.h>
+#include <screen.h>
+#include <nks/thread.h>
+#include <nks/synch.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 = 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 = 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);
+  }
+}
+
+#else /* __NOVELL_LIBC__ */
+/* For native CLib-based NLM seems we can do a bit more simple. */
+#include <nwthread.h>
+
+int main ( void )
+{
+    /* initialize any globals here... */
+
+    /* do this if any global initializing was done
+    SynchronizeStart();
+    */
+    ExitThread (TSR_THREAD, 0);
+    return 0;
+}
+
+#endif /* __NOVELL_LIBC__ */
+
+#else /* NETWARE */
+
+#ifdef __POCC__
+#  pragma warn(disable:2024)  /* Disable warning #2024: Empty input file */
+#endif
+
+#endif /* NETWARE */
diff --git a/lib/nwos.c b/lib/nwos.c
new file mode 100644
index 0000000..ac36512
--- /dev/null
+++ b/lib/nwos.c
@@ -0,0 +1,95 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+#ifdef NETWARE /* Novell NetWare */
+
+#include <stdlib.h>
+
+#ifdef __NOVELL_LIBC__
+/* For native LibC-based NLM we need to do nothing. */
+int netware_init ( void )
+{
+    return 0;
+}
+
+#else /* __NOVELL_LIBC__ */
+
+/* For native CLib-based NLM we need to initialize the LONG namespace. */
+#include <stdio.h>
+#include <nwnspace.h>
+#include <nwthread.h>
+#include <nwadv.h>
+/* Make the CLIB Ctx stuff link */
+#include <netdb.h>
+NETDB_DEFINE_CONTEXT
+/* Make the CLIB Inet stuff link */
+#include <netinet/in.h>
+#include <arpa/inet.h>
+NETINET_DEFINE_CONTEXT
+
+int netware_init ( void )
+{
+    int rc = 0;
+    unsigned int myHandle = GetNLMHandle();
+    /* import UnAugmentAsterisk dynamically for NW4.x compatibility */
+    void (*pUnAugmentAsterisk)(int) = (void(*)(int))
+            ImportSymbol(myHandle, "UnAugmentAsterisk");
+    /* import UseAccurateCaseForPaths dynamically for NW3.x compatibility */
+    void (*pUseAccurateCaseForPaths)(int) = (void(*)(int))
+            ImportSymbol(myHandle, "UseAccurateCaseForPaths");
+    if(pUnAugmentAsterisk)
+        pUnAugmentAsterisk(1);
+    if(pUseAccurateCaseForPaths)
+        pUseAccurateCaseForPaths(1);
+    UnimportSymbol(myHandle, "UnAugmentAsterisk");
+    UnimportSymbol(myHandle, "UseAccurateCaseForPaths");
+    /* set long name space */
+    if((SetCurrentNameSpace(4) == 255)) {
+        rc = 1;
+    }
+    if((SetTargetNameSpace(4) == 255)) {
+        rc = rc + 2;
+    }
+    return rc;
+}
+
+/* dummy function to satisfy newer prelude */
+int __init_environment ( void )
+{
+    return 0;
+}
+
+/* dummy function to satisfy newer prelude */
+int __deinit_environment ( void )
+{
+    return 0;
+}
+
+#endif /* __NOVELL_LIBC__ */
+
+#else /* NETWARE */
+
+#ifdef __POCC__
+#  pragma warn(disable:2024)  /* Disable warning #2024: Empty input file */
+#endif
+
+#endif /* NETWARE */
diff --git a/lib/parsedate.c b/lib/parsedate.c
new file mode 100644
index 0000000..8e26f1c
--- /dev/null
+++ b/lib/parsedate.c
@@ -0,0 +1,510 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+/*
+  A brief summary of the date string formats this parser groks:
+
+  RFC 2616 3.3.1
+
+  Sun, 06 Nov 1994 08:49:37 GMT  ; RFC 822, updated by RFC 1123
+  Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
+  Sun Nov  6 08:49:37 1994       ; ANSI C's asctime() format
+
+  we support dates without week day name:
+
+  06 Nov 1994 08:49:37 GMT
+  06-Nov-94 08:49:37 GMT
+  Nov  6 08:49:37 1994
+
+  without the time zone:
+
+  06 Nov 1994 08:49:37
+  06-Nov-94 08:49:37
+
+  weird order:
+
+  1994 Nov 6 08:49:37  (GNU date fails)
+  GMT 08:49:37 06-Nov-94 Sunday
+  94 6 Nov 08:49:37    (GNU date fails)
+
+  time left out:
+
+  1994 Nov 6
+  06-Nov-94
+  Sun Nov 6 94
+
+  unusual separators:
+
+  1994.Nov.6
+  Sun/Nov/6/94/GMT
+
+  commonly used time zone names:
+
+  Sun, 06 Nov 1994 08:49:37 CET
+  06 Nov 1994 08:49:37 EST
+
+  time zones specified using RFC822 style:
+
+  Sun, 12 Sep 2004 15:05:58 -0700
+  Sat, 11 Sep 2004 21:32:11 +0200
+
+  compact numerical date strings:
+
+  20040912 15:05:58 -0700
+  20040911 +0200
+
+*/
+#include "setup.h"
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h> /* for strtol() */
+#endif
+
+#include <curl/curl.h>
+#include "rawstr.h"
+#include "parsedate.h"
+
+const char * const Curl_wkday[] =
+{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
+static const char * const weekday[] =
+{ "Monday", "Tuesday", "Wednesday", "Thursday",
+  "Friday", "Saturday", "Sunday" };
+const char * const Curl_month[]=
+{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+  "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+struct tzinfo {
+  char name[5];
+  int offset; /* +/- in minutes */
+};
+
+/* Here's a bunch of frequently used time zone names. These were supported
+   by the old getdate parser. */
+#define tDAYZONE -60       /* offset for daylight savings time */
+static const struct tzinfo tz[]= {
+  {"GMT", 0},              /* Greenwich Mean */
+  {"UTC", 0},              /* Universal (Coordinated) */
+  {"WET", 0},              /* Western European */
+  {"BST", 0 tDAYZONE},     /* British Summer */
+  {"WAT", 60},             /* West Africa */
+  {"AST", 240},            /* Atlantic Standard */
+  {"ADT", 240 tDAYZONE},   /* Atlantic Daylight */
+  {"EST", 300},            /* Eastern Standard */
+  {"EDT", 300 tDAYZONE},   /* Eastern Daylight */
+  {"CST", 360},            /* Central Standard */
+  {"CDT", 360 tDAYZONE},   /* Central Daylight */
+  {"MST", 420},            /* Mountain Standard */
+  {"MDT", 420 tDAYZONE},   /* Mountain Daylight */
+  {"PST", 480},            /* Pacific Standard */
+  {"PDT", 480 tDAYZONE},   /* Pacific Daylight */
+  {"YST", 540},            /* Yukon Standard */
+  {"YDT", 540 tDAYZONE},   /* Yukon Daylight */
+  {"HST", 600},            /* Hawaii Standard */
+  {"HDT", 600 tDAYZONE},   /* Hawaii Daylight */
+  {"CAT", 600},            /* Central Alaska */
+  {"AHST", 600},           /* Alaska-Hawaii Standard */
+  {"NT",  660},            /* Nome */
+  {"IDLW", 720},           /* International Date Line West */
+  {"CET", -60},            /* Central European */
+  {"MET", -60},            /* Middle European */
+  {"MEWT", -60},           /* Middle European Winter */
+  {"MEST", -60 tDAYZONE},  /* Middle European Summer */
+  {"CEST", -60 tDAYZONE},  /* Central European Summer */
+  {"MESZ", -60 tDAYZONE},  /* Middle European Summer */
+  {"FWT", -60},            /* French Winter */
+  {"FST", -60 tDAYZONE},   /* French Summer */
+  {"EET", -120},           /* Eastern Europe, USSR Zone 1 */
+  {"WAST", -420},          /* West Australian Standard */
+  {"WADT", -420 tDAYZONE}, /* West Australian Daylight */
+  {"CCT", -480},           /* China Coast, USSR Zone 7 */
+  {"JST", -540},           /* Japan Standard, USSR Zone 8 */
+  {"EAST", -600},          /* Eastern Australian Standard */
+  {"EADT", -600 tDAYZONE}, /* Eastern Australian Daylight */
+  {"GST", -600},           /* Guam Standard, USSR Zone 9 */
+  {"NZT", -720},           /* New Zealand */
+  {"NZST", -720},          /* New Zealand Standard */
+  {"NZDT", -720 tDAYZONE}, /* New Zealand Daylight */
+  {"IDLE", -720},          /* International Date Line East */
+  /* Next up: Military timezone names. RFC822 allowed these, but (as noted in
+     RFC 1123) had their signs wrong. Here we use the correct signs to match
+     actual military usage.
+   */
+  {"A",  +1 * 60},         /* Alpha */
+  {"B",  +2 * 60},         /* Bravo */
+  {"C",  +3 * 60},         /* Charlie */
+  {"D",  +4 * 60},         /* Delta */
+  {"E",  +5 * 60},         /* Echo */
+  {"F",  +6 * 60},         /* Foxtrot */
+  {"G",  +7 * 60},         /* Golf */
+  {"H",  +8 * 60},         /* Hotel */
+  {"I",  +9 * 60},         /* India */
+  /* "J", Juliet is not used as a timezone, to indicate the observer's local time */
+  {"K", +10 * 60},         /* Kilo */
+  {"L", +11 * 60},         /* Lima */
+  {"M", +12 * 60},         /* Mike */
+  {"N",  -1 * 60},         /* November */
+  {"O",  -2 * 60},         /* Oscar */
+  {"P",  -3 * 60},         /* Papa */
+  {"Q",  -4 * 60},         /* Quebec */
+  {"R",  -5 * 60},         /* Romeo */
+  {"S",  -6 * 60},         /* Sierra */
+  {"T",  -7 * 60},         /* Tango */
+  {"U",  -8 * 60},         /* Uniform */
+  {"V",  -9 * 60},         /* Victor */
+  {"W", -10 * 60},         /* Whiskey */
+  {"X", -11 * 60},         /* X-ray */
+  {"Y", -12 * 60},         /* Yankee */
+  {"Z", 0},                /* Zulu, zero meridian, a.k.a. UTC */
+};
+
+/* returns:
+   -1 no day
+   0 monday - 6 sunday
+*/
+
+static int checkday(const char *check, size_t len)
+{
+  int i;
+  const char * const *what;
+  bool found= FALSE;
+  if(len > 3)
+    what = &weekday[0];
+  else
+    what = &Curl_wkday[0];
+  for(i=0; i<7; i++) {
+    if(Curl_raw_equal(check, what[0])) {
+      found=TRUE;
+      break;
+    }
+    what++;
+  }
+  return found?i:-1;
+}
+
+static int checkmonth(const char *check)
+{
+  int i;
+  const char * const *what;
+  bool found= FALSE;
+
+  what = &Curl_month[0];
+  for(i=0; i<12; i++) {
+    if(Curl_raw_equal(check, what[0])) {
+      found=TRUE;
+      break;
+    }
+    what++;
+  }
+  return found?i:-1; /* return the offset or -1, no real offset is -1 */
+}
+
+/* return the time zone offset between GMT and the input one, in number
+   of seconds or -1 if the timezone wasn't found/legal */
+
+static int checktz(const char *check)
+{
+  unsigned int i;
+  const struct tzinfo *what;
+  bool found= FALSE;
+
+  what = tz;
+  for(i=0; i< sizeof(tz)/sizeof(tz[0]); i++) {
+    if(Curl_raw_equal(check, what->name)) {
+      found=TRUE;
+      break;
+    }
+    what++;
+  }
+  return found?what->offset*60:-1;
+}
+
+static void skip(const char **date)
+{
+  /* skip everything that aren't letters or digits */
+  while(**date && !ISALNUM(**date))
+    (*date)++;
+}
+
+enum assume {
+  DATE_MDAY,
+  DATE_YEAR,
+  DATE_TIME
+};
+
+/* this is a clone of 'struct tm' but with all fields we don't need or use
+   cut out */
+struct my_tm {
+  int tm_sec;
+  int tm_min;
+  int tm_hour;
+  int tm_mday;
+  int tm_mon;
+  int tm_year;
+};
+
+/* struct tm to time since epoch in GMT time zone.
+ * This is similar to the standard mktime function but for GMT only, and
+ * doesn't suffer from the various bugs and portability problems that
+ * some systems' implementations have.
+ */
+static time_t my_timegm(struct my_tm *tm)
+{
+  static const int month_days_cumulative [12] =
+    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+  int month, year, leap_days;
+
+  if(tm->tm_year < 70)
+    /* we don't support years before 1970 as they will cause this function
+       to return a negative value */
+    return -1;
+
+  year = tm->tm_year + 1900;
+  month = tm->tm_mon;
+  if (month < 0) {
+    year += (11 - month) / 12;
+    month = 11 - (11 - month) % 12;
+  }
+  else if (month >= 12) {
+    year -= month / 12;
+    month = month % 12;
+  }
+
+  leap_days = year - (tm->tm_mon <= 1);
+  leap_days = ((leap_days / 4) - (leap_days / 100) + (leap_days / 400)
+               - (1969 / 4) + (1969 / 100) - (1969 / 400));
+
+  return ((((time_t) (year - 1970) * 365
+            + leap_days + month_days_cumulative [month] + tm->tm_mday - 1) * 24
+           + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec;
+}
+
+/*
+ * Curl_parsedate()
+ *
+ * Returns:
+ *
+ * PARSEDATE_OK     - a fine conversion
+ * PARSEDATE_FAIL   - failed to convert
+ * PARSEDATE_LATER  - time overflow at the far end of time_t
+ * PARSEDATE_SOONER - time underflow at the low end of time_t
+ */
+
+int Curl_parsedate(const char *date, time_t *output)
+{
+  time_t t = 0;
+  int wdaynum=-1;  /* day of the week number, 0-6 (mon-sun) */
+  int monnum=-1;   /* month of the year number, 0-11 */
+  int mdaynum=-1; /* day of month, 1 - 31 */
+  int hournum=-1;
+  int minnum=-1;
+  int secnum=-1;
+  int yearnum=-1;
+  int tzoff=-1;
+  struct my_tm tm;
+  enum assume dignext = DATE_MDAY;
+  const char *indate = date; /* save the original pointer */
+  int part = 0; /* max 6 parts */
+
+  while(*date && (part < 6)) {
+    bool found=FALSE;
+
+    skip(&date);
+
+    if(ISALPHA(*date)) {
+      /* a name coming up */
+      char buf[32]="";
+      size_t len;
+      sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]",
+             buf);
+      len = strlen(buf);
+
+      if(wdaynum == -1) {
+        wdaynum = checkday(buf, len);
+        if(wdaynum != -1)
+          found = TRUE;
+      }
+      if(!found && (monnum == -1)) {
+        monnum = checkmonth(buf);
+        if(monnum != -1)
+          found = TRUE;
+      }
+
+      if(!found && (tzoff == -1)) {
+        /* this just must be a time zone string */
+        tzoff = checktz(buf);
+        if(tzoff != -1)
+          found = TRUE;
+      }
+
+      if(!found)
+        return PARSEDATE_FAIL; /* bad string */
+
+      date += len;
+    }
+    else if(ISDIGIT(*date)) {
+      /* a digit */
+      int val;
+      char *end;
+      if((secnum == -1) &&
+         (3 == sscanf(date, "%02d:%02d:%02d", &hournum, &minnum, &secnum))) {
+        /* time stamp! */
+        date += 8;
+        found = TRUE;
+      }
+      else {
+        val = (int)strtol(date, &end, 10);
+
+        if((tzoff == -1) &&
+           ((end - date) == 4) &&
+           (val <= 1400) &&
+           (indate< date) &&
+           ((date[-1] == '+' || date[-1] == '-'))) {
+          /* four digits and a value less than or equal to 1400 (to take into
+             account all sorts of funny time zone diffs) and it is preceeded
+             with a plus or minus. This is a time zone indication.  1400 is
+             picked since +1300 is frequently used and +1400 is mentioned as
+             an edge number in the document "ISO C 200X Proposal: Timezone
+             Functions" at http://david.tribble.com/text/c0xtimezone.html If
+             anyone has a more authoritative source for the exact maximum time
+             zone offsets, please speak up! */
+          found = TRUE;
+          tzoff = (val/100 * 60 + val%100)*60;
+
+          /* the + and - prefix indicates the local time compared to GMT,
+             this we need ther reversed math to get what we want */
+          tzoff = date[-1]=='+'?-tzoff:tzoff;
+        }
+
+        if(((end - date) == 8) &&
+           (yearnum == -1) &&
+           (monnum == -1) &&
+           (mdaynum == -1)) {
+          /* 8 digits, no year, month or day yet. This is YYYYMMDD */
+          found = TRUE;
+          yearnum = val/10000;
+          monnum = (val%10000)/100-1; /* month is 0 - 11 */
+          mdaynum = val%100;
+        }
+
+        if(!found && (dignext == DATE_MDAY) && (mdaynum == -1)) {
+          if((val > 0) && (val<32)) {
+            mdaynum = val;
+            found = TRUE;
+          }
+          dignext = DATE_YEAR;
+        }
+
+        if(!found && (dignext == DATE_YEAR) && (yearnum == -1)) {
+          yearnum = val;
+          found = TRUE;
+          if(yearnum < 1900) {
+            if(yearnum > 70)
+              yearnum += 1900;
+            else
+              yearnum += 2000;
+          }
+          if(mdaynum == -1)
+            dignext = DATE_MDAY;
+        }
+
+        if(!found)
+          return PARSEDATE_FAIL;
+
+        date = end;
+      }
+    }
+
+    part++;
+  }
+
+  if(-1 == secnum)
+    secnum = minnum = hournum = 0; /* no time, make it zero */
+
+  if((-1 == mdaynum) ||
+     (-1 == monnum) ||
+     (-1 == yearnum))
+    /* lacks vital info, fail */
+    return PARSEDATE_FAIL;
+
+#if SIZEOF_TIME_T < 5
+  /* 32 bit time_t can only hold dates to the beginning of 2038 */
+  if(yearnum > 2037) {
+    *output = 0x7fffffff;
+    return PARSEDATE_LATER;
+  }
+#endif
+
+  if(yearnum < 1970) {
+    *output = 0;
+    return PARSEDATE_SOONER;
+  }
+
+  tm.tm_sec = secnum;
+  tm.tm_min = minnum;
+  tm.tm_hour = hournum;
+  tm.tm_mday = mdaynum;
+  tm.tm_mon = monnum;
+  tm.tm_year = yearnum - 1900;
+
+  /* my_timegm() returns a time_t. time_t is often 32 bits, even on many
+     architectures that feature 64 bit 'long'.
+
+     Some systems have 64 bit time_t and deal with years beyond 2038. However,
+     even on some of the systems with 64 bit time_t mktime() returns -1 for
+     dates beyond 03:14:07 UTC, January 19, 2038. (Such as AIX 5100-06)
+  */
+  t = my_timegm(&tm);
+
+  /* time zone adjust (cast t to int to compare to negative one) */
+  if(-1 != (int)t) {
+
+    /* Add the time zone diff between local time zone and GMT. */
+    long delta = (long)(tzoff!=-1?tzoff:0);
+
+    if((delta>0) && (t + delta < t))
+      return -1; /* time_t overflow */
+
+    t += delta;
+  }
+
+  *output = t;
+
+  return PARSEDATE_OK;
+}
+
+time_t curl_getdate(const char *p, const time_t *now)
+{
+  time_t parsed;
+  int rc = Curl_parsedate(p, &parsed);
+  (void)now; /* legacy argument from the past that we ignore */
+
+  switch(rc) {
+  case PARSEDATE_OK:
+  case PARSEDATE_LATER:
+  case PARSEDATE_SOONER:
+    return parsed;
+  }
+  /* everything else is fail */
+  return -1;
+}
diff --git a/lib/parsedate.h b/lib/parsedate.h
new file mode 100644
index 0000000..e1bf544
--- /dev/null
+++ b/lib/parsedate.h
@@ -0,0 +1,46 @@
+#ifndef __CURL_PARSEDATE_H
+#define __CURL_PARSEDATE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+extern const char * const Curl_wkday[7];
+extern const char * const Curl_month[12];
+
+/*
+ * Curl_parsedate()
+ *
+ * Returns:
+ *
+ * PARSEDATE_OK     - a fine conversion
+ * PARSEDATE_FAIL   - failed to convert
+ * PARSEDATE_LATER  - time overflow at the far end of time_t
+ * PARSEDATE_SOONER - time underflow at the low end of time_t
+ */
+
+int Curl_parsedate(const char *date, time_t *output);
+
+#define PARSEDATE_OK     0
+#define PARSEDATE_FAIL   -1
+#define PARSEDATE_LATER  1
+#define PARSEDATE_SOONER 2
+
+#endif
diff --git a/lib/pingpong.c b/lib/pingpong.c
new file mode 100644
index 0000000..c6b6f2f
--- /dev/null
+++ b/lib/pingpong.c
@@ -0,0 +1,540 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ *   'pingpong' is for generic back-and-forth support functions used by FTP,
+ *   IMAP, POP3, SMTP and whatever more that likes them.
+ *
+ ***************************************************************************/
+
+#include "setup.h"
+
+#include "urldata.h"
+#include "sendf.h"
+#include "select.h"
+#include "progress.h"
+#include "speedcheck.h"
+#include "pingpong.h"
+#include "multiif.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifdef USE_PINGPONG
+
+/* Returns timeout in ms. 0 or negative number means the timeout has already
+   triggered */
+long Curl_pp_state_timeout(struct pingpong *pp)
+{
+  struct connectdata *conn = pp->conn;
+  struct SessionHandle *data=conn->data;
+  long timeout_ms; /* in milliseconds */
+  long timeout2_ms; /* in milliseconds */
+  long response_time= (data->set.server_response_timeout)?
+    data->set.server_response_timeout: pp->response_time;
+
+  /* if CURLOPT_SERVER_RESPONSE_TIMEOUT is set, use that to determine
+     remaining time, or use pp->response because SERVER_RESPONSE_TIMEOUT is
+     supposed to govern the response for any given server response, not for
+     the time from connect to the given server response. */
+
+  /* Without a requested timeout, we only wait 'response_time' seconds for the
+     full response to arrive before we bail out */
+  timeout_ms = response_time -
+    Curl_tvdiff(Curl_tvnow(), pp->response); /* spent time */
+
+  if(data->set.timeout) {
+    /* if timeout is requested, find out how much remaining time we have */
+    timeout2_ms = data->set.timeout - /* timeout time */
+      Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
+
+    /* pick the lowest number */
+    timeout_ms = CURLMIN(timeout_ms, timeout2_ms);
+  }
+
+  return timeout_ms;
+}
+
+
+/*
+ * Curl_pp_multi_statemach()
+ *
+ * called repeatedly until done when the multi interface is used.
+ */
+CURLcode Curl_pp_multi_statemach(struct pingpong *pp)
+{
+  struct connectdata *conn = pp->conn;
+  curl_socket_t sock = conn->sock[FIRSTSOCKET];
+  int rc;
+  struct SessionHandle *data=conn->data;
+  CURLcode result = CURLE_OK;
+  long timeout_ms = Curl_pp_state_timeout(pp);
+
+  if(timeout_ms <= 0) {
+    failf(data, "server response timeout");
+    return CURLE_OPERATION_TIMEDOUT;
+  }
+
+  rc = Curl_socket_ready(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */
+                         pp->sendleft?sock:CURL_SOCKET_BAD, /* writing */
+                         0);
+
+  if(rc == -1) {
+    failf(data, "select/poll error");
+    return CURLE_OUT_OF_MEMORY;
+  }
+  else if(rc != 0)
+    result = pp->statemach_act(conn);
+
+  /* if rc == 0, then select() timed out */
+
+  return result;
+}
+
+/*
+ * Curl_pp_easy_statemach()
+ *
+ * called repeatedly until done when the easy interface is used.
+ */
+CURLcode Curl_pp_easy_statemach(struct pingpong *pp)
+{
+  struct connectdata *conn = pp->conn;
+  curl_socket_t sock = conn->sock[FIRSTSOCKET];
+  int rc;
+  long interval_ms;
+  long timeout_ms = Curl_pp_state_timeout(pp);
+  struct SessionHandle *data=conn->data;
+  CURLcode result;
+
+  if(timeout_ms <=0 ) {
+    failf(data, "server response timeout");
+    return CURLE_OPERATION_TIMEDOUT; /* already too little time */
+  }
+
+  interval_ms = 1000;  /* use 1 second timeout intervals */
+  if(timeout_ms < interval_ms)
+    interval_ms = timeout_ms;
+
+  rc = Curl_socket_ready(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */
+                         pp->sendleft?sock:CURL_SOCKET_BAD, /* writing */
+                         (int)interval_ms);
+
+  if(Curl_pgrsUpdate(conn))
+    result = CURLE_ABORTED_BY_CALLBACK;
+  else
+    result = Curl_speedcheck(data, Curl_tvnow());
+
+  if(result)
+    ;
+  else if(rc == -1) {
+    failf(data, "select/poll error");
+    result = CURLE_OUT_OF_MEMORY;
+  }
+  else if(rc)
+    result = pp->statemach_act(conn);
+
+  return result;
+}
+
+/* initialize stuff to prepare for reading a fresh new response */
+void Curl_pp_init(struct pingpong *pp)
+{
+  struct connectdata *conn = pp->conn;
+  pp->nread_resp = 0;
+  pp->linestart_resp = conn->data->state.buffer;
+  pp->pending_resp = TRUE;
+  pp->response = Curl_tvnow(); /* start response time-out now! */
+}
+
+
+
+/***********************************************************************
+ *
+ * Curl_pp_sendfv()
+ *
+ * Send the formated string as a command to a pingpong server. Note that
+ * the string should not have any CRLF appended, as this function will
+ * append the necessary things itself.
+ *
+ * NOTE: we build the command in a fixed-length buffer, which sets length
+ * restrictions on the command!
+ *
+ * made to never block
+ */
+CURLcode Curl_pp_vsendf(struct pingpong *pp,
+                        const char *fmt,
+                        va_list args)
+{
+  ssize_t bytes_written;
+/* may still not be big enough for some krb5 tokens */
+#define SBUF_SIZE 1024
+  char s[SBUF_SIZE];
+  size_t write_len;
+  char *sptr=s;
+  CURLcode res = CURLE_OK;
+  struct connectdata *conn = pp->conn;
+  struct SessionHandle *data = conn->data;
+
+#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
+  enum protection_level data_sec = conn->data_prot;
+#endif
+
+  vsnprintf(s, SBUF_SIZE-3, fmt, args);
+
+  strcat(s, "\r\n"); /* append a trailing CRLF */
+
+  bytes_written=0;
+  write_len = strlen(s);
+
+  Curl_pp_init(pp);
+
+#ifdef CURL_DOES_CONVERSIONS
+  res = Curl_convert_to_network(data, s, write_len);
+  /* Curl_convert_to_network calls failf if unsuccessful */
+  if(res != CURLE_OK) {
+    return res;
+  }
+#endif /* CURL_DOES_CONVERSIONS */
+
+#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
+  conn->data_prot = prot_cmd;
+#endif
+  res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
+                   &bytes_written);
+#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
+  conn->data_prot = data_sec;
+#endif
+
+  if(CURLE_OK != res)
+    return res;
+
+  if(conn->data->set.verbose)
+    Curl_debug(conn->data, CURLINFO_HEADER_OUT,
+               sptr, (size_t)bytes_written, conn);
+
+  if(bytes_written != (ssize_t)write_len) {
+    /* the whole chunk was not sent, store the rest of the data */
+    write_len -= bytes_written;
+    sptr += bytes_written;
+    pp->sendthis = malloc(write_len);
+    if(pp->sendthis) {
+      memcpy(pp->sendthis, sptr, write_len);
+      pp->sendsize = pp->sendleft = write_len;
+    }
+    else {
+      failf(data, "out of memory");
+      res = CURLE_OUT_OF_MEMORY;
+    }
+  }
+  else
+    pp->response = Curl_tvnow();
+
+  return res;
+}
+
+
+/***********************************************************************
+ *
+ * Curl_pp_sendf()
+ *
+ * Send the formated string as a command to a pingpong server. Note that
+ * the string should not have any CRLF appended, as this function will
+ * append the necessary things itself.
+ *
+ * NOTE: we build the command in a fixed-length buffer, which sets length
+ * restrictions on the command!
+ *
+ * made to never block
+ */
+CURLcode Curl_pp_sendf(struct pingpong *pp,
+                       const char *fmt, ...)
+{
+  CURLcode res;
+  va_list ap;
+  va_start(ap, fmt);
+
+  res = Curl_pp_vsendf(pp, fmt, ap);
+
+  va_end(ap);
+
+  return res;
+}
+
+/*
+ * Curl_pp_readresp()
+ *
+ * Reads a piece of a server response.
+ */
+CURLcode Curl_pp_readresp(curl_socket_t sockfd,
+                          struct pingpong *pp,
+                          int *code, /* return the server code if done */
+                          size_t *size) /* size of the response */
+{
+  ssize_t perline; /* count bytes per line */
+  bool keepon=TRUE;
+  ssize_t gotbytes;
+  char *ptr;
+  struct connectdata *conn = pp->conn;
+  struct SessionHandle *data = conn->data;
+  char * const buf = data->state.buffer;
+  CURLcode result = CURLE_OK;
+
+  *code = 0; /* 0 for errors or not done */
+  *size = 0;
+
+  ptr=buf + pp->nread_resp;
+
+  /* number of bytes in the current line, so far */
+  perline = (ssize_t)(ptr-pp->linestart_resp);
+
+  keepon=TRUE;
+
+  while((pp->nread_resp<BUFSIZE) && (keepon && !result)) {
+
+    if(pp->cache) {
+      /* we had data in the "cache", copy that instead of doing an actual
+       * read
+       *
+       * 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.
+       */
+      DEBUGASSERT((ptr+pp->cache_size) <= (buf+BUFSIZE+1));
+      memcpy(ptr, pp->cache, pp->cache_size);
+      gotbytes = pp->cache_size;
+      free(pp->cache);    /* free the cache */
+      pp->cache = NULL;   /* clear the pointer */
+      pp->cache_size = 0; /* zero the size just in case */
+    }
+    else {
+      int res;
+#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
+      enum protection_level prot = conn->data_prot;
+
+      conn->data_prot = 0;
+#endif
+      DEBUGASSERT((ptr+BUFSIZE-pp->nread_resp) <= (buf+BUFSIZE+1));
+      res = Curl_read(conn, sockfd, ptr, BUFSIZE-pp->nread_resp,
+                      &gotbytes);
+#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
+      conn->data_prot = prot;
+#endif
+      if(res < 0)
+        /* EWOULDBLOCK */
+        return CURLE_OK; /* return */
+
+#ifdef CURL_DOES_CONVERSIONS
+      if((res == CURLE_OK) && (gotbytes > 0)) {
+        /* convert from the network encoding */
+        res = Curl_convert_from_network(data, ptr, gotbytes);
+        /* Curl_convert_from_network calls failf if unsuccessful */
+      }
+#endif /* CURL_DOES_CONVERSIONS */
+
+      if(CURLE_OK != res) {
+        result = (CURLcode)res; /* Set outer result variable to this error. */
+        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 */
+      ssize_t i;
+      ssize_t clipamount = 0;
+      bool restart = FALSE;
+
+      data->req.headerbytecount += (long)gotbytes;
+
+      pp->nread_resp += 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 defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
+          if(!conn->sec_complete)
+#endif
+            if(data->set.verbose)
+            Curl_debug(data, CURLINFO_HEADER_IN,
+                       pp->linestart_resp, (size_t)perline, conn);
+
+          /*
+           * 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(conn, CLIENTWRITE_HEADER,
+                                     pp->linestart_resp, perline);
+          if(result)
+            return result;
+
+          if(pp->endofresp(pp, code)) {
+            /* 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=pp->linestart_resp, n=0; meow<ptr; meow++, n++)
+              buf[n] = *meow;
+            *meow=0; /* zero terminate */
+            keepon=FALSE;
+            pp->linestart_resp = ptr+1; /* advance pointer */
+            i++; /* skip this before getting out */
+
+            *size = pp->nread_resp; /* size of the response */
+            pp->nread_resp = 0; /* restart */
+            break;
+          }
+          perline=0; /* line starts over here */
+          pp->linestart_resp = 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! */
+        clipamount = gotbytes - i;
+        restart = TRUE;
+      }
+      else if(keepon) {
+
+        if((perline == gotbytes) && (gotbytes > BUFSIZE/2)) {
+          /* We got an excessive line without newlines and we need to deal
+             with it. We keep the first bytes of the line then we throw
+             away the rest. */
+          infof(data, "Excessive server response line length received, %zd bytes."
+                " Stripping\n", gotbytes);
+          restart = TRUE;
+
+          /* we keep 40 bytes since all our pingpong protocols are only
+             interested in the first piece */
+          clipamount = 40;
+        }
+        else if(pp->nread_resp > BUFSIZE/2) {
+          /* We got a large chunk of data and there's potentially still trailing
+             data to take care of, so we put any such part in the "cache", clear
+             the buffer to make space and restart. */
+          clipamount = perline;
+          restart = TRUE;
+        }
+      }
+      else if(i == gotbytes)
+        restart = TRUE;
+
+      if(clipamount) {
+        pp->cache_size = clipamount;
+        pp->cache = malloc(pp->cache_size);
+        if(pp->cache)
+          memcpy(pp->cache, pp->linestart_resp, pp->cache_size);
+        else
+          return CURLE_OUT_OF_MEMORY;
+      }
+      if(restart) {
+        /* now reset a few variables to start over nicely from the start of
+           the big buffer */
+        pp->nread_resp = 0; /* start over from scratch in the buffer */
+        ptr = pp->linestart_resp = buf;
+        perline = 0;
+      }
+
+    } /* there was data */
+
+  } /* while there's buffer left and loop is requested */
+
+  pp->pending_resp = FALSE;
+
+  return result;
+}
+
+int Curl_pp_getsock(struct pingpong *pp,
+                    curl_socket_t *socks,
+                    int numsocks)
+{
+  struct connectdata *conn = pp->conn;
+
+  if(!numsocks)
+    return GETSOCK_BLANK;
+
+  socks[0] = conn->sock[FIRSTSOCKET];
+
+  if(pp->sendleft) {
+    /* write mode */
+    return GETSOCK_WRITESOCK(0);
+  }
+
+  /* read mode */
+  return GETSOCK_READSOCK(0);
+}
+
+CURLcode Curl_pp_flushsend(struct pingpong *pp)
+{
+  /* we have a piece of a command still left to send */
+  struct connectdata *conn = pp->conn;
+  ssize_t written;
+  CURLcode result = CURLE_OK;
+  curl_socket_t sock = conn->sock[FIRSTSOCKET];
+
+  result = Curl_write(conn, sock, pp->sendthis + pp->sendsize -
+                      pp->sendleft, pp->sendleft, &written);
+  if(result)
+    return result;
+
+  if(written != (ssize_t)pp->sendleft) {
+    /* only a fraction was sent */
+    pp->sendleft -= written;
+  }
+  else {
+    free(pp->sendthis);
+    pp->sendthis=NULL;
+    pp->sendleft = pp->sendsize = 0;
+    pp->response = Curl_tvnow();
+  }
+  return CURLE_OK;
+}
+
+CURLcode Curl_pp_disconnect(struct pingpong *pp)
+{
+  if(pp->cache) {
+    free(pp->cache);
+    pp->cache = NULL;
+  }
+  return CURLE_OK;
+}
+
+
+
+#endif
diff --git a/lib/pingpong.h b/lib/pingpong.h
new file mode 100644
index 0000000..a629aee
--- /dev/null
+++ b/lib/pingpong.h
@@ -0,0 +1,147 @@
+#ifndef __PINGPONG_H
+#define __PINGPONG_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, 2009, 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 <stdarg.h>
+
+#include "setup.h"
+
+#if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_FTP) || \
+  !defined(CURL_DISABLE_POP3) || !defined(CURL_DISABLE_SMTP)
+#define USE_PINGPONG
+#endif
+
+/* forward-declaration, this is defined in urldata.h */
+struct connectdata;
+
+/*
+ * 'pingpong' is the generic struct used for protocols doing server<->client
+ * conversations in a back-and-forth style such as FTP, IMAP, POP3, SMTP etc.
+ *
+ * It holds response cache and non-blocking sending data.
+ */
+struct pingpong {
+  char *cache;     /* data cache between getresponse()-calls */
+  size_t cache_size;  /* size of cache in bytes */
+  size_t nread_resp;  /* number of bytes currently read of a server response */
+  char *linestart_resp; /* line start pointer for the server response
+                           reader function */
+  bool pending_resp;  /* set TRUE when a server response is pending or in
+                         progress, and is cleared once the last response is
+                         read */
+  char *sendthis; /* allocated pointer to a buffer that is to be sent to the
+                     server */
+  size_t sendleft; /* number of bytes left to send from the sendthis buffer */
+  size_t sendsize; /* total size of the sendthis buffer */
+  struct timeval response; /* set to Curl_tvnow() when a command has been sent
+                              off, used to time-out response reading */
+  long response_time; /* When no timeout is given, this is the amount of
+                         seconds we await for a server response. */
+
+  struct connectdata *conn; /* points to the connectdata struct that this
+                               belongs to */
+
+  /* Function pointers the protocols MUST implement and provide for the
+     pingpong layer to function */
+
+  CURLcode (*statemach_act)(struct connectdata *conn);
+
+  int (*endofresp)(struct pingpong *pp, int *code);
+};
+
+/*
+ * Curl_pp_multi_statemach()
+ *
+ * called repeatedly until done when the multi interface is used.
+ */
+CURLcode Curl_pp_multi_statemach(struct pingpong *pp);
+
+/*
+ * Curl_pp_easy_statemach()
+ *
+ * called repeatedly until done when the easy interface is used.
+ */
+CURLcode Curl_pp_easy_statemach(struct pingpong *pp);
+
+
+/* initialize stuff to prepare for reading a fresh new response */
+void Curl_pp_init(struct pingpong *pp);
+
+/* Returns timeout in ms. 0 or negative number means the timeout has already
+   triggered */
+long Curl_pp_state_timeout(struct pingpong *pp);
+
+
+/***********************************************************************
+ *
+ * Curl_pp_sendf()
+ *
+ * Send the formated string as a command to a pingpong server. Note that
+ * the string should not have any CRLF appended, as this function will
+ * append the necessary things itself.
+ *
+ * NOTE: we build the command in a fixed-length buffer, which sets length
+ * restrictions on the command!
+ *
+ * made to never block
+ */
+CURLcode Curl_pp_sendf(struct pingpong *pp,
+                       const char *fmt, ...);
+
+/***********************************************************************
+ *
+ * Curl_pp_vsendf()
+ *
+ * Send the formated string as a command to a pingpong server. Note that
+ * the string should not have any CRLF appended, as this function will
+ * append the necessary things itself.
+ *
+ * NOTE: we build the command in a fixed-length buffer, which sets length
+ * restrictions on the command!
+ *
+ * made to never block
+ */
+CURLcode Curl_pp_vsendf(struct pingpong *pp,
+                        const char *fmt,
+                        va_list args);
+
+/*
+ * Curl_pp_readresp()
+ *
+ * Reads a piece of a server response.
+ */
+CURLcode Curl_pp_readresp(curl_socket_t sockfd,
+                          struct pingpong *pp,
+                          int *code, /* return the server code if done */
+                          size_t *size); /* size of the response */
+
+
+CURLcode Curl_pp_flushsend(struct pingpong *pp);
+
+/* call this when a pingpong connection is disconnected */
+CURLcode Curl_pp_disconnect(struct pingpong *pp);
+
+int Curl_pp_getsock(struct pingpong *pp, curl_socket_t *socks,
+                    int numsocks);
+
+#endif /* __PINGPONG_H */
diff --git a/lib/pop3.c b/lib/pop3.c
new file mode 100644
index 0000000..4894f3c
--- /dev/null
+++ b/lib/pop3.c
@@ -0,0 +1,1024 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ * RFC1939 POP3 protocol
+ * RFC2384 POP URL Scheme
+ * RFC2595 Using TLS with IMAP, POP3 and ACAP
+ *
+ ***************************************************************************/
+
+#include "setup.h"
+
+#ifndef CURL_DISABLE_POP3
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.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
+#ifdef HAVE_UTSNAME_H
+#include <sys/utsname.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.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 "easyif.h" /* for Curl_convert_... prototypes */
+
+#include "if2ip.h"
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "socks.h"
+#include "pop3.h"
+
+#include "strtoofft.h"
+#include "strequal.h"
+#include "sslgen.h"
+#include "connect.h"
+#include "strerror.h"
+#include "select.h"
+#include "multiif.h"
+#include "url.h"
+#include "rawstr.h"
+#include "strtoofft.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* Local API functions */
+static CURLcode pop3_parse_url_path(struct connectdata *conn);
+static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *done);
+static CURLcode pop3_do(struct connectdata *conn, bool *done);
+static CURLcode pop3_done(struct connectdata *conn,
+                          CURLcode, bool premature);
+static CURLcode pop3_connect(struct connectdata *conn, bool *done);
+static CURLcode pop3_disconnect(struct connectdata *conn);
+static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done);
+static int pop3_getsock(struct connectdata *conn,
+                        curl_socket_t *socks,
+                        int numsocks);
+static CURLcode pop3_doing(struct connectdata *conn,
+                           bool *dophase_done);
+static CURLcode pop3_setup_connection(struct connectdata * conn);
+
+/*
+ * POP3 protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_pop3 = {
+  "POP3",                           /* scheme */
+  pop3_setup_connection,            /* setup_connection */
+  pop3_do,                          /* do_it */
+  pop3_done,                        /* done */
+  ZERO_NULL,                        /* do_more */
+  pop3_connect,                     /* connect_it */
+  pop3_multi_statemach,             /* connecting */
+  pop3_doing,                       /* doing */
+  pop3_getsock,                     /* proto_getsock */
+  pop3_getsock,                     /* doing_getsock */
+  ZERO_NULL,                        /* perform_getsock */
+  pop3_disconnect,                  /* disconnect */
+  PORT_POP3,                        /* defport */
+  PROT_POP3                         /* protocol */
+};
+
+
+#ifdef USE_SSL
+/*
+ * POP3S protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_pop3s = {
+  "POP3S",                          /* scheme */
+  pop3_setup_connection,            /* setup_connection */
+  pop3_do,                          /* do_it */
+  pop3_done,                        /* done */
+  ZERO_NULL,                        /* do_more */
+  pop3_connect,                     /* connect_it */
+  pop3_multi_statemach,             /* connecting */
+  pop3_doing,                       /* doing */
+  pop3_getsock,                     /* proto_getsock */
+  pop3_getsock,                     /* doing_getsock */
+  ZERO_NULL,                        /* perform_getsock */
+  pop3_disconnect,                  /* disconnect */
+  PORT_POP3S,                       /* defport */
+  PROT_POP3 | PROT_POP3S | PROT_SSL  /* protocol */
+};
+#endif
+
+#ifndef CURL_DISABLE_HTTP
+/*
+ * HTTP-proxyed POP3 protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_pop3_proxy = {
+  "POP3",                               /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  Curl_http,                            /* do_it */
+  Curl_http_done,                       /* done */
+  ZERO_NULL,                            /* do_more */
+  ZERO_NULL,                            /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  PORT_POP3,                            /* defport */
+  PROT_HTTP                             /* protocol */
+};
+
+
+#ifdef USE_SSL
+/*
+ * HTTP-proxyed POP3S protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_pop3s_proxy = {
+  "POP3S",                              /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  Curl_http,                            /* do_it */
+  Curl_http_done,                       /* done */
+  ZERO_NULL,                            /* do_more */
+  ZERO_NULL,                            /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  PORT_POP3S,                           /* defport */
+  PROT_HTTP                             /* protocol */
+};
+#endif
+#endif
+
+
+/* function that checks for a pop3 status code at the start of the given
+   string */
+static int pop3_endofresp(struct pingpong *pp,
+                          int *resp)
+{
+  char *line = pp->linestart_resp;
+  size_t len = pp->nread_resp;
+
+  if( ((len >= 3) && !memcmp("+OK", line, 3)) ||
+      ((len >= 4) && !memcmp("-ERR", line, 4)) ) {
+    *resp=line[1]; /* O or E */
+    return TRUE;
+  }
+
+  return FALSE; /* nothing for us */
+}
+
+/* This is the ONLY way to change POP3 state! */
+static void state(struct connectdata *conn,
+                  pop3state newstate)
+{
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  /* for debug purposes */
+  static const char * const names[]={
+    "STOP",
+    "SERVERGREET",
+    "USER",
+    "PASS",
+    "STARTTLS",
+    "LIST",
+    "RETR",
+    "QUIT",
+    /* LAST */
+  };
+#endif
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  if(pop3c->state != newstate)
+    infof(conn->data, "POP3 %p state change from %s to %s\n",
+          pop3c, names[pop3c->state], names[newstate]);
+#endif
+  pop3c->state = newstate;
+}
+
+static CURLcode pop3_state_user(struct connectdata *conn)
+{
+  CURLcode result;
+  struct FTP *pop3 = conn->data->state.proto.pop3;
+
+  /* send USER */
+  result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s",
+                         pop3->user?pop3->user:"");
+  if(result)
+    return result;
+
+  state(conn, POP3_USER);
+
+  return CURLE_OK;
+}
+
+/* For the POP3 "protocol connect" and "doing" phases only */
+static int pop3_getsock(struct connectdata *conn,
+                        curl_socket_t *socks,
+                        int numsocks)
+{
+  return Curl_pp_getsock(&conn->proto.pop3c.pp, socks, numsocks);
+}
+
+/* for STARTTLS responses */
+static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
+                                         int pop3code,
+                                         pop3state instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  (void)instate; /* no use for this yet */
+
+  if(pop3code != 'O') {
+    failf(data, "STARTTLS denied. %c", pop3code);
+    result = CURLE_LOGIN_DENIED;
+  }
+  else {
+    /* Curl_ssl_connect is BLOCKING */
+    result = Curl_ssl_connect(conn, FIRSTSOCKET);
+    if(CURLE_OK == result) {
+      conn->protocol |= PROT_POP3S;
+      result = pop3_state_user(conn);
+    }
+  }
+  state(conn, POP3_STOP);
+  return result;
+}
+
+/* for USER responses */
+static CURLcode pop3_state_user_resp(struct connectdata *conn,
+                                     int pop3code,
+                                     pop3state instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  struct FTP *pop3 = data->state.proto.pop3;
+
+  (void)instate; /* no use for this yet */
+
+  if(pop3code != 'O') {
+    failf(data, "Access denied. %c", pop3code);
+    result = CURLE_LOGIN_DENIED;
+  }
+
+  /* send PASS */
+  result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s",
+                         pop3->passwd?pop3->passwd:"");
+  if(result)
+    return result;
+
+  state(conn, POP3_PASS);
+  return result;
+}
+
+/* for PASS responses */
+static CURLcode pop3_state_pass_resp(struct connectdata *conn,
+                                     int pop3code,
+                                     pop3state instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  (void)instate; /* no use for this yet */
+
+  if(pop3code != 'O') {
+    failf(data, "Access denied. %c", pop3code);
+    result = CURLE_LOGIN_DENIED;
+  }
+
+  state(conn, POP3_STOP);
+  return result;
+}
+
+/* for the retr response */
+static CURLcode pop3_state_retr_resp(struct connectdata *conn,
+                                     int pop3code,
+                                     pop3state instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  struct FTP *pop3 = data->state.proto.pop3;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  struct pingpong *pp = &pop3c->pp;
+
+  (void)instate; /* no use for this yet */
+
+  if('O' != pop3code) {
+    state(conn, POP3_STOP);
+    return CURLE_RECV_ERROR;
+  }
+
+  /* POP3 download */
+  result=Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE,
+                             pop3->bytecountp,
+                             -1, NULL); /* no upload here */
+
+  if(pp->cache) {
+    /* At this point there is a bunch of data in the header "cache" that is
+       actually body content, send it as body and then skip it. Do note
+       that there may even be additional "headers" after the body. */
+
+    /* we may get the EOB already here! */
+    result = Curl_pop3_write(conn, pp->cache, pp->cache_size);
+    if(result)
+      return result;
+
+    /* cache is drained */
+    free(pp->cache);
+    pp->cache = NULL;
+    pp->cache_size = 0;
+  }
+
+  state(conn, POP3_STOP);
+  return result;
+}
+
+
+/* for the list response */
+static CURLcode pop3_state_list_resp(struct connectdata *conn,
+                                     int pop3code,
+                                     pop3state instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  struct FTP *pop3 = data->state.proto.pop3;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  struct pingpong *pp = &pop3c->pp;
+
+  (void)instate; /* no use for this yet */
+
+  if('O' != pop3code) {
+    state(conn, POP3_STOP);
+    return CURLE_RECV_ERROR;
+  }
+
+  /* POP3 download */
+  result=Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE,
+                             pop3->bytecountp,
+                             -1, NULL); /* no upload here */
+
+  if(pp->cache) {
+    /* cache holds the email ID listing */
+
+    /* we may get the EOB already here! */
+    result = Curl_pop3_write(conn, pp->cache, pp->cache_size);
+    if(result)
+      return result;
+
+    /* cache is drained */
+    free(pp->cache);
+    pp->cache = NULL;
+    pp->cache_size = 0;
+  }
+
+  state(conn, POP3_STOP);
+  return result;
+}
+
+/* start the DO phase for RETR */
+static CURLcode pop3_retr(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+
+  result = Curl_pp_sendf(&conn->proto.pop3c.pp, "RETR %s", pop3c->mailbox);
+  if(result)
+    return result;
+
+  state(conn, POP3_RETR);
+  return result;
+}
+
+/* start the DO phase for LIST */
+static CURLcode pop3_list(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+
+  result = Curl_pp_sendf(&conn->proto.pop3c.pp, "LIST %s", pop3c->mailbox);
+  if(result)
+    return result;
+
+  state(conn, POP3_LIST);
+  return result;
+}
+
+static CURLcode pop3_statemach_act(struct connectdata *conn)
+{
+  CURLcode result;
+  curl_socket_t sock = conn->sock[FIRSTSOCKET];
+  struct SessionHandle *data=conn->data;
+  int pop3code;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  struct pingpong *pp = &pop3c->pp;
+  size_t nread = 0;
+
+  if(pp->sendleft)
+    return Curl_pp_flushsend(pp);
+
+  /* we read a piece of response */
+  result = Curl_pp_readresp(sock, pp, &pop3code, &nread);
+  if(result)
+    return result;
+
+  if(pop3code) {
+    /* we have now received a full POP3 server response */
+    switch(pop3c->state) {
+    case POP3_SERVERGREET:
+      if(pop3code != 'O') {
+        failf(data, "Got unexpected pop3-server response");
+        return CURLE_FTP_WEIRD_SERVER_REPLY;
+      }
+
+      if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
+        /* We don't have a SSL/TLS connection yet, but SSL is requested. Switch
+           to TLS connection now */
+        result = Curl_pp_sendf(&pop3c->pp, "STARTTLS", NULL);
+        state(conn, POP3_STARTTLS);
+      }
+      else
+        result = pop3_state_user(conn);
+      if(result)
+        return result;
+      break;
+
+    case POP3_USER:
+      result = pop3_state_user_resp(conn, pop3code, pop3c->state);
+      break;
+
+    case POP3_PASS:
+      result = pop3_state_pass_resp(conn, pop3code, pop3c->state);
+      break;
+
+    case POP3_STARTTLS:
+      result = pop3_state_starttls_resp(conn, pop3code, pop3c->state);
+      break;
+
+    case POP3_RETR:
+      result = pop3_state_retr_resp(conn, pop3code, pop3c->state);
+      break;
+
+    case POP3_LIST:
+      result = pop3_state_list_resp(conn, pop3code, pop3c->state);
+      break;
+
+    case POP3_QUIT:
+      /* fallthrough, just stop! */
+    default:
+      /* internal error */
+      state(conn, POP3_STOP);
+      break;
+    }
+  }
+  return result;
+}
+
+/* called repeatedly until done from multi.c */
+static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done)
+{
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  CURLcode result = Curl_pp_multi_statemach(&pop3c->pp);
+
+  *done = (bool)(pop3c->state == POP3_STOP);
+
+  return result;
+}
+
+static CURLcode pop3_easy_statemach(struct connectdata *conn)
+{
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  struct pingpong *pp = &pop3c->pp;
+  CURLcode result = CURLE_OK;
+
+  while(pop3c->state != POP3_STOP) {
+    result = Curl_pp_easy_statemach(pp);
+    if(result)
+      break;
+  }
+
+  return result;
+}
+
+/*
+ * Allocate and initialize the struct POP3 for the current SessionHandle.  If
+ * need be.
+ */
+static CURLcode pop3_init(struct connectdata *conn)
+{
+  struct SessionHandle *data = conn->data;
+  struct FTP *pop3 = data->state.proto.pop3;
+  if(!pop3) {
+    pop3 = data->state.proto.pop3 = calloc(sizeof(struct FTP), 1);
+    if(!pop3)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* get some initial data into the pop3 struct */
+  pop3->bytecountp = &data->req.bytecount;
+
+  /* No need to duplicate user+password, the connectdata struct won't change
+     during a session, but we re-init them here since on subsequent inits
+     since the conn struct may have changed or been replaced.
+  */
+  pop3->user = conn->user;
+  pop3->passwd = conn->passwd;
+
+  return CURLE_OK;
+}
+
+/*
+ * pop3_connect() should do everything that is to be considered a part of
+ * the connection phase.
+ *
+ * The variable 'done' points to will be TRUE if the protocol-layer connect
+ * phase is done when this function returns, or FALSE is not. When called as
+ * a part of the easy interface, it will always be TRUE.
+ */
+static CURLcode pop3_connect(struct connectdata *conn,
+                                 bool *done) /* see description above */
+{
+  CURLcode result;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  struct SessionHandle *data=conn->data;
+  struct pingpong *pp = &pop3c->pp;
+
+  *done = FALSE; /* default to not done yet */
+
+  /* If there already is a protocol-specific struct allocated for this
+     sessionhandle, deal with it */
+  Curl_reset_reqproto(conn);
+
+  result = pop3_init(conn);
+  if(CURLE_OK != result)
+    return result;
+
+  /* We always support persistant connections on pop3 */
+  conn->bits.close = FALSE;
+
+  pp->response_time = RESP_TIMEOUT; /* set default response time-out */
+  pp->statemach_act = pop3_statemach_act;
+  pp->endofresp = pop3_endofresp;
+  pp->conn = conn;
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY)
+  if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
+    /* for POP3 over HTTP proxy */
+    struct HTTP http_proxy;
+    struct FTP *pop3_save;
+
+    /* BLOCKING */
+    /* We want "seamless" POP3 operations through HTTP proxy tunnel */
+
+    /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
+     * conn->proto.http; we want POP3 through HTTP and we have to change the
+     * member temporarily for connecting to the HTTP proxy. After
+     * Curl_proxyCONNECT we have to set back the member to the original struct
+     * POP3 pointer
+     */
+    pop3_save = data->state.proto.pop3;
+    memset(&http_proxy, 0, sizeof(http_proxy));
+    data->state.proto.http = &http_proxy;
+
+    result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
+                               conn->host.name, conn->remote_port);
+
+    data->state.proto.pop3 = pop3_save;
+
+    if(CURLE_OK != result)
+      return result;
+  }
+#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */
+
+  if(conn->protocol & PROT_POP3S) {
+    /* BLOCKING */
+    /* POP3S is simply pop3 with SSL for the control channel */
+    /* now, perform the SSL initialization for this socket */
+    result = Curl_ssl_connect(conn, FIRSTSOCKET);
+    if(result)
+      return result;
+  }
+
+  Curl_pp_init(pp); /* init the response reader stuff */
+
+  /* When we connect, we start in the state where we await the server greet
+     response */
+  state(conn, POP3_SERVERGREET);
+
+  if(data->state.used_interface == Curl_if_multi)
+    result = pop3_multi_statemach(conn, done);
+  else {
+    result = pop3_easy_statemach(conn);
+    if(!result)
+      *done = TRUE;
+  }
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_done()
+ *
+ * The DONE function. This does what needs to be done after a single DO has
+ * performed.
+ *
+ * Input argument is already checked for validity.
+ */
+static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
+                          bool premature)
+{
+  struct SessionHandle *data = conn->data;
+  struct FTP *pop3 = data->state.proto.pop3;
+  CURLcode result=CURLE_OK;
+  (void)premature;
+
+  if(!pop3)
+    /* When the easy handle is removed from the multi while libcurl is still
+     * trying to resolve the host name, it seems that the pop3 struct is not
+     * yet initialized, but the removal action calls Curl_done() which calls
+     * this function. So we simply return success if no pop3 pointer is set.
+     */
+    return CURLE_OK;
+
+  if(status) {
+    conn->bits.close = TRUE; /* marked for closure */
+    result = status;      /* use the already set error code */
+  }
+
+  /* clear these for next connection */
+  pop3->transfer = FTPTRANSFER_BODY;
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform()
+ *
+ * This is the actual DO function for POP3. Get a file/directory according to
+ * the options previously setup.
+ */
+
+static
+CURLcode pop3_perform(struct connectdata *conn,
+                     bool *connected,  /* connect status after PASV / PORT */
+                     bool *dophase_done)
+{
+  /* this is POP3 and no proxy */
+  CURLcode result=CURLE_OK;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+
+  DEBUGF(infof(conn->data, "DO phase starts\n"));
+
+  if(conn->data->set.opt_no_body) {
+    /* requested no body means no transfer... */
+    struct FTP *pop3 = conn->data->state.proto.pop3;
+    pop3->transfer = FTPTRANSFER_INFO;
+  }
+
+  *dophase_done = FALSE; /* not done yet */
+
+  /* start the first command in the DO phase */
+  /* If mailbox is empty, then assume user wants listing for mail IDs,
+   * otherwise, attempt to retrieve the mail-id stored in mailbox
+   */
+  if (strlen(pop3c->mailbox))
+    result = pop3_retr(conn);
+  else
+    result = pop3_list(conn);
+  if(result)
+    return result;
+
+  /* run the state-machine */
+  if(conn->data->state.used_interface == Curl_if_multi)
+    result = pop3_multi_statemach(conn, dophase_done);
+  else {
+    result = pop3_easy_statemach(conn);
+    *dophase_done = TRUE; /* with the easy interface we are done here */
+  }
+  *connected = conn->bits.tcpconnect;
+
+  if(*dophase_done)
+    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_do()
+ *
+ * This function is registered as 'curl_do' function. It decodes the path
+ * parts etc as a wrapper to the actual DO function (pop3_perform).
+ *
+ * The input argument is already checked for validity.
+ */
+static CURLcode pop3_do(struct connectdata *conn, bool *done)
+{
+  CURLcode retcode = CURLE_OK;
+
+  *done = FALSE; /* default to false */
+
+  /*
+    Since connections can be re-used between SessionHandles, this might be a
+    connection already existing but on a fresh SessionHandle struct so we must
+    make sure we have a good 'struct POP3' to play with. For new connections,
+    the struct POP3 is allocated and setup in the pop3_connect() function.
+  */
+  Curl_reset_reqproto(conn);
+  retcode = pop3_init(conn);
+  if(retcode)
+    return retcode;
+
+  retcode = pop3_parse_url_path(conn);
+  if(retcode)
+    return retcode;
+
+  retcode = pop3_regular_transfer(conn, done);
+
+  return retcode;
+}
+
+/***********************************************************************
+ *
+ * pop3_quit()
+ *
+ * This should be called before calling sclose().  We should then wait for the
+ * response from the server before returning. The calling code should then try
+ * to close the connection.
+ *
+ */
+static CURLcode pop3_quit(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+
+  result = Curl_pp_sendf(&conn->proto.pop3c.pp, "QUIT", NULL);
+  if(result)
+    return result;
+  state(conn, POP3_QUIT);
+
+  result = pop3_easy_statemach(conn);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_disconnect()
+ *
+ * Disconnect from an POP3 server. Cleanup protocol-specific per-connection
+ * resources. BLOCKING.
+ */
+static CURLcode pop3_disconnect(struct connectdata *conn)
+{
+  struct pop3_conn *pop3c= &conn->proto.pop3c;
+
+  /* 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.
+  */
+
+  /* The POP3 session may or may not have been allocated/setup at this
+     point! */
+  (void)pop3_quit(conn); /* ignore errors on the LOGOUT */
+
+
+  Curl_pp_disconnect(&pop3c->pp);
+
+  return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * pop3_parse_url_path()
+ *
+ * Parse the URL path into separate path components.
+ *
+ */
+static CURLcode pop3_parse_url_path(struct connectdata *conn)
+{
+  /* the pop3 struct is already inited in pop3_connect() */
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  struct SessionHandle *data = conn->data;
+  const char *path = data->state.path;
+  int len;
+
+  /* url decode the path and use this mailbox */
+  pop3c->mailbox = curl_easy_unescape(data, path, 0, &len);
+
+  return CURLE_OK;
+}
+
+/* call this when the DO phase has completed */
+static CURLcode pop3_dophase_done(struct connectdata *conn,
+                                  bool connected)
+{
+  CURLcode result = CURLE_OK;
+  struct FTP *pop3 = conn->data->state.proto.pop3;
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+ (void)connected;
+
+  if(pop3->transfer != FTPTRANSFER_BODY)
+    /* no data to transfer */
+    result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+
+  free(pop3c->mailbox);
+
+  return result;
+}
+
+/* called from multi.c while DOing */
+static CURLcode pop3_doing(struct connectdata *conn,
+                               bool *dophase_done)
+{
+  CURLcode result;
+  result = pop3_multi_statemach(conn, dophase_done);
+
+  if(*dophase_done) {
+    result = pop3_dophase_done(conn, FALSE /* not connected */);
+
+    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+  }
+  return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_regular_transfer()
+ *
+ * The input argument is already checked for validity.
+ *
+ * Performs all commands done before a regular transfer between a local and a
+ * remote host.
+ *
+ */
+static
+CURLcode pop3_regular_transfer(struct connectdata *conn,
+                              bool *dophase_done)
+{
+  CURLcode result=CURLE_OK;
+  bool connected=FALSE;
+  struct SessionHandle *data = conn->data;
+  data->req.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);
+
+  result = pop3_perform(conn,
+                        &connected, /* have we connected after PASV/PORT */
+                        dophase_done); /* all commands in the DO-phase done? */
+
+  if(CURLE_OK == result) {
+
+    if(!*dophase_done)
+      /* the DO phase has not completed yet */
+      return CURLE_OK;
+
+    result = pop3_dophase_done(conn, connected);
+    if(result)
+      return result;
+  }
+
+  return result;
+}
+
+static CURLcode pop3_setup_connection(struct connectdata * conn)
+{
+  struct SessionHandle *data = conn->data;
+
+  if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
+    /* Unless we have asked to tunnel pop3 operations through the proxy, we
+       switch and use HTTP operations only */
+#ifndef CURL_DISABLE_HTTP
+    if(conn->handler == &Curl_handler_pop3)
+      conn->handler = &Curl_handler_pop3_proxy;
+    else {
+#ifdef USE_SSL
+      conn->handler = &Curl_handler_pop3s_proxy;
+#else
+      failf(data, "POP3S not supported!");
+      return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+    }
+    /*
+     * We explicitly mark this connection as persistent here as we're doing
+     * POP3 over HTTP and thus we accidentally avoid setting this value
+     * otherwise.
+     */
+    conn->bits.close = FALSE;
+#else
+    failf(data, "POP3 over http proxy requires HTTP support built-in!");
+    return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+  }
+
+  data->state.path++;   /* don't include the initial slash */
+
+  return CURLE_OK;
+}
+
+/* this is the 5-bytes End-Of-Body marker for POP3 */
+#define POP3_EOB "\x0d\x0a\x2e\x0d\x0a"
+#define POP3_EOB_LEN 5
+
+/*
+ * This function scans the body after the end-of-body and writes everything
+ * until the end is found.
+ */
+CURLcode Curl_pop3_write(struct connectdata *conn,
+                         char *str,
+                         size_t nread)
+{
+  /* This code could be made into a special function in the handler struct. */
+  CURLcode result;
+  struct SessionHandle *data = conn->data;
+  struct SingleRequest *k = &data->req;
+
+  /* Detect the end-of-body marker, which is 5 bytes:
+     0d 0a 2e 0d 0a. This marker can of course be spread out
+     over up to 5 different data chunks. Deal with it! */
+  struct pop3_conn *pop3c = &conn->proto.pop3c;
+  size_t checkmax = (nread >= POP3_EOB_LEN?POP3_EOB_LEN:nread);
+  size_t checkleft = POP3_EOB_LEN-pop3c->eob;
+  size_t check = (checkmax >= checkleft?checkleft:checkmax);
+
+  if(!memcmp(POP3_EOB, &str[nread - check], check)) {
+    /* substring match */
+    pop3c->eob += check;
+    if(pop3c->eob == POP3_EOB_LEN) {
+      /* full match, the transfer is done! */
+      str[nread - check] = '\0';
+      nread -= check;
+      k->keepon &= ~KEEP_RECV;
+      pop3c->eob = 0;
+    }
+  }
+  else if(pop3c->eob) {
+    /* not a match, but we matched a piece before so we must now
+       send that part as body first, before we move on and send
+       this buffer */
+    result = Curl_client_write(conn, CLIENTWRITE_BODY,
+                               (char *)POP3_EOB, pop3c->eob);
+    if(result)
+      return result;
+    pop3c->eob = 0;
+  }
+
+  result = Curl_client_write(conn, CLIENTWRITE_BODY, str, nread);
+
+  return result;
+}
+
+#endif /* CURL_DISABLE_POP3 */
diff --git a/lib/pop3.h b/lib/pop3.h
new file mode 100644
index 0000000..337421c
--- /dev/null
+++ b/lib/pop3.h
@@ -0,0 +1,62 @@
+#ifndef __POP3_H
+#define __POP3_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2009, 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.
+ *
+ ***************************************************************************/
+
+/****************************************************************************
+ * POP3 unique setup
+ ***************************************************************************/
+typedef enum {
+  POP3_STOP,        /* do nothing state, stops the state machine */
+  POP3_SERVERGREET, /* waiting for the initial greeting immediately after
+                       a connect */
+  POP3_USER,
+  POP3_PASS,
+  POP3_STARTTLS,
+  POP3_LIST,
+  POP3_RETR,
+  POP3_QUIT,
+  POP3_LAST  /* never used */
+} pop3state;
+
+/* pop3_conn is used for struct connection-oriented data in the connectdata
+   struct */
+struct pop3_conn {
+  struct pingpong pp;
+  char *mailbox;     /* what to RETR */
+  size_t eob;        /* number of bytes of the EOB (End Of Body) that has been
+                        received thus far */
+  pop3state state; /* always use pop3.c:state() to change state! */
+};
+
+extern const struct Curl_handler Curl_handler_pop3;
+extern const struct Curl_handler Curl_handler_pop3s;
+
+/*
+ * This function scans the body after the end-of-body and writes everything
+ * until the end is found.
+ */
+CURLcode Curl_pop3_write(struct connectdata *conn,
+                         char *str,
+                         size_t nread);
+
+#endif /* __POP3_H */
diff --git a/lib/progress.c b/lib/progress.c
new file mode 100644
index 0000000..e0758f2
--- /dev/null
+++ b/lib/progress.c
@@ -0,0 +1,448 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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 "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, curl_off_t seconds)
+{
+  curl_off_t d, h, m, s;
+  if(seconds <= 0) {
+    strcpy(r, "--:--:--");
+    return;
+  }
+  h = seconds / CURL_OFF_T_C(3600);
+  if(h <= CURL_OFF_T_C(99)) {
+    m = (seconds - (h*CURL_OFF_T_C(3600))) / CURL_OFF_T_C(60);
+    s = (seconds - (h*CURL_OFF_T_C(3600))) - (m*CURL_OFF_T_C(60));
+    snprintf(r, 9, "%2" FORMAT_OFF_T ":%02" FORMAT_OFF_T ":%02" FORMAT_OFF_T,
+             h, m, s);
+  }
+  else {
+    /* this equals to more than 99 hours, switch to a more suitable output
+       format to fit within the limits. */
+    d = seconds / CURL_OFF_T_C(86400);
+    h = (seconds - (d*CURL_OFF_T_C(86400))) / CURL_OFF_T_C(3600);
+    if(d <= CURL_OFF_T_C(999))
+      snprintf(r, 9, "%3" FORMAT_OFF_T "d %02" FORMAT_OFF_T "h", d, h);
+    else
+      snprintf(r, 9, "%7" FORMAT_OFF_T "d", d);
+  }
+}
+
+/* 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  CURL_OFF_T_C(1024)
+#define ONE_MEGABYTE (CURL_OFF_T_C(1024) * ONE_KILOBYTE)
+#define ONE_GIGABYTE (CURL_OFF_T_C(1024) * ONE_MEGABYTE)
+#define ONE_TERABYTE (CURL_OFF_T_C(1024) * ONE_GIGABYTE)
+#define ONE_PETABYTE (CURL_OFF_T_C(1024) * ONE_TERABYTE)
+
+  if(bytes < CURL_OFF_T_C(100000))
+    snprintf(max5, 6, "%5" FORMAT_OFF_T, bytes);
+
+  else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE)
+    snprintf(max5, 6, "%4" FORMAT_OFF_T "k", bytes/ONE_KILOBYTE);
+
+  else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE)
+    /* 'XX.XM' is good as long as we're less than 100 megs */
+    snprintf(max5, 6, "%2" FORMAT_OFF_T ".%0" FORMAT_OFF_T "M",
+              bytes/ONE_MEGABYTE,
+             (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) );
+
+#if (CURL_SIZEOF_CURL_OFF_T > 4)
+
+  else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE)
+    /* 'XXXXM' is good until we're at 10000MB or above */
+    snprintf(max5, 6, "%4" FORMAT_OFF_T "M", bytes/ONE_MEGABYTE);
+
+  else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE)
+    /* 10000 MB - 100 GB, we show it as XX.XG */
+    snprintf(max5, 6, "%2" FORMAT_OFF_T ".%0" FORMAT_OFF_T "G",
+              bytes/ONE_GIGABYTE,
+             (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) );
+
+  else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE)
+    /* up to 10000GB, display without decimal: XXXXG */
+    snprintf(max5, 6, "%4" FORMAT_OFF_T "G", bytes/ONE_GIGABYTE);
+
+  else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE)
+    /* up to 10000TB, display without decimal: XXXXT */
+    snprintf(max5, 6, "%4" FORMAT_OFF_T "T", bytes/ONE_TERABYTE);
+
+  else
+    /* up to 10000PB, display without decimal: XXXXP */
+    snprintf(max5, 6, "%4" FORMAT_OFF_T "P", bytes/ONE_PETABYTE);
+
+    /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number
+       can hold, but our data type is signed so 8192PB will be the maximum. */
+
+#else
+
+  else
+    snprintf(max5, 6, "%4" FORMAT_OFF_T "M", 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 */
+
+  data->progress.speeder_c = 0; /* reset the progress meter display */
+}
+
+/* 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_APPCONNECT:
+    data->progress.t_appconnect =
+      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];
+  curl_off_t dlpercen=0;
+  curl_off_t ulpercen=0;
+  curl_off_t total_percen=0;
+  curl_off_t total_transfer;
+  curl_off_t total_expected_transfer;
+  curl_off_t 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];
+  curl_off_t ulestimate=0;
+  curl_off_t dlestimate=0;
+  curl_off_t total_estimate;
+  bool shownow=FALSE;
+
+  now = Curl_tvnow(); /* what time is it */
+
+  /* The time spent so far (from the start) */
+  data->progress.timespent =
+    (double)(now.tv_sec - data->progress.start.tv_sec) +
+    (double)(now.tv_usec - data->progress.start.tv_usec)/1000000.0;
+  timespent = (curl_off_t)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));
+
+  /* Calculations done at most once a second, unless end is reached */
+  if(data->progress.lastshow != (long)now.tv_sec) {
+    shownow = TRUE;
+
+    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 faster 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 > CURL_OFF_T_C(4294967) /* 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*CURL_OFF_T_C(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;
+
+  } /* Calculations end */
+
+  if(!(data->progress.flags & PGRS_HIDE)) {
+
+    /* progress meter has not been shut off */
+
+    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;
+    }
+
+    if(!shownow)
+      /* only show the internal progress meter once per second */
+      return 0;
+
+    /* If there's no external callback set, use internal code to show
+       progress */
+
+    if(!(data->progress.flags & PGRS_HEADERS_OUT)) {
+      if(data->state.resume_from) {
+        fprintf(data->set.err,
+                "** Resuming transfer from byte position %" FORMAT_OFF_T "\n",
+                data->state.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 */
+    }
+
+    /* Figure out the estimated time of arrival for the upload */
+    if((data->progress.flags & PGRS_UL_SIZE_KNOWN) &&
+       (data->progress.ulspeed > CURL_OFF_T_C(0))) {
+      ulestimate = data->progress.size_ul / data->progress.ulspeed;
+
+      if(data->progress.size_ul > CURL_OFF_T_C(10000))
+        ulpercen = data->progress.uploaded /
+          (data->progress.size_ul/CURL_OFF_T_C(100));
+      else if(data->progress.size_ul > CURL_OFF_T_C(0))
+        ulpercen = (data->progress.uploaded*100) /
+          data->progress.size_ul;
+    }
+
+    /* ... and the download */
+    if((data->progress.flags & PGRS_DL_SIZE_KNOWN) &&
+       (data->progress.dlspeed > CURL_OFF_T_C(0))) {
+      dlestimate = data->progress.size_dl / data->progress.dlspeed;
+
+      if(data->progress.size_dl > CURL_OFF_T_C(10000))
+        dlpercen = data->progress.downloaded /
+          (data->progress.size_dl/CURL_OFF_T_C(100));
+      else if(data->progress.size_dl > CURL_OFF_T_C(0))
+        dlpercen = (data->progress.downloaded*100) /
+          data->progress.size_dl;
+    }
+
+    /* Now figure out which of them is slower and use that one for the
+       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 > CURL_OFF_T_C(10000))
+      total_percen = total_transfer /
+        (total_expected_transfer/CURL_OFF_T_C(100));
+    else if(total_expected_transfer > CURL_OFF_T_C(0))
+      total_percen = (total_transfer*100) / total_expected_transfer;
+
+    fprintf(data->set.err,
+            "\r"
+            "%3" FORMAT_OFF_T " %s  "
+            "%3" FORMAT_OFF_T " %s  "
+            "%3" FORMAT_OFF_T " %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);
+
+  } /* !(data->progress.flags & PGRS_HIDE) */
+
+  return 0;
+}
diff --git a/lib/progress.h b/lib/progress.h
new file mode 100644
index 0000000..95944f0
--- /dev/null
+++ b/lib/progress.h
@@ -0,0 +1,70 @@
+#ifndef __PROGRESS_H
+#define __PROGRESS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2008, 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 "timeval.h"
+
+
+typedef enum {
+  TIMER_NONE,
+  TIMER_NAMELOOKUP,
+  TIMER_CONNECT,
+  TIMER_APPCONNECT,
+  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/lib/qssl.c b/lib/qssl.c
new file mode 100644
index 0000000..5a08a25
--- /dev/null
+++ b/lib/qssl.c
@@ -0,0 +1,497 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+#ifdef USE_QSOSSL
+#include <qsossl.h>
+#include <errno.h>
+#include <string.h>
+#ifdef HAVE_LIMITS_H
+#  include <limits.h>
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "qssl.h"
+#include "sslgen.h"
+#include "connect.h" /* for the connect timeout */
+#include "select.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+
+int Curl_qsossl_init(void)
+
+{
+  /* Nothing to do here. We must have connection data to initialize ssl, so
+   * defer.
+   */
+
+  return 1;
+}
+
+
+void Curl_qsossl_cleanup(void)
+
+{
+  /* Nothing to do. */
+}
+
+
+static CURLcode Curl_qsossl_init_session(struct SessionHandle * data)
+
+{
+  int rc;
+  char * certname;
+  SSLInit initstr;
+  SSLInitApp initappstr;
+
+  /* Initialize the job for SSL according to the current parameters.
+   * QsoSSL offers two ways to do it: SSL_Init_Application() that uses an
+   *  application identifier to select certificates in the main certificate
+   *  store, and SSL_Init() that uses named keyring files and a password.
+   * It is not possible to have different keyrings for the CAs and the
+   *  local certificate. We thus use the certificate name to identify the
+   *  keyring if given, else the CA file name.
+   * If the key file name is given, it is taken as the password for the
+   *  keyring in certificate file.
+   * We first try to SSL_Init_Application(), then SSL_Init() if it failed.
+   */
+
+  certname = data->set.str[STRING_CERT];
+
+  if(!certname) {
+    certname = data->set.str[STRING_SSL_CAFILE];
+
+    if(!certname)
+      return CURLE_OK;          /* Use previous setup. */
+    }
+
+  memset((char *) &initappstr, 0, sizeof initappstr);
+  initappstr.applicationID = certname;
+  initappstr.applicationIDLen = strlen(certname);
+  initappstr.protocol = SSL_VERSION_CURRENT;    /* TLSV1 compat. SSLV[23]. */
+  initappstr.sessionType = SSL_REGISTERED_AS_CLIENT;
+  rc = SSL_Init_Application(&initappstr);
+
+  if(rc == SSL_ERROR_NOT_REGISTERED) {
+    initstr.keyringFileName = certname;
+    initstr.keyringPassword = data->set.str[STRING_KEY];
+    initstr.cipherSuiteList = NULL;    /* Use default. */
+    initstr.cipherSuiteListLen = 0;
+    rc = SSL_Init(&initstr);
+    }
+
+  switch (rc) {
+
+  case 0:                             /* No error. */
+    break;
+
+  case SSL_ERROR_IO:
+    failf(data, "SSL_Init() I/O error: %s", strerror(errno));
+    return CURLE_SSL_CONNECT_ERROR;
+
+  case SSL_ERROR_BAD_CIPHER_SUITE:
+    return CURLE_SSL_CIPHER;
+
+  case SSL_ERROR_KEYPASSWORD_EXPIRED:
+  case SSL_ERROR_NOT_REGISTERED:
+    return CURLE_SSL_CONNECT_ERROR;
+
+  case SSL_ERROR_NO_KEYRING:
+    return CURLE_SSL_CACERT;
+
+  case SSL_ERROR_CERT_EXPIRED:
+    return CURLE_SSL_CERTPROBLEM;
+
+  default:
+    failf(data, "SSL_Init(): %s", SSL_Strerror(rc, NULL));
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  return CURLE_OK;
+}
+
+
+static CURLcode Curl_qsossl_create(struct connectdata * conn, int sockindex)
+
+{
+  SSLHandle * h;
+  struct ssl_connect_data * connssl = &conn->ssl[sockindex];
+
+  h = SSL_Create(conn->sock[sockindex], SSL_ENCRYPT);
+
+  if(!h) {
+    failf(conn->data, "SSL_Create() I/O error: %s", strerror(errno));
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  connssl->handle = h;
+  return CURLE_OK;
+}
+
+
+static int Curl_qsossl_trap_cert(SSLHandle * h)
+
+{
+  return 1;       /* Accept certificate. */
+}
+
+
+static CURLcode Curl_qsossl_handshake(struct connectdata * conn, int sockindex)
+
+{
+  int rc;
+  struct SessionHandle * data = conn->data;
+  struct ssl_connect_data * connssl = &conn->ssl[sockindex];
+  SSLHandle * h = connssl->handle;
+  long timeout_ms;
+
+  h->exitPgm = NULL;
+
+  if(!data->set.ssl.verifyhost)
+    h->exitPgm = Curl_qsossl_trap_cert;
+
+  /* figure out how long time we should wait at maximum */
+  timeout_ms = Curl_timeleft(conn, NULL, TRUE);
+
+  if(timeout_ms < 0) {
+    /* time-out, bail out, go home */
+    failf(data, "Connection time-out");
+    return CURLE_OPERATION_TIMEDOUT;
+  }
+
+  /* SSL_Handshake() timeout resolution is second, so round up. */
+  h->timeout = (timeout_ms + 1000 - 1) / 1000;
+
+  /* Set-up protocol. */
+
+  switch (data->set.ssl.version) {
+
+  default:
+  case CURL_SSLVERSION_DEFAULT:
+    h->protocol = SSL_VERSION_CURRENT;          /* TLSV1 compat. SSLV[23]. */
+    break;
+
+  case CURL_SSLVERSION_TLSv1:
+    h->protocol = TLS_VERSION_1;
+    break;
+
+  case CURL_SSLVERSION_SSLv2:
+    h->protocol = SSL_VERSION_2;
+    break;
+
+  case CURL_SSLVERSION_SSLv3:
+    h->protocol = SSL_VERSION_3;
+    break;
+  }
+
+  rc = SSL_Handshake(h, SSL_HANDSHAKE_AS_CLIENT);
+
+  switch (rc) {
+
+  case 0:                             /* No error. */
+    break;
+
+  case SSL_ERROR_BAD_CERTIFICATE:
+  case SSL_ERROR_BAD_CERT_SIG:
+  case SSL_ERROR_NOT_TRUSTED_ROOT:
+    return CURLE_PEER_FAILED_VERIFICATION;
+
+  case SSL_ERROR_BAD_CIPHER_SUITE:
+  case SSL_ERROR_NO_CIPHERS:
+    return CURLE_SSL_CIPHER;
+
+  case SSL_ERROR_CERTIFICATE_REJECTED:
+  case SSL_ERROR_CERT_EXPIRED:
+  case SSL_ERROR_NO_CERTIFICATE:
+    return CURLE_SSL_CERTPROBLEM;
+
+  case SSL_ERROR_IO:
+    failf(data, "SSL_Handshake() I/O error: %s", strerror(errno));
+    return CURLE_SSL_CONNECT_ERROR;
+
+  default:
+    failf(data, "SSL_Handshake(): %s", SSL_Strerror(rc, NULL));
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  return CURLE_OK;
+}
+
+
+CURLcode Curl_qsossl_connect(struct connectdata * conn, int sockindex)
+
+{
+  struct SessionHandle * data = conn->data;
+  struct ssl_connect_data * connssl = &conn->ssl[sockindex];
+  int rc;
+
+  rc = Curl_qsossl_init_session(data);
+
+  if(rc == CURLE_OK) {
+    rc = Curl_qsossl_create(conn, sockindex);
+
+    if(rc == CURLE_OK)
+      rc = Curl_qsossl_handshake(conn, sockindex);
+    else {
+      SSL_Destroy(connssl->handle);
+      connssl->handle = NULL;
+      connssl->use = FALSE;
+      connssl->state = ssl_connection_none;
+    }
+  }
+  if (rc == CURLE_OK)
+    connssl->state = ssl_connection_complete;
+
+  return rc;
+}
+
+
+static int Curl_qsossl_close_one(struct ssl_connect_data * conn,
+                                 struct SessionHandle * data)
+
+{
+  int rc;
+
+  if(!conn->handle)
+    return 0;
+
+  rc = SSL_Destroy(conn->handle);
+
+  if(rc) {
+    if(rc == SSL_ERROR_IO) {
+      failf(data, "SSL_Destroy() I/O error: %s", strerror(errno));
+      return -1;
+    }
+
+    /* An SSL error. */
+    failf(data, "SSL_Destroy() returned error %s", SSL_Strerror(rc, NULL));
+    return -1;
+  }
+
+  conn->handle = NULL;
+  return 0;
+}
+
+
+void Curl_qsossl_close(struct connectdata *conn, int sockindex)
+
+{
+  struct SessionHandle *data = conn->data;
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+  if(connssl->use)
+    (void) Curl_qsossl_close_one(connssl, data);
+}
+
+
+int Curl_qsossl_close_all(struct SessionHandle * data)
+
+{
+  /* Unimplemented. */
+  (void) data;
+  return 0;
+}
+
+
+int Curl_qsossl_shutdown(struct connectdata * conn, int sockindex)
+
+{
+  struct ssl_connect_data * connssl = &conn->ssl[sockindex];
+  struct SessionHandle *data = conn->data;
+  ssize_t nread;
+  int what;
+  int rc;
+  char buf[120];
+
+  if(!connssl->handle)
+    return 0;
+
+  if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
+    return 0;
+
+  if(Curl_qsossl_close_one(connssl, data))
+    return -1;
+
+  rc = 0;
+
+  what = Curl_socket_ready(conn->sock[sockindex],
+                           CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
+
+  for (;;) {
+    if(what < 0) {
+      /* anything that gets here is fatally bad */
+      failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+      rc = -1;
+      break;
+    }
+
+    if(!what) {                                /* timeout */
+      failf(data, "SSL shutdown timeout");
+      break;
+    }
+
+    /* Something to read, let's do it and hope that it is the close
+       notify alert from the server. No way to SSL_Read now, so use read(). */
+
+    nread = read(conn->sock[sockindex], buf, sizeof(buf));
+
+    if(nread < 0) {
+      failf(data, "read: %s", strerror(errno));
+      rc = -1;
+    }
+
+    if(nread <= 0)
+      break;
+
+    what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0);
+  }
+
+  return rc;
+}
+
+
+/* for documentation see Curl_ssl_send() in sslgen.h */
+ssize_t Curl_qsossl_send(struct connectdata * conn, int sockindex,
+                         const void * mem, size_t len, int * curlcode)
+
+{
+  /* SSL_Write() is said to return 'int' while write() and send() returns
+     'size_t' */
+  int rc;
+
+  rc = SSL_Write(conn->ssl[sockindex].handle, (void *) mem, (int) len);
+
+  if(rc < 0) {
+    switch(rc) {
+
+    case SSL_ERROR_BAD_STATE:
+      /* The operation did not complete; the same SSL I/O function
+         should be called again later. This is basicly an EWOULDBLOCK
+         equivalent. */
+      *curlcode = -1; /* EWOULDBLOCK */
+      return -1;
+
+    case SSL_ERROR_IO:
+      switch (errno) {
+      case EWOULDBLOCK:
+      case EINTR:
+        *curlcode = -1; /* EWOULDBLOCK */
+        return -1;
+        }
+
+      failf(conn->data, "SSL_Write() I/O error: %s", strerror(errno));
+      *curlcode = CURLE_SEND_ERROR;
+      return -1;
+    }
+
+    /* An SSL error. */
+    failf(conn->data, "SSL_Write() returned error %s",
+          SSL_Strerror(rc, NULL));
+    *curlcode = CURLE_SEND_ERROR;
+    return -1;
+  }
+
+  return (ssize_t) rc; /* number of bytes */
+}
+
+
+/* for documentation see Curl_ssl_recv() in sslgen.h */
+ssize_t Curl_qsossl_recv(struct connectdata * conn, int num, char * buf,
+                         size_t buffersize, int * curlcode)
+
+{
+  char error_buffer[120]; /* OpenSSL documents that this must be at
+                             least 120 bytes long. */
+  unsigned long sslerror;
+  int buffsize;
+  int nread;
+
+  buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
+  nread = SSL_Read(conn->ssl[num].handle, buf, buffsize);
+
+  if(nread < 0) {
+    /* failed SSL_read */
+
+    switch (nread) {
+
+    case SSL_ERROR_BAD_STATE:
+      /* there's data pending, re-invoke SSL_Read(). */
+      *curlcode = -1; /* EWOULDBLOCK */
+      return -1;
+
+    case SSL_ERROR_IO:
+      switch (errno) {
+      case EWOULDBLOCK:
+        *curlcode = -1; /* EWOULDBLOCK */
+        return -1;
+        }
+
+      failf(conn->data, "SSL_Read() I/O error: %s", strerror(errno));
+      *curlcode = CURLE_RECV_ERROR;
+      return -1;
+
+    default:
+      failf(conn->data, "SSL read error: %s", SSL_Strerror(nread, NULL));
+      *curlcode = CURLE_RECV_ERROR;
+      return -1;
+    }
+  }
+  return (ssize_t) nread;
+}
+
+
+size_t Curl_qsossl_version(char * buffer, size_t size)
+
+{
+  strncpy(buffer, "IBM OS/400 SSL", size);
+  return strlen(buffer);
+}
+
+
+int Curl_qsossl_check_cxn(struct connectdata * cxn)
+
+{
+  int err;
+  int errlen;
+
+  /* The only thing that can be tested here is at the socket level. */
+
+  if(!cxn->ssl[FIRSTSOCKET].handle)
+    return 0; /* connection has been closed */
+
+  err = 0;
+  errlen = sizeof err;
+
+  if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
+                 (unsigned char *) &err, &errlen) ||
+      errlen != sizeof err || err)
+    return 0; /* connection has been closed */
+
+  return -1;  /* connection status unknown */
+}
+
+#endif /* USE_QSOSSL */
diff --git a/lib/qssl.h b/lib/qssl.h
new file mode 100644
index 0000000..a0cf8cc
--- /dev/null
+++ b/lib/qssl.h
@@ -0,0 +1,75 @@
+#ifndef __QSSL_H
+#define __QSSL_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2008, 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.
+ *
+ ***************************************************************************/
+
+/*
+ * This header should only be needed to get included by sslgen.c and qssl.c
+ */
+
+#include "urldata.h"
+
+#ifdef USE_QSOSSL
+int Curl_qsossl_init(void);
+void Curl_qsossl_cleanup(void);
+CURLcode Curl_qsossl_connect(struct connectdata * conn, int sockindex);
+void Curl_qsossl_close(struct connectdata *conn, int sockindex);
+int Curl_qsossl_close_all(struct SessionHandle * data);
+int Curl_qsossl_shutdown(struct connectdata * conn, int sockindex);
+
+/* for documentation see Curl_ssl_send() in sslgen.h */
+ssize_t Curl_qsossl_send(struct connectdata * conn,
+                         int sockindex,
+                         const void * mem,
+                         size_t len,
+                         int * curlcode);
+
+/* for documentation see Curl_ssl_recv() in sslgen.h */
+ssize_t Curl_qsossl_recv(struct connectdata * conn, /* connection data */
+                         int num,                   /* socketindex */
+                         char * buf,                /* store read data here */
+                         size_t buffersize,         /* max amount to read */
+                         int * curlcode);
+
+size_t Curl_qsossl_version(char * buffer, size_t size);
+int Curl_qsossl_check_cxn(struct connectdata * cxn);
+
+/* API setup for QsoSSL */
+#define curlssl_init Curl_qsossl_init
+#define curlssl_cleanup Curl_qsossl_cleanup
+#define curlssl_connect Curl_qsossl_connect
+
+/*  No session handling for QsoSSL */
+#define curlssl_session_free(x)
+#define curlssl_close_all Curl_qsossl_close_all
+#define curlssl_close Curl_qsossl_close
+#define curlssl_shutdown(x,y) Curl_qsossl_shutdown(x,y)
+#define curlssl_set_engine(x,y) CURLE_FAILED_INIT
+#define curlssl_set_engine_default(x) CURLE_FAILED_INIT
+#define curlssl_engines_list(x) NULL
+#define curlssl_send Curl_qsossl_send
+#define curlssl_recv Curl_qsossl_recv
+#define curlssl_version Curl_qsossl_version
+#define curlssl_check_cxn(x) Curl_qsossl_check_cxn(x)
+#define curlssl_data_pending(x,y) 0
+#endif /* USE_QSOSSL */
+#endif
diff --git a/lib/rawstr.c b/lib/rawstr.c
new file mode 100644
index 0000000..f3b302d
--- /dev/null
+++ b/lib/rawstr.c
@@ -0,0 +1,142 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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 "rawstr.h"
+
+/* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because
+   its behavior is altered by the current locale. */
+char Curl_raw_toupper(char in)
+{
+  switch (in) {
+  case 'a':
+    return 'A';
+  case 'b':
+    return 'B';
+  case 'c':
+    return 'C';
+  case 'd':
+    return 'D';
+  case 'e':
+    return 'E';
+  case 'f':
+    return 'F';
+  case 'g':
+    return 'G';
+  case 'h':
+    return 'H';
+  case 'i':
+    return 'I';
+  case 'j':
+    return 'J';
+  case 'k':
+    return 'K';
+  case 'l':
+    return 'L';
+  case 'm':
+    return 'M';
+  case 'n':
+    return 'N';
+  case 'o':
+    return 'O';
+  case 'p':
+    return 'P';
+  case 'q':
+    return 'Q';
+  case 'r':
+    return 'R';
+  case 's':
+    return 'S';
+  case 't':
+    return 'T';
+  case 'u':
+    return 'U';
+  case 'v':
+    return 'V';
+  case 'w':
+    return 'W';
+  case 'x':
+    return 'X';
+  case 'y':
+    return 'Y';
+  case 'z':
+    return 'Z';
+  }
+  return in;
+}
+
+/*
+ * Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant
+ * to be locale independent and only compare strings we know are safe for
+ * this.  See http://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for
+ * some further explanation to why this function is necessary.
+ *
+ * The function is capable of comparing a-z case insensitively even for
+ * non-ascii.
+ */
+
+int Curl_raw_equal(const char *first, const char *second)
+{
+  while(*first && *second) {
+    if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
+      /* get out of the loop as soon as they don't match */
+      break;
+    first++;
+    second++;
+  }
+  /* we do the comparison here (possibly again), just to make sure that if the
+     loop above is skipped because one of the strings reached zero, we must not
+     return this as a successful match */
+  return (Curl_raw_toupper(*first) == Curl_raw_toupper(*second));
+}
+
+int Curl_raw_nequal(const char *first, const char *second, size_t max)
+{
+  while(*first && *second && max) {
+    if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) {
+      break;
+    }
+    max--;
+    first++;
+    second++;
+  }
+  if(0 == max)
+    return 1; /* they are equal this far */
+
+  return Curl_raw_toupper(*first) == Curl_raw_toupper(*second);
+}
+
+/* Copy an upper case version of the string from src to dest.  The
+ * strings may overlap.  No more than n characters of the string are copied
+ * (including any NUL) and the destination string will NOT be
+ * NUL-terminated if that limit is reached.
+ */
+void Curl_strntoupper(char *dest, const char *src, size_t n)
+{
+  if (n < 1)
+    return;
+
+  do {
+    *dest++ = Curl_raw_toupper(*src);
+  } while (*src++ && --n);
+}
diff --git a/lib/rawstr.h b/lib/rawstr.h
new file mode 100644
index 0000000..7e9747a
--- /dev/null
+++ b/lib/rawstr.h
@@ -0,0 +1,44 @@
+#ifndef __RAWSTR_H
+#define __RAWSTR_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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 <curl/curl.h>
+
+/*
+ * Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant
+ * to be locale independent and only compare strings we know are safe for
+ * this.
+ *
+ * The function is capable of comparing a-z case insensitively even for non-ascii.
+ */
+int Curl_raw_equal(const char *first, const char *second);
+int Curl_raw_nequal(const char *first, const char *second, size_t max);
+
+char Curl_raw_toupper(char in);
+
+/* checkprefix() is a shorter version of the above, used when the first
+   argument is zero-byte terminated */
+#define checkprefix(a,b)    Curl_raw_nequal(a,b,strlen(a))
+
+#endif
+void Curl_strntoupper(char *dest, const char *src, size_t n);
diff --git a/lib/rtsp.c b/lib/rtsp.c
new file mode 100644
index 0000000..8cc200b
--- /dev/null
+++ b/lib/rtsp.c
@@ -0,0 +1,757 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+#ifndef CURL_DISABLE_RTSP
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "easyif.h" /* for Curl_convert_... prototypes */
+#include "multiif.h"
+#include "http.h"
+#include "url.h"
+#include "progress.h"
+#include "rtsp.h"
+#include "rawstr.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"
+
+/*
+ * TODO (general)
+ *  -incoming server requests
+ *      -server CSeq counter
+ *  -digest authentication
+ *  -connect thru proxy
+ *  -pipelining?
+ */
+
+
+#define RTP_PKT_CHANNEL(p)   ((int)((unsigned char)((p)[1])))
+
+#define RTP_PKT_LENGTH(p)  ((((int)((unsigned char)((p)[2]))) << 8) | \
+                             ((int)((unsigned char)((p)[3]))))
+
+static int rtsp_getsock_do(struct connectdata *conn,
+                           curl_socket_t *socks,
+                           int numsocks);
+
+/* this returns the socket to wait for in the DO and DOING state for the multi
+   interface and then we're always _sending_ a request and thus we wait for
+   the single socket to become writable only */
+static int rtsp_getsock_do(struct connectdata *conn,
+                           curl_socket_t *socks,
+                           int numsocks)
+{
+  /* write mode */
+  (void)numsocks; /* unused, we trust it to be at least 1 */
+  socks[0] = conn->sock[FIRSTSOCKET];
+  return GETSOCK_WRITESOCK(0);
+}
+
+static
+CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len);
+
+
+/*
+ * RTSP handler interface.
+ */
+const struct Curl_handler Curl_handler_rtsp = {
+  "RTSP",                               /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  Curl_rtsp,                            /* do_it */
+  Curl_rtsp_done,                       /* done */
+  ZERO_NULL,                            /* do_more */
+  Curl_rtsp_connect,                    /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  rtsp_getsock_do,                      /* doing_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  Curl_rtsp_disconnect,                 /* disconnect */
+  PORT_RTSP,                            /* defport */
+  PROT_RTSP,                            /* protocol */
+};
+
+CURLcode Curl_rtsp_connect(struct connectdata *conn, bool *done)
+{
+  CURLcode httpStatus;
+  struct SessionHandle *data = conn->data;
+
+  httpStatus = Curl_http_connect(conn, done);
+
+  /* Initialize the CSeq if not already done */
+  if(data->state.rtsp_next_client_CSeq == 0)
+    data->state.rtsp_next_client_CSeq = 1;
+  if(data->state.rtsp_next_server_CSeq == 0)
+    data->state.rtsp_next_server_CSeq = 1;
+
+  conn->proto.rtspc.rtp_channel = -1;
+
+  return httpStatus;
+}
+
+CURLcode Curl_rtsp_disconnect(struct connectdata *conn) {
+  Curl_safefree(conn->proto.rtspc.rtp_buf);
+  return CURLE_OK;
+}
+
+
+CURLcode Curl_rtsp_done(struct connectdata *conn,
+                        CURLcode status, bool premature)
+{
+  struct SessionHandle *data = conn->data;
+  struct RTSP *rtsp = data->state.proto.rtsp;
+  CURLcode httpStatus;
+  long CSeq_sent;
+  long CSeq_recv;
+
+  /* Bypass HTTP empty-reply checks on receive */
+  if(data->set.rtspreq == RTSPREQ_RECEIVE)
+    premature = TRUE;
+
+  httpStatus = Curl_http_done(conn, status, premature);
+
+  if(rtsp) {
+    /* Check the sequence numbers */
+    CSeq_sent = rtsp->CSeq_sent;
+    CSeq_recv = rtsp->CSeq_recv;
+    if((data->set.rtspreq != RTSPREQ_RECEIVE) && (CSeq_sent != CSeq_recv)) {
+      failf(data, "The CSeq of this request %ld did not match the response %ld",
+            CSeq_sent, CSeq_recv);
+      return CURLE_RTSP_CSEQ_ERROR;
+    }
+    else if(data->set.rtspreq == RTSPREQ_RECEIVE &&
+            (conn->proto.rtspc.rtp_channel == -1)) {
+      infof(data, "Got an RTP Receive with a CSeq of %ld\n", CSeq_recv);
+      /* TODO CPC: Server -> Client logic here */
+    }
+  }
+
+  return httpStatus;
+}
+
+CURLcode Curl_rtsp(struct connectdata *conn, bool *done)
+{
+  struct SessionHandle *data = conn->data;
+  CURLcode result=CURLE_OK;
+  Curl_RtspReq rtspreq = data->set.rtspreq;
+  struct RTSP *rtsp;
+  struct HTTP *http;
+  Curl_send_buffer *req_buffer;
+  curl_off_t postsize = 0; /* for ANNOUNCE and SET_PARAMETER */
+  curl_off_t putsize = 0; /* for ANNOUNCE and SET_PARAMETER */
+
+  const char *p_request = NULL;
+  const char *p_session_id = NULL;
+  const char *p_accept = NULL;
+  const char *p_accept_encoding = NULL;
+  const char *p_range = NULL;
+  const char *p_referrer = NULL;
+  const char *p_stream_uri = NULL;
+  const char *p_transport = NULL;
+  const char *p_uagent = NULL;
+
+  *done = TRUE;
+
+  Curl_reset_reqproto(conn);
+
+  if(!data->state.proto.rtsp) {
+    /* Only allocate this struct if we don't already have it! */
+
+    rtsp = calloc(1, sizeof(struct RTSP));
+    if(!rtsp)
+      return CURLE_OUT_OF_MEMORY;
+    data->state.proto.rtsp = rtsp;
+  }
+  else {
+    rtsp = data->state.proto.rtsp;
+  }
+
+  http = &(rtsp->http_wrapper);
+  /* Assert that no one has changed the RTSP struct in an evil way */
+  DEBUGASSERT((void *)http == (void *)rtsp);
+
+  rtsp->CSeq_sent = data->state.rtsp_next_client_CSeq;
+  rtsp->CSeq_recv = 0;
+
+  /* Setup the 'p_request' pointer to the proper p_request string
+   * Since all RTSP requests are included here, there is no need to
+   * support custom requests like HTTP.
+   **/
+  DEBUGASSERT((rtspreq > RTSPREQ_NONE && rtspreq < RTSPREQ_LAST));
+  data->set.opt_no_body = TRUE; /* most requests don't contain a body */
+  switch(rtspreq) {
+  case RTSPREQ_NONE:
+    failf(data, "Got invalid RTSP request: RTSPREQ_NONE");
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  case RTSPREQ_OPTIONS:
+    p_request = "OPTIONS";
+    break;
+  case RTSPREQ_DESCRIBE:
+    p_request = "DESCRIBE";
+    data->set.opt_no_body = FALSE;
+    break;
+  case RTSPREQ_ANNOUNCE:
+    p_request = "ANNOUNCE";
+    break;
+  case RTSPREQ_SETUP:
+    p_request = "SETUP";
+    break;
+  case RTSPREQ_PLAY:
+    p_request = "PLAY";
+    break;
+  case RTSPREQ_PAUSE:
+    p_request = "PAUSE";
+    break;
+  case RTSPREQ_TEARDOWN:
+    p_request = "TEARDOWN";
+    break;
+  case RTSPREQ_GET_PARAMETER:
+    /* GET_PARAMETER's no_body status is determined later */
+    p_request = "GET_PARAMETER";
+    break;
+  case RTSPREQ_SET_PARAMETER:
+    p_request = "SET_PARAMETER";
+    break;
+  case RTSPREQ_RECORD:
+    p_request = "RECORD";
+    break;
+  case RTSPREQ_RECEIVE:
+    p_request = "";
+    /* Treat interleaved RTP as body*/
+    data->set.opt_no_body = FALSE;
+    break;
+  case RTSPREQ_LAST:
+    failf(data, "Got invalid RTSP request: RTSPREQ_LAST");
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+
+  if(rtspreq == RTSPREQ_RECEIVE) {
+    result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
+                                 &http->readbytecount, -1, NULL);
+
+    return result;
+  }
+
+  p_session_id = data->set.str[STRING_RTSP_SESSION_ID];
+  if(!p_session_id &&
+     (rtspreq & ~(RTSPREQ_OPTIONS | RTSPREQ_DESCRIBE | RTSPREQ_SETUP))) {
+    failf(data, "Refusing to issue an RTSP request [%s] without a session ID.",
+          p_request ? p_request : "");
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+
+  /* TODO: auth? */
+  /* TODO: proxy? */
+
+  /* Stream URI. Default to server '*' if not specified */
+  if(data->set.str[STRING_RTSP_STREAM_URI]) {
+    p_stream_uri = data->set.str[STRING_RTSP_STREAM_URI];
+  }
+  else {
+    p_stream_uri = "*";
+  }
+
+  /* Transport Header for SETUP requests */
+  p_transport = Curl_checkheaders(data, "Transport:");
+  if(rtspreq == RTSPREQ_SETUP && !p_transport) {
+    /* New Transport: setting? */
+    if(data->set.str[STRING_RTSP_TRANSPORT]) {
+      Curl_safefree(conn->allocptr.rtsp_transport);
+
+      conn->allocptr.rtsp_transport =
+        aprintf("Transport: %s\r\n",
+                data->set.str[STRING_RTSP_TRANSPORT]);
+      if(!conn->allocptr.rtsp_transport)
+        return CURLE_OUT_OF_MEMORY;
+    }
+    else {
+      failf(data,
+            "Refusing to issue an RTSP SETUP without a Transport: header.");
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    }
+
+    p_transport = conn->allocptr.rtsp_transport;
+  }
+
+  /* Accept Headers for DESCRIBE requests */
+  if(rtspreq == RTSPREQ_DESCRIBE) {
+    /* Accept Header */
+    p_accept = Curl_checkheaders(data, "Accept:")?
+      NULL:"Accept: application/sdp\r\n";
+
+    /* Accept-Encoding header */
+    if(!Curl_checkheaders(data, "Accept-Encoding:") &&
+       data->set.str[STRING_ENCODING]) {
+      Curl_safefree(conn->allocptr.accept_encoding);
+      conn->allocptr.accept_encoding =
+        aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
+
+      if(!conn->allocptr.accept_encoding)
+        return CURLE_OUT_OF_MEMORY;
+
+      p_accept_encoding = conn->allocptr.accept_encoding;
+    }
+  }
+
+  /* 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(Curl_checkheaders(data, "User-Agent:") && conn->allocptr.uagent) {
+    Curl_safefree(conn->allocptr.uagent);
+    conn->allocptr.uagent = NULL;
+  }
+  else if(!Curl_checkheaders(data, "User-Agent:") &&
+          data->set.str[STRING_USERAGENT]) {
+    p_uagent = conn->allocptr.uagent;
+  }
+
+  /* Referrer */
+  Curl_safefree(conn->allocptr.ref);
+  if(data->change.referer && !Curl_checkheaders(data, "Referer:"))
+    conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
+  else
+    conn->allocptr.ref = NULL;
+
+  p_referrer = conn->allocptr.ref;
+
+  /*
+   * Range Header
+   * Only applies to PLAY, PAUSE, RECORD
+   *
+   * Go ahead and use the Range stuff supplied for HTTP
+   */
+  if(data->state.use_range &&
+     (rtspreq  & (RTSPREQ_PLAY | RTSPREQ_PAUSE | RTSPREQ_RECORD))) {
+
+    /* Check to see if there is a range set in the custom headers */
+    if(!Curl_checkheaders(data, "Range:") && data->state.range) {
+      Curl_safefree(conn->allocptr.rangeline);
+      conn->allocptr.rangeline = aprintf("Range: %s\r\n", data->state.range);
+      p_range = conn->allocptr.rangeline;
+    }
+  }
+
+  /*
+   * Sanity check the custom headers
+   */
+  if(Curl_checkheaders(data, "CSeq:")) {
+    failf(data, "CSeq cannot be set as a custom header.");
+    return CURLE_RTSP_CSEQ_ERROR;
+  }
+  if(Curl_checkheaders(data, "Session:")) {
+    failf(data, "Session ID cannot be set as a custom header.");
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+
+  /* Initialize a dynamic send buffer */
+  req_buffer = Curl_add_buffer_init();
+
+  if(!req_buffer)
+    return CURLE_OUT_OF_MEMORY;
+
+  result =
+    Curl_add_bufferf(req_buffer,
+                     "%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */
+                     "CSeq: %ld\r\n", /* CSeq */
+                     (p_request ? p_request : ""), p_stream_uri,
+                     rtsp->CSeq_sent);
+  if(result)
+    return result;
+
+  /*
+   * Rather than do a normal alloc line, keep the session_id unformatted
+   * to make comparison easier
+   */
+  if(p_session_id) {
+    result = Curl_add_bufferf(req_buffer, "Session: %s\r\n", p_session_id);
+    if(result)
+      return result;
+  }
+
+  /*
+   * Shared HTTP-like options
+   */
+  result = Curl_add_bufferf(req_buffer,
+                            "%s" /* transport */
+                            "%s" /* accept */
+                            "%s" /* accept-encoding */
+                            "%s" /* range */
+                            "%s" /* referrer */
+                            "%s" /* user-agent */
+                            ,
+                            p_transport ? p_transport : "",
+                            p_accept ? p_accept : "",
+                            p_accept_encoding ? p_accept_encoding : "",
+                            p_range ? p_range : "",
+                            p_referrer ? p_referrer : "",
+                            p_uagent ? p_uagent : "");
+  if(result)
+    return result;
+
+  if((rtspreq == RTSPREQ_SETUP) || (rtspreq == RTSPREQ_DESCRIBE)) {
+    result = Curl_add_timecondition(data, req_buffer);
+    if(result)
+      return result;
+  }
+
+  result = Curl_add_custom_headers(conn, req_buffer);
+  if(result)
+    return result;
+
+  if(rtspreq == RTSPREQ_ANNOUNCE ||
+     rtspreq == RTSPREQ_SET_PARAMETER ||
+     rtspreq == RTSPREQ_GET_PARAMETER) {
+
+    if(data->set.upload) {
+      putsize = data->set.infilesize;
+      data->set.httpreq = HTTPREQ_PUT;
+
+    }
+    else {
+      postsize = (data->set.postfieldsize != -1)?
+        data->set.postfieldsize:
+        (data->set.postfields? (curl_off_t)strlen(data->set.postfields):0);
+      data->set.httpreq = HTTPREQ_POST;
+    }
+
+    if(putsize > 0 || postsize > 0) {
+      /* As stated in the http comments, it is probably not wise to
+       * actually set a custom Content-Length in the headers */
+      if(!Curl_checkheaders(data, "Content-Length:")) {
+        result = Curl_add_bufferf(req_buffer,
+            "Content-Length: %" FORMAT_OFF_T"\r\n",
+            (data->set.upload ? putsize : postsize));
+        if(result)
+          return result;
+      }
+
+      if(rtspreq == RTSPREQ_SET_PARAMETER ||
+         rtspreq == RTSPREQ_GET_PARAMETER) {
+        if(!Curl_checkheaders(data, "Content-Type:")) {
+          result = Curl_add_bufferf(req_buffer,
+              "Content-Type: text/parameters\r\n");
+          if(result)
+            return result;
+        }
+      }
+
+      if(rtspreq == RTSPREQ_ANNOUNCE) {
+        if(!Curl_checkheaders(data, "Content-Type:")) {
+          result = Curl_add_bufferf(req_buffer,
+              "Content-Type: application/sdp\r\n");
+          if(result)
+            return result;
+        }
+      }
+
+    data->state.expect100header = FALSE; /* RTSP posts are simple/small */
+    } else if(rtspreq == RTSPREQ_GET_PARAMETER) {
+      /* Check for an empty GET_PARAMETER (heartbeat) request */
+      data->set.httpreq = HTTPREQ_HEAD;
+      data->set.opt_no_body = TRUE;
+    }
+  }
+
+  /* RTSP never allows chunked transfer */
+  data->req.forbidchunk = TRUE;
+  /* Finish the request buffer */
+  result = Curl_add_buffer(req_buffer, "\r\n", 2);
+  if(result)
+    return result;
+
+  if(postsize > 0) {
+    result = Curl_add_buffer(req_buffer, data->set.postfields,
+                             (size_t)postsize);
+    if(result)
+      return result;
+  }
+
+  /* issue the request */
+  result = Curl_add_buffer_send(req_buffer, conn,
+                                &data->info.request_size, 0, FIRSTSOCKET);
+  if(result) {
+    failf(data, "Failed sending RTSP request");
+    return result;
+  }
+
+  result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
+                               &http->readbytecount,
+                               putsize?FIRSTSOCKET:-1,
+                               putsize?&http->writebytecount:NULL);
+
+  if(result) {
+    failf(data, "Failed RTSP transfer");
+    return result;
+  }
+
+  /* Increment the CSeq on success */
+  data->state.rtsp_next_client_CSeq++;
+
+  if(http->writebytecount) {
+    /* if a request-body has been sent off, we make sure this progress is
+       noted properly */
+    Curl_pgrsSetUploadCounter(data, http->writebytecount);
+    if(Curl_pgrsUpdate(conn))
+      result = CURLE_ABORTED_BY_CALLBACK;
+  }
+
+  return result;
+}
+
+CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data,
+                                 struct connectdata *conn,
+                                 ssize_t *nread,
+                                 bool *readmore) {
+  struct SingleRequest *k = &data->req;
+  struct rtsp_conn *rtspc = &(conn->proto.rtspc);
+
+  char *rtp; /* moving pointer to rtp data */
+  ssize_t rtp_dataleft; /* how much data left to parse in this round */
+  char *scratch;
+  CURLcode result;
+
+  if(rtspc->rtp_buf) {
+    /* There was some leftover data the last time. Merge buffers */
+    char *newptr = realloc(rtspc->rtp_buf, rtspc->rtp_bufsize + *nread);
+    if(!newptr) {
+      Curl_safefree(rtspc->rtp_buf);
+      rtspc->rtp_buf = NULL;
+      rtspc->rtp_bufsize = 0;
+      return CURLE_OUT_OF_MEMORY;
+    }
+    rtspc->rtp_buf = newptr;
+    memcpy(rtspc->rtp_buf + rtspc->rtp_bufsize, k->str, *nread);
+    rtspc->rtp_bufsize += *nread;
+    rtp = rtspc->rtp_buf;
+    rtp_dataleft = rtspc->rtp_bufsize;
+  }
+  else {
+    /* Just parse the request buffer directly */
+    rtp = k->str;
+    rtp_dataleft = *nread;
+  }
+
+  while((rtp_dataleft > 0) &&
+        (rtp[0] == '$')) {
+    if(rtp_dataleft > 4) {
+      int rtp_length;
+
+      /* Parse the header */
+      /* The channel identifier immediately follows and is 1 byte */
+      rtspc->rtp_channel = RTP_PKT_CHANNEL(rtp);
+
+      /* The length is two bytes */
+      rtp_length = RTP_PKT_LENGTH(rtp);
+
+      if(rtp_dataleft < rtp_length + 4) {
+        /* Need more - incomplete payload*/
+        *readmore = TRUE;
+        break;
+      }
+      else {
+        /* We have the full RTP interleaved packet
+         * Write out the header including the leading '$' */
+        DEBUGF(infof(data, "RTP write channel %d rtp_length %d\n",
+              rtspc->rtp_channel, rtp_length));
+        result = rtp_client_write(conn, &rtp[0], rtp_length + 4);
+        if(result) {
+          failf(data, "Got an error writing an RTP packet");
+          *readmore = FALSE;
+          Curl_safefree(rtspc->rtp_buf);
+          rtspc->rtp_buf = NULL;
+          rtspc->rtp_bufsize = 0;
+          return result;
+        }
+
+        /* Move forward in the buffer */
+        rtp_dataleft -= rtp_length + 4;
+        rtp += rtp_length + 4;
+
+        if(data->set.rtspreq == RTSPREQ_RECEIVE) {
+          /* If we are in a passive receive, give control back
+           * to the app as often as we can.
+           */
+          k->keepon &= ~KEEP_RECV;
+        }
+      }
+    }
+    else {
+      /* Need more - incomplete header */
+      *readmore = TRUE;
+      break;
+    }
+  }
+
+  if(rtp_dataleft != 0 && rtp[0] == '$') {
+    DEBUGF(infof(data, "RTP Rewinding %zu %s\n", rtp_dataleft,
+          *readmore ? "(READMORE)" : ""));
+
+    /* Store the incomplete RTP packet for a "rewind" */
+    scratch = malloc(rtp_dataleft);
+    if(!scratch) {
+      Curl_safefree(rtspc->rtp_buf);
+      rtspc->rtp_buf = NULL;
+      rtspc->rtp_bufsize = 0;
+      return CURLE_OUT_OF_MEMORY;
+    }
+    memcpy(scratch, rtp, rtp_dataleft);
+    Curl_safefree(rtspc->rtp_buf);
+    rtspc->rtp_buf = scratch;
+    rtspc->rtp_bufsize = rtp_dataleft;
+
+    /* As far as the transfer is concerned, this data is consumed */
+    *nread = 0;
+    return CURLE_OK;
+  }
+  else {
+    /* Fix up k->str to point just after the last RTP packet */
+    k->str += *nread - rtp_dataleft;
+
+    /* either all of the data has been read or...
+     * rtp now points at the next byte to parse
+     */
+    if(rtp_dataleft > 0)
+      DEBUGASSERT(k->str[0] == rtp[0]);
+
+    DEBUGASSERT(rtp_dataleft <= *nread); /* sanity check */
+
+    *nread = rtp_dataleft;
+  }
+
+  /* If we get here, we have finished with the leftover/merge buffer */
+  Curl_safefree(rtspc->rtp_buf);
+  rtspc->rtp_buf = NULL;
+  rtspc->rtp_bufsize = 0;
+
+  return CURLE_OK;
+}
+
+static
+CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len)
+{
+  struct SessionHandle *data = conn->data;
+  size_t wrote;
+  curl_write_callback writeit;
+
+  if(len == 0) {
+    failf (data, "Cannot write a 0 size RTP packet.");
+    return CURLE_WRITE_ERROR;
+  }
+
+  writeit = data->set.fwrite_rtp?data->set.fwrite_rtp:data->set.fwrite_func;
+  wrote = writeit(ptr, 1, len, data->set.rtp_out);
+
+  if(CURL_WRITEFUNC_PAUSE == wrote) {
+    failf (data, "Cannot pause RTP");
+    return CURLE_WRITE_ERROR;
+  }
+
+  if(wrote != len) {
+    failf (data, "Failed writing RTP data");
+    return CURLE_WRITE_ERROR;
+  }
+
+  return CURLE_OK;
+}
+
+CURLcode Curl_rtsp_parseheader(struct connectdata *conn,
+                               char *header)
+{
+  struct SessionHandle *data = conn->data;
+  long CSeq = 0;
+
+  if(checkprefix("CSeq:", header)) {
+    /* Store the received CSeq. Match is verified in rtsp_done */
+    int nc;
+    char *temp = strdup(header);
+    if(!temp)
+      return CURLE_OUT_OF_MEMORY;
+    Curl_strntoupper(temp, temp, sizeof(temp));
+    nc = sscanf(temp, "CSEQ: %ld", &CSeq);
+    free(temp);
+    if(nc == 1) {
+      data->state.proto.rtsp->CSeq_recv = CSeq; /* mark the request */
+      data->state.rtsp_CSeq_recv = CSeq; /* update the handle */
+    }
+    else {
+      failf(data, "Unable to read the CSeq header: [%s]", header);
+      return CURLE_RTSP_CSEQ_ERROR;
+    }
+  }
+  else if(checkprefix("Session:", header)) {
+    char *start;
+
+    /* Find the first non-space letter */
+    start = header + 9;
+    while(*start && ISSPACE(*start))
+      start++;
+
+    if(!start) {
+      failf(data, "Got a blank Session ID");
+    }
+    else if(data->set.str[STRING_RTSP_SESSION_ID]) {
+      /* If the Session ID is set, then compare */
+      if(strncmp(start, data->set.str[STRING_RTSP_SESSION_ID],
+                 strlen(data->set.str[STRING_RTSP_SESSION_ID]))  != 0) {
+        failf(data, "Got RTSP Session ID Line [%s], but wanted ID [%s]",
+              start, data->set.str[STRING_RTSP_SESSION_ID]);
+        return CURLE_RTSP_SESSION_ERROR;
+      }
+    }
+    else {
+      /* If the Session ID is not set, and we find it in a response, then
+         set it */
+
+      /* The session ID can be an alphanumeric or a 'safe' character
+       *
+       * RFC 2326 15.1 Base Syntax:
+       * safe =  "\$" | "-" | "_" | "." | "+"
+       * */
+      char *end = start;
+      while(*end &&
+            (ISALNUM(*end) || *end == '-' || *end == '_' || *end == '.' ||
+             *end == '+' ||
+             (*end == '\\' && *(end + 1) && *(end + 1) == '$' && (++end, 1))))
+        end++;
+
+      /* Copy the id substring into a new buffer */
+      data->set.str[STRING_RTSP_SESSION_ID] = malloc(end - start + 1);
+      if(data->set.str[STRING_RTSP_SESSION_ID] == NULL)
+        return CURLE_OUT_OF_MEMORY;
+      memcpy(data->set.str[STRING_RTSP_SESSION_ID], start, end - start);
+      (data->set.str[STRING_RTSP_SESSION_ID])[end - start] = '\0';
+    }
+  }
+  return CURLE_OK;
+}
+
+#endif /* CURL_DISABLE_RTSP */
diff --git a/lib/rtsp.h b/lib/rtsp.h
new file mode 100644
index 0000000..c3f8bd7
--- /dev/null
+++ b/lib/rtsp.h
@@ -0,0 +1,82 @@
+#ifndef __RTSP_H_
+#define __RTSP_H_
+
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+#ifndef CURL_DISABLE_RTSP
+
+extern const struct Curl_handler Curl_handler_rtsp;
+
+/*
+ * Parse and write out any available RTP data.
+ *
+ * nread: amount of data left after k->str. will be modified if RTP
+ *        data is parsed and k->str is moved up
+ * readmore: whether or not the RTP parser needs more data right away
+ */
+CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data,
+                                 struct connectdata *conn,
+                                 ssize_t *nread,
+                                 bool *readmore);
+
+
+/* protocol-specific functions set up to be called by the main engine */
+CURLcode Curl_rtsp(struct connectdata *conn, bool *done);
+CURLcode Curl_rtsp_done(struct connectdata *conn, CURLcode, bool premature);
+CURLcode Curl_rtsp_connect(struct connectdata *conn, bool *done);
+CURLcode Curl_rtsp_disconnect(struct connectdata *conn);
+
+CURLcode Curl_rtsp_parseheader(struct connectdata *conn, char *header);
+
+#endif /* CURL_DISABLE_RTSP */
+
+/*
+ * RTSP Connection data
+ *
+ * Currently, only used for tracking incomplete RTP data reads
+ */
+struct rtsp_conn {
+  char *rtp_buf;
+  ssize_t rtp_bufsize;
+  int rtp_channel;
+};
+
+/****************************************************************************
+ * RTSP unique setup
+ ***************************************************************************/
+struct RTSP {
+  /*
+   * http_wrapper MUST be the first element of this structure for the wrap
+   * logic to work. In this way, we get a cheap polymorphism because
+   * &(data->state.proto.rtsp) == &(data->state.proto.http) per the C spec
+   *
+   * HTTP functions can safely treat this as an HTTP struct, but RTSP aware
+   * functions can also index into the later elements.
+   */
+  struct HTTP http_wrapper; /*wrap HTTP to do the heavy lifting */
+
+  long CSeq_sent; /* CSeq of this request */
+  long CSeq_recv; /* CSeq received */
+};
+
+
+#endif /* __RTSP_H_ */
diff --git a/lib/security.c b/lib/security.c
new file mode 100644
index 0000000..03fc679
--- /dev/null
+++ b/lib/security.c
@@ -0,0 +1,546 @@
+/* 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).
+ *
+ * Copyright (C) 2001 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * 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
+#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
+
+#define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */
+#include <curl/mprintf.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "urldata.h"
+#include "krb4.h"
+#include "curl_base64.h"
+#include "sendf.h"
+#include "ftp.h"
+#include "curl_memory.h"
+#include "rawstr.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+static const 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(checkprefix(name, level_names[i].name))
+      return level_names[i].level;
+  return (enum protection_level)-1;
+}
+
+static const struct Curl_sec_client_mech * const mechs[] = {
+#ifdef HAVE_GSSAPI
+  &Curl_krb5_client_mech,
+#endif
+#ifdef HAVE_KRB4
+  &Curl_krb4_client_mech,
+#endif
+  NULL
+};
+
+/* TODO: This function isn't actually used anywhere and should be removed */
+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 && (errno == EINTR || errno == EAGAIN))
+      /* TODO: this will busy loop in the EAGAIN case */
+      continue;
+    else if(b < 0)
+      return -1;
+    len -= b;
+    p += b;
+  }
+  return p - (unsigned char*)buf;
+}
+
+static int
+block_write(int fd, const void *buf, size_t len)
+{
+  const unsigned char *p = buf;
+  int b;
+  while(len) {
+    b = write(fd, p, len);
+    if(b < 0 && (errno == EINTR || errno == EAGAIN))
+      continue;
+    else 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);
+  /* TODO: This realloc will cause a memory leak in an out of memory
+   * condition */
+  buf->data = realloc(buf->data, len);
+  b = buf->data ? block_read(fd, buf->data, len) : -1;
+  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)
+{
+  if(buf->size - buf->index < len)
+    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, const char *from, int length)
+{
+  int bytes;
+  void *buf;
+  enum protection_level protlevel = conn->data_prot;
+  int iscmd = protlevel == prot_cmd;
+
+  if(iscmd) {
+    if(!strncmp(from, "PASS ", 5) || !strncmp(from, "ACCT ", 5))
+      protlevel = prot_private;
+    else
+      protlevel = conn->command_prot;
+  }
+  bytes = (conn->mech->encode)(conn->app_data, from, length, protlevel,
+                               &buf, conn);
+  if(iscmd) {
+    char *cmdbuf;
+
+    bytes = Curl_base64_encode(conn->data, (char *)buf, bytes, &cmdbuf);
+    if(bytes > 0) {
+      if(protlevel == prot_private)
+        block_write(fd, "ENC ", 4);
+      else
+        block_write(fd, "MIC ", 4);
+      block_write(fd, cmdbuf, bytes);
+      block_write(fd, "\r\n", 2);
+      Curl_infof(conn->data, "%s %s\n",
+                 protlevel == prot_private ? "ENC" : "MIC", cmdbuf);
+      free(cmdbuf);
+    }
+  }
+  else {
+    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, const 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);
+  if(len <= 0)
+    len = length;
+  while(length){
+    if(length < len)
+      len = length;
+    sec_send(conn, fd, buffer, len);
+    length -= len;
+    buffer += len;
+    tx += len;
+  }
+  return tx;
+}
+
+ssize_t
+Curl_sec_send(struct connectdata *conn, int num, const char *buffer, int length)
+{
+  curl_socket_t fd = conn->sock[num];
+  return (ssize_t)Curl_sec_write(conn, fd, buffer, length);
+}
+
+int
+Curl_sec_putc(struct connectdata *conn, int c, FILE *F)
+{
+  char ch = (char)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;
+  unsigned char *buf;
+  int code;
+
+  len = Curl_base64_decode(s + 4, &buf); /* XXX */
+  if(len > 0)
+    len = (conn->mech->decode)(conn->app_data, buf, len, level, conn);
+  else
+    return -1;
+
+  if(len < 0) {
+    free(buf);
+    return -1;
+  }
+
+  if(conn->data->set.verbose) {
+    buf[len] = '\n';
+    Curl_debug(conn->data, CURLINFO_HEADER_IN, (char *)buf, len + 1, conn);
+  }
+
+  buf[len] = '\0';
+
+  if(buf[3] == '-')
+    code = 0;
+  else
+    sscanf((char *)buf, "%d", &code);
+  if(buf[len-1] == '\n')
+    buf[len-1] = '\0';
+  strcpy(s, (char *)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;
+  if(level == prot_private)
+    conn->command_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;
+  const struct Curl_sec_client_mech * const *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;
+    /* Set the requested protection level */
+    /* BLOCKING */
+    Curl_sec_set_protection_level(conn);
+    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/lib/select.c b/lib/select.c
new file mode 100644
index 0000000..e6882da
--- /dev/null
+++ b/lib/select.c
@@ -0,0 +1,506 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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"
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE)
+#error "We can't compile without select() or poll() support."
+#endif
+
+#if defined(__BEOS__) && !defined(__HAIKU__)
+/* BeOS has FD_SET defined in socket.h */
+#include <socket.h>
+#endif
+
+#ifdef MSDOS
+#include <dos.h>  /* delay() */
+#endif
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "connect.h"
+#include "select.h"
+
+/* Winsock and TPF sockets are not in range [0..FD_SETSIZE-1] */
+
+#if defined(USE_WINSOCK) || defined(TPF)
+#define VERIFY_SOCK(x) do { } while(0)
+#else
+#define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE))
+#define VERIFY_SOCK(x) do { \
+  if(!VALID_SOCK(x)) { \
+    SET_SOCKERRNO(EINVAL); \
+    return -1; \
+  } \
+} while(0)
+#endif
+
+/* Convenience local macros */
+
+#define elapsed_ms  (int)curlx_tvdiff(curlx_tvnow(), initial_tv)
+
+#ifdef CURL_ACKNOWLEDGE_EINTR
+#define error_not_EINTR (1)
+#else
+#define error_not_EINTR (error != EINTR)
+#endif
+
+/*
+ * Internal function used for waiting a specific amount of ms
+ * in Curl_socket_ready() and Curl_poll() when no file descriptor
+ * is provided to wait on, just being used to delay execution.
+ * WinSock select() and poll() timeout mechanisms need a valid
+ * socket descriptor in a not null file descriptor set to work.
+ * Waiting indefinitely with this function is not allowed, a
+ * zero or negative timeout value will return immediately.
+ * Timeout resolution, accuracy, as well as maximum supported
+ * value is system dependent, neither factor is a citical issue
+ * for the intended use of this function in the library.
+ * On non-DOS and non-Winsock platforms, when compiled with
+ * CURL_ACKNOWLEDGE_EINTR defined, EINTR condition is honored
+ * and function might exit early without awaiting full timeout,
+ * otherwise EINTR will be ignored and full timeout will elapse.
+ *
+ * Return values:
+ *   -1 = system call error, invalid timeout value, or interrupted
+ *    0 = specified timeout has elapsed
+ */
+static int wait_ms(int timeout_ms)
+{
+#if !defined(MSDOS) && !defined(USE_WINSOCK)
+#ifndef HAVE_POLL_FINE
+  struct timeval pending_tv;
+#endif
+  struct timeval initial_tv;
+  int pending_ms;
+  int error;
+#endif
+  int r = 0;
+
+  if(!timeout_ms)
+    return 0;
+  if(timeout_ms < 0) {
+    SET_SOCKERRNO(EINVAL);
+    return -1;
+  }
+#if defined(MSDOS)
+  delay(timeout_ms);
+#elif defined(USE_WINSOCK)
+  Sleep(timeout_ms);
+#else
+  pending_ms = timeout_ms;
+  initial_tv = curlx_tvnow();
+  do {
+#if defined(HAVE_POLL_FINE)
+    r = poll(NULL, 0, pending_ms);
+#else
+    pending_tv.tv_sec = pending_ms / 1000;
+    pending_tv.tv_usec = (pending_ms % 1000) * 1000;
+    r = select(0, NULL, NULL, NULL, &pending_tv);
+#endif /* HAVE_POLL_FINE */
+    if(r != -1)
+      break;
+    error = SOCKERRNO;
+    if(error && error_not_EINTR)
+      break;
+    pending_ms = timeout_ms - elapsed_ms;
+    if(pending_ms <= 0)
+      break;
+  } while(r == -1);
+#endif /* USE_WINSOCK */
+  if(r)
+    r = -1;
+  return r;
+}
+
+/*
+ * This is an internal function used for waiting for read or write
+ * events on a pair of file descriptors.  It uses poll() when a fine
+ * poll() is available, in order to avoid limits with FD_SETSIZE,
+ * otherwise select() is used.  An error is returned if select() is
+ * being used and a file descriptor is too large for FD_SETSIZE.
+ * A negative timeout value makes this function wait indefinitely,
+ * unles no valid file descriptor is given, when this happens the
+ * negative timeout is ignored and the function times out immediately.
+ * When compiled with CURL_ACKNOWLEDGE_EINTR defined, EINTR condition
+ * is honored and function might exit early without awaiting timeout,
+ * otherwise EINTR will be ignored.
+ *
+ * Return values:
+ *   -1 = system call error or fd >= FD_SETSIZE
+ *    0 = timeout
+ *    CURL_CSELECT_IN | CURL_CSELECT_OUT | CURL_CSELECT_ERR
+ */
+int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd,
+                      int timeout_ms)
+{
+#ifdef HAVE_POLL_FINE
+  struct pollfd pfd[2];
+  int num;
+#else
+  struct timeval pending_tv;
+  struct timeval *ptimeout;
+  fd_set fds_read;
+  fd_set fds_write;
+  fd_set fds_err;
+  curl_socket_t maxfd;
+#endif
+  struct timeval initial_tv = {0,0};
+  int pending_ms = 0;
+  int error;
+  int r;
+  int ret;
+
+  if((readfd == CURL_SOCKET_BAD) && (writefd == CURL_SOCKET_BAD)) {
+    r = wait_ms(timeout_ms);
+    return r;
+  }
+
+  /* Avoid initial timestamp, avoid curlx_tvnow() call, when elapsed
+     time in this function does not need to be measured. This happens
+     when function is called with a zero timeout or a negative timeout
+     value indicating a blocking call should be performed. */
+
+  if(timeout_ms > 0) {
+    pending_ms = timeout_ms;
+    initial_tv = curlx_tvnow();
+  }
+
+#ifdef HAVE_POLL_FINE
+
+  num = 0;
+  if(readfd != CURL_SOCKET_BAD) {
+    pfd[num].fd = readfd;
+    pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
+    pfd[num].revents = 0;
+    num++;
+  }
+  if(writefd != CURL_SOCKET_BAD) {
+    pfd[num].fd = writefd;
+    pfd[num].events = POLLWRNORM|POLLOUT;
+    pfd[num].revents = 0;
+    num++;
+  }
+
+  do {
+    if(timeout_ms < 0)
+      pending_ms = -1;
+    else if(!timeout_ms)
+      pending_ms = 0;
+    r = poll(pfd, num, pending_ms);
+    if(r != -1)
+      break;
+    error = SOCKERRNO;
+    if(error && error_not_EINTR)
+      break;
+    if(timeout_ms > 0) {
+      pending_ms = timeout_ms - elapsed_ms;
+      if(pending_ms <= 0)
+        break;
+    }
+  } while(r == -1);
+
+  if(r < 0)
+    return -1;
+  if(r == 0)
+    return 0;
+
+  ret = 0;
+  num = 0;
+  if(readfd != CURL_SOCKET_BAD) {
+    if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
+      ret |= CURL_CSELECT_IN;
+    if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL))
+      ret |= CURL_CSELECT_ERR;
+    num++;
+  }
+  if(writefd != CURL_SOCKET_BAD) {
+    if(pfd[num].revents & (POLLWRNORM|POLLOUT))
+      ret |= CURL_CSELECT_OUT;
+    if(pfd[num].revents & (POLLERR|POLLHUP|POLLNVAL))
+      ret |= CURL_CSELECT_ERR;
+  }
+
+  return ret;
+
+#else  /* HAVE_POLL_FINE */
+
+  FD_ZERO(&fds_err);
+  maxfd = (curl_socket_t)-1;
+
+  FD_ZERO(&fds_read);
+  if(readfd != CURL_SOCKET_BAD) {
+    VERIFY_SOCK(readfd);
+    FD_SET(readfd, &fds_read);
+    FD_SET(readfd, &fds_err);
+    maxfd = readfd;
+  }
+
+  FD_ZERO(&fds_write);
+  if(writefd != CURL_SOCKET_BAD) {
+    VERIFY_SOCK(writefd);
+    FD_SET(writefd, &fds_write);
+    FD_SET(writefd, &fds_err);
+    if(writefd > maxfd)
+      maxfd = writefd;
+  }
+
+  ptimeout = (timeout_ms < 0) ? NULL : &pending_tv;
+
+  do {
+    if(timeout_ms > 0) {
+      pending_tv.tv_sec = pending_ms / 1000;
+      pending_tv.tv_usec = (pending_ms % 1000) * 1000;
+    }
+    else if(!timeout_ms) {
+      pending_tv.tv_sec = 0;
+      pending_tv.tv_usec = 0;
+    }
+    r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
+    if(r != -1)
+      break;
+    error = SOCKERRNO;
+    if(error && error_not_EINTR)
+      break;
+    if(timeout_ms > 0) {
+      pending_ms = timeout_ms - elapsed_ms;
+      if(pending_ms <= 0)
+        break;
+    }
+  } while(r == -1);
+
+  if(r < 0)
+    return -1;
+  if(r == 0)
+    return 0;
+
+  ret = 0;
+  if(readfd != CURL_SOCKET_BAD) {
+    if(FD_ISSET(readfd, &fds_read))
+      ret |= CURL_CSELECT_IN;
+    if(FD_ISSET(readfd, &fds_err))
+      ret |= CURL_CSELECT_ERR;
+  }
+  if(writefd != CURL_SOCKET_BAD) {
+    if(FD_ISSET(writefd, &fds_write))
+      ret |= CURL_CSELECT_OUT;
+    if(FD_ISSET(writefd, &fds_err))
+      ret |= CURL_CSELECT_ERR;
+  }
+
+  return ret;
+
+#endif  /* HAVE_POLL_FINE */
+
+}
+
+/*
+ * This is a wrapper around poll().  If poll() does not exist, then
+ * select() is used instead.  An error is returned if select() is
+ * being used and a file descriptor is too large for FD_SETSIZE.
+ * A negative timeout value makes this function wait indefinitely,
+ * unles no valid file descriptor is given, when this happens the
+ * negative timeout is ignored and the function times out immediately.
+ * When compiled with CURL_ACKNOWLEDGE_EINTR defined, EINTR condition
+ * is honored and function might exit early without awaiting timeout,
+ * otherwise EINTR will be ignored.
+ *
+ * Return values:
+ *   -1 = system call error or fd >= FD_SETSIZE
+ *    0 = timeout
+ *    N = number of structures with non zero revent fields
+ */
+int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
+{
+#ifndef HAVE_POLL_FINE
+  struct timeval pending_tv;
+  struct timeval *ptimeout;
+  fd_set fds_read;
+  fd_set fds_write;
+  fd_set fds_err;
+  curl_socket_t maxfd;
+#endif
+  struct timeval initial_tv = {0,0};
+  bool fds_none = TRUE;
+  unsigned int i;
+  int pending_ms = 0;
+  int error;
+  int r;
+
+  if(ufds) {
+    for (i = 0; i < nfds; i++) {
+      if(ufds[i].fd != CURL_SOCKET_BAD) {
+        fds_none = FALSE;
+        break;
+      }
+    }
+  }
+  if(fds_none) {
+    r = wait_ms(timeout_ms);
+    return r;
+  }
+
+  /* Avoid initial timestamp, avoid curlx_tvnow() call, when elapsed
+     time in this function does not need to be measured. This happens
+     when function is called with a zero timeout or a negative timeout
+     value indicating a blocking call should be performed. */
+
+  if(timeout_ms > 0) {
+    pending_ms = timeout_ms;
+    initial_tv = curlx_tvnow();
+  }
+
+#ifdef HAVE_POLL_FINE
+
+  do {
+    if(timeout_ms < 0)
+      pending_ms = -1;
+    else if(!timeout_ms)
+      pending_ms = 0;
+    r = poll(ufds, nfds, pending_ms);
+    if(r != -1)
+      break;
+    error = SOCKERRNO;
+    if(error && error_not_EINTR)
+      break;
+    if(timeout_ms > 0) {
+      pending_ms = timeout_ms - elapsed_ms;
+      if(pending_ms <= 0)
+        break;
+    }
+  } while(r == -1);
+
+  if(r < 0)
+    return -1;
+  if(r == 0)
+    return 0;
+
+  for (i = 0; i < nfds; i++) {
+    if(ufds[i].fd == CURL_SOCKET_BAD)
+      continue;
+    if(ufds[i].revents & POLLHUP)
+      ufds[i].revents |= POLLIN;
+    if(ufds[i].revents & POLLERR)
+      ufds[i].revents |= (POLLIN|POLLOUT);
+  }
+
+#else  /* HAVE_POLL_FINE */
+
+  FD_ZERO(&fds_read);
+  FD_ZERO(&fds_write);
+  FD_ZERO(&fds_err);
+  maxfd = (curl_socket_t)-1;
+
+  for (i = 0; i < nfds; i++) {
+    ufds[i].revents = 0;
+    if(ufds[i].fd == CURL_SOCKET_BAD)
+      continue;
+    VERIFY_SOCK(ufds[i].fd);
+    if(ufds[i].events & (POLLIN|POLLOUT|POLLPRI|
+                          POLLRDNORM|POLLWRNORM|POLLRDBAND)) {
+      if(ufds[i].fd > maxfd)
+        maxfd = ufds[i].fd;
+      if(ufds[i].events & (POLLRDNORM|POLLIN))
+        FD_SET(ufds[i].fd, &fds_read);
+      if(ufds[i].events & (POLLWRNORM|POLLOUT))
+        FD_SET(ufds[i].fd, &fds_write);
+      if(ufds[i].events & (POLLRDBAND|POLLPRI))
+        FD_SET(ufds[i].fd, &fds_err);
+    }
+  }
+
+  ptimeout = (timeout_ms < 0) ? NULL : &pending_tv;
+
+  do {
+    if(timeout_ms > 0) {
+      pending_tv.tv_sec = pending_ms / 1000;
+      pending_tv.tv_usec = (pending_ms % 1000) * 1000;
+    }
+    else if(!timeout_ms) {
+      pending_tv.tv_sec = 0;
+      pending_tv.tv_usec = 0;
+    }
+    r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
+    if(r != -1)
+      break;
+    error = SOCKERRNO;
+    if(error && error_not_EINTR)
+      break;
+    if(timeout_ms > 0) {
+      pending_ms = timeout_ms - elapsed_ms;
+      if(pending_ms <= 0)
+        break;
+    }
+  } while(r == -1);
+
+  if(r < 0)
+    return -1;
+  if(r == 0)
+    return 0;
+
+  r = 0;
+  for (i = 0; i < nfds; i++) {
+    ufds[i].revents = 0;
+    if(ufds[i].fd == CURL_SOCKET_BAD)
+      continue;
+    if(FD_ISSET(ufds[i].fd, &fds_read))
+      ufds[i].revents |= POLLIN;
+    if(FD_ISSET(ufds[i].fd, &fds_write))
+      ufds[i].revents |= POLLOUT;
+    if(FD_ISSET(ufds[i].fd, &fds_err))
+      ufds[i].revents |= POLLPRI;
+    if(ufds[i].revents != 0)
+      r++;
+  }
+
+#endif  /* HAVE_POLL_FINE */
+
+  return r;
+}
+
+#ifdef TPF
+/*
+ * This is a replacement for select() on the TPF platform.
+ * It is used whenever libcurl calls select().
+ * The call below to tpf_process_signals() is required because
+ * TPF's select calls are not signal interruptible.
+ *
+ * Return values are the same as select's.
+ */
+int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
+                       fd_set* excepts, struct timeval* tv)
+{
+   int rc;
+
+   rc = tpf_select_bsd(maxfds, reads, writes, excepts, tv);
+   tpf_process_signals();
+   return(rc);
+}
+#endif /* TPF */
diff --git a/lib/select.h b/lib/select.h
new file mode 100644
index 0000000..e431e5f
--- /dev/null
+++ b/lib/select.h
@@ -0,0 +1,97 @@
+#ifndef __SELECT_H
+#define __SELECT_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2008, 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"
+
+#ifdef HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#elif defined(HAVE_POLL_H)
+#include <poll.h>
+#endif
+
+/*
+ * poll() function on Windows Vista and later is called WSAPoll()
+ */
+
+#if defined(USE_WINSOCK) && (USE_WINSOCK > 1) && \
+    defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)
+#  undef  HAVE_POLL
+#  define HAVE_POLL 1
+#  undef  HAVE_POLL_FINE
+#  define HAVE_POLL_FINE 1
+#  define poll(x,y,z) WSAPoll((x),(y),(z))
+#  if defined(_MSC_VER) && defined(POLLRDNORM)
+#    undef  POLLPRI
+#    define POLLPRI POLLRDBAND
+#    define HAVE_STRUCT_POLLFD 1
+#  endif
+#endif
+
+/*
+ * Definition of pollfd struct and constants for platforms lacking them.
+ */
+
+#if !defined(HAVE_STRUCT_POLLFD) && \
+    !defined(HAVE_SYS_POLL_H) && \
+    !defined(HAVE_POLL_H)
+
+#define POLLIN      0x01
+#define POLLPRI     0x02
+#define POLLOUT     0x04
+#define POLLERR     0x08
+#define POLLHUP     0x10
+#define POLLNVAL    0x20
+
+struct pollfd
+{
+    curl_socket_t fd;
+    short   events;
+    short   revents;
+};
+
+#endif
+
+#ifndef POLLRDNORM
+#define POLLRDNORM POLLIN
+#endif
+
+#ifndef POLLWRNORM
+#define POLLWRNORM POLLOUT
+#endif
+
+#ifndef POLLRDBAND
+#define POLLRDBAND POLLPRI
+#endif
+
+int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd,
+                      int timeout_ms);
+
+int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms);
+
+#ifdef TPF
+int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
+                       fd_set* excepts, struct timeval* tv);
+#endif
+
+#endif /* __SELECT_H */
diff --git a/lib/sendf.c b/lib/sendf.c
new file mode 100644
index 0000000..ff4aee3
--- /dev/null
+++ b/lib/sendf.c
@@ -0,0 +1,707 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#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"
+#include "sslgen.h"
+#include "ssh.h"
+#include "multiif.h"
+#include "rtsp.h"
+
+#define _MPRINTF_REPLACE /* use the internal *printf() functions */
+#include <curl/mprintf.h>
+
+/* the krb4 functions only exists for FTP and if krb4 or gssapi is defined */
+#if !defined(CURL_DISABLE_FTP) && (defined(HAVE_KRB4) || defined(HAVE_GSSAPI))
+#include "krb4.h"
+#else
+#define Curl_sec_send(a,b,c,d) -1
+#define Curl_sec_read(a,b,c,d) -1
+#endif
+
+#include <string.h>
+#include "curl_memory.h"
+#include "strerror.h"
+#include "easyif.h" /* for the Curl_convert_from_network prototype */
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifdef CURL_DO_LINEEND_CONV
+/*
+ * convert_lineends() changes CRLF (\r\n) end-of-line markers to a single LF
+ * (\n), with special processing for CRLF sequences that are split between two
+ * blocks of data.  Remaining, bare CRs are changed to LFs.  The possibly new
+ * size of the data is returned.
+ */
+static size_t convert_lineends(struct SessionHandle *data,
+                               char *startPtr, size_t size)
+{
+  char *inPtr, *outPtr;
+
+  /* sanity check */
+  if((startPtr == NULL) || (size < 1)) {
+    return(size);
+  }
+
+  if(data->state.prev_block_had_trailing_cr == TRUE) {
+    /* The previous block of incoming data
+       had a trailing CR, which was turned into a LF. */
+    if(*startPtr == '\n') {
+      /* This block of incoming data starts with the
+         previous block's LF so get rid of it */
+      memmove(startPtr, startPtr+1, size-1);
+      size--;
+      /* and it wasn't a bare CR but a CRLF conversion instead */
+      data->state.crlf_conversions++;
+    }
+    data->state.prev_block_had_trailing_cr = FALSE; /* reset the flag */
+  }
+
+  /* find 1st CR, if any */
+  inPtr = outPtr = memchr(startPtr, '\r', size);
+  if(inPtr) {
+    /* at least one CR, now look for CRLF */
+    while(inPtr < (startPtr+size-1)) {
+      /* note that it's size-1, so we'll never look past the last byte */
+      if(memcmp(inPtr, "\r\n", 2) == 0) {
+        /* CRLF found, bump past the CR and copy the NL */
+        inPtr++;
+        *outPtr = *inPtr;
+        /* keep track of how many CRLFs we converted */
+        data->state.crlf_conversions++;
+      }
+      else {
+        if(*inPtr == '\r') {
+          /* lone CR, move LF instead */
+          *outPtr = '\n';
+        }
+        else {
+          /* not a CRLF nor a CR, just copy whatever it is */
+          *outPtr = *inPtr;
+        }
+      }
+      outPtr++;
+      inPtr++;
+    } /* end of while loop */
+
+    if(inPtr < startPtr+size) {
+      /* handle last byte */
+      if(*inPtr == '\r') {
+        /* deal with a CR at the end of the buffer */
+        *outPtr = '\n'; /* copy a NL instead */
+        /* note that a CRLF might be split across two blocks */
+        data->state.prev_block_had_trailing_cr = TRUE;
+      }
+      else {
+        /* copy last byte */
+        *outPtr = *inPtr;
+      }
+      outPtr++;
+    }
+    if(outPtr < startPtr+size)
+      /* tidy up by null terminating the now shorter data */
+      *outPtr = '\0';
+
+    return(outPtr - startPtr);
+  }
+  return(size);
+}
+#endif /* CURL_DO_LINEEND_CONV */
+
+/* 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;
+    size_t len;
+    char print_buffer[2048 + 1];
+    va_start(ap, fmt);
+    vsnprintf(print_buffer, sizeof(print_buffer), fmt, ap);
+    va_end(ap);
+    len = strlen(print_buffer);
+    Curl_debug(data, CURLINFO_TEXT, print_buffer, len, 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;
+  size_t len;
+  va_start(ap, fmt);
+
+  vsnprintf(data->state.buffer, BUFSIZE, fmt, ap);
+
+  if(data->set.errorbuffer && !data->state.errorbuf) {
+    snprintf(data->set.errorbuffer, CURL_ERROR_SIZE, "%s", data->state.buffer);
+    data->state.errorbuf = TRUE; /* wrote error string */
+  }
+  if(data->set.verbose) {
+    len = strlen(data->state.buffer);
+    if(len < BUFSIZE - 1) {
+      data->state.buffer[len] = '\n';
+      data->state.buffer[++len] = '\0';
+    }
+    Curl_debug(data, CURLINFO_TEXT, data->state.buffer, len, NULL);
+  }
+
+  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 = CURLE_OK;
+  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;
+
+  for(;;) {
+    /* 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, (size_t)bytes_written, conn);
+
+    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;
+}
+
+static ssize_t send_plain(struct connectdata *conn,
+                          int num,
+                          const void *mem,
+                          size_t len)
+{
+  curl_socket_t sockfd = conn->sock[num];
+  ssize_t bytes_written = swrite(sockfd, mem, len);
+
+  if(-1 == bytes_written) {
+    int err = SOCKERRNO;
+
+    if(
+#ifdef WSAEWOULDBLOCK
+      /* This is how Windows does it */
+      (WSAEWOULDBLOCK == err)
+#else
+      /* 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;
+    else
+      failf(conn->data, "Send failure: %s",
+            Curl_strerror(conn, err));
+  }
+  return bytes_written;
+}
+
+/*
+ * Curl_write() is an internal write function that sends data to the
+ * server. Works with plain sockets, SCP, SSL or kerberos.
+ *
+ * If the write would block (EWOULDBLOCK), we return CURLE_OK and
+ * (*written == 0). Otherwise we return regular CURLcode value.
+ */
+CURLcode Curl_write(struct connectdata *conn,
+                    curl_socket_t sockfd,
+                    const void *mem,
+                    size_t len,
+                    ssize_t *written)
+{
+  ssize_t bytes_written;
+  int curlcode = CURLE_OK;
+  int num = (sockfd == conn->sock[SECONDARYSOCKET]);
+
+  if(conn->ssl[num].state == ssl_connection_complete)
+    bytes_written = Curl_ssl_send(conn, num, mem, len, &curlcode);
+  else if(Curl_ssh_enabled(conn, PROT_SCP))
+    bytes_written = Curl_scp_send(conn, num, mem, len);
+  else if(Curl_ssh_enabled(conn, PROT_SFTP))
+    bytes_written = Curl_sftp_send(conn, num, mem, len);
+  else if(conn->sec_complete)
+    bytes_written = Curl_sec_send(conn, num, mem, len);
+  else
+    bytes_written = send_plain(conn, num, mem, len);
+
+  *written = bytes_written;
+  if(-1 != bytes_written)
+    /* we completely ignore the curlcode value when -1 is not returned */
+    return CURLE_OK;
+
+  /* handle EWOULDBLOCK or a send failure */
+  switch(curlcode) {
+  case /* EWOULDBLOCK */ -1:
+    *written = /* EWOULDBLOCK */ 0;
+    return CURLE_OK;
+
+  case CURLE_OK:
+    /* general send failure */
+    return CURLE_SEND_ERROR;
+
+  default:
+    /* we got a specific curlcode, forward it */
+    return (CURLcode)curlcode;
+  }
+}
+
+/*
+ * Curl_write_plain() is an internal write function that sends data to the
+ * server using plain sockets only. Otherwise meant to have the exact same
+ * proto as Curl_write()
+ */
+CURLcode Curl_write_plain(struct connectdata *conn,
+                          curl_socket_t sockfd,
+                          const void *mem,
+                          size_t len,
+                          ssize_t *written)
+{
+  ssize_t bytes_written;
+  CURLcode retcode;
+  int num = (sockfd == conn->sock[SECONDARYSOCKET]);
+
+  bytes_written = send_plain(conn, num, mem, len);
+
+  *written = bytes_written;
+  retcode = (-1 != bytes_written)?CURLE_OK:CURLE_SEND_ERROR;
+
+  return retcode;
+}
+
+static CURLcode pausewrite(struct SessionHandle *data,
+                           int type, /* what type of data */
+                           const char *ptr,
+                           size_t len)
+{
+  /* signalled to pause sending on this connection, but since we have data
+     we want to send we need to dup it to save a copy for when the sending
+     is again enabled */
+  struct SingleRequest *k = &data->req;
+  char *dupl = malloc(len);
+  if(!dupl)
+    return CURLE_OUT_OF_MEMORY;
+
+  memcpy(dupl, ptr, len);
+
+  /* store this information in the state struct for later use */
+  data->state.tempwrite = dupl;
+  data->state.tempwritesize = len;
+  data->state.tempwritetype = type;
+
+  /* mark the connection as RECV paused */
+  k->keepon |= KEEP_RECV_PAUSE;
+
+  DEBUGF(infof(data, "Pausing with %zu bytes in buffer for type %02x\n",
+               len, type));
+
+  return CURLE_OK;
+}
+
+
+/* Curl_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.
+
+   If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the
+   local character encoding.  This is a problem and should be changed in
+   the future to leave the original data alone.
+ */
+CURLcode Curl_client_write(struct connectdata *conn,
+                           int type,
+                           char *ptr,
+                           size_t len)
+{
+  struct SessionHandle *data = conn->data;
+  size_t wrote;
+
+  if(0 == len)
+    len = strlen(ptr);
+
+  /* If reading is actually paused, we're forced to append this chunk of data
+     to the already held data, but only if it is the same type as otherwise it
+     can't work and it'll return error instead. */
+  if(data->req.keepon & KEEP_RECV_PAUSE) {
+    size_t newlen;
+    char *newptr;
+    if(type != data->state.tempwritetype)
+      /* major internal confusion */
+      return CURLE_RECV_ERROR;
+
+    DEBUGASSERT(data->state.tempwrite);
+
+    /* figure out the new size of the data to save */
+    newlen = len + data->state.tempwritesize;
+    /* allocate the new memory area */
+    newptr = realloc(data->state.tempwrite, newlen);
+    if(!newptr)
+      return CURLE_OUT_OF_MEMORY;
+    /* copy the new data to the end of the new area */
+    memcpy(newptr + data->state.tempwritesize, ptr, len);
+    /* update the pointer and the size */
+    data->state.tempwrite = newptr;
+    data->state.tempwritesize = newlen;
+
+    return CURLE_OK;
+  }
+
+  if(type & CLIENTWRITE_BODY) {
+    if((conn->protocol&PROT_FTP) && conn->proto.ftpc.transfertype == 'A') {
+#ifdef CURL_DOES_CONVERSIONS
+      /* convert from the network encoding */
+      size_t rc;
+      rc = Curl_convert_from_network(data, ptr, len);
+      /* Curl_convert_from_network calls failf if unsuccessful */
+      if(rc != CURLE_OK)
+        return rc;
+#endif /* CURL_DOES_CONVERSIONS */
+
+#ifdef CURL_DO_LINEEND_CONV
+      /* convert end-of-line markers */
+      len = convert_lineends(data, ptr, len);
+#endif /* CURL_DO_LINEEND_CONV */
+    }
+    /* If the previous block of data ended with CR and this block of data is
+       just a NL, then the length might be zero */
+    if(len) {
+      wrote = data->set.fwrite_func(ptr, 1, len, data->set.out);
+    }
+    else {
+      wrote = len;
+    }
+
+    if(CURL_WRITEFUNC_PAUSE == wrote)
+      return pausewrite(data, type, ptr, len);
+
+    if(wrote != len) {
+      failf(data, "Failed writing body (%zu != %zu)", wrote, len);
+      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_func;
+
+    /* Note: The header is in the host encoding
+       regardless of the ftp transfer mode (ASCII/Image) */
+
+    wrote = writeit(ptr, 1, len, data->set.writeheader);
+    if(CURL_WRITEFUNC_PAUSE == wrote)
+      /* here we pass in the HEADER bit only since if this was body as well
+         then it was passed already and clearly that didn't trigger the pause,
+         so this is saved for later with the HEADER bit only */
+      return pausewrite(data, CLIENTWRITE_HEADER, ptr, len);
+
+    if(wrote != len) {
+      failf (data, "Failed writing header");
+      return CURLE_WRITE_ERROR;
+    }
+  }
+
+  return CURLE_OK;
+}
+
+int Curl_read_plain(curl_socket_t sockfd,
+                         char *buf,
+                         size_t bytesfromsocket,
+                         ssize_t *n)
+{
+  ssize_t nread = sread(sockfd, buf, bytesfromsocket);
+
+  if(-1 == nread) {
+    int err = SOCKERRNO;
+#ifdef USE_WINSOCK
+    if(WSAEWOULDBLOCK == err)
+#else
+    if((EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err))
+#endif
+      return -1;
+    else
+      return CURLE_RECV_ERROR;
+  }
+
+  /* we only return number of bytes read when we return OK */
+  *n = nread;
+  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 sizerequested,     /* max amount to read */
+              ssize_t *n)               /* amount bytes read */
+{
+  ssize_t nread = 0;
+  size_t bytesfromsocket = 0;
+  char *buffertofill = NULL;
+  bool pipelining = (bool)(conn->data->multi &&
+                     Curl_multi_canPipeline(conn->data->multi));
+
+  /* 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 session can pipeline, check connection buffer  */
+  if(pipelining) {
+    size_t bytestocopy = CURLMIN(conn->buf_len - conn->read_pos,
+                                 sizerequested);
+
+    /* Copy from our master buffer first if we have some unread data there*/
+    if(bytestocopy > 0) {
+      memcpy(buf, conn->master_buffer + conn->read_pos, bytestocopy);
+      conn->read_pos += bytestocopy;
+      conn->bits.stream_was_rewound = FALSE;
+
+      *n = (ssize_t)bytestocopy;
+      return CURLE_OK;
+    }
+    /* If we come here, it means that there is no data to read from the buffer,
+     * so we read from the socket */
+    bytesfromsocket = CURLMIN(sizerequested, BUFSIZE * sizeof (char));
+    buffertofill = conn->master_buffer;
+  }
+  else {
+    bytesfromsocket = CURLMIN((long)sizerequested,
+                              conn->data->set.buffer_size ?
+                              conn->data->set.buffer_size : BUFSIZE);
+    buffertofill = buf;
+  }
+
+  if(conn->ssl[num].state == ssl_connection_complete) {
+    int curlcode = CURLE_RECV_ERROR;
+    nread = Curl_ssl_recv(conn, num, buffertofill, bytesfromsocket, &curlcode);
+
+    if(nread == -1)
+      return curlcode;
+  }
+  else if(Curl_ssh_enabled(conn, (PROT_SCP|PROT_SFTP))) {
+    if(conn->protocol & PROT_SCP)
+      nread = Curl_scp_recv(conn, num, buffertofill, bytesfromsocket);
+    else if(conn->protocol & PROT_SFTP)
+      nread = Curl_sftp_recv(conn, num, buffertofill, bytesfromsocket);
+#ifdef LIBSSH2CHANNEL_EAGAIN
+    if(nread == LIBSSH2CHANNEL_EAGAIN)
+      /* EWOULDBLOCK */
+      return -1;
+#endif
+    if(nread < 0)
+      /* since it is negative and not EAGAIN, it was a protocol-layer error */
+      return CURLE_RECV_ERROR;
+  }
+  else {
+    if(conn->sec_complete)
+      nread = Curl_sec_read(conn, sockfd, buffertofill,
+                            bytesfromsocket);
+    /* TODO: Need to handle EAGAIN here somehow, similar to how it
+     * is done in Curl_read_plain, either right here or in Curl_sec_read
+     * itself. */
+    else {
+      int ret = Curl_read_plain(sockfd, buffertofill, bytesfromsocket,
+                                     &nread);
+      if(ret)
+        return ret;
+    }
+  }
+  if(nread >= 0) {
+    if(pipelining) {
+      memcpy(buf, conn->master_buffer, nread);
+      conn->buf_len = nread;
+      conn->read_pos = nread;
+    }
+
+    *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 s_infotype[CURLINFO_END][3] = {
+    "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
+
+#ifdef CURL_DOES_CONVERSIONS
+  char buf[BUFSIZE+1];
+  size_t conv_size = 0;
+
+  switch(type) {
+  case CURLINFO_HEADER_OUT:
+    /* assume output headers are ASCII */
+    /* copy the data into my buffer so the original is unchanged */
+    if(size > BUFSIZE) {
+      size = BUFSIZE; /* truncate if necessary */
+      buf[BUFSIZE] = '\0';
+    }
+    conv_size = size;
+    memcpy(buf, ptr, size);
+    /* Special processing is needed for this block if it
+     * contains both headers and data (separated by CRLFCRLF).
+     * We want to convert just the headers, leaving the data as-is.
+     */
+    if(size > 4) {
+      size_t i;
+      for(i = 0; i < size-4; i++) {
+        if(memcmp(&buf[i], "\x0d\x0a\x0d\x0a", 4) == 0) {
+          /* convert everthing through this CRLFCRLF but no further */
+          conv_size = i + 4;
+          break;
+        }
+      }
+    }
+
+    Curl_convert_from_network(data, buf, conv_size);
+    /* Curl_convert_from_network calls failf if unsuccessful */
+    /* we might as well continue even if it fails...   */
+    ptr = buf; /* switch pointer to use my buffer instead */
+    break;
+  default:
+    /* leave everything else as-is */
+    break;
+  }
+#endif /* CURL_DOES_CONVERSIONS */
+
+  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);
+#ifdef CURL_DOES_CONVERSIONS
+    if(size != conv_size) {
+      /* we had untranslated data so we need an explicit newline */
+      fwrite("\n", 1, 1, data->set.err);
+    }
+#endif
+    break;
+  default: /* nada */
+    break;
+  }
+  return 0;
+}
+
+int Curl_debug(struct SessionHandle *data, curl_infotype type,
+               char *ptr, size_t size,
+               struct connectdata *conn)
+{
+  int rc;
+  if(data->set.printhost && conn && conn->host.dispname) {
+    char buffer[160];
+    const char *t=NULL;
+    const char *w="Data";
+    switch (type) {
+    case CURLINFO_HEADER_IN:
+      w = "Header";
+    case CURLINFO_DATA_IN:
+      t = "from";
+      break;
+    case CURLINFO_HEADER_OUT:
+      w = "Header";
+    case CURLINFO_DATA_OUT:
+      t = "to";
+      break;
+    default:
+      break;
+    }
+
+    if(t) {
+      snprintf(buffer, sizeof(buffer), "[%s %s %s]", w, t,
+               conn->host.dispname);
+      rc = showit(data, CURLINFO_TEXT, buffer, strlen(buffer));
+      if(rc)
+        return rc;
+    }
+  }
+  rc = showit(data, type, ptr, size);
+  return rc;
+}
diff --git a/lib/sendf.h b/lib/sendf.h
new file mode 100644
index 0000000..5732a0b
--- /dev/null
+++ b/lib/sendf.h
@@ -0,0 +1,85 @@
+#ifndef HEADER_CURL_SENDF_H
+#define HEADER_CURL_SENDF_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+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, ...);
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+
+#if defined(HAVE_VARIADIC_MACROS_C99)
+#define infof(...)  do { } while (0)
+#elif defined(HAVE_VARIADIC_MACROS_GCC)
+#define infof(x...)  do { } while (0)
+#else
+#define infof (void)
+#endif
+
+#else /* CURL_DISABLE_VERBOSE_STRINGS */
+
+#define infof Curl_infof
+
+#endif /* CURL_DISABLE_VERBOSE_STRINGS */
+
+#define failf Curl_failf
+
+#define CLIENTWRITE_BODY   (1<<0)
+#define CLIENTWRITE_HEADER (1<<1)
+#define CLIENTWRITE_BOTH   (CLIENTWRITE_BODY|CLIENTWRITE_HEADER)
+
+CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr,
+                           size_t len);
+
+/* internal read-function, does plain socket only */
+int Curl_read_plain(curl_socket_t sockfd,
+                    char *buf,
+                    size_t bytesfromsocket,
+                    ssize_t *n);
+
+/* 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, SCP, SFTP and krb4 */
+CURLcode Curl_write(struct connectdata *conn,
+                    curl_socket_t sockfd,
+                    const void *mem, size_t len,
+                    ssize_t *written);
+
+/* internal write-function, does plain sockets ONLY */
+CURLcode Curl_write_plain(struct connectdata *conn,
+                          curl_socket_t sockfd,
+                          const 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,
+               struct connectdata *conn);
+
+
+#endif /* HEADER_CURL_SENDF_H */
diff --git a/lib/setup-os400.h b/lib/setup-os400.h
new file mode 100644
index 0000000..cdeefe3
--- /dev/null
+++ b/lib/setup-os400.h
@@ -0,0 +1,140 @@
+#ifndef HEADER_CURL_SETUP_OS400_H
+#define HEADER_CURL_SETUP_OS400_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+
+/* OS/400 netdb.h does not define NI_MAXHOST. */
+#define NI_MAXHOST      1025
+
+/* OS/400 netdb.h does not define NI_MAXSERV. */
+#define NI_MAXSERV      32
+
+/* No OS/400 header file defines u_int32_t. */
+typedef unsigned long   u_int32_t;
+
+
+/* System API wrapper prototypes and definitions to support ASCII parameters. */
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <qsossl.h>
+#include <gssapi.h>
+
+extern int      Curl_getaddrinfo_a(const char * nodename, const char * servname,
+                                   const struct addrinfo * hints,
+                                   struct addrinfo * * res);
+#define getaddrinfo             Curl_getaddrinfo_a
+
+
+extern int      Curl_getnameinfo_a(const struct sockaddr * sa,
+                                   curl_socklen_t salen,
+                                   char * nodename, curl_socklen_t nodenamelen,
+                                   char * servname, curl_socklen_t servnamelen,
+                                   int flags);
+#define getnameinfo             Curl_getnameinfo_a
+
+
+/* SSL wrappers. */
+
+extern int      Curl_SSL_Init_Application_a(SSLInitApp * init_app);
+#define SSL_Init_Application    Curl_SSL_Init_Application_a
+
+
+extern int      Curl_SSL_Init_a(SSLInit * init);
+#define SSL_Init                Curl_SSL_Init_a
+
+
+extern char *   Curl_SSL_Strerror_a(int sslreturnvalue, SSLErrorMsg * serrmsgp);
+#define SSL_Strerror            Curl_SSL_Strerror_a
+
+
+/* GSSAPI wrappers. */
+
+extern OM_uint32 Curl_gss_import_name_a(OM_uint32 * minor_status,
+                                        gss_buffer_t in_name,
+                                        gss_OID in_name_type,
+                                        gss_name_t * out_name);
+#define gss_import_name         Curl_gss_import_name_a
+
+
+extern OM_uint32 Curl_gss_display_status_a(OM_uint32 * minor_status,
+                                           OM_uint32 status_value,
+                                           int status_type, gss_OID mech_type,
+                                           gss_msg_ctx_t * message_context,
+                                           gss_buffer_t status_string);
+#define gss_display_status      Curl_gss_display_status_a
+
+
+extern OM_uint32 Curl_gss_init_sec_context_a(OM_uint32 * minor_status,
+                                             gss_cred_id_t cred_handle,
+                                             gss_ctx_id_t * context_handle,
+                                             gss_name_t target_name,
+                                             gss_OID mech_type,
+                                             gss_flags_t req_flags,
+                                             OM_uint32 time_req,
+                                             gss_channel_bindings_t
+                                             input_chan_bindings,
+                                             gss_buffer_t input_token,
+                                             gss_OID * actual_mech_type,
+                                             gss_buffer_t output_token,
+                                             gss_flags_t * ret_flags,
+                                             OM_uint32 * time_rec);
+#define gss_init_sec_context    Curl_gss_init_sec_context_a
+
+
+extern OM_uint32 Curl_gss_delete_sec_context_a(OM_uint32 * minor_status,
+                                               gss_ctx_id_t * context_handle,
+                                               gss_buffer_t output_token);
+#define gss_delete_sec_context  Curl_gss_delete_sec_context_a
+
+/* LDAP wrappers. */
+
+#define BerValue                struct berval
+
+#define ldap_url_parse          ldap_url_parse_utf8
+#define ldap_init               Curl_ldap_init_a
+#define ldap_simple_bind_s      Curl_ldap_simple_bind_s_a
+#define ldap_search_s           Curl_ldap_search_s_a
+#define ldap_get_values_len     Curl_ldap_get_values_len_a
+#define ldap_err2string         Curl_ldap_err2string_a
+#define ldap_get_dn             Curl_ldap_get_dn_a
+#define ldap_first_attribute    Curl_ldap_first_attribute_a
+#define ldap_next_attribute     Curl_ldap_next_attribute_a
+
+/* Some socket functions must be wrapped to process textual addresses
+   like AF_UNIX. */
+
+extern int Curl_os400_connect(int sd, struct sockaddr * destaddr, int addrlen);
+extern int Curl_os400_bind(int sd, struct sockaddr * localaddr, int addrlen);
+extern int Curl_os400_sendto(int sd, char * buffer, int buflen, int flags,
+            struct sockaddr * dstaddr, int addrlen);
+extern int Curl_os400_recvfrom(int sd, char * buffer, int buflen, int flags,
+                                struct sockaddr * fromaddr, int * addrlen);
+
+#define connect                 Curl_os400_connect
+#define bind                    Curl_os400_bind
+#define sendto                  Curl_os400_sendto
+#define recvfrom                Curl_os400_recvfrom
+
+
+#endif /* HEADER_CURL_SETUP_OS400_H */
diff --git a/lib/setup.h b/lib/setup.h
new file mode 100644
index 0000000..ca98ad7
--- /dev/null
+++ b/lib/setup.h
@@ -0,0 +1,551 @@
+#ifndef HEADER_CURL_LIB_SETUP_H
+#define HEADER_CURL_LIB_SETUP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+/*
+ * Define WIN32 when build target is Win32 API
+ */
+
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) && !defined(__SYMBIAN32__)
+#define WIN32
+#endif
+
+/*
+ * Include configuration script results or hand-crafted
+ * configuration file for platforms which lack config tool.
+ */
+
+#ifdef HAVE_CONFIG_H
+
+#include "curl_config.h"
+
+#else /* HAVE_CONFIG_H */
+
+#ifdef _WIN32_WCE
+#  include "config-win32ce.h"
+#else
+#  ifdef WIN32
+#    include "config-win32.h"
+#  endif
+#endif
+
+#if defined(macintosh) && defined(__MRC__)
+#  include "config-mac.h"
+#endif
+
+#ifdef __AMIGA__
+#  include "amigaos.h"
+#endif
+
+#ifdef __SYMBIAN32__
+#  include "config-symbian.h"
+#endif
+
+#ifdef __OS400__
+#  include "config-os400.h"
+#endif
+
+#ifdef TPF
+#  include "config-tpf.h"
+#endif
+
+#ifdef __VXWORKS__
+#  include "config-vxworks.h"
+#endif
+
+#endif /* HAVE_CONFIG_H */
+
+/* ================================================================ */
+/* Definition of preprocessor macros/symbols which modify compiler  */
+/* behavior or generated code characteristics must be done here,   */
+/* as appropriate, before any system header file is included. It is */
+/* also possible to have them defined in the config file included   */
+/* before this point. As a result of all this we frown inclusion of */
+/* system header files in our config files, avoid this at any cost. */
+/* ================================================================ */
+
+/*
+ * AIX 4.3 and newer needs _THREAD_SAFE defined to build
+ * proper reentrant code. Others may also need it.
+ */
+
+#ifdef NEED_THREAD_SAFE
+#  ifndef _THREAD_SAFE
+#    define _THREAD_SAFE
+#  endif
+#endif
+
+/*
+ * Tru64 needs _REENTRANT set for a few function prototypes and
+ * things to appear in the system header files. Unixware needs it
+ * to build proper reentrant code. Others may also need it.
+ */
+
+#ifdef NEED_REENTRANT
+#  ifndef _REENTRANT
+#    define _REENTRANT
+#  endif
+#endif
+
+/* ================================================================ */
+/*  If you need to include a system header file for your platform,  */
+/*  please, do it beyond the point further indicated in this file.  */
+/* ================================================================ */
+
+/*
+ * libcurl's external interface definitions are also used internally,
+ * and might also include required system header files to define them.
+ */
+
+#include <curl/curlbuild.h>
+
+/*
+ * Compile time sanity checks must also be done when building the library.
+ */
+
+#include <curl/curlrules.h>
+
+/*
+ * Ensure that no one is using the old SIZEOF_CURL_OFF_T macro
+ */
+
+#ifdef SIZEOF_CURL_OFF_T
+#  error "SIZEOF_CURL_OFF_T shall not be defined!"
+   Error Compilation_aborted_SIZEOF_CURL_OFF_T_shall_not_be_defined
+#endif
+
+/*
+ * Set up internal curl_off_t formatting string directives for
+ * exclusive use with libcurl's internal *printf functions.
+ */
+
+#ifdef FORMAT_OFF_T
+#  error "FORMAT_OFF_T shall not be defined before this point!"
+   Error Compilation_aborted_FORMAT_OFF_T_already_defined
+#endif
+
+#ifdef FORMAT_OFF_TU
+#  error "FORMAT_OFF_TU shall not be defined before this point!"
+   Error Compilation_aborted_FORMAT_OFF_TU_already_defined
+#endif
+
+#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
+#  define FORMAT_OFF_T  "lld"
+#  define FORMAT_OFF_TU "llu"
+#else
+#  define FORMAT_OFF_T  "ld"
+#  define FORMAT_OFF_TU "lu"
+#endif
+
+/*
+ * Disable other protocols when http is the only one desired.
+ */
+
+#ifdef HTTP_ONLY
+#  define CURL_DISABLE_TFTP
+#  define CURL_DISABLE_FTP
+#  define CURL_DISABLE_LDAP
+#  define CURL_DISABLE_TELNET
+#  define CURL_DISABLE_DICT
+#  define CURL_DISABLE_FILE
+#  define CURL_DISABLE_RTSP
+#endif
+
+/*
+ * When http is disabled rtsp is not supported.
+ */
+
+#if defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_RTSP)
+#  define CURL_DISABLE_RTSP
+#endif
+
+/* ================================================================ */
+/* No system header file shall be included in this file before this */
+/* point. The only allowed ones are those included from curlbuild.h */
+/* ================================================================ */
+
+/*
+ * OS/400 setup file includes some system headers.
+ */
+
+#ifdef __OS400__
+#  include "setup-os400.h"
+#endif
+
+/*
+ * Include header files for windows builds before redefining anything.
+ * Use this preprocessor block only to include or exclude windows.h,
+ * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs
+ * to any other further and independent block.  Under Cygwin things work
+ * just as under linux (e.g. <sys/socket.h>) and the winsock headers should
+ * never be included when __CYGWIN__ is defined.  configure script takes
+ * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H,
+ * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined.
+ */
+
+#ifdef HAVE_WINDOWS_H
+#  ifndef WIN32_LEAN_AND_MEAN
+#    define WIN32_LEAN_AND_MEAN
+#  endif
+#  include <windows.h>
+#  ifdef HAVE_WINSOCK2_H
+#    include <winsock2.h>
+#    ifdef HAVE_WS2TCPIP_H
+#       include <ws2tcpip.h>
+#    endif
+#  else
+#    ifdef HAVE_WINSOCK_H
+#      include <winsock.h>
+#    endif
+#  endif
+#endif
+
+/*
+ * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else
+ * define USE_WINSOCK to 1 if we have and use WINSOCK  API, else
+ * undefine USE_WINSOCK.
+ */
+
+#undef USE_WINSOCK
+
+#ifdef HAVE_WINSOCK2_H
+#  define USE_WINSOCK 2
+#else
+#  ifdef HAVE_WINSOCK_H
+#    define USE_WINSOCK 1
+#  endif
+#endif
+
+#ifdef HAVE_EXTRA_STRICMP_H
+#  include <extra/stricmp.h>
+#endif
+
+#ifdef HAVE_EXTRA_STRDUP_H
+#  include <extra/strdup.h>
+#endif
+
+#ifdef TPF
+#  include <strings.h>    /* for bzero, strcasecmp, and strncasecmp */
+#  include <string.h>     /* for strcpy and strlen */
+#  include <stdlib.h>     /* for rand and srand */
+#  include <sys/socket.h> /* for select and ioctl*/
+#  include <netdb.h>      /* for in_addr_t definition */
+#  include <tpf/sysapi.h> /* for tpf_process_signals */
+   /* change which select is used for libcurl */
+#  define select(a,b,c,d,e) tpf_select_libcurl(a,b,c,d,e)
+#endif
+
+#ifdef __VXWORKS__
+#  include <sockLib.h>    /* for generic BSD socket functions */
+#  include <ioLib.h>      /* for basic I/O interface functions */
+#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
+
+#ifndef STDC_HEADERS /* no standard C headers! */
+#include <curl/stdcheaders.h>
+#endif
+
+#ifdef __POCC__
+#  include <sys/types.h>
+#  include <unistd.h>
+#  define sys_nerr EILSEQ
+#endif
+
+/*
+ * Salford-C kludge section (mostly borrowed from wxWidgets).
+ */
+#ifdef __SALFORDC__
+  #pragma suppress 353             /* Possible nested comments */
+  #pragma suppress 593             /* Define not used */
+  #pragma suppress 61              /* enum has no name */
+  #pragma suppress 106             /* unnamed, unused parameter */
+  #include <clib.h>
+#endif
+
+/*
+ * Large file (>2Gb) support using WIN32 functions.
+ */
+
+#ifdef USE_WIN32_LARGE_FILES
+#  include <io.h>
+#  include <sys/types.h>
+#  include <sys/stat.h>
+#  define lseek(fdes,offset,whence)  _lseeki64(fdes, offset, whence)
+#  define fstat(fdes,stp)            _fstati64(fdes, stp)
+#  define stat(fname,stp)            _stati64(fname, stp)
+#  define struct_stat                struct _stati64
+#  define LSEEK_ERROR                (__int64)-1
+#endif
+
+/*
+ * Small file (<2Gb) support using WIN32 functions.
+ */
+
+#ifdef USE_WIN32_SMALL_FILES
+#  include <io.h>
+#  include <sys/types.h>
+#  include <sys/stat.h>
+#  define lseek(fdes,offset,whence)  _lseek(fdes, (long)offset, whence)
+#  define fstat(fdes,stp)            _fstat(fdes, stp)
+#  define stat(fname,stp)            _stat(fname, stp)
+#  define struct_stat                struct _stat
+#  define LSEEK_ERROR                (long)-1
+#endif
+
+#ifndef struct_stat
+#  define struct_stat struct stat
+#endif
+
+#ifndef LSEEK_ERROR
+#  define LSEEK_ERROR (off_t)-1
+#endif
+
+/*
+ * Default sizeof(off_t) in case it hasn't been defined in config file.
+ */
+
+#ifndef SIZEOF_OFF_T
+#  if defined(__VMS) && !defined(__VAX)
+#    if defined(_LARGEFILE)
+#      define SIZEOF_OFF_T 8
+#    endif
+#  elif defined(__OS400__) && defined(__ILEC400__)
+#    if defined(_LARGE_FILES)
+#      define SIZEOF_OFF_T 8
+#    endif
+#  elif defined(__MVS__) && defined(__IBMC__)
+#    if defined(_LP64) || defined(_LARGE_FILES)
+#      define SIZEOF_OFF_T 8
+#    endif
+#  elif defined(__370__) && defined(__IBMC__)
+#    if defined(_LP64) || defined(_LARGE_FILES)
+#      define SIZEOF_OFF_T 8
+#    endif
+#  endif
+#  ifndef SIZEOF_OFF_T
+#    define SIZEOF_OFF_T 4
+#  endif
+#endif
+
+/* Below we define some functions. They should
+
+   4. set the SIGALRM signal timeout
+   5. set dir/file naming defines
+   */
+
+#ifdef WIN32
+
+#  define DIR_CHAR      "\\"
+#  define DOT_CHAR      "_"
+
+#else /* WIN32 */
+
+#  ifdef MSDOS  /* Watt-32 */
+
+#    include <sys/ioctl.h>
+#    define select(n,r,w,x,t) select_s(n,r,w,x,t)
+#    define ioctl(x,y,z) ioctlsocket(x,y,(char *)(z))
+#    include <tcp.h>
+#    ifdef word
+#      undef word
+#    endif
+#    ifdef byte
+#      undef byte
+#    endif
+
+#  endif /* MSDOS */
+
+#  ifdef __minix
+     /* Minix 3 versions up to at least 3.1.3 are missing these prototypes */
+     extern char * strtok_r(char *s, const char *delim, char **last);
+     extern struct tm * gmtime_r(const time_t * const timep, struct tm *tmp);
+#  endif
+
+#  define DIR_CHAR      "/"
+#  ifndef DOT_CHAR
+#    define DOT_CHAR      "."
+#  endif
+
+#  ifdef MSDOS
+#    undef DOT_CHAR
+#    define DOT_CHAR      "_"
+#  endif
+
+#  ifndef fileno /* sunos 4 have this as a macro! */
+     int fileno( FILE *stream);
+#  endif
+
+#endif /* WIN32 */
+
+/*
+ * msvc 6.0 requires PSDK in order to have INET6_ADDRSTRLEN
+ * defined in ws2tcpip.h as well as to provide IPv6 support.
+ */
+
+#if defined(_MSC_VER) && !defined(__POCC__)
+#  if !defined(HAVE_WS2TCPIP_H) || \
+     ((_MSC_VER < 1300) && !defined(INET6_ADDRSTRLEN))
+#    undef HAVE_GETADDRINFO_THREADSAFE
+#    undef HAVE_FREEADDRINFO
+#    undef HAVE_GETADDRINFO
+#    undef HAVE_GETNAMEINFO
+#    undef ENABLE_IPV6
+#  endif
+#endif
+
+/* ---------------------------------------------------------------- */
+/*             resolver specialty compile-time defines              */
+/*         CURLRES_* defines to use in the host*.c sources          */
+/* ---------------------------------------------------------------- */
+
+/*
+ * lcc-win32 doesn't have _beginthreadex(), lacks threads support.
+ */
+
+#if defined(__LCC__) && defined(WIN32)
+#  undef USE_THREADS_POSIX
+#  undef USE_THREADS_WIN32
+#endif
+
+/*
+ * MSVC threads support requires a multi-threaded runtime library.
+ * _beginthreadex() is not available in single-threaded ones.
+ */
+
+#if defined(_MSC_VER) && !defined(__POCC__) && !defined(_MT)
+#  undef USE_THREADS_POSIX
+#  undef USE_THREADS_WIN32
+#endif
+
+/*
+ * Mutually exclusive CURLRES_* definitions.
+ */
+
+#ifdef USE_ARES
+#  define CURLRES_ASYNCH
+#  define CURLRES_ARES
+#elif defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
+#  define CURLRES_ASYNCH
+#  define CURLRES_THREADED
+#else
+#  define CURLRES_SYNCH
+#endif
+
+#ifdef ENABLE_IPV6
+#  define CURLRES_IPV6
+#else
+#  define CURLRES_IPV4
+#endif
+
+/* ---------------------------------------------------------------- */
+
+/*
+ * When using WINSOCK, TELNET protocol requires WINSOCK2 API.
+ */
+
+#if defined(USE_WINSOCK) && (USE_WINSOCK != 2)
+#  define CURL_DISABLE_TELNET 1
+#endif
+
+/*
+ * msvc 6.0 does not have struct sockaddr_storage and
+ * does not define IPPROTO_ESP in winsock2.h. But both
+ * are available if PSDK is properly installed.
+ */
+
+#if defined(_MSC_VER) && !defined(__POCC__)
+#  if !defined(HAVE_WINSOCK2_H) || ((_MSC_VER < 1300) && !defined(IPPROTO_ESP))
+#    undef HAVE_STRUCT_SOCKADDR_STORAGE
+#  endif
+#endif
+
+/*
+ * Intentionally fail to build when using msvc 6.0 without PSDK installed.
+ * The brave of heart can circumvent this, defining ALLOW_MSVC6_WITHOUT_PSDK
+ * in lib/config-win32.h although absolutely discouraged and unsupported.
+ */
+
+#if defined(_MSC_VER) && !defined(__POCC__)
+#  if !defined(HAVE_WINDOWS_H) || ((_MSC_VER < 1300) && !defined(_FILETIME_))
+#    if !defined(ALLOW_MSVC6_WITHOUT_PSDK)
+#      error MSVC 6.0 requires 'February 2003 Platform SDK' a.k.a. 'Windows Server 2003 PSDK'
+#    else
+#      define CURL_DISABLE_LDAP 1
+#    endif
+#  endif
+#endif
+
+#ifdef NETWARE
+int netware_init(void);
+#ifndef __NOVELL_LIBC__
+#include <sys/bsdskt.h>
+#include <sys/timeval.h>
+#endif
+#endif
+
+#if defined(HAVE_LIBIDN) && defined(HAVE_TLD_H)
+/* The lib was present and the tld.h header (which is missing in libidn 0.3.X
+   but we only work with libidn 0.4.1 or later) */
+#define USE_LIBIDN
+#endif
+
+#ifndef SIZEOF_TIME_T
+/* assume default size of time_t to be 32 bit */
+#define SIZEOF_TIME_T 4
+#endif
+
+#define LIBIDN_REQUIRED_VERSION "0.4.1"
+
+#if defined(USE_GNUTLS) || defined(USE_SSLEAY) || defined(USE_NSS) || defined(USE_QSOSSL)
+#define USE_SSL    /* SSL support has been enabled */
+#endif
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_NTLM)
+#if defined(USE_SSLEAY) || defined(USE_WINDOWS_SSPI) || defined(USE_GNUTLS)
+#define USE_NTLM
+#endif
+#endif
+
+/* non-configure builds may define CURL_WANTS_CA_BUNDLE_ENV */
+#if defined(CURL_WANTS_CA_BUNDLE_ENV) && !defined(CURL_CA_BUNDLE)
+#define CURL_CA_BUNDLE getenv("CURL_CA_BUNDLE")
+#endif
+
+/*
+ * Include macros and defines that should only be processed once.
+ */
+
+#ifndef __SETUP_ONCE_H
+#include "setup_once.h"
+#endif
+
+#endif /* HEADER_CURL_LIB_SETUP_H */
diff --git a/lib/setup_once.h b/lib/setup_once.h
new file mode 100644
index 0000000..473eef2
--- /dev/null
+++ b/lib/setup_once.h
@@ -0,0 +1,450 @@
+#ifndef __SETUP_ONCE_H
+#define __SETUP_ONCE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+
+/********************************************************************
+ *                              NOTICE                              *
+ *                             ========                             *
+ *                                                                  *
+ *  Content of header files lib/setup_once.h and ares/setup_once.h  *
+ *  must be kept in sync. Modify the other one if you change this.  *
+ *                                                                  *
+ ********************************************************************/
+
+
+/*
+ * Inclusion of common header files.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef NEED_MALLOC_H
+#include <malloc.h>
+#endif
+
+#ifdef NEED_MEMORY_H
+#include <memory.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#ifdef TIME_WITH_SYS_TIME
+#include <time.h>
+#endif
+#else
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#endif
+
+#ifdef WIN32
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_STDBOOL_H
+#include <stdbool.h>
+#endif
+
+
+/*
+ * Definition of timeval struct for platforms that don't have it.
+ */
+
+#ifndef HAVE_STRUCT_TIMEVAL
+struct timeval {
+ long tv_sec;
+ long tv_usec;
+};
+#endif
+
+
+/*
+ * If we have the MSG_NOSIGNAL define, make sure we use
+ * it as the fourth argument of function send()
+ */
+
+#ifdef HAVE_MSG_NOSIGNAL
+#define SEND_4TH_ARG MSG_NOSIGNAL
+#else
+#define SEND_4TH_ARG 0
+#endif
+
+
+#if defined(__minix)
+/* Minix doesn't support recv on TCP sockets */
+#define sread(x,y,z) (ssize_t)read((RECV_TYPE_ARG1)(x), \
+                                   (RECV_TYPE_ARG2)(y), \
+                                   (RECV_TYPE_ARG3)(z))
+
+#elif defined(HAVE_RECV)
+/*
+ * The definitions for the return type and arguments types
+ * of functions recv() and send() belong and come from the
+ * configuration file. Do not define them in any other place.
+ *
+ * HAVE_RECV is defined if you have a function named recv()
+ * which is used to read incoming data from sockets. If your
+ * function has another name then don't define HAVE_RECV.
+ *
+ * If HAVE_RECV is defined then RECV_TYPE_ARG1, RECV_TYPE_ARG2,
+ * RECV_TYPE_ARG3, RECV_TYPE_ARG4 and RECV_TYPE_RETV must also
+ * be defined.
+ *
+ * HAVE_SEND is defined if you have a function named send()
+ * which is used to write outgoing data on a connected socket.
+ * If yours has another name then don't define HAVE_SEND.
+ *
+ * If HAVE_SEND is defined then SEND_TYPE_ARG1, SEND_QUAL_ARG2,
+ * SEND_TYPE_ARG2, SEND_TYPE_ARG3, SEND_TYPE_ARG4 and
+ * SEND_TYPE_RETV must also be defined.
+ */
+
+#if !defined(RECV_TYPE_ARG1) || \
+    !defined(RECV_TYPE_ARG2) || \
+    !defined(RECV_TYPE_ARG3) || \
+    !defined(RECV_TYPE_ARG4) || \
+    !defined(RECV_TYPE_RETV)
+  /* */
+  Error Missing_definition_of_return_and_arguments_types_of_recv
+  /* */
+#else
+#define sread(x,y,z) (ssize_t)recv((RECV_TYPE_ARG1)(x), \
+                                   (RECV_TYPE_ARG2)(y), \
+                                   (RECV_TYPE_ARG3)(z), \
+                                   (RECV_TYPE_ARG4)(0))
+#endif
+#else /* HAVE_RECV */
+#ifndef sread
+  /* */
+  Error Missing_definition_of_macro_sread
+  /* */
+#endif
+#endif /* HAVE_RECV */
+
+
+#if defined(__minix)
+/* Minix doesn't support send on TCP sockets */
+#define swrite(x,y,z) (ssize_t)write((SEND_TYPE_ARG1)(x), \
+                                    (SEND_TYPE_ARG2)(y), \
+                                    (SEND_TYPE_ARG3)(z))
+
+#elif defined(HAVE_SEND)
+#if !defined(SEND_TYPE_ARG1) || \
+    !defined(SEND_QUAL_ARG2) || \
+    !defined(SEND_TYPE_ARG2) || \
+    !defined(SEND_TYPE_ARG3) || \
+    !defined(SEND_TYPE_ARG4) || \
+    !defined(SEND_TYPE_RETV)
+  /* */
+  Error Missing_definition_of_return_and_arguments_types_of_send
+  /* */
+#else
+#define swrite(x,y,z) (ssize_t)send((SEND_TYPE_ARG1)(x), \
+                                    (SEND_TYPE_ARG2)(y), \
+                                    (SEND_TYPE_ARG3)(z), \
+                                    (SEND_TYPE_ARG4)(SEND_4TH_ARG))
+#endif
+#else /* HAVE_SEND */
+#ifndef swrite
+  /* */
+  Error Missing_definition_of_macro_swrite
+  /* */
+#endif
+#endif /* HAVE_SEND */
+
+
+#if 0
+#if defined(HAVE_RECVFROM)
+/*
+ * Currently recvfrom is only used on udp sockets.
+ */
+#if !defined(RECVFROM_TYPE_ARG1) || \
+    !defined(RECVFROM_TYPE_ARG2) || \
+    !defined(RECVFROM_TYPE_ARG3) || \
+    !defined(RECVFROM_TYPE_ARG4) || \
+    !defined(RECVFROM_TYPE_ARG5) || \
+    !defined(RECVFROM_TYPE_ARG6) || \
+    !defined(RECVFROM_TYPE_RETV)
+  /* */
+  Error Missing_definition_of_return_and_arguments_types_of_recvfrom
+  /* */
+#else
+#define sreadfrom(s,b,bl,f,fl) (ssize_t)recvfrom((RECVFROM_TYPE_ARG1)  (s),  \
+                                                 (RECVFROM_TYPE_ARG2 *)(b),  \
+                                                 (RECVFROM_TYPE_ARG3)  (bl), \
+                                                 (RECVFROM_TYPE_ARG4)  (0),  \
+                                                 (RECVFROM_TYPE_ARG5 *)(f),  \
+                                                 (RECVFROM_TYPE_ARG6 *)(fl))
+#endif
+#else /* HAVE_RECVFROM */
+#ifndef sreadfrom
+  /* */
+  Error Missing_definition_of_macro_sreadfrom
+  /* */
+#endif
+#endif /* HAVE_RECVFROM */
+
+
+#ifdef RECVFROM_TYPE_ARG6_IS_VOID
+#  define RECVFROM_ARG6_T int
+#else
+#  define RECVFROM_ARG6_T RECVFROM_TYPE_ARG6
+#endif
+#endif /* if 0 */
+
+
+/*
+ * Function-like macro definition used to close a socket.
+ */
+
+#if defined(HAVE_CLOSESOCKET)
+#  define sclose(x)  closesocket((x))
+#elif defined(HAVE_CLOSESOCKET_CAMEL)
+#  define sclose(x)  CloseSocket((x))
+#else
+#  define sclose(x)  close((x))
+#endif
+
+
+/*
+ * Uppercase macro versions of ANSI/ISO is*() functions/macros which
+ * avoid negative number inputs with argument byte codes > 127.
+ */
+
+#define ISSPACE(x)  (isspace((int)  ((unsigned char)x)))
+#define ISDIGIT(x)  (isdigit((int)  ((unsigned char)x)))
+#define ISALNUM(x)  (isalnum((int)  ((unsigned char)x)))
+#define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x)))
+#define ISGRAPH(x)  (isgraph((int)  ((unsigned char)x)))
+#define ISALPHA(x)  (isalpha((int)  ((unsigned char)x)))
+#define ISPRINT(x)  (isprint((int)  ((unsigned char)x)))
+#define ISUPPER(x)  (isupper((int)  ((unsigned char)x)))
+#define ISLOWER(x)  (islower((int)  ((unsigned char)x)))
+
+#define ISBLANK(x)  (int)((((unsigned char)x) == ' ') || \
+                          (((unsigned char)x) == '\t'))
+
+
+/*
+ * Typedef to 'unsigned char' if bool is not an available 'typedefed' type.
+ */
+
+#ifndef HAVE_BOOL_T
+typedef unsigned char bool;
+#define HAVE_BOOL_T
+#endif
+
+
+/*
+ * Default definition of uppercase TRUE and FALSE.
+ */
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+
+/*
+ * Typedef to 'int' if sig_atomic_t is not an available 'typedefed' type.
+ */
+
+#ifndef HAVE_SIG_ATOMIC_T
+typedef int sig_atomic_t;
+#define HAVE_SIG_ATOMIC_T
+#endif
+
+
+/*
+ * Convenience SIG_ATOMIC_T definition
+ */
+
+#ifdef HAVE_SIG_ATOMIC_T_VOLATILE
+#define SIG_ATOMIC_T static sig_atomic_t
+#else
+#define SIG_ATOMIC_T static volatile sig_atomic_t
+#endif
+
+
+/*
+ * Default return type for signal handlers.
+ */
+
+#ifndef RETSIGTYPE
+#define RETSIGTYPE void
+#endif
+
+
+/*
+ * Macro used to include code only in debug builds.
+ */
+
+#ifdef DEBUGBUILD
+#define DEBUGF(x) x
+#else
+#define DEBUGF(x) do { } while (0)
+#endif
+
+
+/*
+ * Macro used to include assertion code only in debug builds.
+ */
+
+#if defined(DEBUGBUILD) && defined(HAVE_ASSERT_H)
+#define DEBUGASSERT(x) assert(x)
+#else
+#define DEBUGASSERT(x) do { } while (0)
+#endif
+
+
+/*
+ * Macro SOCKERRNO / SET_SOCKERRNO() returns / sets the *socket-related* errno
+ * (or equivalent) on this platform to hide platform details to code using it.
+ */
+
+#ifdef USE_WINSOCK
+#define SOCKERRNO         ((int)WSAGetLastError())
+#define SET_SOCKERRNO(x)  (WSASetLastError((int)(x)))
+#else
+#define SOCKERRNO         (errno)
+#define SET_SOCKERRNO(x)  (errno = (x))
+#endif
+
+
+/*
+ * Macro ERRNO / SET_ERRNO() returns / sets the NOT *socket-related* errno
+ * (or equivalent) on this platform to hide platform details to code using it.
+ */
+
+#ifdef WIN32
+#define ERRNO         ((int)GetLastError())
+#define SET_ERRNO(x)  (SetLastError((DWORD)(x)))
+#else
+#define ERRNO         (errno)
+#define SET_ERRNO(x)  (errno = (x))
+#endif
+
+
+/*
+ * Portable error number symbolic names defined to Winsock error codes.
+ */
+
+#ifdef USE_WINSOCK
+#undef  EBADF            /* override definition in errno.h */
+#define EBADF            WSAEBADF
+#undef  EINTR            /* override definition in errno.h */
+#define EINTR            WSAEINTR
+#undef  EINVAL           /* override definition in errno.h */
+#define EINVAL           WSAEINVAL
+#define EWOULDBLOCK      WSAEWOULDBLOCK
+#define EINPROGRESS      WSAEINPROGRESS
+#define EALREADY         WSAEALREADY
+#define ENOTSOCK         WSAENOTSOCK
+#define EDESTADDRREQ     WSAEDESTADDRREQ
+#define EMSGSIZE         WSAEMSGSIZE
+#define EPROTOTYPE       WSAEPROTOTYPE
+#define ENOPROTOOPT      WSAENOPROTOOPT
+#define EPROTONOSUPPORT  WSAEPROTONOSUPPORT
+#define ESOCKTNOSUPPORT  WSAESOCKTNOSUPPORT
+#define EOPNOTSUPP       WSAEOPNOTSUPP
+#define EPFNOSUPPORT     WSAEPFNOSUPPORT
+#define EAFNOSUPPORT     WSAEAFNOSUPPORT
+#define EADDRINUSE       WSAEADDRINUSE
+#define EADDRNOTAVAIL    WSAEADDRNOTAVAIL
+#define ENETDOWN         WSAENETDOWN
+#define ENETUNREACH      WSAENETUNREACH
+#define ENETRESET        WSAENETRESET
+#define ECONNABORTED     WSAECONNABORTED
+#define ECONNRESET       WSAECONNRESET
+#define ENOBUFS          WSAENOBUFS
+#define EISCONN          WSAEISCONN
+#define ENOTCONN         WSAENOTCONN
+#define ESHUTDOWN        WSAESHUTDOWN
+#define ETOOMANYREFS     WSAETOOMANYREFS
+#define ETIMEDOUT        WSAETIMEDOUT
+#define ECONNREFUSED     WSAECONNREFUSED
+#define ELOOP            WSAELOOP
+#ifndef ENAMETOOLONG     /* possible previous definition in errno.h */
+#define ENAMETOOLONG     WSAENAMETOOLONG
+#endif
+#define EHOSTDOWN        WSAEHOSTDOWN
+#define EHOSTUNREACH     WSAEHOSTUNREACH
+#ifndef ENOTEMPTY        /* possible previous definition in errno.h */
+#define ENOTEMPTY        WSAENOTEMPTY
+#endif
+#define EPROCLIM         WSAEPROCLIM
+#define EUSERS           WSAEUSERS
+#define EDQUOT           WSAEDQUOT
+#define ESTALE           WSAESTALE
+#define EREMOTE          WSAEREMOTE
+#endif
+
+
+/*
+ *  Actually use __32_getpwuid() on 64-bit VMS builds for getpwuid()
+ */
+
+#if defined(__VMS) && \
+    defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
+#define getpwuid __32_getpwuid
+#endif
+
+
+/*
+ * Macro argv_item_t hides platform details to code using it.
+ */
+
+#ifdef __VMS
+#define argv_item_t  __char_ptr32
+#else
+#define argv_item_t  char *
+#endif
+
+
+/*
+ * We use this ZERO_NULL to avoid picky compiler warnings,
+ * when assigning a NULL pointer to a function pointer var.
+ */
+
+#define ZERO_NULL 0
+
+
+#endif /* __SETUP_ONCE_H */
+
diff --git a/lib/share.c b/lib/share.c
new file mode 100644
index 0000000..e6b8e7a
--- /dev/null
+++ b/lib/share.c
@@ -0,0 +1,218 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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 <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 = calloc(1, sizeof(struct Curl_share));
+  if(share)
+    share->specifier |= (1<<CURL_LOCK_DATA_SHARE);
+
+  return share;
+}
+
+#undef curl_share_setopt
+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;
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+    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;
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+      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);
+    share->hostcache = NULL;
+  }
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+  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/lib/share.h b/lib/share.h
new file mode 100644
index 0000000..ea8e233
--- /dev/null
+++ b/lib/share.h
@@ -0,0 +1,55 @@
+#ifndef __CURL_SHARE_H
+#define __CURL_SHARE_H
+
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2005, 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 "cookie.h"
+
+/* SalfordC says "A structure member may not be volatile". Hence:
+ */
+#ifdef __SALFORDC__
+#define CURL_VOLATILE
+#else
+#define CURL_VOLATILE volatile
+#endif
+
+/* this struct is libcurl-private, don't export details */
+struct Curl_share {
+  unsigned int specifier;
+  CURL_VOLATILE unsigned int dirty;
+
+  curl_lock_function lockfunc;
+  curl_unlock_function unlockfunc;
+  void *clientdata;
+
+  struct 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/lib/slist.c b/lib/slist.c
new file mode 100644
index 0000000..7c0f67b
--- /dev/null
+++ b/lib/slist.c
@@ -0,0 +1,135 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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 <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include <string.h>
+#include "curl_memory.h"
+#include "slist.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 returns
+ * the address of the first record, so that you can use 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 program.
+ */
+struct curl_slist *curl_slist_append(struct curl_slist *list,
+                                     const char *data)
+{
+  struct curl_slist     *last;
+  struct curl_slist     *new_item;
+
+  new_item = malloc(sizeof(struct curl_slist));
+  if(new_item) {
+    char *dupdata = strdup(data);
+    if(dupdata) {
+      new_item->next = NULL;
+      new_item->data = dupdata;
+    }
+    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;
+}
+
+/*
+ * Curl_slist_duplicate() duplicates a linked list. It always returns the
+ * address of the first record of the cloned list or NULL in case of an
+ * error (or if the input list was NULL).
+ */
+struct curl_slist *Curl_slist_duplicate(struct curl_slist *inlist)
+{
+  struct curl_slist *outlist = NULL;
+  struct curl_slist *tmp;
+
+  while(inlist) {
+    tmp = curl_slist_append(outlist, inlist->data);
+
+    if (!tmp) {
+      curl_slist_free_all(outlist);
+      return NULL;
+    }
+
+    outlist = tmp;
+    inlist = inlist->next;
+  }
+  return outlist;
+}
+
+/* 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);
+}
+
diff --git a/lib/slist.h b/lib/slist.h
new file mode 100644
index 0000000..161b150
--- /dev/null
+++ b/lib/slist.h
@@ -0,0 +1,32 @@
+#ifndef __SLIST_H
+#define __SLIST_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+/*
+ * Curl_slist_duplicate() duplicates a linked list. It always returns the
+ * address of the first record of the cloned list or NULL in case of an
+ * error (or if the input list was NULL).
+ */
+struct curl_slist *Curl_slist_duplicate(struct curl_slist *inlist);
+
+#endif /* __SLIST_H */
diff --git a/lib/smtp.c b/lib/smtp.c
new file mode 100644
index 0000000..654f435
--- /dev/null
+++ b/lib/smtp.c
@@ -0,0 +1,1105 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ * RFC2821 SMTP protocol
+ * RFC3207 SMTP over TLS
+ *
+ ***************************************************************************/
+
+#include "setup.h"
+
+#ifndef CURL_DISABLE_SMTP
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.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
+#ifdef HAVE_UTSNAME_H
+#include <sys/utsname.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.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 "easyif.h" /* for Curl_convert_... prototypes */
+
+#include "if2ip.h"
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "socks.h"
+#include "smtp.h"
+
+#include "strtoofft.h"
+#include "strequal.h"
+#include "sslgen.h"
+#include "connect.h"
+#include "strerror.h"
+#include "select.h"
+#include "multiif.h"
+#include "url.h"
+#include "rawstr.h"
+#include "strtoofft.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* Local API functions */
+static CURLcode smtp_regular_transfer(struct connectdata *conn, bool *done);
+static CURLcode smtp_do(struct connectdata *conn, bool *done);
+static CURLcode smtp_done(struct connectdata *conn,
+                          CURLcode, bool premature);
+static CURLcode smtp_connect(struct connectdata *conn, bool *done);
+static CURLcode smtp_disconnect(struct connectdata *conn);
+static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done);
+static int smtp_getsock(struct connectdata *conn,
+                        curl_socket_t *socks,
+                        int numsocks);
+static CURLcode smtp_doing(struct connectdata *conn,
+                           bool *dophase_done);
+static CURLcode smtp_setup_connection(struct connectdata * conn);
+
+
+/*
+ * SMTP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_smtp = {
+  "SMTP",                           /* scheme */
+  smtp_setup_connection,            /* setup_connection */
+  smtp_do,                          /* do_it */
+  smtp_done,                        /* done */
+  ZERO_NULL,                        /* do_more */
+  smtp_connect,                     /* connect_it */
+  smtp_multi_statemach,             /* connecting */
+  smtp_doing,                       /* doing */
+  smtp_getsock,                     /* proto_getsock */
+  smtp_getsock,                     /* doing_getsock */
+  ZERO_NULL,                        /* perform_getsock */
+  smtp_disconnect,                  /* disconnect */
+  PORT_SMTP,                        /* defport */
+  PROT_SMTP                         /* protocol */
+};
+
+
+#ifdef USE_SSL
+/*
+ * SMTPS protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_smtps = {
+  "SMTPS",                          /* scheme */
+  smtp_setup_connection,            /* setup_connection */
+  smtp_do,                          /* do_it */
+  smtp_done,                        /* done */
+  ZERO_NULL,                        /* do_more */
+  smtp_connect,                     /* connect_it */
+  smtp_multi_statemach,             /* connecting */
+  smtp_doing,                       /* doing */
+  smtp_getsock,                     /* proto_getsock */
+  smtp_getsock,                     /* doing_getsock */
+  ZERO_NULL,                        /* perform_getsock */
+  smtp_disconnect,                  /* disconnect */
+  PORT_SMTPS,                       /* defport */
+  PROT_SMTP | PROT_SMTPS | PROT_SSL  /* protocol */
+};
+#endif
+
+#ifndef CURL_DISABLE_HTTP
+/*
+ * HTTP-proxyed SMTP protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_smtp_proxy = {
+  "SMTP",                               /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  Curl_http,                            /* do_it */
+  Curl_http_done,                       /* done */
+  ZERO_NULL,                            /* do_more */
+  ZERO_NULL,                            /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  PORT_SMTP,                            /* defport */
+  PROT_HTTP                             /* protocol */
+};
+
+
+#ifdef USE_SSL
+/*
+ * HTTP-proxyed SMTPS protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_smtps_proxy = {
+  "SMTPS",                              /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  Curl_http,                            /* do_it */
+  Curl_http_done,                       /* done */
+  ZERO_NULL,                            /* do_more */
+  ZERO_NULL,                            /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  PORT_SMTPS,                           /* defport */
+  PROT_HTTP                             /* protocol */
+};
+#endif
+#endif
+
+
+/* fucntion that checks for an ending smtp status code at the start of the
+   given string */
+static int smtp_endofresp(struct pingpong *pp, int *resp)
+{
+  char *line = pp->linestart_resp;
+  size_t len = pp->nread_resp;
+
+  if( (len >= 4) && (' ' == line[3]) &&
+      ISDIGIT(line[0]) && ISDIGIT(line[1]) && ISDIGIT(line[2])) {
+    *resp=atoi(line);
+    return TRUE;
+  }
+
+  return FALSE; /* nothing for us */
+}
+
+/* This is the ONLY way to change SMTP state! */
+static void state(struct connectdata *conn,
+                  smtpstate newstate)
+{
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  /* for debug purposes */
+  static const char * const names[]={
+    "STOP",
+    "SERVERGREET",
+    "EHLO",
+    "HELO",
+    "STARTTLS",
+    "MAIL",
+    "RCPT",
+    "DATA",
+    "POSTDATA",
+    "QUIT",
+    /* LAST */
+  };
+#endif
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  if(smtpc->state != newstate)
+    infof(conn->data, "SMTP %p state change from %s to %s\n",
+          smtpc, names[smtpc->state], names[newstate]);
+#endif
+  smtpc->state = newstate;
+}
+
+static CURLcode smtp_state_ehlo(struct connectdata *conn)
+{
+  CURLcode result;
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+  /* send EHLO */
+  result = Curl_pp_sendf(&conn->proto.smtpc.pp, "EHLO %s", smtpc->domain);
+
+  if(result)
+    return result;
+
+  state(conn, SMTP_EHLO);
+  return CURLE_OK;
+}
+
+static CURLcode smtp_state_helo(struct connectdata *conn)
+{
+  CURLcode result;
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+  /* send HELO */
+  result = Curl_pp_sendf(&conn->proto.smtpc.pp, "HELO %s", smtpc->domain);
+
+  if(result)
+    return result;
+
+  state(conn, SMTP_HELO);
+  return CURLE_OK;
+}
+
+/* For the SMTP "protocol connect" and "doing" phases only */
+static int smtp_getsock(struct connectdata *conn,
+                        curl_socket_t *socks,
+                        int numsocks)
+{
+  return Curl_pp_getsock(&conn->proto.smtpc.pp, socks, numsocks);
+}
+
+/* for STARTTLS responses */
+static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
+                                         int smtpcode,
+                                         smtpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  (void)instate; /* no use for this yet */
+
+  if(smtpcode != 220) {
+    if(data->set.ftp_ssl == CURLUSESSL_TRY)
+      state(conn, SMTP_STOP);
+    else {
+      failf(data, "STARTTLS denied. %c", smtpcode);
+      result = CURLE_LOGIN_DENIED;
+    }
+  }
+  else {
+    /* Curl_ssl_connect is BLOCKING */
+    result = Curl_ssl_connect(conn, FIRSTSOCKET);
+    if(CURLE_OK == result) {
+      conn->protocol |= PROT_SMTPS;
+      result = smtp_state_ehlo(conn);
+    }
+  }
+  return result;
+}
+
+/* for EHLO responses */
+static CURLcode smtp_state_ehlo_resp(struct connectdata *conn,
+                                     int smtpcode,
+                                     smtpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+
+  (void)instate; /* no use for this yet */
+
+  if(smtpcode/100 != 2) {
+    if(data->set.ftp_ssl <= CURLUSESSL_TRY)
+      result = smtp_state_helo(conn);
+    else {
+      failf(data, "Access denied: %d", smtpcode);
+      result = CURLE_LOGIN_DENIED;
+    }
+  } 
+  else if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
+    /* We don't have a SSL/TLS connection yet, but SSL is requested. Switch
+       to TLS connection now */
+    result = Curl_pp_sendf(&conn->proto.smtpc.pp, "STARTTLS", NULL);
+    state(conn, SMTP_STARTTLS);
+  }
+  else {
+    /* end the connect phase */
+    state(conn, SMTP_STOP);
+  }
+  return result;
+}
+
+/* for HELO responses */
+static CURLcode smtp_state_helo_resp(struct connectdata *conn,
+                                     int smtpcode,
+                                     smtpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+
+  (void)instate; /* no use for this yet */
+
+  if(smtpcode/100 != 2) {
+    failf(data, "Access denied: %d", smtpcode);
+    result = CURLE_LOGIN_DENIED;
+  } 
+  else {
+    /* end the connect phase */
+    state(conn, SMTP_STOP);
+  }
+  return result;
+}
+
+/* start the DO phase */
+static CURLcode smtp_mail(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+
+  /* send MAIL */
+  result = Curl_pp_sendf(&conn->proto.smtpc.pp, "MAIL FROM:%s",
+                         data->set.str[STRING_MAIL_FROM]);
+  if(result)
+    return result;
+
+  state(conn, SMTP_MAIL);
+  return result;
+}
+
+static CURLcode smtp_rcpt_to(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+  /* send RCPT TO */
+  if(smtpc->rcpt) {
+    if(smtpc->rcpt->data[0] == '<')
+      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:%s",
+                             smtpc->rcpt->data);
+    else
+      result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>",
+                             smtpc->rcpt->data);
+    if(!result)
+      state(conn, SMTP_RCPT);
+  }
+  return result;
+}
+
+/* for MAIL responses */
+static CURLcode smtp_state_mail_resp(struct connectdata *conn,
+                                     int smtpcode,
+                                     smtpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  (void)instate; /* no use for this yet */
+
+  if(smtpcode/100 != 2) {
+    failf(data, "Access denied: %d", smtpcode);
+    result = CURLE_LOGIN_DENIED;
+    state(conn, SMTP_STOP);
+  }
+  else {
+    struct smtp_conn *smtpc = &conn->proto.smtpc;
+    smtpc->rcpt = data->set.mail_rcpt;
+
+    result = smtp_rcpt_to(conn);
+  }
+
+  return result;
+}
+
+/* for RCPT responses */
+static CURLcode smtp_state_rcpt_resp(struct connectdata *conn,
+                                     int smtpcode,
+                                     smtpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  (void)instate; /* no use for this yet */
+
+  if(smtpcode/100 != 2) {
+    failf(data, "Access denied: %d", smtpcode);
+    result = CURLE_LOGIN_DENIED;
+    state(conn, SMTP_STOP);
+  }
+  else {
+    struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+    if(smtpc->rcpt) {
+      smtpc->rcpt = smtpc->rcpt->next;
+      result = smtp_rcpt_to(conn);
+
+      /* if we failed or still is in RCPT sending, return */
+      if(result || smtpc->rcpt)
+        return result;
+    }
+
+    /* send DATA */
+    result = Curl_pp_sendf(&conn->proto.smtpc.pp, "DATA", "");
+    if(result)
+      return result;
+
+    state(conn, SMTP_DATA);
+  }
+  return result;
+}
+
+/* for the DATA response */
+static CURLcode smtp_state_data_resp(struct connectdata *conn,
+                                     int smtpcode,
+                                     smtpstate instate)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  struct FTP *smtp = data->state.proto.smtp;
+
+  (void)instate; /* no use for this yet */
+
+  if(smtpcode != 354) {
+    state(conn, SMTP_STOP);
+    return CURLE_RECV_ERROR;
+  }
+
+  /* SMTP upload */
+  result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
+                               FIRSTSOCKET, smtp->bytecountp);
+
+  state(conn, SMTP_STOP);
+  return result;
+}
+
+/* for the POSTDATA response, which is received after the entire DATA
+   part has been sent off to the server */
+static CURLcode smtp_state_postdata_resp(struct connectdata *conn,
+                                     int smtpcode,
+                                     smtpstate instate)
+{
+  CURLcode result = CURLE_OK;
+
+  (void)instate; /* no use for this yet */
+
+  if(smtpcode != 250)
+    result = CURLE_RECV_ERROR;
+
+  state(conn, SMTP_STOP);
+  return result;
+}
+
+static CURLcode smtp_statemach_act(struct connectdata *conn)
+{
+  CURLcode result;
+  curl_socket_t sock = conn->sock[FIRSTSOCKET];
+  struct SessionHandle *data=conn->data;
+  int smtpcode;
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+  struct pingpong *pp = &smtpc->pp;
+  size_t nread = 0;
+
+  if(pp->sendleft)
+    /* we have a piece of a command still left to send */
+    return Curl_pp_flushsend(pp);
+
+  /* we read a piece of response */
+  result = Curl_pp_readresp(sock, pp, &smtpcode, &nread);
+  if(result)
+    return result;
+
+  if(smtpcode) {
+    /* we have now received a full SMTP server response */
+    switch(smtpc->state) {
+    case SMTP_SERVERGREET:
+      if(smtpcode/100 != 2) {
+        failf(data, "Got unexpected smtp-server response: %d", smtpcode);
+        return CURLE_FTP_WEIRD_SERVER_REPLY;
+      }
+
+      result = smtp_state_ehlo(conn);
+      if(result)
+        return result;
+      break;
+
+    case SMTP_EHLO:
+      result = smtp_state_ehlo_resp(conn, smtpcode, smtpc->state);
+      break;
+
+    case SMTP_HELO:
+      result = smtp_state_helo_resp(conn, smtpcode, smtpc->state);
+      break;
+
+    case SMTP_MAIL:
+      result = smtp_state_mail_resp(conn, smtpcode, smtpc->state);
+      break;
+
+    case SMTP_RCPT:
+      result = smtp_state_rcpt_resp(conn, smtpcode, smtpc->state);
+      break;
+
+    case SMTP_STARTTLS:
+      result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state);
+      break;
+
+    case SMTP_DATA:
+      result = smtp_state_data_resp(conn, smtpcode, smtpc->state);
+      break;
+
+    case SMTP_POSTDATA:
+      result = smtp_state_postdata_resp(conn, smtpcode, smtpc->state);
+      break;
+
+    case SMTP_QUIT:
+      /* fallthrough, just stop! */
+    default:
+      /* internal error */
+      state(conn, SMTP_STOP);
+      break;
+    }
+  }
+  return result;
+}
+
+/* called repeatedly until done from multi.c */
+static CURLcode smtp_multi_statemach(struct connectdata *conn,
+                                     bool *done)
+{
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+  CURLcode result = Curl_pp_multi_statemach(&smtpc->pp);
+
+  *done = (bool)(smtpc->state == SMTP_STOP);
+
+  return result;
+}
+
+static CURLcode smtp_easy_statemach(struct connectdata *conn)
+{
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+  struct pingpong *pp = &smtpc->pp;
+  CURLcode result = CURLE_OK;
+
+  while(smtpc->state != SMTP_STOP) {
+    result = Curl_pp_easy_statemach(pp);
+    if(result)
+      break;
+  }
+
+  return result;
+}
+
+/*
+ * Allocate and initialize the struct SMTP for the current SessionHandle.  If
+ * need be.
+ */
+static CURLcode smtp_init(struct connectdata *conn)
+{
+  struct SessionHandle *data = conn->data;
+  struct FTP *smtp = data->state.proto.smtp;
+  if(!smtp) {
+    smtp = data->state.proto.smtp = calloc(sizeof(struct FTP), 1);
+    if(!smtp)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* get some initial data into the smtp struct */
+  smtp->bytecountp = &data->req.bytecount;
+
+  /* No need to duplicate user+password, the connectdata struct won't change
+     during a session, but we re-init them here since on subsequent inits
+     since the conn struct may have changed or been replaced.
+  */
+  smtp->user = conn->user;
+  smtp->passwd = conn->passwd;
+
+  return CURLE_OK;
+}
+
+/*
+ * smtp_connect() should do everything that is to be considered a part of
+ * the connection phase.
+ *
+ * The variable 'done' points to will be TRUE if the protocol-layer connect
+ * phase is done when this function returns, or FALSE is not. When called as
+ * a part of the easy interface, it will always be TRUE.
+ */
+static CURLcode smtp_connect(struct connectdata *conn,
+                             bool *done) /* see description above */
+{
+  CURLcode result;
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+  struct SessionHandle *data=conn->data;
+  struct pingpong *pp=&smtpc->pp;
+  const char *path = conn->data->state.path;
+  int len;
+
+#ifdef HAVE_GETHOSTNAME
+    char localhost[1024 + 1];
+#endif
+
+  *done = FALSE; /* default to not done yet */
+
+  /* If there already is a protocol-specific struct allocated for this
+     sessionhandle, deal with it */
+  Curl_reset_reqproto(conn);
+
+  result = smtp_init(conn);
+  if(CURLE_OK != result)
+    return result;
+
+  /* We always support persistant connections on smtp */
+  conn->bits.close = FALSE;
+
+  pp->response_time = RESP_TIMEOUT; /* set default response time-out */
+  pp->statemach_act = smtp_statemach_act;
+  pp->endofresp = smtp_endofresp;
+  pp->conn = conn;
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY)
+  if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
+    /* for SMTP over HTTP proxy */
+    struct HTTP http_proxy;
+    struct FTP *smtp_save;
+
+    /* BLOCKING */
+    /* We want "seamless" SMTP operations through HTTP proxy tunnel */
+
+    /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
+     * conn->proto.http; we want SMTP through HTTP and we have to change the
+     * member temporarily for connecting to the HTTP proxy. After
+     * Curl_proxyCONNECT we have to set back the member to the original struct
+     * SMTP pointer
+     */
+    smtp_save = data->state.proto.smtp;
+    memset(&http_proxy, 0, sizeof(http_proxy));
+    data->state.proto.http = &http_proxy;
+
+    result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
+                               conn->host.name, conn->remote_port);
+
+    data->state.proto.smtp = smtp_save;
+
+    if(CURLE_OK != result)
+      return result;
+  }
+#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY */
+
+  if(conn->protocol & PROT_SMTPS) {
+    /* BLOCKING */
+    /* SMTPS is simply smtp with SSL for the control channel */
+    /* now, perform the SSL initialization for this socket */
+    result = Curl_ssl_connect(conn, FIRSTSOCKET);
+    if(result)
+      return result;
+  }
+
+  Curl_pp_init(pp); /* init the response reader stuff */
+
+  pp->response_time = RESP_TIMEOUT; /* set default response time-out */
+  pp->statemach_act = smtp_statemach_act;
+  pp->endofresp = smtp_endofresp;
+  pp->conn = conn;
+
+  if(!*path) {
+#ifdef HAVE_GETHOSTNAME
+    if(!gethostname(localhost, sizeof localhost))
+      path = localhost;
+    else
+#endif
+    path = "localhost";
+  }
+
+  /* url decode the path and use it as domain with EHLO */
+  smtpc->domain = curl_easy_unescape(conn->data, path, 0, &len);
+  if (!smtpc->domain)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* When we connect, we start in the state where we await the server greeting
+   */
+  state(conn, SMTP_SERVERGREET);
+
+  if(data->state.used_interface == Curl_if_multi)
+    result = smtp_multi_statemach(conn, done);
+  else {
+    result = smtp_easy_statemach(conn);
+    if(!result)
+      *done = TRUE;
+  }
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_done()
+ *
+ * The DONE function. This does what needs to be done after a single DO has
+ * performed.
+ *
+ * Input argument is already checked for validity.
+ */
+static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
+                          bool premature)
+{
+  struct SessionHandle *data = conn->data;
+  struct FTP *smtp = data->state.proto.smtp;
+  CURLcode result=CURLE_OK;
+  ssize_t bytes_written;
+  (void)premature;
+
+  if(!smtp)
+    /* When the easy handle is removed from the multi while libcurl is still
+     * trying to resolve the host name, it seems that the smtp struct is not
+     * yet initialized, but the removal action calls Curl_done() which calls
+     * this function. So we simply return success if no smtp pointer is set.
+     */
+    return CURLE_OK;
+
+  if(status) {
+    conn->bits.close = TRUE; /* marked for closure */
+    result = status;      /* use the already set error code */
+  }
+  else
+    /* TODO: make this work even when the socket is EWOULDBLOCK in this call! */
+
+    /* write to socket (send away data) */
+    result = Curl_write(conn,
+                        conn->writesockfd,  /* socket to send to */
+                        SMTP_EOB,           /* buffer pointer */
+                        SMTP_EOB_LEN,       /* buffer size */
+                        &bytes_written);    /* actually sent away */
+
+
+  if(status == CURLE_OK) {
+    struct smtp_conn *smtpc = &conn->proto.smtpc;
+    struct pingpong *pp= &smtpc->pp;
+    pp->response = Curl_tvnow(); /* timeout relative now */
+
+    state(conn, SMTP_POSTDATA);
+    /* run the state-machine
+
+       TODO: when the multi interface is used, this _really_ should be using
+       the smtp_multi_statemach function but we have no general support for
+       non-blocking DONE operations, not in the multi state machine and with
+       Curl_done() invokes on several places in the code!
+    */
+    result = smtp_easy_statemach(conn);
+  }
+
+  /* clear these for next connection */
+  smtp->transfer = FTPTRANSFER_BODY;
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform()
+ *
+ * This is the actual DO function for SMTP. Get a file/directory according to
+ * the options previously setup.
+ */
+
+static
+CURLcode smtp_perform(struct connectdata *conn,
+                     bool *connected,  /* connect status after PASV / PORT */
+                     bool *dophase_done)
+{
+  /* this is SMTP and no proxy */
+  CURLcode result=CURLE_OK;
+
+  DEBUGF(infof(conn->data, "DO phase starts\n"));
+
+  if(conn->data->set.opt_no_body) {
+    /* requested no body means no transfer... */
+    struct FTP *smtp = conn->data->state.proto.smtp;
+    smtp->transfer = FTPTRANSFER_INFO;
+  }
+
+  *dophase_done = FALSE; /* not done yet */
+
+  /* start the first command in the DO phase */
+  result = smtp_mail(conn);
+  if(result)
+    return result;
+
+  /* run the state-machine */
+  if(conn->data->state.used_interface == Curl_if_multi)
+    result = smtp_multi_statemach(conn, dophase_done);
+  else {
+    result = smtp_easy_statemach(conn);
+    *dophase_done = TRUE; /* with the easy interface we are done here */
+  }
+  *connected = conn->bits.tcpconnect;
+
+  if(*dophase_done)
+    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_do()
+ *
+ * This function is registered as 'curl_do' function. It decodes the path
+ * parts etc as a wrapper to the actual DO function (smtp_perform).
+ *
+ * The input argument is already checked for validity.
+ */
+static CURLcode smtp_do(struct connectdata *conn, bool *done)
+{
+  CURLcode retcode = CURLE_OK;
+
+  *done = FALSE; /* default to false */
+
+  /*
+    Since connections can be re-used between SessionHandles, this might be a
+    connection already existing but on a fresh SessionHandle struct so we must
+    make sure we have a good 'struct SMTP' to play with. For new connections,
+    the struct SMTP is allocated and setup in the smtp_connect() function.
+  */
+  Curl_reset_reqproto(conn);
+  retcode = smtp_init(conn);
+  if(retcode)
+    return retcode;
+
+  retcode = smtp_regular_transfer(conn, done);
+
+  return retcode;
+}
+
+/***********************************************************************
+ *
+ * smtp_quit()
+ *
+ * This should be called before calling sclose().  We should then wait for the
+ * response from the server before returning. The calling code should then try
+ * to close the connection.
+ *
+ */
+static CURLcode smtp_quit(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+
+  result = Curl_pp_sendf(&conn->proto.smtpc.pp, "QUIT", NULL);
+  if(result)
+    return result;
+  state(conn, SMTP_QUIT);
+
+  result = smtp_easy_statemach(conn);
+
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_disconnect()
+ *
+ * Disconnect from an SMTP server. Cleanup protocol-specific per-connection
+ * resources. BLOCKING.
+ */
+static CURLcode smtp_disconnect(struct connectdata *conn)
+{
+  struct smtp_conn *smtpc= &conn->proto.smtpc;
+
+  /* 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.
+  */
+
+  /* The SMTP session may or may not have been allocated/setup at this
+     point! */
+  if (smtpc->pp.conn)
+    (void)smtp_quit(conn); /* ignore errors on the LOGOUT */
+
+  Curl_pp_disconnect(&smtpc->pp);
+
+  return CURLE_OK;
+}
+
+/* call this when the DO phase has completed */
+static CURLcode smtp_dophase_done(struct connectdata *conn,
+                                  bool connected)
+{
+  CURLcode result = CURLE_OK;
+  struct FTP *smtp = conn->data->state.proto.smtp;
+  struct smtp_conn *smtpc= &conn->proto.smtpc;
+  (void)connected;
+
+  if(smtp->transfer != FTPTRANSFER_BODY)
+    /* no data to transfer */
+    result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+
+  free(smtpc->domain);
+
+  return result;
+}
+
+/* called from multi.c while DOing */
+static CURLcode smtp_doing(struct connectdata *conn,
+                               bool *dophase_done)
+{
+  CURLcode result;
+  result = smtp_multi_statemach(conn, dophase_done);
+
+  if(*dophase_done) {
+    result = smtp_dophase_done(conn, FALSE /* not connected */);
+
+    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+  }
+  return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_regular_transfer()
+ *
+ * The input argument is already checked for validity.
+ *
+ * Performs all commands done before a regular transfer between a local and a
+ * remote host.
+ */
+static
+CURLcode smtp_regular_transfer(struct connectdata *conn,
+                              bool *dophase_done)
+{
+  CURLcode result=CURLE_OK;
+  bool connected=FALSE;
+  struct SessionHandle *data = conn->data;
+  data->req.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);
+
+  result = smtp_perform(conn,
+                        &connected, /* have we connected after PASV/PORT */
+                        dophase_done); /* all commands in the DO-phase done? */
+
+  if(CURLE_OK == result) {
+
+    if(!*dophase_done)
+      /* the DO phase has not completed yet */
+      return CURLE_OK;
+
+    result = smtp_dophase_done(conn, connected);
+    if(result)
+      return result;
+  }
+
+  return result;
+}
+
+static CURLcode smtp_setup_connection(struct connectdata * conn)
+{
+  struct SessionHandle *data = conn->data;
+
+  if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
+    /* Unless we have asked to tunnel smtp operations through the proxy, we
+       switch and use HTTP operations only */
+#ifndef CURL_DISABLE_HTTP
+    if(conn->handler == &Curl_handler_smtp)
+      conn->handler = &Curl_handler_smtp_proxy;
+    else {
+#ifdef USE_SSL
+      conn->handler = &Curl_handler_smtps_proxy;
+#else
+      failf(data, "SMTPS not supported!");
+      return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+    }
+    /*
+     * We explicitly mark this connection as persistent here as we're doing
+     * SMTP over HTTP and thus we accidentally avoid setting this value
+     * otherwise.
+     */
+    conn->bits.close = FALSE;
+#else
+    failf(data, "SMTP over http proxy requires HTTP support built-in!");
+    return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+  }
+
+  data->state.path++;   /* don't include the initial slash */
+
+  return CURLE_OK;
+}
+
+CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread)
+{
+  /* When sending SMTP payload, we must detect CRLF.CRLF sequences in
+   * the data and make sure it is sent as CRLF..CRLF instead, as
+   * otherwise it will wrongly be detected as end of data by the server.
+   */
+  ssize_t i;
+  ssize_t si;
+  struct smtp_conn *smtpc = &conn->proto.smtpc;
+  struct SessionHandle *data = conn->data;
+
+  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;
+  }
+  /* This loop can be improved by some kind of Boyer-Moore style of
+     approach but that is saved for later... */
+  for(i = 0, si = 0; i < nread; i++, si++) {
+    ssize_t left = nread - i;
+
+    if(left>= (ssize_t)(SMTP_EOB_LEN-smtpc->eob)) {
+      if(!memcmp(SMTP_EOB+smtpc->eob, &data->req.upload_fromhere[i],
+                 SMTP_EOB_LEN-smtpc->eob)) {
+        /* It matched, copy the replacement data to the target buffer
+           instead. Note that the replacement does not contain the
+           trailing CRLF but we instead continue to match on that one
+           to deal with repeated sequences. Like CRLF.CRLF.CRLF etc
+        */
+        memcpy(&data->state.scratch[si], SMTP_EOB_REPL,
+               SMTP_EOB_REPL_LEN);
+        si+=SMTP_EOB_REPL_LEN-1; /* minus one since the for() increments
+                                          it */
+        i+=SMTP_EOB_LEN-smtpc->eob-1-2;
+        smtpc->eob = 0; /* start over */
+        continue;
+      }
+    }
+    else if(!memcmp(SMTP_EOB+smtpc->eob, &data->req.upload_fromhere[i],
+                    left)) {
+      /* the last piece of the data matches the EOB so we can't send that
+         until we know the rest of it */
+      smtpc->eob += left;
+      break;
+    }
+
+    data->state.scratch[si] = data->req.upload_fromhere[i];
+  } /* for() */
+
+  if(si != nread) {
+    /* only use the new buffer if we replaced something */
+    nread = si;
+
+    /* upload from the new (replaced) buffer instead */
+    data->req.upload_fromhere = data->state.scratch;
+
+    /* set the new amount too */
+    data->req.upload_present = nread;
+  }
+  return CURLE_OK;
+}
+
+#endif /* CURL_DISABLE_SMTP */
diff --git a/lib/smtp.h b/lib/smtp.h
new file mode 100644
index 0000000..4716338
--- /dev/null
+++ b/lib/smtp.h
@@ -0,0 +1,69 @@
+#ifndef __SMTP_H
+#define __SMTP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2009 - 2010, 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 "pingpong.h"
+
+/****************************************************************************
+ * SMTP unique setup
+ ***************************************************************************/
+typedef enum {
+  SMTP_STOP,        /* do nothing state, stops the state machine */
+  SMTP_SERVERGREET, /* waiting for the initial greeting immediately after
+                       a connect */
+  SMTP_EHLO,
+  SMTP_HELO,
+  SMTP_STARTTLS,
+  SMTP_MAIL, /* MAIL FROM */
+  SMTP_RCPT, /* RCPT TO */
+  SMTP_DATA,
+  SMTP_POSTDATA,
+  SMTP_QUIT,
+  SMTP_LAST  /* never used */
+} smtpstate;
+
+/* smtp_conn is used for struct connection-oriented data in the connectdata
+   struct */
+struct smtp_conn {
+  struct pingpong pp;
+  char *domain;    /* what to send in the EHLO */
+  size_t eob;         /* number of bytes of the EOB (End Of Body) that has been
+                         received thus far */
+  smtpstate state; /* always use smtp.c:state() to change state! */
+  struct curl_slist *rcpt;
+};
+
+extern const struct Curl_handler Curl_handler_smtp;
+extern const struct Curl_handler Curl_handler_smtps;
+
+/* this is the 5-bytes End-Of-Body marker for SMTP */
+#define SMTP_EOB "\x0d\x0a\x2e\x0d\x0a"
+#define SMTP_EOB_LEN 5
+
+/* if found in data, replace it with this string instead */
+#define SMTP_EOB_REPL "\x0d\x0a\x2e\x2e"
+#define SMTP_EOB_REPL_LEN 4
+
+CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread);
+
+#endif /* __SMTP_H */
diff --git a/lib/sockaddr.h b/lib/sockaddr.h
new file mode 100644
index 0000000..c69411b
--- /dev/null
+++ b/lib/sockaddr.h
@@ -0,0 +1,37 @@
+#ifndef __SOCKADDR_H
+#define __SOCKADDR_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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"
+
+#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
+struct Curl_sockaddr_storage {
+  struct sockaddr_storage buffer;
+};
+#else
+struct Curl_sockaddr_storage {
+  char buffer[256];   /* this should be big enough to fit a lot */
+};
+#endif
+
+#endif /* __SOCKADDR_H */
diff --git a/lib/socks.c b/lib/socks.c
new file mode 100644
index 0000000..eb79567
--- /dev/null
+++ b/lib/socks.c
@@ -0,0 +1,726 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+#if !defined(CURL_DISABLE_PROXY) || defined(USE_WINDOWS_SSPI)
+#include <string.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.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 "urldata.h"
+#include "sendf.h"
+#include "strequal.h"
+#include "select.h"
+#include "connect.h"
+#include "timeval.h"
+#include "socks.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * Helper read-from-socket functions. Does the same as Curl_read() but it
+ * blocks until all bytes amount of buffersize will be read. No more, no less.
+ *
+ * This is STUPID BLOCKING behaviour which we frown upon, but right now this
+ * is what we have...
+ */
+int Curl_blockread_all(struct connectdata *conn, /* connection data */
+                       curl_socket_t sockfd,     /* read from this socket */
+                       char *buf,                /* store read data here */
+                       ssize_t buffersize,       /* max amount to read */
+                       ssize_t *n,               /* amount bytes read */
+                       long conn_timeout)        /* timeout for data wait
+                                                    relative to
+                                                    conn->created */
+{
+  ssize_t nread;
+  ssize_t allread = 0;
+  int result;
+  struct timeval tvnow;
+  long conntime;
+  *n = 0;
+  for(;;) {
+    tvnow = Curl_tvnow();
+    /* calculating how long connection is establishing */
+    conntime = Curl_tvdiff(tvnow, conn->created);
+    if(conntime > conn_timeout) {
+      /* we already got the timeout */
+      result = ~CURLE_OK;
+      break;
+    }
+    if(Curl_socket_ready(sockfd, CURL_SOCKET_BAD,
+                   (int)(conn_timeout - conntime)) <= 0) {
+      result = ~CURLE_OK;
+      break;
+    }
+    result = Curl_read_plain(sockfd, buf, buffersize, &nread);
+    if(result)
+      break;
+
+    if(buffersize == nread) {
+      allread += nread;
+      *n = allread;
+      result = CURLE_OK;
+      break;
+    }
+    if(!nread) {
+      result = ~CURLE_OK;
+      break;
+    }
+
+    buffersize -= nread;
+    buf += nread;
+    allread += nread;
+  }
+  return result;
+}
+
+/*
+* This function logs in to a SOCKS4 proxy and sends the specifics to the final
+* destination server.
+*
+* Reference :
+*   http://socks.permeo.com/protocol/socks4.protocol
+*
+* Note :
+*   Set protocol4a=true for  "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)"
+*   Nonsupport "Identification Protocol (RFC1413)"
+*/
+CURLcode Curl_SOCKS4(const char *proxy_name,
+                     const char *hostname,
+                     int remote_port,
+                     int sockindex,
+                     struct connectdata *conn,
+                     bool protocol4a)
+{
+#define SOCKS4REQLEN 262
+  unsigned char socksreq[SOCKS4REQLEN]; /* room for SOCKS4 request incl. user
+                                           id */
+  int result;
+  CURLcode code;
+  curl_socket_t sock = conn->sock[sockindex];
+  long timeout;
+  struct SessionHandle *data = conn->data;
+
+  /* get timeout */
+  timeout = Curl_timeleft(conn, NULL, TRUE);
+
+  if(timeout < 0) {
+    /* time-out, bail out, go home */
+    failf(data, "Connection time-out");
+    return CURLE_OPERATION_TIMEDOUT;
+  }
+
+  curlx_nonblock(sock, FALSE);
+
+  /*
+   * Compose socks4 request
+   *
+   * Request format
+   *
+   *     +----+----+----+----+----+----+----+----+----+----+....+----+
+   *     | VN | CD | DSTPORT |      DSTIP        | USERID       |NULL|
+   *     +----+----+----+----+----+----+----+----+----+----+....+----+
+   * # of bytes:  1    1      2              4           variable       1
+   */
+
+  socksreq[0] = 4; /* version (SOCKS4) */
+  socksreq[1] = 1; /* connect */
+  *((unsigned short*)&socksreq[2]) = htons((unsigned short)remote_port);
+
+  /* DNS resolve only for SOCKS4, not SOCKS4a */
+  if (!protocol4a) {
+    struct Curl_dns_entry *dns;
+    Curl_addrinfo *hp=NULL;
+    int rc;
+
+    rc = Curl_resolv(conn, hostname, remote_port, &dns);
+
+    if(rc == CURLRESOLV_ERROR)
+      return CURLE_COULDNT_RESOLVE_PROXY;
+
+    if(rc == CURLRESOLV_PENDING)
+      /* this requires that we're in "wait for resolve" state */
+      rc = Curl_wait_for_resolv(conn, &dns);
+
+    /*
+     * 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])) {
+        /* Set DSTIP */
+        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(data, dns); /* not used anymore from now on */
+
+    }
+    if(!hp) {
+      failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.",
+            hostname);
+      return CURLE_COULDNT_RESOLVE_HOST;
+    }
+  }
+
+  /*
+   * This is currently not supporting "Identification Protocol (RFC1413)".
+   */
+  socksreq[8] = 0; /* ensure empty userid is NUL-terminated */
+  if(proxy_name)
+    strlcat((char*)socksreq + 8, proxy_name, sizeof(socksreq) - 8);
+
+  /*
+   * Make connection
+   */
+  {
+    ssize_t actualread;
+    ssize_t written;
+    ssize_t hostnamelen = 0;
+    int packetsize = 9 +
+      (int)strlen((char*)socksreq + 8); /* size including NUL */
+
+    /* If SOCKS4a, set special invalid IP address 0.0.0.x */
+    if (protocol4a) {
+      socksreq[4] = 0;
+      socksreq[5] = 0;
+      socksreq[6] = 0;
+      socksreq[7] = 1;
+      /* If still enough room in buffer, also append hostname */
+      hostnamelen = (ssize_t)strlen(hostname) + 1; /* length including NUL */
+      if (packetsize + hostnamelen <= SOCKS4REQLEN)
+        strcpy((char*)socksreq + packetsize, hostname);
+      else
+        hostnamelen = 0; /* Flag: hostname did not fit in buffer */
+    }
+
+    /* Send request */
+    code = Curl_write_plain(conn, sock, (char *)socksreq,
+                            packetsize + hostnamelen,
+                            &written);
+    if((code != CURLE_OK) || (written != packetsize + hostnamelen)) {
+      failf(data, "Failed to send SOCKS4 connect request.");
+      return CURLE_COULDNT_CONNECT;
+    }
+    if (protocol4a && hostnamelen == 0) {
+      /* SOCKS4a with very long hostname - send that name separately */
+      hostnamelen = (ssize_t)strlen(hostname) + 1;
+      code = Curl_write_plain(conn, sock, (char *)hostname, hostnamelen,
+                              &written);
+      if((code != CURLE_OK) || (written != hostnamelen)) {
+        failf(data, "Failed to send SOCKS4 connect request.");
+        return CURLE_COULDNT_CONNECT;
+      }
+    }
+
+    packetsize = 8; /* receive data size */
+
+    /* Receive response */
+    result = Curl_blockread_all(conn, sock, (char *)socksreq, packetsize,
+                           &actualread, timeout);
+    if((result != CURLE_OK) || (actualread != packetsize)) {
+      failf(data, "Failed to receive SOCKS4 connect request ack.");
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    /*
+     * Response format
+     *
+     *     +----+----+----+----+----+----+----+----+
+     *     | VN | CD | DSTPORT |      DSTIP        |
+     *     +----+----+----+----+----+----+----+----+
+     * # of bytes:  1    1      2              4
+     *
+     * VN is the version of the reply code and should be 0. CD is the result
+     * code with one of the following values:
+     *
+     * 90: request granted
+     * 91: request rejected or failed
+     * 92: request rejected because SOCKS server cannot connect to
+     *     identd on the client
+     * 93: request rejected because the client program and identd
+     *     report different user-ids
+     */
+
+    /* wrong version ? */
+    if(socksreq[0] != 0) {
+      failf(data,
+            "SOCKS4 reply has wrong version, version should be 4.");
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    /* Result */
+    switch(socksreq[1])
+    {
+    case 90:
+      if (protocol4a)
+        infof(data, "SOCKS4a request granted.\n");
+      else
+        infof(data, "SOCKS4 request granted.\n");
+      break;
+    case 91:
+      failf(data,
+            "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
+            ", request rejected or failed.",
+            (unsigned char)socksreq[4], (unsigned char)socksreq[5],
+            (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+            (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
+            socksreq[1]);
+      return CURLE_COULDNT_CONNECT;
+    case 92:
+      failf(data,
+            "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
+            ", request rejected because SOCKS server cannot connect to "
+            "identd on the client.",
+            (unsigned char)socksreq[4], (unsigned char)socksreq[5],
+            (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+            (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
+            socksreq[1]);
+      return CURLE_COULDNT_CONNECT;
+    case 93:
+      failf(data,
+            "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
+            ", request rejected because the client program and identd "
+            "report different user-ids.",
+            (unsigned char)socksreq[4], (unsigned char)socksreq[5],
+            (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+            (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
+            socksreq[1]);
+      return CURLE_COULDNT_CONNECT;
+    default:
+      failf(data,
+            "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
+            ", Unknown.",
+            (unsigned char)socksreq[4], (unsigned char)socksreq[5],
+            (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+            (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
+            socksreq[1]);
+      return CURLE_COULDNT_CONNECT;
+    }
+  }
+
+  curlx_nonblock(sock, TRUE);
+
+  return CURLE_OK; /* Proxy was successful! */
+}
+
+/*
+ * This function logs in to a SOCKS5 proxy and sends the specifics to the final
+ * destination server.
+ */
+CURLcode Curl_SOCKS5(const char *proxy_name,
+                     const char *proxy_password,
+                     const char *hostname,
+                     int remote_port,
+                     int sockindex,
+                     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;
+  curl_socket_t sock = conn->sock[sockindex];
+  struct SessionHandle *data = conn->data;
+  long timeout;
+  bool socks5_resolve_local = (bool)(data->set.proxytype == CURLPROXY_SOCKS5);
+  const size_t hostname_len = strlen(hostname);
+  ssize_t packetsize = 0;
+
+  /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */
+  if(!socks5_resolve_local && hostname_len > 255)
+  {
+    infof(conn->data,"SOCKS5: server resolving disabled for hostnames of "
+          "length > 255 [actual len=%zu]\n", hostname_len);
+    socks5_resolve_local = TRUE;
+  }
+
+  /* get timeout */
+  timeout = Curl_timeleft(conn, NULL, TRUE);
+
+  if(timeout < 0) {
+    /* time-out, bail out, go home */
+    failf(data, "Connection time-out");
+    return CURLE_OPERATION_TIMEDOUT;
+  }
+
+  curlx_nonblock(sock, TRUE);
+
+  /* wait until socket gets connected */
+  result = Curl_socket_ready(CURL_SOCKET_BAD, sock, (int)timeout);
+
+  if(-1 == result) {
+    failf(conn->data, "SOCKS5: no connection here");
+    return CURLE_COULDNT_CONNECT;
+  }
+  else if(0 == result) {
+    failf(conn->data, "SOCKS5: connection timeout");
+    return CURLE_OPERATION_TIMEDOUT;
+  }
+
+  if(result & CURL_CSELECT_ERR) {
+    failf(conn->data, "SOCKS5: error occured during connection");
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  socksreq[0] = 5; /* version */
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+  socksreq[1] = (char)(proxy_name ? 3 : 2); /* number of methods (below) */
+  socksreq[2] = 0; /* no authentication */
+  socksreq[3] = 1; /* gssapi */
+  socksreq[4] = 2; /* username/password */
+#else
+  socksreq[1] = (char)(proxy_name ? 2 : 1); /* number of methods (below) */
+  socksreq[2] = 0; /* no authentication */
+  socksreq[3] = 2; /* username/password */
+#endif
+
+  curlx_nonblock(sock, FALSE);
+
+  code = Curl_write_plain(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]),
+                          &written);
+  if((code != CURLE_OK) || (written != (2 + (int)socksreq[1]))) {
+    failf(data, "Unable to send initial SOCKS5 request.");
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  curlx_nonblock(sock, TRUE);
+
+  result = Curl_socket_ready(sock, CURL_SOCKET_BAD, (int)timeout);
+
+  if(-1 == result) {
+    failf(conn->data, "SOCKS5 nothing to read");
+    return CURLE_COULDNT_CONNECT;
+  }
+  else if(0 == result) {
+    failf(conn->data, "SOCKS5 read timeout");
+    return CURLE_OPERATION_TIMEDOUT;
+  }
+
+  if(result & CURL_CSELECT_ERR) {
+    failf(conn->data, "SOCKS5 read error occured");
+    return CURLE_RECV_ERROR;
+  }
+
+  curlx_nonblock(sock, FALSE);
+
+  result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread,
+                            timeout);
+  if((result != CURLE_OK) || (actualread != 2)) {
+    failf(data, "Unable to receive initial SOCKS5 response.");
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  if(socksreq[0] != 5) {
+    failf(data, "Received invalid version in initial SOCKS5 response.");
+    return CURLE_COULDNT_CONNECT;
+  }
+  if(socksreq[1] == 0) {
+    /* Nothing to do, no authentication needed */
+    ;
+  }
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+  else if(socksreq[1] == 1) {
+    code = Curl_SOCKS5_gssapi_negotiate(sockindex, conn);
+    if(code != CURLE_OK) {
+      failf(data, "Unable to negotiate SOCKS5 gssapi context.");
+      return CURLE_COULDNT_CONNECT;
+    }
+  }
+#endif
+  else if(socksreq[1] == 2) {
+    /* Needs user name and password */
+    size_t userlen, pwlen;
+    int len;
+    if(proxy_name && proxy_password) {
+      userlen = strlen(proxy_name);
+      pwlen = strlen(proxy_password);
+    }
+    else {
+      userlen = 0;
+      pwlen = 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, userlen);
+    len += (int)userlen;
+    socksreq[len++] = (char) pwlen;
+    memcpy(socksreq + len, proxy_password, pwlen);
+    len += (int)pwlen;
+
+    code = Curl_write_plain(conn, sock, (char *)socksreq, len, &written);
+    if((code != CURLE_OK) || (len != written)) {
+      failf(data, "Failed to send SOCKS5 sub-negotiation request.");
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread,
+                         timeout);
+    if((result != CURLE_OK) || (actualread != 2)) {
+      failf(data, "Unable to receive SOCKS5 sub-negotiation response.");
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    /* ignore the first (VER) byte */
+    if(socksreq[1] != 0) { /* status */
+      failf(data, "User was rejected by the SOCKS5 server (%d %d).",
+            socksreq[0], socksreq[1]);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    /* Everything is good so far, user was authenticated! */
+  }
+  else {
+    /* error */
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+    if(socksreq[1] == 255) {
+#else
+    if(socksreq[1] == 1) {
+      failf(data,
+            "SOCKS5 GSSAPI per-message authentication is not supported.");
+      return CURLE_COULDNT_CONNECT;
+    }
+    else if(socksreq[1] == 255) {
+#endif
+      if(!proxy_name || !*proxy_name) {
+        failf(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(data, "No authentication method was acceptable.");
+      }
+      return CURLE_COULDNT_CONNECT;
+    }
+    else {
+      failf(data,
+            "Undocumented SOCKS5 mode attempted to be used by server.");
+      return CURLE_COULDNT_CONNECT;
+    }
+  }
+
+  /* Authentication is complete, now specify destination to the proxy */
+  socksreq[0] = 5; /* version (SOCKS5) */
+  socksreq[1] = 1; /* connect */
+  socksreq[2] = 0; /* must be zero */
+
+  if(!socks5_resolve_local) {
+    packetsize = (ssize_t)(5 + hostname_len + 2);
+
+    socksreq[3] = 3; /* ATYP: domain name = 3 */
+    socksreq[4] = (char) hostname_len; /* address length */
+    memcpy(&socksreq[5], hostname, hostname_len); /* address bytes w/o NULL */
+
+    *((unsigned short*)&socksreq[hostname_len+5]) =
+      htons((unsigned short)remote_port);
+  }
+  else {
+    struct Curl_dns_entry *dns;
+    Curl_addrinfo *hp=NULL;
+    int rc = Curl_resolv(conn, hostname, remote_port, &dns);
+
+    packetsize = 10;
+
+    socksreq[3] = 1; /* IPv4 = 1 */
+
+    if(rc == CURLRESOLV_ERROR)
+      return CURLE_COULDNT_RESOLVE_HOST;
+
+    if(rc == CURLRESOLV_PENDING)
+      /* this requires that we're in "wait for resolve" state */
+      rc = Curl_wait_for_resolv(conn, &dns);
+
+    /*
+     * 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(data, dns); /* not used anymore from now on */
+    }
+    if(!hp) {
+      failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.",
+            hostname);
+      return CURLE_COULDNT_RESOLVE_HOST;
+    }
+
+    *((unsigned short*)&socksreq[8]) = htons((unsigned short)remote_port);
+  }
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+  if(conn->socks5_gssapi_enctype) {
+    failf(data, "SOCKS5 gssapi protection not yet implemented.");
+  } else
+#endif
+  code = Curl_write_plain(conn, sock, (char *)socksreq, packetsize, &written);
+  if((code != CURLE_OK) || (written != packetsize)) {
+    failf(data, "Failed to send SOCKS5 connect request.");
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  packetsize = 10; /* minimum packet size is 10 */
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+  if(conn->socks5_gssapi_enctype) {
+    failf(data, "SOCKS5 gssapi protection not yet implemented.");
+  } else
+#endif
+    result = Curl_blockread_all(conn, sock, (char *)socksreq, packetsize,
+                           &actualread, timeout);
+  if((result != CURLE_OK) || (actualread != packetsize)) {
+    failf(data, "Failed to receive SOCKS5 connect request ack.");
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  if(socksreq[0] != 5) { /* version */
+    failf(data,
+          "SOCKS5 reply has wrong version, version should be 5.");
+    return CURLE_COULDNT_CONNECT;
+  }
+  if(socksreq[1] != 0) { /* Anything besides 0 is an error */
+      failf(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(*(unsigned short*)(&socksreq[8])),
+            socksreq[1]);
+      return CURLE_COULDNT_CONNECT;
+  }
+
+  /* Fix: in general, returned BND.ADDR is variable length parameter by RFC
+     1928, so the reply packet should be read until the end to avoid errors at
+     subsequent protocol level.
+
+    +----+-----+-------+------+----------+----------+
+    |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
+    +----+-----+-------+------+----------+----------+
+    | 1  |  1  | X'00' |  1   | Variable |    2     |
+    +----+-----+-------+------+----------+----------+
+
+     ATYP:
+     o  IP v4 address: X'01', BND.ADDR = 4 byte
+     o  domain name:  X'03', BND.ADDR = [ 1 byte length, string ]
+     o  IP v6 address: X'04', BND.ADDR = 16 byte
+     */
+
+  /* Calculate real packet size */
+  if(socksreq[3] == 3) {
+    /* domain name */
+    int addrlen = (int) socksreq[4];
+    packetsize = 5 + addrlen + 2;
+  }
+  else if(socksreq[3] == 4) {
+    /* IPv6 */
+    packetsize = 4 + 16 + 2;
+  }
+
+  /* At this point we already read first 10 bytes */
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+  if(!conn->socks5_gssapi_enctype) {
+    /* decrypt_gssapi_blockread already read the whole packet */
+#endif
+    if(packetsize > 10) {
+      packetsize -= 10;
+      result = Curl_blockread_all(conn, sock, (char *)&socksreq[10],
+                                  packetsize, &actualread, timeout);
+      if((result != CURLE_OK) || (actualread != packetsize)) {
+        failf(data, "Failed to receive SOCKS5 connect request ack.");
+        return CURLE_COULDNT_CONNECT;
+      }
+    }
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+  }
+#endif
+
+  curlx_nonblock(sock, TRUE);
+  return CURLE_OK; /* Proxy was successful! */
+}
+
+#endif /* CURL_DISABLE_PROXY */
+
diff --git a/lib/socks.h b/lib/socks.h
new file mode 100644
index 0000000..2bea66b
--- /dev/null
+++ b/lib/socks.h
@@ -0,0 +1,69 @@
+#ifndef __SOCKS_H
+#define __SOCKS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+/*
+ * Helper read-from-socket functions. Does the same as Curl_read() but it
+ * blocks until all bytes amount of buffersize will be read. No more, no less.
+ *
+ * This is STUPID BLOCKING behaviour which we frown upon, but right now this
+ * is what we have...
+ */
+int Curl_blockread_all(struct connectdata *conn,
+                       curl_socket_t sockfd,
+                       char *buf,
+                       ssize_t buffersize,
+                       ssize_t *n,
+                       long conn_timeout);
+
+/*
+ * This function logs in to a SOCKS4(a) proxy and sends the specifics to the
+ * final destination server.
+ */
+CURLcode Curl_SOCKS4(const char *proxy_name,
+                     const char *hostname,
+                     int remote_port,
+                     int sockindex,
+                     struct connectdata *conn,
+                     bool protocol4a);
+
+/*
+ * This function logs in to a SOCKS5 proxy and sends the specifics to the
+ * final destination server.
+ */
+CURLcode Curl_SOCKS5(const char *proxy_name,
+                     const char *proxy_password,
+                     const char *hostname,
+                     int remote_port,
+                     int sockindex,
+                     struct connectdata *conn);
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+/*
+ * This function handles the sockss5 gssapie negotiation and initialisation
+ */
+CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
+                                      struct connectdata *conn);
+#endif
+
+#endif  /* __SOCKS_H */
diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c
new file mode 100644
index 0000000..1ff6f60
--- /dev/null
+++ b/lib/socks_gssapi.c
@@ -0,0 +1,548 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2009, Markus Moeller, <markus_moeller@compuserve.com>
+ *
+ * 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"
+
+#ifndef CURL_DISABLE_PROXY
+
+#ifdef HAVE_GSSAPI
+#ifdef HAVE_OLD_GSSMIT
+#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
+#endif
+#ifndef gss_nt_service_name
+#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
+#endif
+#include <string.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "connect.h"
+#include "timeval.h"
+#include "socks.h"
+
+static gss_ctx_id_t     gss_context = GSS_C_NO_CONTEXT;
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * Helper gssapi error functions.
+ */
+static int check_gss_err(struct SessionHandle *data,
+                         OM_uint32 major_status,
+                         OM_uint32 minor_status,
+                         const char* function)
+{
+  if(GSS_ERROR(major_status)) {
+    OM_uint32 maj_stat,min_stat;
+    OM_uint32 msg_ctx = 0;
+    gss_buffer_desc status_string;
+    char buf[1024];
+    size_t len;
+
+    len = 0;
+    msg_ctx = 0;
+    while(!msg_ctx) {
+      /* convert major status code (GSS-API error) to text */
+      maj_stat = gss_display_status(&min_stat, major_status,
+                                    GSS_C_GSS_CODE,
+                                    GSS_C_NULL_OID,
+                                    &msg_ctx, &status_string);
+      if(maj_stat == GSS_S_COMPLETE) {
+        if(sizeof(buf) > len + status_string.length + 1) {
+          strcpy(buf+len, (char*) status_string.value);
+          len += status_string.length;
+        }
+        gss_release_buffer(&min_stat, &status_string);
+        break;
+      }
+      gss_release_buffer(&min_stat, &status_string);
+    }
+    if(sizeof(buf) > len + 3) {
+      strcpy(buf+len, ".\n");
+      len += 2;
+    }
+    msg_ctx = 0;
+    while(!msg_ctx) {
+      /* convert minor status code (underlying routine error) to text */
+      maj_stat = gss_display_status(&min_stat, minor_status,
+                                    GSS_C_MECH_CODE,
+                                    GSS_C_NULL_OID,
+                                    &msg_ctx, &status_string);
+      if(maj_stat == GSS_S_COMPLETE) {
+        if(sizeof(buf) > len + status_string.length) {
+          strcpy(buf+len, (char*) status_string.value);
+          len += status_string.length;
+        }
+        gss_release_buffer(&min_stat, &status_string);
+        break;
+      }
+      gss_release_buffer(&min_stat, &status_string);
+    }
+    failf(data, "GSSAPI error: %s failed:\n%s\n", function, buf);
+    return(1);
+  }
+
+  return(0);
+}
+
+CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
+                                      struct connectdata *conn)
+{
+  struct SessionHandle *data = conn->data;
+  curl_socket_t sock = conn->sock[sockindex];
+  CURLcode code;
+  ssize_t actualread;
+  ssize_t written;
+  int result;
+  long timeout;
+  OM_uint32 gss_major_status, gss_minor_status, gss_status;
+  OM_uint32 gss_ret_flags;
+  int gss_conf_state, gss_enc;
+  gss_buffer_desc  service = GSS_C_EMPTY_BUFFER;
+  gss_buffer_desc  gss_send_token = GSS_C_EMPTY_BUFFER;
+  gss_buffer_desc  gss_recv_token = GSS_C_EMPTY_BUFFER;
+  gss_buffer_desc  gss_w_token = GSS_C_EMPTY_BUFFER;
+  gss_buffer_desc* gss_token = GSS_C_NO_BUFFER;
+  gss_name_t       server = GSS_C_NO_NAME;
+  gss_name_t       gss_client_name = GSS_C_NO_NAME;
+  u_short          us_length;
+  char             *user=NULL;
+  unsigned char socksreq[4]; /* room for gssapi exchange header only */
+  char *serviceptr = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE];
+
+  /* get timeout */
+  timeout = Curl_timeleft(conn, NULL, TRUE);
+
+  /*   GSSAPI request looks like
+   * +----+------+-----+----------------+
+   * |VER | MTYP | LEN |     TOKEN      |
+   * +----+------+----------------------+
+   * | 1  |  1   |  2  | up to 2^16 - 1 |
+   * +----+------+-----+----------------+
+   */
+
+  /* prepare service name */
+  if (strchr(serviceptr,'/')) {
+    service.value = malloc(strlen(serviceptr));
+    if(!service.value)
+      return CURLE_OUT_OF_MEMORY;
+    service.length = strlen(serviceptr);
+    memcpy(service.value, serviceptr, service.length);
+
+    gss_major_status = gss_import_name(&gss_minor_status, &service,
+                                       (gss_OID) GSS_C_NULL_OID, &server);
+  }
+  else {
+    service.value = malloc(strlen(serviceptr) +strlen(conn->proxy.name)+2);
+    if(!service.value)
+      return CURLE_OUT_OF_MEMORY;
+    service.length = strlen(serviceptr) +strlen(conn->proxy.name)+1;
+    snprintf(service.value, service.length+1, "%s@%s",
+             serviceptr, conn->proxy.name);
+
+    gss_major_status = gss_import_name(&gss_minor_status, &service,
+                                       gss_nt_service_name, &server);
+  }
+
+  gss_release_buffer(&gss_status, &service); /* clear allocated memory */
+
+  if(check_gss_err(data,gss_major_status,
+                   gss_minor_status,"gss_import_name()")) {
+    failf(data, "Failed to create service name.");
+    gss_release_name(&gss_status, &server);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  /* As long as we need to keep sending some context info, and there's no  */
+  /* errors, keep sending it...                                            */
+  for(;;) {
+    gss_major_status = gss_init_sec_context(&gss_minor_status,
+                                            GSS_C_NO_CREDENTIAL,
+                                            &gss_context, server,
+                                            GSS_C_NULL_OID,
+                                            GSS_C_MUTUAL_FLAG |
+                                            GSS_C_REPLAY_FLAG,
+                                            0,
+                                            NULL,
+                                            gss_token,
+                                            NULL,
+                                            &gss_send_token,
+                                            &gss_ret_flags,
+                                            NULL);
+
+    if(gss_token != GSS_C_NO_BUFFER)
+      gss_release_buffer(&gss_status, &gss_recv_token);
+    if(check_gss_err(data,gss_major_status,
+                     gss_minor_status,"gss_init_sec_context")) {
+      gss_release_name(&gss_status, &server);
+      gss_release_buffer(&gss_status, &gss_recv_token);
+      gss_release_buffer(&gss_status, &gss_send_token);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      failf(data, "Failed to initial GSSAPI token.");
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    if(gss_send_token.length != 0) {
+      socksreq[0] = 1;    /* gssapi subnegotiation version */
+      socksreq[1] = 1;    /* authentication message type */
+      us_length = htons((short)gss_send_token.length);
+      memcpy(socksreq+2,&us_length,sizeof(short));
+
+      code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
+      if((code != CURLE_OK) || (4 != written)) {
+        failf(data, "Failed to send GSSAPI authentication request.");
+        gss_release_name(&gss_status, &server);
+        gss_release_buffer(&gss_status, &gss_recv_token);
+        gss_release_buffer(&gss_status, &gss_send_token);
+        gss_delete_sec_context(&gss_status, &gss_context, NULL);
+        return CURLE_COULDNT_CONNECT;
+      }
+
+      code = Curl_write_plain(conn, sock, (char *)gss_send_token.value,
+                              gss_send_token.length, &written);
+
+      if((code != CURLE_OK) || ((ssize_t)gss_send_token.length != written)) {
+        failf(data, "Failed to send GSSAPI authentication token.");
+        gss_release_name(&gss_status, &server);
+        gss_release_buffer(&gss_status, &gss_recv_token);
+        gss_release_buffer(&gss_status, &gss_send_token);
+        gss_delete_sec_context(&gss_status, &gss_context, NULL);
+        return CURLE_COULDNT_CONNECT;
+      }
+
+    }
+
+    gss_release_buffer(&gss_status, &gss_send_token);
+    gss_release_buffer(&gss_status, &gss_recv_token);
+    if(gss_major_status != GSS_S_CONTINUE_NEEDED) break;
+
+    /* analyse response */
+
+    /*   GSSAPI response looks like
+     * +----+------+-----+----------------+
+     * |VER | MTYP | LEN |     TOKEN      |
+     * +----+------+----------------------+
+     * | 1  |  1   |  2  | up to 2^16 - 1 |
+     * +----+------+-----+----------------+
+     */
+
+    result=Curl_blockread_all(conn, sock, (char *)socksreq, 4,
+                              &actualread, timeout);
+    if(result != CURLE_OK || actualread != 4) {
+      failf(data, "Failed to receive GSSAPI authentication response.");
+      gss_release_name(&gss_status, &server);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    /* ignore the first (VER) byte */
+    if(socksreq[1] == 255) { /* status / message type */
+      failf(data, "User was rejected by the SOCKS5 server (%d %d).",
+            socksreq[0], socksreq[1]);
+      gss_release_name(&gss_status, &server);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    if(socksreq[1] != 1) { /* status / messgae type */
+      failf(data, "Invalid GSSAPI authentication response type (%d %d).",
+            socksreq[0], socksreq[1]);
+      gss_release_name(&gss_status, &server);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    memcpy(&us_length, socksreq+2, sizeof(short));
+    us_length = ntohs(us_length);
+
+    gss_recv_token.length=us_length;
+    gss_recv_token.value=malloc(us_length);
+    if(!gss_recv_token.value) {
+      failf(data,
+            "Could not allocate memory for GSSAPI authentication "
+            "response token.");
+      gss_release_name(&gss_status, &server);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
+                              gss_recv_token.length,
+                              &actualread, timeout);
+
+    if(result != CURLE_OK || actualread != us_length) {
+      failf(data, "Failed to receive GSSAPI authentication token.");
+      gss_release_name(&gss_status, &server);
+      gss_release_buffer(&gss_status, &gss_recv_token);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    gss_token = &gss_recv_token;
+  }
+
+  gss_release_name(&gss_status, &server);
+
+  /* Everything is good so far, user was authenticated! */
+  gss_major_status = gss_inquire_context (&gss_minor_status, gss_context,
+                                          &gss_client_name, NULL, NULL, NULL,
+                                          NULL, NULL, NULL);
+  if(check_gss_err(data,gss_major_status,
+                   gss_minor_status,"gss_inquire_context")) {
+    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    gss_release_name(&gss_status, &gss_client_name);
+    failf(data, "Failed to determine user name.");
+    return CURLE_COULDNT_CONNECT;
+  }
+  gss_major_status = gss_display_name(&gss_minor_status, gss_client_name,
+                                      &gss_send_token, NULL);
+  if(check_gss_err(data,gss_major_status,
+                   gss_minor_status,"gss_display_name")) {
+    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    gss_release_name(&gss_status, &gss_client_name);
+    gss_release_buffer(&gss_status, &gss_send_token);
+    failf(data, "Failed to determine user name.");
+    return CURLE_COULDNT_CONNECT;
+  }
+  user=malloc(gss_send_token.length+1);
+  if(!user) {
+    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    gss_release_name(&gss_status, &gss_client_name);
+    gss_release_buffer(&gss_status, &gss_send_token);
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  memcpy(user, gss_send_token.value, gss_send_token.length);
+  user[gss_send_token.length] = '\0';
+  gss_release_name(&gss_status, &gss_client_name);
+  gss_release_buffer(&gss_status, &gss_send_token);
+  infof(data, "SOCKS5 server authencticated user %s with gssapi.\n",user);
+  free(user);
+  user=NULL;
+
+  /* Do encryption */
+  socksreq[0] = 1;    /* gssapi subnegotiation version */
+  socksreq[1] = 2;    /* encryption message type */
+
+  gss_enc = 0; /* no data protection */
+  /* do confidentiality protection if supported */
+  if(gss_ret_flags & GSS_C_CONF_FLAG)
+    gss_enc = 2;
+  /* else do integrity protection */
+  else if(gss_ret_flags & GSS_C_INTEG_FLAG)
+    gss_enc = 1;
+
+  infof(data, "SOCKS5 server supports gssapi %s data protection.\n",
+        (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality"));
+  /* force for the moment to no data protection */
+  gss_enc = 0;
+  /*
+   * Sending the encryption type in clear seems wrong. It should be
+   * protected with gss_seal()/gss_wrap(). See RFC1961 extract below
+   * The NEC reference implementations on which this is based is
+   * therefore at fault
+   *
+   *  +------+------+------+.......................+
+   *  + ver  | mtyp | len  |   token               |
+   *  +------+------+------+.......................+
+   *  + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets |
+   *  +------+------+------+.......................+
+   *
+   *   Where:
+   *
+   *  - "ver" is the protocol version number, here 1 to represent the
+   *    first version of the SOCKS/GSS-API protocol
+   *
+   *  - "mtyp" is the message type, here 2 to represent a protection
+   *    -level negotiation message
+   *
+   *  - "len" is the length of the "token" field in octets
+   *
+   *  - "token" is the GSS-API encapsulated protection level
+   *
+   * The token is produced by encapsulating an octet containing the
+   * required protection level using gss_seal()/gss_wrap() with conf_req
+   * set to FALSE.  The token is verified using gss_unseal()/
+   * gss_unwrap().
+   *
+   */
+  if(data->set.socks5_gssapi_nec) {
+    us_length = htons((short)1);
+    memcpy(socksreq+2,&us_length,sizeof(short));
+  }
+  else {
+    gss_send_token.length = 1;
+    gss_send_token.value = malloc(1);
+    if(!gss_send_token.value) {
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      return CURLE_OUT_OF_MEMORY;
+    }
+    memcpy(gss_send_token.value, &gss_enc, 1);
+
+    gss_major_status = gss_wrap(&gss_minor_status, gss_context, 0,
+                                GSS_C_QOP_DEFAULT, &gss_send_token,
+                                &gss_conf_state, &gss_w_token);
+
+    if(check_gss_err(data,gss_major_status,gss_minor_status,"gss_wrap")) {
+      gss_release_buffer(&gss_status, &gss_send_token);
+      gss_release_buffer(&gss_status, &gss_w_token);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      failf(data, "Failed to wrap GSSAPI encryption value into token.");
+      return CURLE_COULDNT_CONNECT;
+    }
+    gss_release_buffer(&gss_status, &gss_send_token);
+
+    us_length = htons((short)gss_w_token.length);
+    memcpy(socksreq+2,&us_length,sizeof(short));
+  }
+
+  code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
+  if((code != CURLE_OK) || (4 != written)) {
+    failf(data, "Failed to send GSSAPI encryption request.");
+    gss_release_buffer(&gss_status, &gss_w_token);
+    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  if(data->set.socks5_gssapi_nec) {
+    memcpy(socksreq, &gss_enc, 1);
+    code = Curl_write_plain(conn, sock, socksreq, 1, &written);
+    if((code != CURLE_OK) || ( 1 != written)) {
+      failf(data, "Failed to send GSSAPI encryption type.");
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      return CURLE_COULDNT_CONNECT;
+    }
+  } else {
+    code = Curl_write_plain(conn, sock, (char *)gss_w_token.value,
+                            gss_w_token.length, &written);
+    if((code != CURLE_OK) || ((ssize_t)gss_w_token.length != written)) {
+      failf(data, "Failed to send GSSAPI encryption type.");
+      gss_release_buffer(&gss_status, &gss_w_token);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      return CURLE_COULDNT_CONNECT;
+    }
+    gss_release_buffer(&gss_status, &gss_w_token);
+  }
+
+  result=Curl_blockread_all(conn, sock, (char *)socksreq, 4,
+                            &actualread, timeout);
+  if(result != CURLE_OK || actualread != 4) {
+    failf(data, "Failed to receive GSSAPI encryption response.");
+    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  /* ignore the first (VER) byte */
+  if(socksreq[1] == 255) { /* status / message type */
+    failf(data, "User was rejected by the SOCKS5 server (%d %d).",
+          socksreq[0], socksreq[1]);
+    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  if(socksreq[1] != 2) { /* status / messgae type */
+    failf(data, "Invalid GSSAPI encryption response type (%d %d).",
+          socksreq[0], socksreq[1]);
+    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  memcpy(&us_length, socksreq+2, sizeof(short));
+  us_length = ntohs(us_length);
+
+  gss_recv_token.length= us_length;
+  gss_recv_token.value=malloc(gss_recv_token.length);
+  if(!gss_recv_token.value) {
+    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    return CURLE_OUT_OF_MEMORY;
+  }
+  result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
+                            gss_recv_token.length,
+                            &actualread, timeout);
+
+  if(result != CURLE_OK || actualread != us_length) {
+    failf(data, "Failed to receive GSSAPI encryptrion type.");
+    gss_release_buffer(&gss_status, &gss_recv_token);
+    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  if(!data->set.socks5_gssapi_nec) {
+    gss_major_status = gss_unwrap(&gss_minor_status, gss_context,
+                                  &gss_recv_token, &gss_w_token,
+                                  0, GSS_C_QOP_DEFAULT);
+
+    if(check_gss_err(data,gss_major_status,gss_minor_status,"gss_unwrap")) {
+      gss_release_buffer(&gss_status, &gss_recv_token);
+      gss_release_buffer(&gss_status, &gss_w_token);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      failf(data, "Failed to unwrap GSSAPI encryption value into token.");
+      return CURLE_COULDNT_CONNECT;
+    }
+    gss_release_buffer(&gss_status, &gss_recv_token);
+
+    if(gss_w_token.length != 1) {
+      failf(data, "Invalid GSSAPI encryption response length (%d).",
+            gss_w_token.length);
+      gss_release_buffer(&gss_status, &gss_w_token);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    memcpy(socksreq,gss_w_token.value,gss_w_token.length);
+    gss_release_buffer(&gss_status, &gss_w_token);
+  }
+  else {
+    if(gss_recv_token.length != 1) {
+      failf(data, "Invalid GSSAPI encryption response length (%d).",
+            gss_recv_token.length);
+      gss_release_buffer(&gss_status, &gss_recv_token);
+      gss_delete_sec_context(&gss_status, &gss_context, NULL);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    memcpy(socksreq,gss_recv_token.value,gss_recv_token.length);
+    gss_release_buffer(&gss_status, &gss_recv_token);
+  }
+
+  infof(data, "SOCKS5 access with%s protection granted.\n",
+        (socksreq[0]==0)?"out gssapi data":
+        ((socksreq[0]==1)?" gssapi integrity":" gssapi confidentiality"));
+
+  conn->socks5_gssapi_enctype = socksreq[0];
+  if(socksreq[0] == 0)
+    gss_delete_sec_context(&gss_status, &gss_context, NULL);
+
+  return CURLE_OK;
+}
+#endif
+
+#endif /* CURL_DISABLE_PROXY */
diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c
new file mode 100644
index 0000000..e9fd551
--- /dev/null
+++ b/lib/socks_sspi.c
@@ -0,0 +1,696 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2009, Markus Moeller, <markus_moeller@compuserve.com>
+ *
+ * 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"
+
+#ifdef USE_WINDOWS_SSPI
+
+#include <string.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "connect.h"
+#include "timeval.h"
+#include "socks.h"
+#include "curl_sspi.h"
+
+#define _MPRINTF_REPLACE /* use the internal *printf() functions */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * Definitions required from ntsecapi.h are directly provided below this point
+ * to avoid including ntsecapi.h due to a conflict with OpenSSL's safestack.h
+ */
+#define KERB_WRAP_NO_ENCRYPT 0x80000001
+
+/*
+ * Helper sspi error functions.
+ */
+static int check_sspi_err(struct SessionHandle *data,
+                          SECURITY_STATUS major_status,
+                          SECURITY_STATUS minor_status,
+                          const char* function)
+{
+  const char *txt;
+  (void)minor_status;
+
+  if(major_status != SEC_E_OK &&
+     major_status != SEC_I_COMPLETE_AND_CONTINUE &&
+     major_status != SEC_I_COMPLETE_NEEDED &&
+     major_status != SEC_I_CONTINUE_NEEDED) {
+    failf(data, "SSPI error: %s failed: %d\n", function, major_status);
+    switch (major_status) {
+    case SEC_I_COMPLETE_AND_CONTINUE:
+      txt="SEC_I_COMPLETE_AND_CONTINUE";
+      break;
+    case SEC_I_COMPLETE_NEEDED:
+      txt="SEC_I_COMPLETE_NEEDED";
+      break;
+    case SEC_I_CONTINUE_NEEDED:
+      txt="SEC_I_CONTINUE_NEEDED";
+      break;
+    case SEC_I_CONTEXT_EXPIRED:
+      txt="SEC_I_CONTEXT_EXPIRED";
+      break;
+    case SEC_I_INCOMPLETE_CREDENTIALS:
+      txt="SEC_I_INCOMPLETE_CREDENTIALS";
+      break;
+    case SEC_I_RENEGOTIATE:
+      txt="SEC_I_RENEGOTIATE";
+      break;
+    case SEC_E_BUFFER_TOO_SMALL:
+      txt="SEC_E_BUFFER_TOO_SMALL";
+      break;
+    case SEC_E_CONTEXT_EXPIRED:
+      txt="SEC_E_CONTEXT_EXPIRED";
+      break;
+    case SEC_E_CRYPTO_SYSTEM_INVALID:
+      txt="SEC_E_CRYPTO_SYSTEM_INVALID";
+      break;
+    case SEC_E_INCOMPLETE_MESSAGE:
+      txt="SEC_E_INCOMPLETE_MESSAGE";
+      break;
+    case SEC_E_INSUFFICIENT_MEMORY:
+      txt="SEC_E_INSUFFICIENT_MEMORY";
+      break;
+    case SEC_E_INTERNAL_ERROR:
+      txt="SEC_E_INTERNAL_ERROR";
+      break;
+    case SEC_E_INVALID_HANDLE:
+      txt="SEC_E_INVALID_HANDLE";
+      break;
+    case SEC_E_INVALID_TOKEN:
+      txt="SEC_E_INVALID_TOKEN";
+      break;
+    case SEC_E_LOGON_DENIED:
+      txt="SEC_E_LOGON_DENIED";
+      break;
+    case SEC_E_MESSAGE_ALTERED:
+      txt="SEC_E_MESSAGE_ALTERED";
+      break;
+    case SEC_E_NO_AUTHENTICATING_AUTHORITY:
+      txt="SEC_E_NO_AUTHENTICATING_AUTHORITY";
+      break;
+    case SEC_E_NO_CREDENTIALS:
+      txt="SEC_E_NO_CREDENTIALS";
+      break;
+    case SEC_E_NOT_OWNER:
+      txt="SEC_E_NOT_OWNER";
+      break;
+    case SEC_E_OUT_OF_SEQUENCE:
+      txt="SEC_E_OUT_OF_SEQUENCE";
+      break;
+    case SEC_E_QOP_NOT_SUPPORTED:
+      txt="SEC_E_QOP_NOT_SUPPORTED";
+      break;
+    case SEC_E_SECPKG_NOT_FOUND:
+      txt="SEC_E_SECPKG_NOT_FOUND";
+      break;
+    case SEC_E_TARGET_UNKNOWN:
+      txt="SEC_E_TARGET_UNKNOWN";
+      break;
+    case SEC_E_UNKNOWN_CREDENTIALS:
+      txt="SEC_E_UNKNOWN_CREDENTIALS";
+      break;
+    case SEC_E_UNSUPPORTED_FUNCTION:
+      txt="SEC_E_UNSUPPORTED_FUNCTION";
+      break;
+    case SEC_E_WRONG_PRINCIPAL:
+      txt="SEC_E_WRONG_PRINCIPAL";
+      break;
+    default:
+      txt="Unknown error";
+
+    }
+    failf(data, "SSPI error: %s failed: %s\n", function, txt);
+    return 1;
+  }
+  return 0;
+}
+
+/* This is the SSPI-using version of this function */
+CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
+                                      struct connectdata *conn)
+{
+  struct SessionHandle *data = conn->data;
+  curl_socket_t sock = conn->sock[sockindex];
+  CURLcode code;
+  ssize_t actualread;
+  ssize_t written;
+  int result;
+  long timeout;
+  /* Needs GSSAPI authentication */
+  SECURITY_STATUS sspi_major_status, sspi_minor_status=0;
+  unsigned long sspi_ret_flags=0;
+  int gss_enc;
+  SecBuffer sspi_send_token, sspi_recv_token, sspi_w_token[3];
+  SecBufferDesc input_desc, output_desc, wrap_desc;
+  SecPkgContext_Sizes sspi_sizes;
+  CredHandle cred_handle;
+  CtxtHandle sspi_context;
+  PCtxtHandle context_handle = NULL;
+  SecPkgCredentials_Names names;
+  TimeStamp expiry;
+  char *service_name=NULL;
+  u_short us_length;
+  ULONG qop;
+  unsigned char socksreq[4]; /* room for gssapi exchange header only */
+  char *service = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE];
+
+  /* get timeout */
+  timeout = Curl_timeleft(conn, NULL, TRUE);
+
+  /*   GSSAPI request looks like
+   * +----+------+-----+----------------+
+   * |VER | MTYP | LEN |     TOKEN      |
+   * +----+------+----------------------+
+   * | 1  |  1   |  2  | up to 2^16 - 1 |
+   * +----+------+-----+----------------+
+   */
+
+  /* prepare service name */
+  if (strchr(service, '/')) {
+    service_name = malloc(strlen(service));
+    if(!service_name)
+      return CURLE_OUT_OF_MEMORY;
+    memcpy(service_name, service, strlen(service));
+  }
+  else {
+    service_name = malloc(strlen(service) + strlen(conn->proxy.name) + 2);
+    if(!service_name)
+      return CURLE_OUT_OF_MEMORY;
+    snprintf(service_name,strlen(service) +strlen(conn->proxy.name)+2,"%s/%s",
+             service,conn->proxy.name);
+  }
+
+  input_desc.cBuffers = 1;
+  input_desc.pBuffers = &sspi_recv_token;
+  input_desc.ulVersion = SECBUFFER_VERSION;
+
+  sspi_recv_token.BufferType = SECBUFFER_TOKEN;
+  sspi_recv_token.cbBuffer = 0;
+  sspi_recv_token.pvBuffer = NULL;
+
+  output_desc.cBuffers = 1;
+  output_desc.pBuffers = &sspi_send_token;
+  output_desc.ulVersion = SECBUFFER_VERSION;
+
+  sspi_send_token.BufferType = SECBUFFER_TOKEN;
+  sspi_send_token.cbBuffer = 0;
+  sspi_send_token.pvBuffer = NULL;
+
+  wrap_desc.cBuffers = 3;
+  wrap_desc.pBuffers = sspi_w_token;
+  wrap_desc.ulVersion = SECBUFFER_VERSION;
+
+  cred_handle.dwLower = 0;
+  cred_handle.dwUpper = 0;
+
+  sspi_major_status = s_pSecFn->AcquireCredentialsHandleA( NULL,
+                                                           (char *)"Kerberos",
+                                                           SECPKG_CRED_OUTBOUND,
+                                                           NULL,
+                                                           NULL,
+                                                           NULL,
+                                                           NULL,
+                                                           &cred_handle,
+                                                           &expiry);
+
+  if(check_sspi_err(data, sspi_major_status,sspi_minor_status,
+                    "AcquireCredentialsHandleA") ) {
+    failf(data, "Failed to acquire credentials.");
+    free(service_name);
+    service_name=NULL;
+    s_pSecFn->FreeCredentialsHandle(&cred_handle);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  /* As long as we need to keep sending some context info, and there's no  */
+  /* errors, keep sending it...                                            */
+  for(;;) {
+
+    sspi_major_status = s_pSecFn->InitializeSecurityContextA(
+                                    &cred_handle,
+                                    context_handle,
+                                    service_name,
+                                    ISC_REQ_MUTUAL_AUTH |
+                                    ISC_REQ_ALLOCATE_MEMORY |
+                                    ISC_REQ_CONFIDENTIALITY |
+                                    ISC_REQ_REPLAY_DETECT,
+                                    0,
+                                    SECURITY_NATIVE_DREP,
+                                    &input_desc,
+                                    0,
+                                    &sspi_context,
+                                    &output_desc,
+                                    &sspi_ret_flags,
+                                    &expiry);
+
+    if(sspi_recv_token.pvBuffer) {
+      s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+      sspi_recv_token.pvBuffer = NULL;
+      sspi_recv_token.cbBuffer = 0;
+    }
+
+    if(check_sspi_err(data,sspi_major_status,sspi_minor_status,
+                      "InitializeSecurityContextA") ){
+      free(service_name);
+      service_name=NULL;
+      s_pSecFn->FreeCredentialsHandle(&cred_handle);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+      failf(data, "Failed to initialise security context.");
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    if(sspi_send_token.cbBuffer != 0) {
+      socksreq[0] = 1;    /* gssapi subnegotiation version */
+      socksreq[1] = 1;    /* authentication message type */
+      us_length = htons((short)sspi_send_token.cbBuffer);
+      memcpy(socksreq+2, &us_length, sizeof(short));
+
+      code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
+      if((code != CURLE_OK) || (4 != written)) {
+        failf(data, "Failed to send SSPI authentication request.");
+        free(service_name);
+        service_name=NULL;
+        s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+        s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+        s_pSecFn->FreeCredentialsHandle(&cred_handle);
+        s_pSecFn->DeleteSecurityContext(&sspi_context);
+        return CURLE_COULDNT_CONNECT;
+      }
+
+      code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer,
+                              sspi_send_token.cbBuffer, &written);
+      if((code != CURLE_OK) || (sspi_send_token.cbBuffer != (size_t)written)) {
+        failf(data, "Failed to send SSPI authentication token.");
+        free(service_name);
+        service_name=NULL;
+        s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+        s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+        s_pSecFn->FreeCredentialsHandle(&cred_handle);
+        s_pSecFn->DeleteSecurityContext(&sspi_context);
+        return CURLE_COULDNT_CONNECT;
+      }
+
+    }
+
+    s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+    sspi_send_token.pvBuffer = NULL;
+    sspi_send_token.cbBuffer = 0;
+    s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+    sspi_recv_token.pvBuffer = NULL;
+    sspi_recv_token.cbBuffer = 0;
+    if(sspi_major_status != SEC_I_CONTINUE_NEEDED)  break;
+
+    /* analyse response */
+
+    /*   GSSAPI response looks like
+     * +----+------+-----+----------------+
+     * |VER | MTYP | LEN |     TOKEN      |
+     * +----+------+----------------------+
+     * | 1  |  1   |  2  | up to 2^16 - 1 |
+     * +----+------+-----+----------------+
+     */
+
+    result=Curl_blockread_all(conn, sock, (char *)socksreq, 4,
+                              &actualread, timeout);
+    if(result != CURLE_OK || actualread != 4) {
+      failf(data, "Failed to receive SSPI authentication response.");
+      free(service_name);
+      service_name=NULL;
+      s_pSecFn->FreeCredentialsHandle(&cred_handle);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    /* ignore the first (VER) byte */
+    if(socksreq[1] == 255) { /* status / message type */
+      failf(data, "User was rejected by the SOCKS5 server (%d %d).",
+            socksreq[0], socksreq[1]);
+      free(service_name);
+      service_name=NULL;
+      s_pSecFn->FreeCredentialsHandle(&cred_handle);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    if(socksreq[1] != 1) { /* status / messgae type */
+      failf(data, "Invalid SSPI authentication response type (%d %d).",
+            socksreq[0], socksreq[1]);
+      free(service_name);
+      service_name=NULL;
+      s_pSecFn->FreeCredentialsHandle(&cred_handle);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    memcpy(&us_length, socksreq+2, sizeof(short));
+    us_length = ntohs(us_length);
+
+    sspi_recv_token.cbBuffer = us_length;
+    sspi_recv_token.pvBuffer = malloc(us_length);
+
+    if(!sspi_recv_token.pvBuffer) {
+      free(service_name);
+      service_name=NULL;
+      s_pSecFn->FreeCredentialsHandle(&cred_handle);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_OUT_OF_MEMORY;
+    }
+    result = Curl_blockread_all(conn, sock, (char *)sspi_recv_token.pvBuffer,
+                                sspi_recv_token.cbBuffer,
+                                &actualread, timeout);
+
+    if(result != CURLE_OK || actualread != us_length) {
+      failf(data, "Failed to receive SSPI authentication token.");
+      free(service_name);
+      service_name=NULL;
+      s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+      s_pSecFn->FreeCredentialsHandle(&cred_handle);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    context_handle = &sspi_context;
+  }
+
+  free(service_name);
+  service_name=NULL;
+
+  /* Everything is good so far, user was authenticated! */
+  sspi_major_status = s_pSecFn->QueryCredentialsAttributes( &cred_handle,
+                                                            SECPKG_CRED_ATTR_NAMES,
+                                                            &names);
+  s_pSecFn->FreeCredentialsHandle(&cred_handle);
+  if(check_sspi_err(data,sspi_major_status,sspi_minor_status,
+                    "QueryCredentialAttributes") ){
+    s_pSecFn->DeleteSecurityContext(&sspi_context);
+    s_pSecFn->FreeContextBuffer(names.sUserName);
+    failf(data, "Failed to determine user name.");
+    return CURLE_COULDNT_CONNECT;
+  }
+  infof(data, "SOCKS5 server authencticated user %s with gssapi.\n",
+        names.sUserName);
+  s_pSecFn->FreeContextBuffer(names.sUserName);
+
+  /* Do encryption */
+  socksreq[0] = 1;    /* gssapi subnegotiation version */
+  socksreq[1] = 2;    /* encryption message type */
+
+  gss_enc = 0; /* no data protection */
+  /* do confidentiality protection if supported */
+  if(sspi_ret_flags & ISC_REQ_CONFIDENTIALITY)
+    gss_enc = 2;
+  /* else do integrity protection */
+  else if(sspi_ret_flags & ISC_REQ_INTEGRITY)
+    gss_enc = 1;
+
+  infof(data, "SOCKS5 server supports gssapi %s data protection.\n",
+        (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality") );
+  /* force to no data protection, avoid encryption/decryption for now */
+  gss_enc = 0;
+  /*
+   * Sending the encryption type in clear seems wrong. It should be
+   * protected with gss_seal()/gss_wrap(). See RFC1961 extract below
+   * The NEC reference implementations on which this is based is
+   * therefore at fault
+   *
+   *  +------+------+------+.......................+
+   *  + ver  | mtyp | len  |   token               |
+   *  +------+------+------+.......................+
+   *  + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets |
+   *  +------+------+------+.......................+
+   *
+   *   Where:
+   *
+   *  - "ver" is the protocol version number, here 1 to represent the
+   *    first version of the SOCKS/GSS-API protocol
+   *
+   *  - "mtyp" is the message type, here 2 to represent a protection
+   *    -level negotiation message
+   *
+   *  - "len" is the length of the "token" field in octets
+   *
+   *  - "token" is the GSS-API encapsulated protection level
+   *
+   * The token is produced by encapsulating an octet containing the
+   * required protection level using gss_seal()/gss_wrap() with conf_req
+   * set to FALSE.  The token is verified using gss_unseal()/
+   * gss_unwrap().
+   *
+   */
+
+  if(data->set.socks5_gssapi_nec) {
+    us_length = htons((short)1);
+    memcpy(socksreq+2, &us_length, sizeof(short));
+  }
+  else {
+    sspi_major_status = s_pSecFn->QueryContextAttributesA( &sspi_context,
+                                                           SECPKG_ATTR_SIZES,
+                                                           &sspi_sizes);
+    if(check_sspi_err(data,sspi_major_status,sspi_minor_status,
+                      "QueryContextAttributesA")) {
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      failf(data, "Failed to query security context attributes.");
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    sspi_w_token[0].cbBuffer = sspi_sizes.cbSecurityTrailer;
+    sspi_w_token[0].BufferType = SECBUFFER_TOKEN;
+    sspi_w_token[0].pvBuffer = malloc(sspi_sizes.cbSecurityTrailer);
+
+    if(!sspi_w_token[0].pvBuffer) {
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    sspi_w_token[1].cbBuffer = 1;
+    sspi_w_token[1].pvBuffer = malloc(1);
+    if(!sspi_w_token[1].pvBuffer){
+      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    memcpy(sspi_w_token[1].pvBuffer,&gss_enc,1);
+    sspi_w_token[2].BufferType = SECBUFFER_PADDING;
+    sspi_w_token[2].cbBuffer = sspi_sizes.cbBlockSize;
+    sspi_w_token[2].pvBuffer = malloc(sspi_sizes.cbBlockSize);
+    if(!sspi_w_token[2].pvBuffer) {
+      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+      s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_OUT_OF_MEMORY;
+    }
+    sspi_major_status = s_pSecFn->EncryptMessage( &sspi_context,
+                                                  KERB_WRAP_NO_ENCRYPT,
+                                                  &wrap_desc,
+                                                  0);
+    if(check_sspi_err(data,sspi_major_status,sspi_minor_status,
+                      "EncryptMessage") ) {
+      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+      s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+      s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      failf(data, "Failed to query security context attributes.");
+      return CURLE_COULDNT_CONNECT;
+    }
+    sspi_send_token.cbBuffer = sspi_w_token[0].cbBuffer
+      + sspi_w_token[1].cbBuffer
+      + sspi_w_token[2].cbBuffer;
+    sspi_send_token.pvBuffer = malloc(sspi_send_token.cbBuffer);
+    if(!sspi_send_token.pvBuffer) {
+      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+      s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+      s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    memcpy(sspi_send_token.pvBuffer, sspi_w_token[0].pvBuffer,
+           sspi_w_token[0].cbBuffer);
+    memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer,
+           sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer);
+    memcpy((PUCHAR) sspi_send_token.pvBuffer
+           +sspi_w_token[0].cbBuffer
+           +sspi_w_token[1].cbBuffer,
+           sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer);
+
+    s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+    sspi_w_token[0].pvBuffer = NULL;
+    sspi_w_token[0].cbBuffer = 0;
+    s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+    sspi_w_token[1].pvBuffer = NULL;
+    sspi_w_token[1].cbBuffer = 0;
+    s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
+    sspi_w_token[2].pvBuffer = NULL;
+    sspi_w_token[2].cbBuffer = 0;
+
+    us_length = htons((short)sspi_send_token.cbBuffer);
+    memcpy(socksreq+2,&us_length,sizeof(short));
+  }
+
+  code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
+  if((code != CURLE_OK) || (4 != written)) {
+    failf(data, "Failed to send SSPI encryption request.");
+    s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+    s_pSecFn->DeleteSecurityContext(&sspi_context);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  if(data->set.socks5_gssapi_nec) {
+    memcpy(socksreq,&gss_enc,1);
+    code = Curl_write_plain(conn, sock, (char *)socksreq, 1, &written);
+    if((code != CURLE_OK) || (1 != written)) {
+      failf(data, "Failed to send SSPI encryption type.");
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_COULDNT_CONNECT;
+    }
+  } else {
+    code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer,
+                            sspi_send_token.cbBuffer, &written);
+    if((code != CURLE_OK) || (sspi_send_token.cbBuffer != (size_t)written)) {
+      failf(data, "Failed to send SSPI encryption type.");
+      s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_COULDNT_CONNECT;
+    }
+    s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+  }
+
+  result=Curl_blockread_all(conn, sock, (char *)socksreq, 4,
+                            &actualread, timeout);
+  if(result != CURLE_OK || actualread != 4) {
+    failf(data, "Failed to receive SSPI encryption response.");
+    s_pSecFn->DeleteSecurityContext(&sspi_context);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  /* ignore the first (VER) byte */
+  if(socksreq[1] == 255) { /* status / message type */
+    failf(data, "User was rejected by the SOCKS5 server (%d %d).",
+          socksreq[0], socksreq[1]);
+    s_pSecFn->DeleteSecurityContext(&sspi_context);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  if(socksreq[1] != 2) { /* status / message type */
+    failf(data, "Invalid SSPI encryption response type (%d %d).",
+          socksreq[0], socksreq[1]);
+    s_pSecFn->DeleteSecurityContext(&sspi_context);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+  memcpy(&us_length, socksreq+2, sizeof(short));
+  us_length = ntohs(us_length);
+
+  sspi_w_token[0].cbBuffer = us_length;
+  sspi_w_token[0].pvBuffer = malloc(us_length);
+  if(!sspi_w_token[0].pvBuffer) {
+    s_pSecFn->DeleteSecurityContext(&sspi_context);
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  result=Curl_blockread_all(conn, sock, (char *)sspi_w_token[0].pvBuffer,
+                            sspi_w_token[0].cbBuffer,
+                            &actualread, timeout);
+
+  if(result != CURLE_OK || actualread != us_length) {
+    failf(data, "Failed to receive SSPI encryption type.");
+    s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+    s_pSecFn->DeleteSecurityContext(&sspi_context);
+    return CURLE_COULDNT_CONNECT;
+  }
+
+
+  if(!data->set.socks5_gssapi_nec) {
+    wrap_desc.cBuffers = 2;
+    sspi_w_token[0].BufferType = SECBUFFER_STREAM;
+    sspi_w_token[1].BufferType = SECBUFFER_DATA;
+    sspi_w_token[1].cbBuffer = 0;
+    sspi_w_token[1].pvBuffer = NULL;
+
+    sspi_major_status = s_pSecFn->DecryptMessage( &sspi_context,
+                                                  &wrap_desc,
+                                                  0,
+                                                  &qop);
+
+    if(check_sspi_err(data,sspi_major_status,sspi_minor_status,
+                      "DecryptMessage")) {
+      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+      s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      failf(data, "Failed to query security context attributes.");
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    if(sspi_w_token[1].cbBuffer != 1) {
+      failf(data, "Invalid SSPI encryption response length (%d).",
+            sspi_w_token[1].cbBuffer);
+      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+      s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_COULDNT_CONNECT;
+    }
+
+    memcpy(socksreq,sspi_w_token[1].pvBuffer,sspi_w_token[1].cbBuffer);
+    s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+    s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+  } else {
+    if(sspi_w_token[0].cbBuffer != 1) {
+      failf(data, "Invalid SSPI encryption response length (%d).",
+            sspi_w_token[0].cbBuffer);
+      s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+      s_pSecFn->DeleteSecurityContext(&sspi_context);
+      return CURLE_COULDNT_CONNECT;
+    }
+    memcpy(socksreq,sspi_w_token[0].pvBuffer,sspi_w_token[0].cbBuffer);
+    s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+  }
+
+  infof(data, "SOCKS5 access with%s protection granted.\n",
+        (socksreq[0]==0)?"out gssapi data":
+        ((socksreq[0]==1)?" gssapi integrity":" gssapi confidentiality"));
+
+  /* For later use if encryption is required
+     conn->socks5_gssapi_enctype = socksreq[0];
+     if (socksreq[0] != 0)
+     conn->socks5_sspi_context = sspi_context;
+     else {
+     s_pSecFn->DeleteSecurityContext(&sspi_context);
+     conn->socks5_sspi_context = sspi_context;
+     }
+  */
+  return CURLE_OK;
+}
+#endif
diff --git a/lib/speedcheck.c b/lib/speedcheck.c
new file mode 100644
index 0000000..38bad5a
--- /dev/null
+++ b/lib/speedcheck.c
@@ -0,0 +1,74 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 <stdio.h>
+#include <string.h>
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "multiif.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)) {
+    long howlong = Curl_tvdiff(now, data->state.keeps_speed);
+
+    /* 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( (howlong/1000) > data->set.low_speed_time) {
+      /* we have been this slow for long enough, now die */
+      failf(data,
+            "Operation too slow. "
+            "Less than %ld bytes/sec transfered the last %ld seconds",
+            data->set.low_speed_limit,
+            data->set.low_speed_time);
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+    Curl_expire(data, howlong);
+  }
+  else {
+    /* we keep up the required speed all right */
+    data->state.keeps_speed = now;
+
+    if(data->set.low_speed_limit)
+      /* if there is a low speed limit enabled, we set the expire timer to
+         make this connection's speed get checked again no later than when
+         this time is up */
+      Curl_expire(data, data->set.low_speed_time*1000);
+  }
+  return CURLE_OK;
+}
diff --git a/lib/speedcheck.h b/lib/speedcheck.h
new file mode 100644
index 0000000..fc40e7d
--- /dev/null
+++ b/lib/speedcheck.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_SPEEDCHECK_H
+#define HEADER_CURL_SPEEDCHECK_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 "timeval.h"
+
+void Curl_speedinit(struct SessionHandle *data);
+CURLcode Curl_speedcheck(struct SessionHandle *data,
+                         struct timeval now);
+
+#endif /* HEADER_CURL_SPEEDCHECK_H */
diff --git a/lib/splay.c b/lib/splay.c
new file mode 100644
index 0000000..db3dbea
--- /dev/null
+++ b/lib/splay.c
@@ -0,0 +1,438 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1997 - 2009, 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 "splay.h"
+
+/*
+ * This macro compares two node keys i and j and returns:
+ *
+ *  negative value: when i is smaller than j
+ *  zero          : when i is equal   to   j
+ *  positive when : when i is larger  than j
+ */
+#define compare(i,j) Curl_splaycomparekeys((i),(j))
+
+/*
+ * Splay using the key i (which may or may not be in the tree.) The starting
+ * root is t.
+ */
+struct Curl_tree *Curl_splay(struct timeval i,
+                             struct Curl_tree *t)
+{
+  struct Curl_tree N, *l, *r, *y;
+  long comp;
+
+  if(t == NULL)
+    return t;
+  N.smaller = N.larger = NULL;
+  l = r = &N;
+
+  for (;;) {
+    comp = compare(i, t->key);
+    if(comp < 0) {
+      if(t->smaller == NULL)
+        break;
+      if(compare(i, t->smaller->key) < 0) {
+        y = t->smaller;                           /* rotate smaller */
+        t->smaller = y->larger;
+        y->larger = t;
+        t = y;
+        if(t->smaller == NULL)
+          break;
+      }
+      r->smaller = t;                               /* link smaller */
+      r = t;
+      t = t->smaller;
+    }
+    else if(comp > 0) {
+      if(t->larger == NULL)
+        break;
+      if(compare(i, t->larger->key) > 0) {
+        y = t->larger;                          /* rotate larger */
+        t->larger = y->smaller;
+        y->smaller = t;
+        t = y;
+        if(t->larger == NULL)
+          break;
+      }
+      l->larger = t;                              /* link larger */
+      l = t;
+      t = t->larger;
+    }
+    else
+      break;
+  }
+
+  l->larger = t->smaller;                                /* assemble */
+  r->smaller = t->larger;
+  t->smaller = N.larger;
+  t->larger = N.smaller;
+
+  return t;
+}
+
+/* Insert key i into the tree t.  Return a pointer to the resulting tree or
+   NULL if something went wrong. */
+struct Curl_tree *Curl_splayinsert(struct timeval i,
+                                   struct Curl_tree *t,
+                                   struct Curl_tree *node)
+{
+  static struct timeval KEY_NOTUSED = {-1,-1}; /* key that will *NEVER* appear */
+
+  if(node == NULL)
+    return t;
+
+  if(t != NULL) {
+    t = Curl_splay(i,t);
+    if(compare(i, t->key)==0) {
+      /* There already exists a node in the tree with the very same key. Build
+         a linked list of nodes. We make the new 'node' struct the new master
+         node and make the previous node the first one in the 'same' list. */
+
+      node->same = t;
+      node->key = i;
+      node->smaller = t->smaller;
+      node->larger = t->larger;
+
+      t->smaller = node; /* in the sub node for this same key, we use the
+                            smaller pointer to point back to the master
+                            node */
+
+      t->key = KEY_NOTUSED; /* and we set the key in the sub node to NOTUSED
+                               to quickly identify this node as a subnode */
+
+      return node; /* new root node */
+    }
+  }
+
+  if(t == NULL) {
+    node->smaller = node->larger = NULL;
+  }
+  else if(compare(i, t->key) < 0) {
+    node->smaller = t->smaller;
+    node->larger = t;
+    t->smaller = NULL;
+
+  }
+  else {
+    node->larger = t->larger;
+    node->smaller = t;
+    t->larger = NULL;
+  }
+  node->key = i;
+
+  node->same = NULL; /* no identical node (yet) */
+  return node;
+}
+
+#if 0
+/* Deletes 'i' from the tree if it's there (with an exact match). Returns a
+   pointer to the resulting tree.
+
+   Function not used in libcurl.
+*/
+struct Curl_tree *Curl_splayremove(struct timeval i,
+                                   struct Curl_tree *t,
+                                   struct Curl_tree **removed)
+{
+  struct Curl_tree *x;
+
+  *removed = NULL; /* default to no removed */
+
+  if(t==NULL)
+    return NULL;
+
+  t = Curl_splay(i,t);
+  if(compare(i, t->key) == 0) {               /* found it */
+
+    /* FIRST! Check if there is a list with identical sizes */
+    if((x = t->same) != NULL) {
+      /* there is, pick one from the list */
+
+      /* 'x' is the new root node */
+
+      x->key = t->key;
+      x->larger = t->larger;
+      x->smaller = t->smaller;
+
+      *removed = t;
+      return x; /* new root */
+    }
+
+    if(t->smaller == NULL) {
+      x = t->larger;
+    }
+    else {
+      x = Curl_splay(i, t->smaller);
+      x->larger = t->larger;
+    }
+    *removed = t;
+
+    return x;
+  }
+  else
+    return t;                         /* It wasn't there */
+}
+#endif
+
+/* Finds and deletes the best-fit node from the tree. Return a pointer to the
+   resulting tree.  best-fit means the node with the given or lower key */
+struct Curl_tree *Curl_splaygetbest(struct timeval i,
+                                    struct Curl_tree *t,
+                                    struct Curl_tree **removed)
+{
+  struct Curl_tree *x;
+
+  if(!t) {
+    *removed = NULL; /* none removed since there was no root */
+    return NULL;
+  }
+
+  t = Curl_splay(i,t);
+  if(compare(i, t->key) < 0) {
+    /* too big node, try the smaller chain */
+    if(t->smaller)
+      t=Curl_splay(t->smaller->key, t);
+    else {
+      /* fail */
+      *removed = NULL;
+      return t;
+    }
+  }
+
+  if(compare(i, t->key) >= 0) {               /* found it */
+    /* FIRST! Check if there is a list with identical keys */
+    x = t->same;
+    if(x) {
+      /* there is, pick one from the list */
+
+      /* 'x' is the new root node */
+
+      x->key = t->key;
+      x->larger = t->larger;
+      x->smaller = t->smaller;
+
+      *removed = t;
+      return x; /* new root */
+    }
+
+    if(t->smaller == NULL) {
+      x = t->larger;
+    }
+    else {
+      x = Curl_splay(i, t->smaller);
+      x->larger = t->larger;
+    }
+    *removed = t;
+
+    return x;
+  }
+  else {
+    *removed = NULL; /* no match */
+    return t;        /* It wasn't there */
+  }
+}
+
+
+/* Deletes the very node we point out from the tree if it's there. Stores a
+   pointer to the new resulting tree in 'newroot'.
+
+   Returns zero on success and non-zero on errors! TODO: document error codes.
+   When returning error, it does not touch the 'newroot' pointer.
+
+   NOTE: when the last node of the tree is removed, there's no tree left so
+   'newroot' will be made to point to NULL.
+*/
+int Curl_splayremovebyaddr(struct Curl_tree *t,
+                           struct Curl_tree *removenode,
+                           struct Curl_tree **newroot)
+{
+  static struct timeval KEY_NOTUSED = {-1,-1}; /* key that will *NEVER* appear */
+  struct Curl_tree *x;
+
+  if(!t || !removenode)
+    return 1;
+
+  if(compare(KEY_NOTUSED, removenode->key) == 0) {
+    /* Key set to NOTUSED means it is a subnode within a 'same' linked list
+       and thus we can unlink it easily. The 'smaller' link of a subnode
+       links to the parent node. */
+    if(removenode->smaller == NULL)
+      return 3;
+
+    removenode->smaller->same = removenode->same;
+    if(removenode->same)
+      removenode->same->smaller = removenode->smaller;
+
+    /* Ensures that double-remove gets caught. */
+    removenode->smaller = NULL;
+
+    /* voila, we're done! */
+    *newroot = t; /* return the same root */
+    return 0;
+  }
+
+  t = Curl_splay(removenode->key, t);
+
+  /* First make sure that we got the same root node as the one we want
+     to remove, as otherwise we might be trying to remove a node that
+     isn't actually in the tree.
+
+     We cannot just compare the keys here as a double remove in quick
+     succession of a node with key != KEY_NOTUSED && same != NULL
+     could return the same key but a different node. */
+  if(t != removenode)
+    return 2;
+
+  /* Check if there is a list with identical sizes, as then we're trying to
+     remove the root node of a list of nodes with identical keys. */
+  x = t->same;
+  if(x) {
+    /* 'x' is the new root node, we just make it use the root node's
+       smaller/larger links */
+
+    x->key = t->key;
+    x->larger = t->larger;
+    x->smaller = t->smaller;
+  }
+  else {
+    /* Remove the root node */
+    if(t->smaller == NULL)
+      x = t->larger;
+    else {
+      x = Curl_splay(removenode->key, t->smaller);
+      x->larger = t->larger;
+    }
+  }
+
+  *newroot = x; /* store new root pointer */
+
+  return 0;
+}
+
+#ifdef DEBUGBUILD
+
+void Curl_splayprint(struct Curl_tree * t, int d, char output)
+{
+  struct Curl_tree *node;
+  int i;
+  int count;
+  if(t == NULL)
+    return;
+
+  Curl_splayprint(t->larger, d+1, output);
+  for (i=0; i<d; i++)
+    if(output)
+      fprintf(stderr, "  ");
+
+  if(output) {
+#ifdef TEST_SPLAY
+    fprintf(stderr, "%ld[%d]", (long)t->key.tv_usec, i);
+#else
+    fprintf(stderr, "%ld.%ld[%d]", (long)t->key.tv_sec, (long)t->key.tv_usec, i);
+#endif
+  }
+
+  for(count=0, node = t->same; node; node = node->same, count++)
+    ;
+
+  if(output) {
+    if(count)
+      fprintf(stderr, " [%d more]\n", count);
+    else
+      fprintf(stderr, "\n");
+  }
+
+  Curl_splayprint(t->smaller, d+1, output);
+}
+#endif
+
+#ifdef TEST_SPLAY
+
+/*#define TEST2 */
+#define MAX 50
+#define TEST2
+
+/* A sample use of these functions.  Start with the empty tree, insert some
+   stuff into it, and then delete it */
+int main(int argc, argv_item_t argv[])
+{
+  struct Curl_tree *root, *t;
+  void *ptrs[MAX];
+  int adds=0;
+  int rc;
+
+  static const long sizes[]={
+    50, 60, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120, 200, 300,
+    220, 80, 90, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120, 200,
+    300, 220, 80, 90, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120,
+    200, 300, 220, 80, 90};
+  int i;
+  root = NULL;              /* the empty tree */
+
+  for (i = 0; i < MAX; i++) {
+    struct timeval key;
+    ptrs[i] = t = malloc(sizeof(struct Curl_tree));
+
+    key.tv_sec = 0;
+#ifdef TEST2
+    key.tv_usec = sizes[i];
+#elif defined(TEST1)
+    key.tv_usec = (541*i)%1023;
+#elif defined(TEST3)
+    key.tv_usec = 100;
+#endif
+
+    t->payload = (void *)key.tv_usec; /* for simplicity */
+    if(!t) {
+      puts("out of memory!");
+      return 0;
+    }
+    root = Curl_splayinsert(key, root, t);
+  }
+
+#if 0
+  puts("Result:");
+  Curl_splayprint(root, 0, 1);
+#endif
+
+#if 1
+  for (i = 0; i < MAX; i++) {
+    int rem = (i+7)%MAX;
+    struct Curl_tree *r;
+    printf("Tree look:\n");
+    Curl_splayprint(root, 0, 1);
+    printf("remove pointer %d, payload %ld\n", rem,
+           (long)((struct Curl_tree *)ptrs[rem])->payload);
+    rc = Curl_splayremovebyaddr(root, (struct Curl_tree *)ptrs[rem], &root);
+    if(rc)
+      /* failed! */
+      printf("remove %d failed!\n", rem);
+  }
+#endif
+
+  return 0;
+}
+
+#endif /* TEST_SPLAY */
diff --git a/lib/splay.h b/lib/splay.h
new file mode 100644
index 0000000..832e4e2
--- /dev/null
+++ b/lib/splay.h
@@ -0,0 +1,65 @@
+#ifndef __SPLAY_H
+#define __SPLAY_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1997 - 2009, 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.
+ *
+ ***************************************************************************/
+
+struct Curl_tree {
+  struct Curl_tree *smaller; /* smaller node */
+  struct Curl_tree *larger;  /* larger node */
+  struct Curl_tree *same;    /* points to a node with identical key */
+  struct timeval key;        /* this node's "sort" key */
+  void *payload;             /* data the splay code doesn't care about */
+};
+
+struct Curl_tree *Curl_splay(struct timeval i,
+                             struct Curl_tree *t);
+
+struct Curl_tree *Curl_splayinsert(struct timeval key,
+                                   struct Curl_tree *t,
+                                   struct Curl_tree *newnode);
+
+#if 0
+struct Curl_tree *Curl_splayremove(struct timeval key,
+                                   struct Curl_tree *t,
+                                   struct Curl_tree **removed);
+#endif
+
+struct Curl_tree *Curl_splaygetbest(struct timeval key,
+                                    struct Curl_tree *t,
+                                    struct Curl_tree **removed);
+
+int Curl_splayremovebyaddr(struct Curl_tree *t,
+                           struct Curl_tree *removenode,
+                           struct Curl_tree **newroot);
+
+#define Curl_splaycomparekeys(i,j) ( ((i.tv_sec)  < (j.tv_sec))  ? -1 : \
+                                   ( ((i.tv_sec)  > (j.tv_sec))  ?  1 : \
+                                   ( ((i.tv_usec) < (j.tv_usec)) ? -1 : \
+                                   ( ((i.tv_usec) > (j.tv_usec)) ?  1 : 0 ))))
+
+#ifdef DEBUGBUILD
+void Curl_splayprint(struct Curl_tree * t, int d, char output);
+#else
+#define Curl_splayprint(x,y,z)
+#endif
+
+#endif
diff --git a/lib/ssh.c b/lib/ssh.c
new file mode 100644
index 0000000..ff5994b
--- /dev/null
+++ b/lib/ssh.c
@@ -0,0 +1,3033 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+/* #define CURL_LIBSSH2_DEBUG */
+
+#include "setup.h"
+
+#ifdef USE_LIBSSH2
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+#ifdef HAVE_LIMITS_H
+#  include <limits.h>
+#endif
+
+#include <libssh2.h>
+#include <libssh2_sftp.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+
+#ifndef WIN32
+#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_UTSNAME_H
+#include <sys/utsname.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+#endif /* !WIN32 */
+
+#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 "easyif.h" /* for Curl_convert_... prototypes */
+
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "ssh.h"
+#include "url.h"
+#include "speedcheck.h"
+#include "getinfo.h"
+
+#include "strequal.h"
+#include "sslgen.h"
+#include "connect.h"
+#include "strerror.h"
+#include "inet_ntop.h"
+#include "parsedate.h" /* for the week day and month names */
+#include "sockaddr.h" /* required for Curl_sockaddr_storage */
+#include "strtoofft.h"
+#include "multiif.h"
+#include "select.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024 /* just an extra precaution since there are systems that
+                         have their definition hidden well */
+#endif
+
+/* Local functions: */
+static const char *sftp_libssh2_strerror(unsigned long err);
+static LIBSSH2_ALLOC_FUNC(libssh2_malloc);
+static LIBSSH2_REALLOC_FUNC(libssh2_realloc);
+static LIBSSH2_FREE_FUNC(libssh2_free);
+
+static CURLcode get_pathname(const char **cpp, char **path);
+
+static CURLcode ssh_connect(struct connectdata *conn, bool *done);
+static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done);
+static CURLcode ssh_do(struct connectdata *conn, bool *done);
+
+static CURLcode ssh_getworkingpath(struct connectdata *conn,
+                                   char *homedir, /* when SFTP is used */
+                                   char **path);
+
+static CURLcode scp_done(struct connectdata *conn,
+                         CURLcode, bool premature);
+static CURLcode scp_doing(struct connectdata *conn,
+                          bool *dophase_done);
+static CURLcode scp_disconnect(struct connectdata *conn);
+
+static CURLcode sftp_done(struct connectdata *conn,
+                          CURLcode, bool premature);
+static CURLcode sftp_doing(struct connectdata *conn,
+                           bool *dophase_done);
+static CURLcode sftp_disconnect(struct connectdata *conn);
+static
+CURLcode sftp_perform(struct connectdata *conn,
+                      bool *connected,
+                      bool *dophase_done);
+
+static int ssh_getsock(struct connectdata *conn,
+                       curl_socket_t *sock, /* points to numsocks number
+                                               of sockets */
+                       int numsocks);
+
+static int ssh_perform_getsock(const struct connectdata *conn,
+                               curl_socket_t *sock, /* points to numsocks
+                                                       number of sockets */
+                               int numsocks);
+
+/*
+ * SCP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_scp = {
+  "SCP",                                /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  ssh_do,                               /* do_it */
+  scp_done,                             /* done */
+  ZERO_NULL,                            /* do_more */
+  ssh_connect,                          /* connect_it */
+  ssh_multi_statemach,                  /* connecting */
+  scp_doing,                            /* doing */
+  ssh_getsock,                          /* proto_getsock */
+  ssh_getsock,                          /* doing_getsock */
+  ssh_perform_getsock,                  /* perform_getsock */
+  scp_disconnect,                       /* disconnect */
+  PORT_SSH,                             /* defport */
+  PROT_SCP                              /* protocol */
+};
+
+
+/*
+ * SFTP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_sftp = {
+  "SFTP",                               /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  ssh_do,                               /* do_it */
+  sftp_done,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  ssh_connect,                          /* connect_it */
+  ssh_multi_statemach,                  /* connecting */
+  sftp_doing,                           /* doing */
+  ssh_getsock,                          /* proto_getsock */
+  ssh_getsock,                          /* doing_getsock */
+  ssh_perform_getsock,                  /* perform_getsock */
+  sftp_disconnect,                      /* disconnect */
+  PORT_SSH,                             /* defport */
+  PROT_SFTP                             /* protocol */
+};
+
+
+static void
+kbd_callback(const char *name, int name_len, const char *instruction,
+             int instruction_len, int num_prompts,
+             const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
+             LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
+             void **abstract)
+{
+  struct connectdata *conn = (struct connectdata *)*abstract;
+
+#ifdef CURL_LIBSSH2_DEBUG
+  fprintf(stderr, "name=%s\n", name);
+  fprintf(stderr, "name_len=%d\n", name_len);
+  fprintf(stderr, "instruction=%s\n", instruction);
+  fprintf(stderr, "instruction_len=%d\n", instruction_len);
+  fprintf(stderr, "num_prompts=%d\n", num_prompts);
+#else
+  (void)name;
+  (void)name_len;
+  (void)instruction;
+  (void)instruction_len;
+#endif  /* CURL_LIBSSH2_DEBUG */
+  if(num_prompts == 1) {
+    responses[0].text = strdup(conn->passwd);
+    responses[0].length = (unsigned int)strlen(conn->passwd);
+  }
+  (void)prompts;
+  (void)abstract;
+} /* kbd_callback */
+
+static CURLcode sftp_libssh2_error_to_CURLE(int err)
+{
+  switch (err) {
+    case LIBSSH2_FX_OK:
+      return CURLE_OK;
+
+    case LIBSSH2_FX_NO_SUCH_FILE:
+    case LIBSSH2_FX_NO_SUCH_PATH:
+      return CURLE_REMOTE_FILE_NOT_FOUND;
+
+    case LIBSSH2_FX_PERMISSION_DENIED:
+    case LIBSSH2_FX_WRITE_PROTECT:
+    case LIBSSH2_FX_LOCK_CONFlICT:
+      return CURLE_REMOTE_ACCESS_DENIED;
+
+    case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM:
+    case LIBSSH2_FX_QUOTA_EXCEEDED:
+      return CURLE_REMOTE_DISK_FULL;
+
+    case LIBSSH2_FX_FILE_ALREADY_EXISTS:
+      return CURLE_REMOTE_FILE_EXISTS;
+
+    case LIBSSH2_FX_DIR_NOT_EMPTY:
+      return CURLE_QUOTE_ERROR;
+
+    default:
+      break;
+  }
+
+  return CURLE_SSH;
+}
+
+static CURLcode libssh2_session_error_to_CURLE(int err)
+{
+  switch (err) {
+    /* Ordered by order of appearance in libssh2.h */
+    case LIBSSH2_ERROR_NONE:
+      return CURLE_OK;
+
+    case LIBSSH2_ERROR_SOCKET_NONE:
+      return CURLE_COULDNT_CONNECT;
+
+    case LIBSSH2_ERROR_ALLOC:
+      return CURLE_OUT_OF_MEMORY;
+
+    case LIBSSH2_ERROR_SOCKET_SEND:
+      return CURLE_SEND_ERROR;
+
+    case LIBSSH2_ERROR_HOSTKEY_INIT:
+    case LIBSSH2_ERROR_HOSTKEY_SIGN:
+    case LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED:
+    case LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED:
+      return CURLE_PEER_FAILED_VERIFICATION;
+
+    case LIBSSH2_ERROR_PASSWORD_EXPIRED:
+      return CURLE_LOGIN_DENIED;
+
+    case LIBSSH2_ERROR_SOCKET_TIMEOUT:
+    case LIBSSH2_ERROR_TIMEOUT:
+      return CURLE_OPERATION_TIMEDOUT;
+
+    case LIBSSH2_ERROR_EAGAIN:
+      return CURLE_AGAIN;
+  }
+
+  /* TODO: map some more of the libssh2 errors to the more appropriate CURLcode
+     error code, and possibly add a few new SSH-related one. We must however
+     not return or even depend on libssh2 errors in the public libcurl API */
+
+  return CURLE_SSH;
+}
+
+static LIBSSH2_ALLOC_FUNC(libssh2_malloc)
+{
+  (void)abstract; /* arg not used */
+  return malloc(count);
+}
+
+static LIBSSH2_REALLOC_FUNC(libssh2_realloc)
+{
+  (void)abstract; /* arg not used */
+  return realloc(ptr, count);
+}
+
+static LIBSSH2_FREE_FUNC(libssh2_free)
+{
+  (void)abstract; /* arg not used */
+  free(ptr);
+}
+
+/*
+ * SSH State machine related code
+ */
+/* This is the ONLY way to change SSH state! */
+static void state(struct connectdata *conn, sshstate nowstate)
+{
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  /* for debug purposes */
+  static const char * const names[] = {
+    "SSH_STOP",
+    "SSH_S_STARTUP",
+    "SSH_HOSTKEY",
+    "SSH_AUTHLIST",
+    "SSH_AUTH_PKEY_INIT",
+    "SSH_AUTH_PKEY",
+    "SSH_AUTH_PASS_INIT",
+    "SSH_AUTH_PASS",
+    "SSH_AUTH_HOST_INIT",
+    "SSH_AUTH_HOST",
+    "SSH_AUTH_KEY_INIT",
+    "SSH_AUTH_KEY",
+    "SSH_AUTH_DONE",
+    "SSH_SFTP_INIT",
+    "SSH_SFTP_REALPATH",
+    "SSH_SFTP_QUOTE_INIT",
+    "SSH_SFTP_POSTQUOTE_INIT",
+    "SSH_SFTP_QUOTE",
+    "SSH_SFTP_NEXT_QUOTE",
+    "SSH_SFTP_QUOTE_STAT",
+    "SSH_SFTP_QUOTE_SETSTAT",
+    "SSH_SFTP_QUOTE_SYMLINK",
+    "SSH_SFTP_QUOTE_MKDIR",
+    "SSH_SFTP_QUOTE_RENAME",
+    "SSH_SFTP_QUOTE_RMDIR",
+    "SSH_SFTP_QUOTE_UNLINK",
+    "SSH_SFTP_TRANS_INIT",
+    "SSH_SFTP_UPLOAD_INIT",
+    "SSH_SFTP_CREATE_DIRS_INIT",
+    "SSH_SFTP_CREATE_DIRS",
+    "SSH_SFTP_CREATE_DIRS_MKDIR",
+    "SSH_SFTP_READDIR_INIT",
+    "SSH_SFTP_READDIR",
+    "SSH_SFTP_READDIR_LINK",
+    "SSH_SFTP_READDIR_BOTTOM",
+    "SSH_SFTP_READDIR_DONE",
+    "SSH_SFTP_DOWNLOAD_INIT",
+    "SSH_SFTP_DOWNLOAD_STAT",
+    "SSH_SFTP_CLOSE",
+    "SSH_SFTP_SHUTDOWN",
+    "SSH_SCP_TRANS_INIT",
+    "SSH_SCP_UPLOAD_INIT",
+    "SSH_SCP_DOWNLOAD_INIT",
+    "SSH_SCP_DONE",
+    "SSH_SCP_SEND_EOF",
+    "SSH_SCP_WAIT_EOF",
+    "SSH_SCP_WAIT_CLOSE",
+    "SSH_SCP_CHANNEL_FREE",
+    "SSH_SESSION_DISCONNECT",
+    "SSH_SESSION_FREE",
+    "QUIT"
+  };
+#endif
+  struct ssh_conn *sshc = &conn->proto.sshc;
+
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  if(sshc->state != nowstate) {
+    infof(conn->data, "SFTP %p state change from %s to %s\n",
+          sshc, names[sshc->state], names[nowstate]);
+  }
+#endif
+
+  sshc->state = nowstate;
+}
+
+/* figure out the path to work with in this particular request */
+static CURLcode ssh_getworkingpath(struct connectdata *conn,
+                                   char *homedir,  /* when SFTP is used */
+                                   char **path) /* returns the  allocated
+                                                   real path to work with */
+{
+  struct SessionHandle *data = conn->data;
+  char *real_path = NULL;
+  char *working_path;
+  int working_path_len;
+
+  working_path = curl_easy_unescape(data, data->state.path, 0,
+                                    &working_path_len);
+  if(!working_path)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Check for /~/ , indicating relative to the user's home directory */
+  if(conn->protocol & PROT_SCP) {
+    real_path = malloc(working_path_len+1);
+    if(real_path == NULL) {
+      free(working_path);
+      return CURLE_OUT_OF_MEMORY;
+    }
+    if((working_path_len > 1) && (working_path[1] == '~'))
+      /* It is referenced to the home directory, so strip the leading '/' */
+      memcpy(real_path, working_path+1, 1 + working_path_len-1);
+    else
+      memcpy(real_path, working_path, 1 + working_path_len);
+  }
+  else if(conn->protocol & PROT_SFTP) {
+    if((working_path_len > 1) && (working_path[1] == '~')) {
+      size_t homelen = strlen(homedir);
+      real_path = malloc(homelen + working_path_len + 1);
+      if(real_path == NULL) {
+        free(working_path);
+        return CURLE_OUT_OF_MEMORY;
+      }
+      /* It is referenced to the home directory, so strip the
+         leading '/' */
+      memcpy(real_path, homedir, homelen);
+      real_path[homelen] = '/';
+      real_path[homelen+1] = '\0';
+      if(working_path_len > 3) {
+        memcpy(real_path+homelen+1, working_path + 3,
+               1 + working_path_len -3);
+      }
+    }
+    else {
+      real_path = malloc(working_path_len+1);
+      if(real_path == NULL) {
+        free(working_path);
+        return CURLE_OUT_OF_MEMORY;
+      }
+      memcpy(real_path, working_path, 1+working_path_len);
+    }
+  }
+
+  free(working_path);
+
+  /* store the pointer for the caller to receive */
+  *path = real_path;
+
+  return CURLE_OK;
+}
+
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+static int sshkeycallback(CURL *easy,
+                          const struct curl_khkey *knownkey, /* known */
+                          const struct curl_khkey *foundkey, /* found */
+                          enum curl_khmatch match,
+                          void *clientp)
+{
+  (void)easy;
+  (void)knownkey;
+  (void)foundkey;
+  (void)clientp;
+
+  /* we only allow perfect matches, and we reject everything else */
+  return (match != CURLKHMATCH_OK)?CURLKHSTAT_REJECT:CURLKHSTAT_FINE;
+}
+#endif
+
+/*
+ * Earlier libssh2 versions didn't have the ability to seek to 64bit positions
+ * with 32bit size_t.
+ */
+#ifdef HAVE_LIBSSH2_SFTP_SEEK64
+#define SFTP_SEEK(x,y) libssh2_sftp_seek64(x, (libssh2_uint64_t)y)
+#else
+#define SFTP_SEEK(x,y) libssh2_sftp_seek(x, (size_t)y)
+#endif
+
+/*
+ * ssh_statemach_act() runs the SSH state machine as far as it can without
+ * blocking and without reaching the end.  The data the pointer 'block' points
+ * to will be set to TRUE if the libssh2 function returns LIBSSH2_ERROR_EAGAIN
+ * meaning it wants to be called again when the socket is ready
+ */
+
+static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+  struct SSHPROTO *sftp_scp = data->state.proto.ssh;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  curl_socket_t sock = conn->sock[FIRSTSOCKET];
+#ifdef CURL_LIBSSH2_DEBUG
+  const char *fingerprint;
+#endif /* CURL_LIBSSH2_DEBUG */
+  const char *host_public_key_md5;
+  int rc = LIBSSH2_ERROR_NONE, i;
+  int err;
+  int seekerr = CURL_SEEKFUNC_OK;
+  *block = 0; /* we're not blocking by default */
+
+  do {
+
+    switch(sshc->state) {
+    case SSH_S_STARTUP:
+      sshc->secondCreateDirs = 0;
+      sshc->nextstate = SSH_NO_STATE;
+      sshc->actualcode = CURLE_OK;
+
+      rc = libssh2_session_startup(sshc->ssh_session, sock);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc) {
+        failf(data, "Failure establishing ssh session");
+        state(conn, SSH_SESSION_FREE);
+        sshc->actualcode = CURLE_FAILED_INIT;
+        break;
+      }
+
+      /* Set libssh2 to non-blocking, since everything internally is
+         non-blocking */
+      libssh2_session_set_blocking(sshc->ssh_session, 0);
+
+      state(conn, SSH_HOSTKEY);
+
+      /* fall-through */
+    case SSH_HOSTKEY:
+
+#ifdef CURL_LIBSSH2_DEBUG
+      /*
+       * Before we authenticate we should check the hostkey's fingerprint
+       * against our known hosts. How that is handled (reading from file,
+       * whatever) is up to us. As for know not much is implemented, besides
+       * showing how to get the fingerprint.
+       */
+      fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
+                                         LIBSSH2_HOSTKEY_HASH_MD5);
+
+      /* The fingerprint points to static storage (!), don't free() it. */
+      infof(data, "Fingerprint: ");
+      for (rc = 0; rc < 16; rc++) {
+        infof(data, "%02X ", (unsigned char) fingerprint[rc]);
+      }
+      infof(data, "\n");
+#endif /* CURL_LIBSSH2_DEBUG */
+
+      /* Before we authenticate we check the hostkey's MD5 fingerprint
+       * against a known fingerprint, if available.  This implementation pulls
+       * it from the curl option.
+       */
+      if(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5] &&
+         strlen(data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]) == 32) {
+        char buf[33];
+        host_public_key_md5 = libssh2_hostkey_hash(sshc->ssh_session,
+                                                   LIBSSH2_HOSTKEY_HASH_MD5);
+        for (i = 0; i < 16; i++)
+          snprintf(&buf[i*2], 3, "%02x",
+                   (unsigned char) host_public_key_md5[i]);
+        if(!strequal(buf, data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5])) {
+          failf(data,
+                "Denied establishing ssh session: mismatch md5 fingerprint. "
+                "Remote %s is not equal to %s",
+                buf, data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5]);
+          state(conn, SSH_SESSION_FREE);
+          sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+          break;
+        }
+      }
+
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+      if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
+        /* we're asked to verify the host against a file */
+        int keytype;
+        size_t keylen;
+        const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
+                                                        &keylen, &keytype);
+        int keycheck;
+        int keybit;
+
+        if(remotekey) {
+          /*
+           * A subject to figure out is what host name we need to pass in here.
+           * What host name does OpenSSH store in its file if an IDN name is
+           * used?
+           */
+          struct libssh2_knownhost *host;
+          enum curl_khmatch keymatch;
+          curl_sshkeycallback func =
+            data->set.ssh_keyfunc?data->set.ssh_keyfunc:sshkeycallback;
+          struct curl_khkey knownkey;
+          struct curl_khkey *knownkeyp = NULL;
+          struct curl_khkey foundkey;
+
+          keybit = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
+            LIBSSH2_KNOWNHOST_KEY_SSHRSA:LIBSSH2_KNOWNHOST_KEY_SSHDSS;
+
+          keycheck = libssh2_knownhost_check(sshc->kh,
+                                             conn->host.name,
+                                             remotekey, keylen,
+                                             LIBSSH2_KNOWNHOST_TYPE_PLAIN|
+                                             LIBSSH2_KNOWNHOST_KEYENC_RAW|
+                                             keybit,
+                                             &host);
+
+          infof(data, "SSH host check: %d, key: %s\n", keycheck,
+                (keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)?
+                host->key:"<none>");
+
+          /* setup 'knownkey' */
+          if(keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH) {
+            knownkey.key = host->key;
+            knownkey.len = 0;
+            knownkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
+              CURLKHTYPE_RSA : CURLKHTYPE_DSS;
+            knownkeyp = &knownkey;
+          }
+
+          /* setup 'foundkey' */
+          foundkey.key = remotekey;
+          foundkey.len = keylen;
+          foundkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
+            CURLKHTYPE_RSA : CURLKHTYPE_DSS;
+
+          /*
+           * if any of the LIBSSH2_KNOWNHOST_CHECK_* defines and the
+           * curl_khmatch enum are ever modified, we need to introduce a
+           * translation table here!
+           */
+          keymatch = (enum curl_khmatch)keycheck;
+
+          /* Ask the callback how to behave */
+          rc = func(data, knownkeyp, /* from the knownhosts file */
+                    &foundkey, /* from the remote host */
+                    keymatch, data->set.ssh_keyfunc_userp);
+        }
+        else
+          /* no remotekey means failure! */
+          rc = CURLKHSTAT_REJECT;
+
+        switch(rc) {
+        default: /* unknown return codes will equal reject */
+        case CURLKHSTAT_REJECT:
+          state(conn, SSH_SESSION_FREE);
+        case CURLKHSTAT_DEFER:
+          /* DEFER means bail out but keep the SSH_HOSTKEY state */
+          result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+          break;
+        case CURLKHSTAT_FINE:
+        case CURLKHSTAT_FINE_ADD_TO_FILE:
+          /* proceed */
+          if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) {
+            /* the found host+key didn't match but has been told to be fine
+               anyway so we add it in memory */
+            int addrc = libssh2_knownhost_add(sshc->kh,
+                                              conn->host.name, NULL,
+                                              remotekey, keylen,
+                                              LIBSSH2_KNOWNHOST_TYPE_PLAIN|
+                                              LIBSSH2_KNOWNHOST_KEYENC_RAW|
+                                              keybit, NULL);
+            if(addrc)
+              infof(data, "Warning adding the known host %s failed!\n",
+                    conn->host.name);
+            else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE) {
+              /* now we write the entire in-memory list of known hosts to the
+                 known_hosts file */
+              int wrc =
+                libssh2_knownhost_writefile(sshc->kh,
+                                            data->set.str[STRING_SSH_KNOWNHOSTS],
+                                            LIBSSH2_KNOWNHOST_FILE_OPENSSH);
+              if(wrc) {
+                infof(data, "Warning, writing %s failed!\n",
+                      data->set.str[STRING_SSH_KNOWNHOSTS]);
+              }
+            }
+          }
+          break;
+        }
+      }
+#endif /* HAVE_LIBSSH2_KNOWNHOST_API */
+
+      state(conn, SSH_AUTHLIST);
+      break;
+
+    case SSH_AUTHLIST:
+      /*
+       * Figure out authentication methods
+       * NB: As soon as we have provided a username to an openssh server we
+       * must never change it later. Thus, always specify the correct username
+       * here, even though the libssh2 docs kind of indicate that it should be
+       * possible to get a 'generic' list (not user-specific) of authentication
+       * methods, presumably with a blank username. That won't work in my
+       * experience.
+       * So always specify it here.
+       */
+      sshc->authlist = libssh2_userauth_list(sshc->ssh_session,
+                                             conn->user,
+                                             (unsigned int)strlen(conn->user));
+
+      if(!sshc->authlist) {
+        if((err = libssh2_session_last_errno(sshc->ssh_session)) ==
+           LIBSSH2_ERROR_EAGAIN) {
+          rc = LIBSSH2_ERROR_EAGAIN;
+          break;
+        }
+        else {
+          state(conn, SSH_SESSION_FREE);
+          sshc->actualcode = libssh2_session_error_to_CURLE(err);
+          break;
+        }
+      }
+      infof(data, "SSH authentication methods available: %s\n",
+            sshc->authlist);
+
+      state(conn, SSH_AUTH_PKEY_INIT);
+      break;
+
+    case SSH_AUTH_PKEY_INIT:
+      /*
+       * Check the supported auth types in the order I feel is most secure
+       * with the requested type of authentication
+       */
+      sshc->authed = FALSE;
+
+      if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) &&
+         (strstr(sshc->authlist, "publickey") != NULL)) {
+        char *home;
+
+        sshc->rsa_pub = sshc->rsa = NULL;
+
+        /* To ponder about: should really the lib be messing about with the
+           HOME environment variable etc? */
+        home = curl_getenv("HOME");
+
+        if(data->set.str[STRING_SSH_PUBLIC_KEY])
+          sshc->rsa_pub = aprintf("%s", data->set.str[STRING_SSH_PUBLIC_KEY]);
+        else if(home)
+          sshc->rsa_pub = aprintf("%s/.ssh/id_dsa.pub", home);
+        else
+          /* as a final resort, try current dir! */
+          sshc->rsa_pub = strdup("id_dsa.pub");
+
+        if(sshc->rsa_pub == NULL) {
+          Curl_safefree(home);
+          home = NULL;
+          state(conn, SSH_SESSION_FREE);
+          sshc->actualcode = CURLE_OUT_OF_MEMORY;
+          break;
+        }
+
+        if(data->set.str[STRING_SSH_PRIVATE_KEY])
+          sshc->rsa = aprintf("%s", data->set.str[STRING_SSH_PRIVATE_KEY]);
+        else if(home)
+          sshc->rsa = aprintf("%s/.ssh/id_dsa", home);
+        else
+          /* as a final resort, try current dir! */
+          sshc->rsa = strdup("id_dsa");
+
+        if(sshc->rsa == NULL) {
+          Curl_safefree(home);
+          home = NULL;
+          Curl_safefree(sshc->rsa_pub);
+          sshc->rsa_pub = NULL;
+          state(conn, SSH_SESSION_FREE);
+          sshc->actualcode = CURLE_OUT_OF_MEMORY;
+          break;
+        }
+
+        sshc->passphrase = data->set.str[STRING_KEY_PASSWD];
+        if(!sshc->passphrase)
+          sshc->passphrase = "";
+
+        Curl_safefree(home);
+        home = NULL;
+
+        infof(data, "Using ssh public key file %s\n", sshc->rsa_pub);
+        infof(data, "Using ssh private key file %s\n", sshc->rsa);
+
+        state(conn, SSH_AUTH_PKEY);
+      }
+      else {
+        state(conn, SSH_AUTH_PASS_INIT);
+      }
+      break;
+
+    case SSH_AUTH_PKEY:
+      /* The function below checks if the files exists, no need to stat() here.
+       */
+      rc = libssh2_userauth_publickey_fromfile_ex(sshc->ssh_session,
+                                                  conn->user,
+                                                  (unsigned int)
+                                                  strlen(conn->user),
+                                                  sshc->rsa_pub,
+                                                  sshc->rsa, sshc->passphrase);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+
+      Curl_safefree(sshc->rsa_pub);
+      sshc->rsa_pub = NULL;
+      Curl_safefree(sshc->rsa);
+      sshc->rsa = NULL;
+
+      if(rc == 0) {
+        sshc->authed = TRUE;
+        infof(data, "Initialized SSH public key authentication\n");
+        state(conn, SSH_AUTH_DONE);
+      }
+      else {
+        char *err_msg;
+        (void)libssh2_session_last_error(sshc->ssh_session,
+                                         &err_msg, NULL, 0);
+        infof(data, "SSH public key authentication failed: %s\n", err_msg);
+        state(conn, SSH_AUTH_PASS_INIT);
+      }
+      break;
+
+    case SSH_AUTH_PASS_INIT:
+      if((data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD) &&
+         (strstr(sshc->authlist, "password") != NULL)) {
+        state(conn, SSH_AUTH_PASS);
+      }
+      else {
+        state(conn, SSH_AUTH_HOST_INIT);
+      }
+      break;
+
+    case SSH_AUTH_PASS:
+      rc = libssh2_userauth_password_ex(sshc->ssh_session, conn->user,
+                                        (unsigned int)strlen(conn->user),
+                                        conn->passwd,
+                                        (unsigned int)strlen(conn->passwd),
+                                        NULL);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc == 0) {
+        sshc->authed = TRUE;
+        infof(data, "Initialized password authentication\n");
+        state(conn, SSH_AUTH_DONE);
+      }
+      else {
+        state(conn, SSH_AUTH_HOST_INIT);
+      }
+      break;
+
+    case SSH_AUTH_HOST_INIT:
+      if((data->set.ssh_auth_types & CURLSSH_AUTH_HOST) &&
+         (strstr(sshc->authlist, "hostbased") != NULL)) {
+        state(conn, SSH_AUTH_HOST);
+      }
+      else {
+        state(conn, SSH_AUTH_KEY_INIT);
+      }
+      break;
+
+    case SSH_AUTH_HOST:
+      state(conn, SSH_AUTH_KEY_INIT);
+      break;
+
+    case SSH_AUTH_KEY_INIT:
+      if((data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD)
+         && (strstr(sshc->authlist, "keyboard-interactive") != NULL)) {
+        state(conn, SSH_AUTH_KEY);
+      }
+      else {
+        state(conn, SSH_AUTH_DONE);
+      }
+      break;
+
+    case SSH_AUTH_KEY:
+      /* Authentication failed. Continue with keyboard-interactive now. */
+      rc = libssh2_userauth_keyboard_interactive_ex(sshc->ssh_session,
+                                                    conn->user,
+                                                    (unsigned int)
+                                                    strlen(conn->user),
+                                                    &kbd_callback);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc == 0) {
+        sshc->authed = TRUE;
+        infof(data, "Initialized keyboard interactive authentication\n");
+      }
+      state(conn, SSH_AUTH_DONE);
+      break;
+
+    case SSH_AUTH_DONE:
+      if(!sshc->authed) {
+        failf(data, "Authentication failure");
+        state(conn, SSH_SESSION_FREE);
+        sshc->actualcode = CURLE_LOGIN_DENIED;
+        break;
+      }
+
+      /*
+       * At this point we have an authenticated ssh session.
+       */
+      infof(data, "Authentication complete\n");
+
+      Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSH is connected */
+
+      conn->sockfd = sock;
+      conn->writesockfd = CURL_SOCKET_BAD;
+
+      if(conn->protocol == PROT_SFTP) {
+        state(conn, SSH_SFTP_INIT);
+        break;
+      }
+      infof(data, "SSH CONNECT phase done\n");
+      state(conn, SSH_STOP);
+      break;
+
+    case SSH_SFTP_INIT:
+      /*
+       * Start the libssh2 sftp session
+       */
+      sshc->sftp_session = libssh2_sftp_init(sshc->ssh_session);
+      if(!sshc->sftp_session) {
+        if(libssh2_session_last_errno(sshc->ssh_session) ==
+           LIBSSH2_ERROR_EAGAIN) {
+          rc = LIBSSH2_ERROR_EAGAIN;
+          break;
+        }
+        else {
+          char *err_msg;
+
+          (void)libssh2_session_last_error(sshc->ssh_session,
+                                           &err_msg, NULL, 0);
+          failf(data, "Failure initializing sftp session: %s", err_msg);
+          state(conn, SSH_SESSION_FREE);
+          sshc->actualcode = CURLE_FAILED_INIT;
+          break;
+        }
+      }
+      state(conn, SSH_SFTP_REALPATH);
+      break;
+
+    case SSH_SFTP_REALPATH:
+    {
+      char tempHome[PATH_MAX];
+
+      /*
+       * Get the "home" directory
+       */
+      rc = libssh2_sftp_realpath(sshc->sftp_session, ".",
+                                 tempHome, PATH_MAX-1);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc > 0) {
+        /* It seems that this string is not always NULL terminated */
+        tempHome[rc] = '\0';
+        sshc->homedir = strdup(tempHome);
+        if(!sshc->homedir) {
+          state(conn, SSH_SFTP_CLOSE);
+          sshc->actualcode = CURLE_OUT_OF_MEMORY;
+          break;
+        }
+      }
+      else {
+        /* Return the error type */
+        err = (int)(libssh2_sftp_last_error(sshc->sftp_session));
+        result = sftp_libssh2_error_to_CURLE(err);
+        sshc->actualcode = result?result:CURLE_SSH;
+        DEBUGF(infof(data, "error = %d makes libcurl = %d\n",
+                     err, (int)result));
+        state(conn, SSH_STOP);
+        break;
+      }
+    }
+    /* This is the last step in the SFTP connect phase. Do note that while
+       we get the homedir here, we get the "workingpath" in the DO action
+       since the homedir will remain the same between request but the
+       working path will not. */
+    DEBUGF(infof(data, "SSH CONNECT phase done\n"));
+    state(conn, SSH_STOP);
+    break;
+
+    case SSH_SFTP_QUOTE_INIT:
+
+      result = ssh_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
+      if(result) {
+        sshc->actualcode = result;
+        state(conn, SSH_STOP);
+        break;
+      }
+
+      if(data->set.quote) {
+        infof(data, "Sending quote commands\n");
+        sshc->quote_item = data->set.quote;
+        state(conn, SSH_SFTP_QUOTE);
+      }
+      else {
+        state(conn, SSH_SFTP_TRANS_INIT);
+      }
+      break;
+
+    case SSH_SFTP_POSTQUOTE_INIT:
+      if(data->set.postquote) {
+        infof(data, "Sending quote commands\n");
+        sshc->quote_item = data->set.postquote;
+        state(conn, SSH_SFTP_QUOTE);
+      }
+      else {
+        state(conn, SSH_STOP);
+      }
+      break;
+
+    case SSH_SFTP_QUOTE:
+      /* Send any quote commands */
+    {
+      const char *cp;
+
+      /*
+       * Support some of the "FTP" commands
+       */
+      if(curl_strequal("pwd", sshc->quote_item->data)) {
+        /* output debug output if that is requested */
+        if(data->set.verbose) {
+          char tmp[PATH_MAX+1];
+
+          Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"PWD\n", 4, conn);
+          snprintf(tmp, PATH_MAX, "257 \"%s\" is current directory.\n",
+                   sftp_scp->path);
+          Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp), conn);
+        }
+        state(conn, SSH_SFTP_NEXT_QUOTE);
+        break;
+      }
+      else if(sshc->quote_item->data) {
+        /*
+         * the arguments following the command must be separated from the
+         * command with a space so we can check for it unconditionally
+         */
+        cp = strchr(sshc->quote_item->data, ' ');
+        if(cp == NULL) {
+          failf(data, "Syntax error in SFTP command. Supply parameter(s)!");
+          state(conn, SSH_SFTP_CLOSE);
+          sshc->actualcode = CURLE_QUOTE_ERROR;
+          break;
+        }
+
+        /*
+         * also, every command takes at least one argument so we get that
+         * first argument right now
+         */
+        result = get_pathname(&cp, &sshc->quote_path1);
+        if(result) {
+          if(result == CURLE_OUT_OF_MEMORY)
+            failf(data, "Out of memory");
+          else
+            failf(data, "Syntax error: Bad first parameter");
+          state(conn, SSH_SFTP_CLOSE);
+          sshc->actualcode = result;
+          break;
+        }
+
+        /*
+         * SFTP is a binary protocol, so we don't send text commands to
+         * the server. Instead, we scan for commands for commands used by
+         * OpenSSH's sftp program and call the appropriate libssh2
+         * functions.
+         */
+        if(curl_strnequal(sshc->quote_item->data, "chgrp ", 6) ||
+           curl_strnequal(sshc->quote_item->data, "chmod ", 6) ||
+           curl_strnequal(sshc->quote_item->data, "chown ", 6) ) {
+          /* attribute change */
+
+          /* sshc->quote_path1 contains the mode to set */
+          /* get the destination */
+          result = get_pathname(&cp, &sshc->quote_path2);
+          if(result) {
+            if(result == CURLE_OUT_OF_MEMORY)
+              failf(data, "Out of memory");
+            else
+              failf(data, "Syntax error in chgrp/chmod/chown: "
+                    "Bad second parameter");
+            Curl_safefree(sshc->quote_path1);
+            sshc->quote_path1 = NULL;
+            state(conn, SSH_SFTP_CLOSE);
+            sshc->actualcode = result;
+            break;
+          }
+          memset(&sshc->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
+          state(conn, SSH_SFTP_QUOTE_STAT);
+          break;
+        }
+        else if(curl_strnequal(sshc->quote_item->data, "ln ", 3) ||
+                curl_strnequal(sshc->quote_item->data, "symlink ", 8)) {
+          /* symbolic linking */
+          /* sshc->quote_path1 is the source */
+          /* get the destination */
+          result = get_pathname(&cp, &sshc->quote_path2);
+          if(result) {
+            if(result == CURLE_OUT_OF_MEMORY)
+              failf(data, "Out of memory");
+            else
+              failf(data,
+                    "Syntax error in ln/symlink: Bad second parameter");
+            Curl_safefree(sshc->quote_path1);
+            sshc->quote_path1 = NULL;
+            state(conn, SSH_SFTP_CLOSE);
+            sshc->actualcode = result;
+            break;
+          }
+          state(conn, SSH_SFTP_QUOTE_SYMLINK);
+          break;
+        }
+        else if(curl_strnequal(sshc->quote_item->data, "mkdir ", 6)) {
+          /* create dir */
+          state(conn, SSH_SFTP_QUOTE_MKDIR);
+          break;
+        }
+        else if(curl_strnequal(sshc->quote_item->data, "rename ", 7)) {
+          /* rename file */
+          /* first param is the source path */
+          /* second param is the dest. path */
+          result = get_pathname(&cp, &sshc->quote_path2);
+          if(result) {
+            if(result == CURLE_OUT_OF_MEMORY)
+              failf(data, "Out of memory");
+            else
+              failf(data, "Syntax error in rename: Bad second parameter");
+            Curl_safefree(sshc->quote_path1);
+            sshc->quote_path1 = NULL;
+            state(conn, SSH_SFTP_CLOSE);
+            sshc->actualcode = result;
+            break;
+          }
+          state(conn, SSH_SFTP_QUOTE_RENAME);
+          break;
+        }
+        else if(curl_strnequal(sshc->quote_item->data, "rmdir ", 6)) {
+          /* delete dir */
+          state(conn, SSH_SFTP_QUOTE_RMDIR);
+          break;
+        }
+        else if(curl_strnequal(sshc->quote_item->data, "rm ", 3)) {
+          state(conn, SSH_SFTP_QUOTE_UNLINK);
+          break;
+        }
+
+        failf(data, "Unknown SFTP command");
+        Curl_safefree(sshc->quote_path1);
+        sshc->quote_path1 = NULL;
+        Curl_safefree(sshc->quote_path2);
+        sshc->quote_path2 = NULL;
+        state(conn, SSH_SFTP_CLOSE);
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+    }
+    if(!sshc->quote_item) {
+      state(conn, SSH_SFTP_TRANS_INIT);
+    }
+    break;
+
+    case SSH_SFTP_NEXT_QUOTE:
+      if(sshc->quote_path1) {
+        Curl_safefree(sshc->quote_path1);
+        sshc->quote_path1 = NULL;
+      }
+      if(sshc->quote_path2) {
+        Curl_safefree(sshc->quote_path2);
+        sshc->quote_path2 = NULL;
+      }
+
+      sshc->quote_item = sshc->quote_item->next;
+
+      if(sshc->quote_item) {
+        state(conn, SSH_SFTP_QUOTE);
+      }
+      else {
+        if(sshc->nextstate != SSH_NO_STATE) {
+          state(conn, sshc->nextstate);
+          sshc->nextstate = SSH_NO_STATE;
+        }
+        else {
+          state(conn, SSH_SFTP_TRANS_INIT);
+        }
+      }
+      break;
+
+    case SSH_SFTP_QUOTE_STAT:
+      if(!curl_strnequal(sshc->quote_item->data, "chmod", 5)) {
+        /* Since chown and chgrp only set owner OR group but libssh2 wants to
+         * set them both at once, we need to obtain the current ownership
+         * first.  This takes an extra protocol round trip.
+         */
+        rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
+                                  (unsigned int)strlen(sshc->quote_path2),
+                                  LIBSSH2_SFTP_STAT,
+                                  &sshc->quote_attrs);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc != 0) { /* get those attributes */
+          err = (int)(libssh2_sftp_last_error(sshc->sftp_session));
+          Curl_safefree(sshc->quote_path1);
+          sshc->quote_path1 = NULL;
+          Curl_safefree(sshc->quote_path2);
+          sshc->quote_path2 = NULL;
+          failf(data, "Attempt to get SFTP stats failed: %s",
+                sftp_libssh2_strerror(err));
+          state(conn, SSH_SFTP_CLOSE);
+          sshc->actualcode = CURLE_QUOTE_ERROR;
+          break;
+        }
+      }
+
+      /* Now set the new attributes... */
+      if(curl_strnequal(sshc->quote_item->data, "chgrp", 5)) {
+        sshc->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10);
+        sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
+        if(sshc->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0])) {
+          Curl_safefree(sshc->quote_path1);
+          sshc->quote_path1 = NULL;
+          Curl_safefree(sshc->quote_path2);
+          sshc->quote_path2 = NULL;
+          failf(data, "Syntax error: chgrp gid not a number");
+          state(conn, SSH_SFTP_CLOSE);
+          sshc->actualcode = CURLE_QUOTE_ERROR;
+          break;
+        }
+      }
+      else if(curl_strnequal(sshc->quote_item->data, "chmod", 5)) {
+        sshc->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8);
+        sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS;
+        /* permissions are octal */
+        if(sshc->quote_attrs.permissions == 0 &&
+           !ISDIGIT(sshc->quote_path1[0])) {
+          Curl_safefree(sshc->quote_path1);
+          sshc->quote_path1 = NULL;
+          Curl_safefree(sshc->quote_path2);
+          sshc->quote_path2 = NULL;
+          failf(data, "Syntax error: chmod permissions not a number");
+          state(conn, SSH_SFTP_CLOSE);
+          sshc->actualcode = CURLE_QUOTE_ERROR;
+          break;
+        }
+      }
+      else if(curl_strnequal(sshc->quote_item->data, "chown", 5)) {
+        sshc->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10);
+        sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
+        if(sshc->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0])) {
+          Curl_safefree(sshc->quote_path1);
+          sshc->quote_path1 = NULL;
+          Curl_safefree(sshc->quote_path2);
+          sshc->quote_path2 = NULL;
+          failf(data, "Syntax error: chown uid not a number");
+          state(conn, SSH_SFTP_CLOSE);
+          sshc->actualcode = CURLE_QUOTE_ERROR;
+          break;
+        }
+      }
+
+      /* Now send the completed structure... */
+      state(conn, SSH_SFTP_QUOTE_SETSTAT);
+      break;
+
+    case SSH_SFTP_QUOTE_SETSTAT:
+      rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
+                                (unsigned int)strlen(sshc->quote_path2),
+                                LIBSSH2_SFTP_SETSTAT,
+                                &sshc->quote_attrs);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc != 0) {
+        err = (int)(libssh2_sftp_last_error(sshc->sftp_session));
+        Curl_safefree(sshc->quote_path1);
+        sshc->quote_path1 = NULL;
+        Curl_safefree(sshc->quote_path2);
+        sshc->quote_path2 = NULL;
+        failf(data, "Attempt to set SFTP stats failed: %s",
+              sftp_libssh2_strerror(err));
+        state(conn, SSH_SFTP_CLOSE);
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      state(conn, SSH_SFTP_NEXT_QUOTE);
+      break;
+
+    case SSH_SFTP_QUOTE_SYMLINK:
+      rc = libssh2_sftp_symlink_ex(sshc->sftp_session, sshc->quote_path1,
+                                   (unsigned int)strlen(sshc->quote_path1),
+                                   sshc->quote_path2,
+                                   (unsigned int)strlen(sshc->quote_path2),
+                                   LIBSSH2_SFTP_SYMLINK);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc != 0) {
+        err = (int)(libssh2_sftp_last_error(sshc->sftp_session));
+        Curl_safefree(sshc->quote_path1);
+        sshc->quote_path1 = NULL;
+        Curl_safefree(sshc->quote_path2);
+        sshc->quote_path2 = NULL;
+        failf(data, "symlink command failed: %s",
+              sftp_libssh2_strerror(err));
+        state(conn, SSH_SFTP_CLOSE);
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      state(conn, SSH_SFTP_NEXT_QUOTE);
+      break;
+
+    case SSH_SFTP_QUOTE_MKDIR:
+      rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshc->quote_path1,
+                                 (unsigned int)strlen(sshc->quote_path1),
+                                 0755);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc != 0) {
+        err = (int)(libssh2_sftp_last_error(sshc->sftp_session));
+        Curl_safefree(sshc->quote_path1);
+        sshc->quote_path1 = NULL;
+        failf(data, "mkdir command failed: %s", sftp_libssh2_strerror(err));
+        state(conn, SSH_SFTP_CLOSE);
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      state(conn, SSH_SFTP_NEXT_QUOTE);
+      break;
+
+    case SSH_SFTP_QUOTE_RENAME:
+      rc = libssh2_sftp_rename_ex(sshc->sftp_session, sshc->quote_path1,
+                                  (unsigned int)strlen(sshc->quote_path1),
+                                  sshc->quote_path2,
+                                  (unsigned int)strlen(sshc->quote_path2),
+                                  LIBSSH2_SFTP_RENAME_OVERWRITE |
+                                  LIBSSH2_SFTP_RENAME_ATOMIC |
+                                  LIBSSH2_SFTP_RENAME_NATIVE);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc != 0) {
+        err = (int)(libssh2_sftp_last_error(sshc->sftp_session));
+        Curl_safefree(sshc->quote_path1);
+        sshc->quote_path1 = NULL;
+        Curl_safefree(sshc->quote_path2);
+        sshc->quote_path2 = NULL;
+        failf(data, "rename command failed: %s", sftp_libssh2_strerror(err));
+        state(conn, SSH_SFTP_CLOSE);
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      state(conn, SSH_SFTP_NEXT_QUOTE);
+      break;
+
+    case SSH_SFTP_QUOTE_RMDIR:
+      rc = libssh2_sftp_rmdir_ex(sshc->sftp_session, sshc->quote_path1,
+                                 (unsigned int)strlen(sshc->quote_path1));
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc != 0) {
+        err = (int)(libssh2_sftp_last_error(sshc->sftp_session));
+        Curl_safefree(sshc->quote_path1);
+        sshc->quote_path1 = NULL;
+        failf(data, "rmdir command failed: %s", sftp_libssh2_strerror(err));
+        state(conn, SSH_SFTP_CLOSE);
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      state(conn, SSH_SFTP_NEXT_QUOTE);
+      break;
+
+    case SSH_SFTP_QUOTE_UNLINK:
+      rc = libssh2_sftp_unlink_ex(sshc->sftp_session, sshc->quote_path1,
+                                  (unsigned int)strlen(sshc->quote_path1));
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc != 0) {
+        err = (int)(libssh2_sftp_last_error(sshc->sftp_session));
+        Curl_safefree(sshc->quote_path1);
+        sshc->quote_path1 = NULL;
+        failf(data, "rm command failed: %s", sftp_libssh2_strerror(err));
+        state(conn, SSH_SFTP_CLOSE);
+        sshc->actualcode = CURLE_QUOTE_ERROR;
+        break;
+      }
+      state(conn, SSH_SFTP_NEXT_QUOTE);
+      break;
+
+    case SSH_SFTP_TRANS_INIT:
+      if(data->set.upload)
+        state(conn, SSH_SFTP_UPLOAD_INIT);
+      else {
+        if(data->set.opt_no_body)
+          state(conn, SSH_STOP);
+        else if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/')
+          state(conn, SSH_SFTP_READDIR_INIT);
+        else
+          state(conn, SSH_SFTP_DOWNLOAD_INIT);
+      }
+      break;
+
+    case SSH_SFTP_UPLOAD_INIT:
+    {
+      unsigned long flags;
+      /*
+       * NOTE!!!  libssh2 requires that the destination path is a full path
+       *          that includes the destination file and name OR ends in a "/"
+       *          If this is not done the destination file will be named the
+       *          same name as the last directory in the path.
+       */
+
+      if(data->state.resume_from != 0) {
+        LIBSSH2_SFTP_ATTRIBUTES attrs;
+        if(data->state.resume_from< 0) {
+          rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path,
+                                    (unsigned int)strlen(sftp_scp->path),
+                                    LIBSSH2_SFTP_STAT, &attrs);
+          if(rc == LIBSSH2_ERROR_EAGAIN) {
+            break;
+          }
+          else if(rc) {
+            data->state.resume_from = 0;
+          }
+          else {
+            data->state.resume_from = attrs.filesize;
+          }
+        }
+      }
+
+      if(data->set.ftp_append)
+        /* Try to open for append, but create if nonexisting */
+        flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_APPEND;
+      else if (data->state.resume_from > 0)
+        /* If we have restart position then open for append */
+        flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_APPEND;
+      else
+        /* Clear file before writing (normal behaviour) */
+        flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC;
+
+      sshc->sftp_handle =
+        libssh2_sftp_open_ex(sshc->sftp_session, sftp_scp->path,
+                             (unsigned int)strlen(sftp_scp->path),
+                             flags, data->set.new_file_perms,
+                             LIBSSH2_SFTP_OPENFILE);
+
+      if(!sshc->sftp_handle) {
+        rc = libssh2_session_last_errno(sshc->ssh_session);
+
+        if(LIBSSH2_ERROR_EAGAIN == rc)
+          break;
+        else {
+          if(LIBSSH2_ERROR_SFTP_PROTOCOL == rc)
+            /* only when there was an SFTP protocol error can we extract
+               the sftp error! */
+            err = (int)(libssh2_sftp_last_error(sshc->sftp_session));
+          else
+            err = -1; /* not an sftp error at all */
+
+          if(sshc->secondCreateDirs) {
+            state(conn, SSH_SFTP_CLOSE);
+            sshc->actualcode = err>= LIBSSH2_FX_OK?
+              sftp_libssh2_error_to_CURLE(err):CURLE_SSH;
+            failf(data, "Creating the dir/file failed: %s",
+                  sftp_libssh2_strerror(err));
+            break;
+          }
+          else if(((err == LIBSSH2_FX_NO_SUCH_FILE) ||
+                   (err == LIBSSH2_FX_FAILURE) ||
+                   (err == LIBSSH2_FX_NO_SUCH_PATH)) &&
+                  (data->set.ftp_create_missing_dirs &&
+                   (strlen(sftp_scp->path) > 1))) {
+            /* try to create the path remotely */
+            sshc->secondCreateDirs = 1;
+            state(conn, SSH_SFTP_CREATE_DIRS_INIT);
+            break;
+          }
+          state(conn, SSH_SFTP_CLOSE);
+          sshc->actualcode = err>= LIBSSH2_FX_OK?
+            sftp_libssh2_error_to_CURLE(err):CURLE_SSH;
+          if(!sshc->actualcode) {
+            /* Sometimes, for some reason libssh2_sftp_last_error() returns
+               zero even though libssh2_sftp_open() failed previously! We need
+               to work around that! */
+            sshc->actualcode = CURLE_SSH;
+            err=-1;
+          }
+          failf(data, "Upload failed: %s (%d/%d)",
+                err>= LIBSSH2_FX_OK?sftp_libssh2_strerror(err):"ssh error",
+                err, rc);
+          break;
+        }
+      }
+
+      /* If we have restart point then we need to seek to the correct
+         position. */
+      if(data->state.resume_from > 0) {
+        /* Let's read off the proper amount of bytes from the input. */
+        if(conn->seek_func) {
+          seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
+                                    SEEK_SET);
+        }
+
+        if(seekerr != CURL_SEEKFUNC_OK){
+
+          if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
+            failf(data, "Could not seek stream");
+            return CURLE_FTP_COULDNT_USE_REST;
+          }
+          /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
+          else {
+            curl_off_t passed=0;
+            curl_off_t readthisamountnow;
+            curl_off_t actuallyread;
+            do {
+              readthisamountnow = (data->state.resume_from - passed);
+
+              if(readthisamountnow > BUFSIZE)
+                readthisamountnow = BUFSIZE;
+
+              actuallyread =
+                (curl_off_t) conn->fread_func(data->state.buffer, 1,
+                                              (size_t)readthisamountnow,
+                                              conn->fread_in);
+
+              passed += actuallyread;
+              if((actuallyread <= 0) || (actuallyread > readthisamountnow)) {
+                /* this checks for greater-than only to make sure that the
+                   CURL_READFUNC_ABORT return code still aborts */
+                failf(data, "Failed to read data");
+                return CURLE_FTP_COULDNT_USE_REST;
+              }
+            } while(passed < data->state.resume_from);
+          }
+        }
+
+        /* now, decrease the size of the read */
+        if(data->set.infilesize>0) {
+          data->set.infilesize -= data->state.resume_from;
+          data->req.size = data->set.infilesize;
+          Curl_pgrsSetUploadSize(data, data->set.infilesize);
+        }
+
+        SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
+      }
+      if(data->set.infilesize>0) {
+        data->req.size = data->set.infilesize;
+        Curl_pgrsSetUploadSize(data, data->set.infilesize);
+      }
+      /* upload data */
+      result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL,
+                                   FIRSTSOCKET, NULL);
+
+      /* not set by Curl_setup_transfer to preserve keepon bits */
+      conn->sockfd = conn->writesockfd;
+
+      if(result) {
+        state(conn, SSH_SFTP_CLOSE);
+        sshc->actualcode = result;
+      }
+      else {
+        /* store this original bitmask setup to use later on if we can't
+           figure out a "real" bitmask */
+        sshc->orig_waitfor = data->req.keepon;
+
+        state(conn, SSH_STOP);
+      }
+      break;
+    }
+
+    case SSH_SFTP_CREATE_DIRS_INIT:
+      if(strlen(sftp_scp->path) > 1) {
+        sshc->slash_pos = sftp_scp->path + 1; /* ignore the leading '/' */
+        state(conn, SSH_SFTP_CREATE_DIRS);
+      }
+      else {
+        state(conn, SSH_SFTP_UPLOAD_INIT);
+      }
+      break;
+
+    case SSH_SFTP_CREATE_DIRS:
+      if((sshc->slash_pos = strchr(sshc->slash_pos, '/')) != NULL) {
+        *sshc->slash_pos = 0;
+
+        infof(data, "Creating directory '%s'\n", sftp_scp->path);
+        state(conn, SSH_SFTP_CREATE_DIRS_MKDIR);
+        break;
+      }
+      else {
+        state(conn, SSH_SFTP_UPLOAD_INIT);
+      }
+      break;
+
+    case SSH_SFTP_CREATE_DIRS_MKDIR:
+      /* 'mode' - parameter is preliminary - default to 0644 */
+      rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sftp_scp->path,
+                                 (unsigned int)strlen(sftp_scp->path),
+                                 data->set.new_directory_perms);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      *sshc->slash_pos = '/';
+      ++sshc->slash_pos;
+      if(rc == -1) {
+        unsigned int sftp_err = 0;
+        /*
+         * Abort if failure wasn't that the dir already exists or the
+         * permission was denied (creation might succeed further down the
+         * path) - retry on unspecific FAILURE also
+         */
+        sftp_err = (unsigned int)(libssh2_sftp_last_error(sshc->sftp_session));
+        if((sftp_err != LIBSSH2_FX_FILE_ALREADY_EXISTS) &&
+           (sftp_err != LIBSSH2_FX_FAILURE) &&
+           (sftp_err != LIBSSH2_FX_PERMISSION_DENIED)) {
+          result = sftp_libssh2_error_to_CURLE(sftp_err);
+          state(conn, SSH_SFTP_CLOSE);
+          sshc->actualcode = result?result:CURLE_SSH;
+          break;
+        }
+      }
+      state(conn, SSH_SFTP_CREATE_DIRS);
+      break;
+
+    case SSH_SFTP_READDIR_INIT:
+      /*
+       * This is a directory that we are trying to get, so produce a directory
+       * listing
+       */
+      sshc->sftp_handle = libssh2_sftp_open_ex(sshc->sftp_session,
+                                               sftp_scp->path,
+                                               (unsigned int)
+                                               strlen(sftp_scp->path),
+                                               0, 0, LIBSSH2_SFTP_OPENDIR);
+      if(!sshc->sftp_handle) {
+        if(libssh2_session_last_errno(sshc->ssh_session) ==
+           LIBSSH2_ERROR_EAGAIN) {
+          rc = LIBSSH2_ERROR_EAGAIN;
+          break;
+        }
+        else {
+          err = (int)(libssh2_sftp_last_error(sshc->sftp_session));
+          failf(data, "Could not open directory for reading: %s",
+                sftp_libssh2_strerror(err));
+          state(conn, SSH_SFTP_CLOSE);
+          result = sftp_libssh2_error_to_CURLE(err);
+          sshc->actualcode = result?result:CURLE_SSH;
+          break;
+        }
+      }
+      if((sshc->readdir_filename = malloc(PATH_MAX+1)) == NULL) {
+        state(conn, SSH_SFTP_CLOSE);
+        sshc->actualcode = CURLE_OUT_OF_MEMORY;
+        break;
+      }
+      if((sshc->readdir_longentry = malloc(PATH_MAX+1)) == NULL) {
+        Curl_safefree(sshc->readdir_filename);
+        sshc->readdir_filename = NULL;
+        state(conn, SSH_SFTP_CLOSE);
+        sshc->actualcode = CURLE_OUT_OF_MEMORY;
+        break;
+      }
+      state(conn, SSH_SFTP_READDIR);
+      break;
+
+    case SSH_SFTP_READDIR:
+      sshc->readdir_len = libssh2_sftp_readdir_ex(sshc->sftp_handle,
+                                                  sshc->readdir_filename,
+                                                  PATH_MAX,
+                                                  sshc->readdir_longentry,
+                                                  PATH_MAX,
+                                                  &sshc->readdir_attrs);
+      if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) {
+        rc = LIBSSH2_ERROR_EAGAIN;
+        break;
+      }
+      if(sshc->readdir_len > 0) {
+        sshc->readdir_filename[sshc->readdir_len] = '\0';
+
+        if(data->set.ftp_list_only) {
+          char *tmpLine;
+
+          tmpLine = aprintf("%s\n", sshc->readdir_filename);
+          if(tmpLine == NULL) {
+            state(conn, SSH_SFTP_CLOSE);
+            sshc->actualcode = CURLE_OUT_OF_MEMORY;
+            break;
+          }
+          result = Curl_client_write(conn, CLIENTWRITE_BODY,
+                                     tmpLine, sshc->readdir_len+1);
+          Curl_safefree(tmpLine);
+
+          if(result) {
+            state(conn, SSH_STOP);
+            break;
+          }
+          /* since this counts what we send to the client, we include the
+             newline in this counter */
+          data->req.bytecount += sshc->readdir_len+1;
+
+          /* output debug output if that is requested */
+          if(data->set.verbose) {
+            Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_filename,
+                       sshc->readdir_len, conn);
+          }
+        }
+        else {
+          sshc->readdir_currLen = (int)strlen(sshc->readdir_longentry);
+          sshc->readdir_totalLen = 80 + sshc->readdir_currLen;
+          sshc->readdir_line = calloc(sshc->readdir_totalLen, 1);
+          if(!sshc->readdir_line) {
+            Curl_safefree(sshc->readdir_filename);
+            sshc->readdir_filename = NULL;
+            Curl_safefree(sshc->readdir_longentry);
+            sshc->readdir_longentry = NULL;
+            state(conn, SSH_SFTP_CLOSE);
+            sshc->actualcode = CURLE_OUT_OF_MEMORY;
+            break;
+          }
+
+          memcpy(sshc->readdir_line, sshc->readdir_longentry,
+                 sshc->readdir_currLen);
+          if((sshc->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
+             ((sshc->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
+              LIBSSH2_SFTP_S_IFLNK)) {
+            sshc->readdir_linkPath = malloc(PATH_MAX + 1);
+            if(sshc->readdir_linkPath == NULL) {
+              Curl_safefree(sshc->readdir_filename);
+              sshc->readdir_filename = NULL;
+              Curl_safefree(sshc->readdir_longentry);
+              sshc->readdir_longentry = NULL;
+              state(conn, SSH_SFTP_CLOSE);
+              sshc->actualcode = CURLE_OUT_OF_MEMORY;
+              break;
+            }
+
+            snprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", sftp_scp->path,
+                     sshc->readdir_filename);
+            state(conn, SSH_SFTP_READDIR_LINK);
+            break;
+          }
+          state(conn, SSH_SFTP_READDIR_BOTTOM);
+          break;
+        }
+      }
+      else if(sshc->readdir_len == 0) {
+        Curl_safefree(sshc->readdir_filename);
+        sshc->readdir_filename = NULL;
+        Curl_safefree(sshc->readdir_longentry);
+        sshc->readdir_longentry = NULL;
+        state(conn, SSH_SFTP_READDIR_DONE);
+        break;
+      }
+      else if(sshc->readdir_len <= 0) {
+        err = (int)(libssh2_sftp_last_error(sshc->sftp_session));
+        result = sftp_libssh2_error_to_CURLE(err);
+        sshc->actualcode = result?result:CURLE_SSH;
+        failf(data, "Could not open remote file for reading: %s :: %d",
+              sftp_libssh2_strerror(err),
+              libssh2_session_last_errno(sshc->ssh_session));
+        Curl_safefree(sshc->readdir_filename);
+        sshc->readdir_filename = NULL;
+        Curl_safefree(sshc->readdir_longentry);
+        sshc->readdir_longentry = NULL;
+        state(conn, SSH_SFTP_CLOSE);
+        break;
+      }
+      break;
+
+    case SSH_SFTP_READDIR_LINK:
+      sshc->readdir_len =
+        libssh2_sftp_symlink_ex(sshc->sftp_session,
+                                sshc->readdir_linkPath,
+                                (unsigned int) strlen(sshc->readdir_linkPath),
+                                sshc->readdir_filename,
+                                PATH_MAX, LIBSSH2_SFTP_READLINK);
+      if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) {
+        rc = LIBSSH2_ERROR_EAGAIN;
+        break;
+      }
+      Curl_safefree(sshc->readdir_linkPath);
+      sshc->readdir_linkPath = NULL;
+      sshc->readdir_line = realloc(sshc->readdir_line,
+                                   sshc->readdir_totalLen + 4 +
+                                   sshc->readdir_len);
+      if(!sshc->readdir_line) {
+        Curl_safefree(sshc->readdir_filename);
+        sshc->readdir_filename = NULL;
+        Curl_safefree(sshc->readdir_longentry);
+        sshc->readdir_longentry = NULL;
+        state(conn, SSH_SFTP_CLOSE);
+        sshc->actualcode = CURLE_OUT_OF_MEMORY;
+        break;
+      }
+
+      sshc->readdir_currLen += snprintf(sshc->readdir_line +
+                                        sshc->readdir_currLen,
+                                        sshc->readdir_totalLen -
+                                        sshc->readdir_currLen,
+                                        " -> %s",
+                                        sshc->readdir_filename);
+
+      state(conn, SSH_SFTP_READDIR_BOTTOM);
+      break;
+
+    case SSH_SFTP_READDIR_BOTTOM:
+      sshc->readdir_currLen += snprintf(sshc->readdir_line +
+                                        sshc->readdir_currLen,
+                                        sshc->readdir_totalLen -
+                                        sshc->readdir_currLen, "\n");
+      result = Curl_client_write(conn, CLIENTWRITE_BODY,
+                                 sshc->readdir_line,
+                                 sshc->readdir_currLen);
+
+      if(result == CURLE_OK) {
+
+        /* output debug output if that is requested */
+        if(data->set.verbose) {
+          Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line,
+                     sshc->readdir_currLen, conn);
+        }
+        data->req.bytecount += sshc->readdir_currLen;
+      }
+      Curl_safefree(sshc->readdir_line);
+      sshc->readdir_line = NULL;
+      if(result) {
+        state(conn, SSH_STOP);
+      }
+      else
+        state(conn, SSH_SFTP_READDIR);
+      break;
+
+    case SSH_SFTP_READDIR_DONE:
+      if(libssh2_sftp_closedir(sshc->sftp_handle) ==
+         LIBSSH2_ERROR_EAGAIN) {
+        rc = LIBSSH2_ERROR_EAGAIN;
+        break;
+      }
+      sshc->sftp_handle = NULL;
+      Curl_safefree(sshc->readdir_filename);
+      sshc->readdir_filename = NULL;
+      Curl_safefree(sshc->readdir_longentry);
+      sshc->readdir_longentry = NULL;
+
+      /* no data to transfer */
+      result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+      state(conn, SSH_STOP);
+      break;
+
+    case SSH_SFTP_DOWNLOAD_INIT:
+      /*
+       * Work on getting the specified file
+       */
+      sshc->sftp_handle =
+        libssh2_sftp_open_ex(sshc->sftp_session, sftp_scp->path,
+                             (unsigned int)strlen(sftp_scp->path),
+                             LIBSSH2_FXF_READ, data->set.new_file_perms,
+                             LIBSSH2_SFTP_OPENFILE);
+      if(!sshc->sftp_handle) {
+        if(libssh2_session_last_errno(sshc->ssh_session) ==
+           LIBSSH2_ERROR_EAGAIN) {
+          rc = LIBSSH2_ERROR_EAGAIN;
+          break;
+        }
+        else {
+          err = (int)(libssh2_sftp_last_error(sshc->sftp_session));
+          failf(data, "Could not open remote file for reading: %s",
+                sftp_libssh2_strerror(err));
+          state(conn, SSH_SFTP_CLOSE);
+          result = sftp_libssh2_error_to_CURLE(err);
+          sshc->actualcode = result?result:CURLE_SSH;
+          break;
+        }
+      }
+      state(conn, SSH_SFTP_DOWNLOAD_STAT);
+      break;
+
+    case SSH_SFTP_DOWNLOAD_STAT:
+    {
+      LIBSSH2_SFTP_ATTRIBUTES attrs;
+
+      rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path,
+                                (unsigned int)strlen(sftp_scp->path),
+                                LIBSSH2_SFTP_STAT, &attrs);
+      if(rc == LIBSSH2_ERROR_EAGAIN) {
+        break;
+      }
+      else if(rc) {
+        /*
+         * libssh2_sftp_open() didn't return an error, so maybe the server
+         * just doesn't support stat()
+         */
+        data->req.size = -1;
+        data->req.maxdownload = -1;
+      }
+      else {
+        curl_off_t size;
+
+        size = attrs.filesize;
+        if(conn->data->state.use_range) {
+          curl_off_t from, to;
+          char *ptr;
+          char *ptr2;
+
+          from=curlx_strtoofft(conn->data->state.range, &ptr, 0);
+          while(ptr && *ptr && (isspace((int)*ptr) || (*ptr=='-')))
+            ptr++;
+          to=curlx_strtoofft(ptr, &ptr2, 0);
+          if((ptr == ptr2) /* no "to" value given */
+             || (to >= size)) {
+            to = size - 1;
+          }
+          if(from < 0) {
+            /* from is relative to end of file */
+            from += size;
+          }
+          if(from >= size) {
+            failf(data, "Offset (%"
+                  FORMAT_OFF_T ") was beyond file size (%" FORMAT_OFF_T ")",
+                  from, attrs.filesize);
+            return CURLE_BAD_DOWNLOAD_RESUME;
+          }
+          if(from > to) {
+            from = to;
+            size = 0;
+          }
+          else {
+            size = to - from + 1;
+          }
+
+          SFTP_SEEK(conn->proto.sshc.sftp_handle, from);
+        }
+        data->req.size = size;
+        data->req.maxdownload = size;
+        Curl_pgrsSetDownloadSize(data, size);
+      }
+
+      /* We can resume if we can seek to the resume position */
+      if(data->state.resume_from) {
+        if(data->state.resume_from< 0) {
+          /* We're supposed to download the last abs(from) bytes */
+          if((curl_off_t)attrs.filesize < -data->state.resume_from) {
+            failf(data, "Offset (%"
+                  FORMAT_OFF_T ") was beyond file size (%" FORMAT_OFF_T ")",
+                  data->state.resume_from, attrs.filesize);
+            return CURLE_BAD_DOWNLOAD_RESUME;
+          }
+          /* download from where? */
+          data->state.resume_from = attrs.filesize - data->state.resume_from;
+        }
+        else {
+          if((curl_off_t)attrs.filesize < data->state.resume_from) {
+            failf(data, "Offset (%" FORMAT_OFF_T
+                  ") was beyond file size (%" FORMAT_OFF_T ")",
+                  data->state.resume_from, attrs.filesize);
+            return CURLE_BAD_DOWNLOAD_RESUME;
+          }
+        }
+        /* Does a completed file need to be seeked and started or closed ? */
+        /* Now store the number of bytes we are expected to download */
+        data->req.size = attrs.filesize - data->state.resume_from;
+        data->req.maxdownload = attrs.filesize - data->state.resume_from;
+        Curl_pgrsSetDownloadSize(data,
+                                 attrs.filesize - data->state.resume_from);
+        SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
+      }
+    }
+    /* Setup the actual download */
+    if(data->req.size == 0) {
+      /* no data to transfer */
+      result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+      infof(data, "File already completely downloaded\n");
+      state(conn, SSH_STOP);
+      break;
+    }
+    else {
+      result = Curl_setup_transfer(conn, FIRSTSOCKET, data->req.size,
+                                   FALSE, NULL, -1, NULL);
+
+      /* not set by Curl_setup_transfer to preserve keepon bits */
+      conn->writesockfd = conn->sockfd;
+
+      /* FIXME: here should be explained why we need it to start the
+       * download */
+      conn->cselect_bits = CURL_CSELECT_IN;
+    }
+    if(result) {
+      state(conn, SSH_SFTP_CLOSE);
+      sshc->actualcode = result;
+    }
+    else {
+      state(conn, SSH_STOP);
+    }
+    break;
+
+    case SSH_SFTP_CLOSE:
+      if(sshc->sftp_handle) {
+        rc = libssh2_sftp_close(sshc->sftp_handle);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc < 0) {
+          infof(data, "Failed to close libssh2 file\n");
+        }
+        sshc->sftp_handle = NULL;
+      }
+      Curl_safefree(sftp_scp->path);
+      sftp_scp->path = NULL;
+
+      DEBUGF(infof(data, "SFTP DONE done\n"));
+#if 0 /* PREV */
+      state(conn, SSH_SFTP_SHUTDOWN);
+#endif
+      state(conn, SSH_STOP);
+      result = sshc->actualcode;
+      break;
+
+    case SSH_SFTP_SHUTDOWN:
+      /* during times we get here due to a broken transfer and then the
+         sftp_handle might not have been taken down so make sure that is done
+         before we proceed */
+
+      if(sshc->sftp_handle) {
+        rc = libssh2_sftp_close(sshc->sftp_handle);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc < 0) {
+          infof(data, "Failed to close libssh2 file\n");
+        }
+        sshc->sftp_handle = NULL;
+      }
+      if(sshc->sftp_session) {
+        rc = libssh2_sftp_shutdown(sshc->sftp_session);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc < 0) {
+          infof(data, "Failed to stop libssh2 sftp subsystem\n");
+        }
+        sshc->sftp_session = NULL;
+      }
+
+      Curl_safefree(sshc->homedir);
+      sshc->homedir = NULL;
+
+      state(conn, SSH_SESSION_DISCONNECT);
+      break;
+
+    case SSH_SCP_TRANS_INIT:
+      result = ssh_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
+      if(result) {
+        sshc->actualcode = result;
+        state(conn, SSH_STOP);
+        break;
+      }
+
+      if(data->set.upload) {
+        if(data->set.infilesize < 0) {
+          failf(data, "SCP requires a known file size for upload");
+          sshc->actualcode = CURLE_UPLOAD_FAILED;
+          state(conn, SSH_SCP_CHANNEL_FREE);
+          break;
+        }
+        state(conn, SSH_SCP_UPLOAD_INIT);
+      }
+      else {
+        state(conn, SSH_SCP_DOWNLOAD_INIT);
+      }
+      break;
+
+    case SSH_SCP_UPLOAD_INIT:
+      /*
+       * libssh2 requires that the destination path is a full path that
+       * includes the destination file and name OR ends in a "/" .  If this is
+       * not done the destination file will be named the same name as the last
+       * directory in the path.
+       */
+      sshc->ssh_channel =
+        libssh2_scp_send_ex(sshc->ssh_session, sftp_scp->path,
+                            (int)(data->set.new_file_perms),
+                            (size_t)data->set.infilesize, 0, 0);
+      if(!sshc->ssh_channel) {
+        if(libssh2_session_last_errno(sshc->ssh_session) ==
+           LIBSSH2_ERROR_EAGAIN) {
+          rc = LIBSSH2_ERROR_EAGAIN;
+          break;
+        }
+        else {
+          int ssh_err;
+          char *err_msg;
+
+          ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session,
+                                                     &err_msg, NULL, 0));
+          failf(conn->data, "%s", err_msg);
+          state(conn, SSH_SCP_CHANNEL_FREE);
+          sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
+          break;
+        }
+      }
+
+      /* upload data */
+      result = Curl_setup_transfer(conn, -1, data->req.size, FALSE, NULL,
+                                   FIRSTSOCKET, NULL);
+
+      /* not set by Curl_setup_transfer to preserve keepon bits */
+      conn->sockfd = conn->writesockfd;
+
+      if(result) {
+        state(conn, SSH_SCP_CHANNEL_FREE);
+        sshc->actualcode = result;
+      }
+      else {
+        state(conn, SSH_STOP);
+      }
+      break;
+
+    case SSH_SCP_DOWNLOAD_INIT:
+    {
+      /*
+       * We must check the remote file; if it is a directory no values will
+       * be set in sb
+       */
+      struct stat sb;
+      curl_off_t bytecount;
+
+      /* clear the struct scp recv will fill in */
+      memset(&sb, 0, sizeof(struct stat));
+
+      /* get a fresh new channel from the ssh layer */
+      sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session,
+                                           sftp_scp->path, &sb);
+      if(!sshc->ssh_channel) {
+        if(libssh2_session_last_errno(sshc->ssh_session) ==
+           LIBSSH2_ERROR_EAGAIN) {
+          rc = LIBSSH2_ERROR_EAGAIN;
+          break;
+        }
+        else {
+          int ssh_err;
+          char *err_msg;
+
+          ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session,
+                                                     &err_msg, NULL, 0));
+          failf(conn->data, "%s", err_msg);
+          state(conn, SSH_SCP_CHANNEL_FREE);
+          sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
+          break;
+        }
+      }
+
+      /* download data */
+      bytecount = (curl_off_t)sb.st_size;
+      data->req.maxdownload =  (curl_off_t)sb.st_size;
+      result = Curl_setup_transfer(conn, FIRSTSOCKET,
+                                   bytecount, FALSE, NULL, -1, NULL);
+
+      /* not set by Curl_setup_transfer to preserve keepon bits */
+      conn->writesockfd = conn->sockfd;
+
+      /* FIXME: here should be explained why we need it to start the
+       * download */
+      conn->cselect_bits = CURL_CSELECT_IN;
+
+      if(result) {
+        state(conn, SSH_SCP_CHANNEL_FREE);
+        sshc->actualcode = result;
+      }
+      else
+        state(conn, SSH_STOP);
+    }
+    break;
+
+    case SSH_SCP_DONE:
+      if(data->set.upload)
+        state(conn, SSH_SCP_SEND_EOF);
+      else
+        state(conn, SSH_SCP_CHANNEL_FREE);
+      break;
+
+    case SSH_SCP_SEND_EOF:
+      if(sshc->ssh_channel) {
+        rc = libssh2_channel_send_eof(sshc->ssh_channel);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc) {
+          infof(data, "Failed to send libssh2 channel EOF\n");
+        }
+      }
+      state(conn, SSH_SCP_WAIT_EOF);
+      break;
+
+    case SSH_SCP_WAIT_EOF:
+      if(sshc->ssh_channel) {
+        rc = libssh2_channel_wait_eof(sshc->ssh_channel);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc) {
+          infof(data, "Failed to get channel EOF: %d\n", rc);
+        }
+      }
+      state(conn, SSH_SCP_WAIT_CLOSE);
+      break;
+
+    case SSH_SCP_WAIT_CLOSE:
+      if(sshc->ssh_channel) {
+        rc = libssh2_channel_wait_closed(sshc->ssh_channel);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc) {
+          infof(data, "Channel failed to close: %d\n", rc);
+        }
+      }
+      state(conn, SSH_SCP_CHANNEL_FREE);
+      break;
+
+    case SSH_SCP_CHANNEL_FREE:
+      if(sshc->ssh_channel) {
+        rc = libssh2_channel_free(sshc->ssh_channel);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc < 0) {
+          infof(data, "Failed to free libssh2 scp subsystem\n");
+        }
+        sshc->ssh_channel = NULL;
+      }
+      DEBUGF(infof(data, "SCP DONE phase complete\n"));
+#if 0 /* PREV */
+      state(conn, SSH_SESSION_DISCONNECT);
+#endif
+      state(conn, SSH_STOP);
+      result = sshc->actualcode;
+      break;
+
+    case SSH_SESSION_DISCONNECT:
+      /* during weird times when we've been prematurely aborted, the channel
+         is still alive when we reach this state and we MUST kill the channel
+         properly first */
+      if(sshc->ssh_channel) {
+        rc = libssh2_channel_free(sshc->ssh_channel);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc < 0) {
+          infof(data, "Failed to free libssh2 scp subsystem\n");
+        }
+        sshc->ssh_channel = NULL;
+      }
+
+      if(sshc->ssh_session) {
+        rc = libssh2_session_disconnect(sshc->ssh_session, "Shutdown");
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc < 0) {
+          infof(data, "Failed to disconnect libssh2 session\n");
+        }
+      }
+
+      Curl_safefree(sshc->homedir);
+      sshc->homedir = NULL;
+
+      state(conn, SSH_SESSION_FREE);
+      break;
+
+    case SSH_SESSION_FREE:
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+      if(sshc->kh) {
+        libssh2_knownhost_free(sshc->kh);
+        sshc->kh = NULL;
+      }
+#endif
+
+      if(sshc->ssh_session) {
+        rc = libssh2_session_free(sshc->ssh_session);
+        if(rc == LIBSSH2_ERROR_EAGAIN) {
+          break;
+        }
+        else if(rc < 0) {
+          infof(data, "Failed to free libssh2 session\n");
+        }
+        sshc->ssh_session = NULL;
+      }
+      conn->bits.close = TRUE;
+      sshc->nextstate = SSH_NO_STATE;
+      state(conn, SSH_STOP);
+      result = sshc->actualcode;
+      break;
+
+    case SSH_QUIT:
+      /* fallthrough, just stop! */
+    default:
+      /* internal error */
+      sshc->nextstate = SSH_NO_STATE;
+      state(conn, SSH_STOP);
+      break;
+    }
+
+  } while(!rc && (sshc->state != SSH_STOP));
+
+  if(rc == LIBSSH2_ERROR_EAGAIN) {
+    /* we would block, we need to wait for the socket to be ready (in the
+       right direction too)! */
+    *block = TRUE;
+  }
+
+  return result;
+}
+
+/* called by the multi interface to figure out what socket(s) to wait for and
+   for what actions in the DO_DONE, PERFORM and WAITPERFORM states */
+static int ssh_perform_getsock(const struct connectdata *conn,
+                               curl_socket_t *sock, /* points to numsocks
+                                                       number of sockets */
+                               int numsocks)
+{
+#ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
+  int bitmap = GETSOCK_BLANK;
+  (void)numsocks;
+
+  sock[0] = conn->sock[FIRSTSOCKET];
+
+  if(conn->waitfor & KEEP_RECV)
+    bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
+
+  if(conn->waitfor & KEEP_SEND)
+    bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
+
+  return bitmap;
+#else
+  /* if we don't know the direction we can use the generic *_getsock()
+     function even for the protocol_connect and doing states */
+  return Curl_single_getsock(conn, sock, numsocks);
+#endif
+}
+
+/* Generic function called by the multi interface to figure out what socket(s)
+   to wait for and for what actions during the DOING and PROTOCONNECT states*/
+static int ssh_getsock(struct connectdata *conn,
+                       curl_socket_t *sock, /* points to numsocks number
+                                               of sockets */
+                       int numsocks)
+{
+#ifndef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
+  (void)conn;
+  (void)sock;
+  (void)numsocks;
+  /* if we don't know any direction we can just play along as we used to and
+     not provide any sensible info */
+  return GETSOCK_BLANK;
+#else
+  /* if we know the direction we can use the generic *_getsock() function even
+     for the protocol_connect and doing states */
+  return ssh_perform_getsock(conn, sock, numsocks);
+#endif
+}
+
+#ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
+/*
+ * When one of the libssh2 functions has returned LIBSSH2_ERROR_EAGAIN this
+ * function is used to figure out in what direction and stores this info so
+ * that the multi interface can take advantage of it. Make sure to call this
+ * function in all cases so that when it _doesn't_ return EAGAIN we can
+ * restore the default wait bits.
+ */
+static void ssh_block2waitfor(struct connectdata *conn, bool block)
+{
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  int dir;
+  if(!block)
+    conn->waitfor = 0;
+  else if((dir = libssh2_session_block_directions(sshc->ssh_session))) {
+    /* translate the libssh2 define bits into our own bit defines */
+    conn->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND)?KEEP_RECV:0) |
+      ((dir&LIBSSH2_SESSION_BLOCK_OUTBOUND)?KEEP_SEND:0);
+  }
+  else
+    /* It didn't block or libssh2 didn't reveal in which direction, put back
+       the original set */
+    conn->waitfor = sshc->orig_waitfor;
+}
+#else
+  /* no libssh2 directional support so we simply don't know */
+#define ssh_block2waitfor(x,y)
+#endif
+
+/* called repeatedly until done from multi.c */
+static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done)
+{
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  CURLcode result = CURLE_OK;
+  bool block; /* we store the status and use that to provide a ssh_getsock()
+                 implementation */
+
+  result = ssh_statemach_act(conn, &block);
+  *done = (bool)(sshc->state == SSH_STOP);
+  ssh_block2waitfor(conn, block);
+
+  return result;
+}
+
+static CURLcode ssh_easy_statemach(struct connectdata *conn)
+{
+  struct ssh_conn *sshc = &conn->proto.sshc;
+  CURLcode result = CURLE_OK;
+
+  while((sshc->state != SSH_STOP) && !result) {
+    bool block;
+    result = ssh_statemach_act(conn, &block);
+
+#ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
+    if((CURLE_OK == result) && block) {
+      int dir = libssh2_session_block_directions(sshc->ssh_session);
+      curl_socket_t sock = conn->sock[FIRSTSOCKET];
+      curl_socket_t fd_read = CURL_SOCKET_BAD;
+      curl_socket_t fd_write = CURL_SOCKET_BAD;
+      if (LIBSSH2_SESSION_BLOCK_INBOUND & dir) {
+        fd_read = sock;
+      }
+      if (LIBSSH2_SESSION_BLOCK_OUTBOUND & dir) {
+        fd_write = sock;
+      }
+      /* wait for the socket to become ready */
+      Curl_socket_ready(fd_read, fd_write, 1000); /* ignore result */
+    }
+#endif
+
+  }
+
+  return result;
+}
+
+/*
+ * SSH setup and connection
+ */
+static CURLcode ssh_init(struct connectdata *conn)
+{
+  struct SessionHandle *data = conn->data;
+  struct SSHPROTO *ssh;
+  struct ssh_conn *sshc = &conn->proto.sshc;
+
+  sshc->actualcode = CURLE_OK; /* reset error code */
+  sshc->secondCreateDirs =0;   /* reset the create dir attempt state
+                                  variable */
+
+  if(data->state.proto.ssh)
+    return CURLE_OK;
+
+  ssh = calloc(1, sizeof(struct SSHPROTO));
+  if(!ssh)
+    return CURLE_OUT_OF_MEMORY;
+
+  data->state.proto.ssh = ssh;
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
+ * do protocol-specific actions at connect-time.
+ */
+static CURLcode ssh_connect(struct connectdata *conn, bool *done)
+{
+#ifdef CURL_LIBSSH2_DEBUG
+  curl_socket_t sock;
+#endif
+  struct ssh_conn *ssh;
+  CURLcode result;
+  struct SessionHandle *data = conn->data;
+
+  /* We default to persistent connections. We set this already in this connect
+     function to make the re-use checks properly be able to check this bit. */
+  conn->bits.close = FALSE;
+
+  /* If there already is a protocol-specific struct allocated for this
+     sessionhandle, deal with it */
+  Curl_reset_reqproto(conn);
+
+  result = ssh_init(conn);
+  if(result)
+    return result;
+
+  ssh = &conn->proto.sshc;
+
+#ifdef CURL_LIBSSH2_DEBUG
+  if(conn->user) {
+    infof(data, "User: %s\n", conn->user);
+  }
+  if(conn->passwd) {
+    infof(data, "Password: %s\n", conn->passwd);
+  }
+  sock = conn->sock[FIRSTSOCKET];
+#endif /* CURL_LIBSSH2_DEBUG */
+
+  ssh->ssh_session = libssh2_session_init_ex(libssh2_malloc, libssh2_free,
+                                             libssh2_realloc, conn);
+  if(ssh->ssh_session == NULL) {
+    failf(data, "Failure initialising ssh session");
+    return CURLE_FAILED_INIT;
+  }
+
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+  if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
+    int rc;
+    ssh->kh = libssh2_knownhost_init(ssh->ssh_session);
+    if(!ssh->kh) {
+      /* eeek. TODO: free the ssh_session! */
+      return CURLE_FAILED_INIT;
+    }
+
+    /* read all known hosts from there */
+    rc = libssh2_knownhost_readfile(ssh->kh,
+                                    data->set.str[STRING_SSH_KNOWNHOSTS],
+                                    LIBSSH2_KNOWNHOST_FILE_OPENSSH);
+    if(rc) {
+      infof(data, "Failed to read known hosts from %s\n",
+            data->set.str[STRING_SSH_KNOWNHOSTS]);
+    }
+  }
+#endif /* HAVE_LIBSSH2_KNOWNHOST_API */
+
+#ifdef CURL_LIBSSH2_DEBUG
+  libssh2_trace(ssh->ssh_session, ~0);
+  infof(data, "SSH socket: %d\n", (int)sock);
+#endif /* CURL_LIBSSH2_DEBUG */
+
+  state(conn, SSH_S_STARTUP);
+
+  if(data->state.used_interface == Curl_if_multi)
+    result = ssh_multi_statemach(conn, done);
+  else {
+    result = ssh_easy_statemach(conn);
+    if(!result)
+      *done = TRUE;
+  }
+
+  return result;
+}
+
+/*
+ ***********************************************************************
+ *
+ * scp_perform()
+ *
+ * This is the actual DO function for SCP. Get a file according to
+ * the options previously setup.
+ */
+
+static
+CURLcode scp_perform(struct connectdata *conn,
+                      bool *connected,
+                      bool *dophase_done)
+{
+  CURLcode result = CURLE_OK;
+
+  DEBUGF(infof(conn->data, "DO phase starts\n"));
+
+  *dophase_done = FALSE; /* not done yet */
+
+  /* start the first command in the DO phase */
+  state(conn, SSH_SCP_TRANS_INIT);
+
+  /* run the state-machine */
+  if(conn->data->state.used_interface == Curl_if_multi) {
+    result = ssh_multi_statemach(conn, dophase_done);
+  }
+  else {
+    result = ssh_easy_statemach(conn);
+    *dophase_done = TRUE; /* with the easy interface we are done here */
+  }
+  *connected = conn->bits.tcpconnect;
+
+  if(*dophase_done) {
+    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+  }
+
+  return result;
+}
+
+/* called from multi.c while DOing */
+static CURLcode scp_doing(struct connectdata *conn,
+                               bool *dophase_done)
+{
+  CURLcode result;
+  result = ssh_multi_statemach(conn, dophase_done);
+
+  if(*dophase_done) {
+    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+  }
+  return result;
+}
+
+/*
+ * The DO function is generic for both protocols. There was previously two
+ * separate ones but this way means less duplicated code.
+ */
+
+static CURLcode ssh_do(struct connectdata *conn, bool *done)
+{
+  CURLcode res;
+  bool connected = 0;
+  struct SessionHandle *data = conn->data;
+
+  *done = FALSE; /* default to false */
+
+  /*
+    Since connections can be re-used between SessionHandles, this might be a
+    connection already existing but on a fresh SessionHandle struct so we must
+    make sure we have a good 'struct SSHPROTO' to play with. For new
+    connections, the struct SSHPROTO is allocated and setup in the
+    ssh_connect() function.
+  */
+  Curl_reset_reqproto(conn);
+  res = ssh_init(conn);
+  if(res)
+    return res;
+
+  data->req.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);
+
+  if(conn->protocol & PROT_SCP)
+    res = scp_perform(conn, &connected,  done);
+  else
+    res = sftp_perform(conn, &connected,  done);
+
+  return res;
+}
+
+/* BLOCKING, but the function is using the state machine so the only reason
+   this is still blocking is that the multi interface code has no support for
+   disconnecting operations that takes a while */
+static CURLcode scp_disconnect(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct ssh_conn *ssh = &conn->proto.sshc;
+
+  Curl_safefree(conn->data->state.proto.ssh);
+  conn->data->state.proto.ssh = NULL;
+
+  if(ssh->ssh_session) {
+    /* only if there's a session still around to use! */
+
+    state(conn, SSH_SESSION_DISCONNECT);
+
+    result = ssh_easy_statemach(conn);
+  }
+
+  return result;
+}
+
+/* generic done function for both SCP and SFTP called from their specific
+   done functions */
+static CURLcode ssh_done(struct connectdata *conn, CURLcode status)
+{
+  CURLcode result = CURLE_OK;
+  struct SSHPROTO *sftp_scp = conn->data->state.proto.ssh;
+
+  if(status == CURLE_OK) {
+    /* run the state-machine
+
+       TODO: when the multi interface is used, this _really_ should be using
+       the ssh_multi_statemach function but we have no general support for
+       non-blocking DONE operations, not in the multi state machine and with
+       Curl_done() invokes on several places in the code!
+    */
+    result = ssh_easy_statemach(conn);
+  }
+  else
+    result = status;
+
+  Curl_safefree(sftp_scp->path);
+  sftp_scp->path = NULL;
+  Curl_pgrsDone(conn);
+
+  conn->data->req.keepon = 0; /* clear all bits */
+  return result;
+}
+
+
+static CURLcode scp_done(struct connectdata *conn, CURLcode status,
+                         bool premature)
+{
+  (void)premature; /* not used */
+
+  if(status == CURLE_OK)
+    state(conn, SSH_SCP_DONE);
+
+  return ssh_done(conn, status);
+
+}
+
+/* return number of received (decrypted) bytes */
+ssize_t Curl_scp_send(struct connectdata *conn, int sockindex,
+                      const void *mem, size_t len)
+{
+  ssize_t nwrite;
+  (void)sockindex; /* we only support SCP on the fixed known primary socket */
+
+  /* libssh2_channel_write() returns int! */
+  nwrite = (ssize_t)
+    libssh2_channel_write(conn->proto.sshc.ssh_channel, mem, len);
+
+  ssh_block2waitfor(conn, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+
+  if(nwrite == LIBSSH2_ERROR_EAGAIN)
+    return 0;
+
+  return nwrite;
+}
+
+/*
+ * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
+ * a regular CURLcode value.
+ */
+ssize_t Curl_scp_recv(struct connectdata *conn, int sockindex,
+                      char *mem, size_t len)
+{
+  ssize_t nread;
+  (void)sockindex; /* we only support SCP on the fixed known primary socket */
+
+  /* libssh2_channel_read() returns int */
+  nread = (ssize_t)
+    libssh2_channel_read(conn->proto.sshc.ssh_channel, mem, len);
+
+  ssh_block2waitfor(conn, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+
+  return nread;
+}
+
+/*
+ * =============== SFTP ===============
+ */
+
+/*
+ ***********************************************************************
+ *
+ * sftp_perform()
+ *
+ * This is the actual DO function for SFTP. Get a file/directory according to
+ * the options previously setup.
+ */
+
+static
+CURLcode sftp_perform(struct connectdata *conn,
+                      bool *connected,
+                      bool *dophase_done)
+{
+  CURLcode result = CURLE_OK;
+
+  DEBUGF(infof(conn->data, "DO phase starts\n"));
+
+  *dophase_done = FALSE; /* not done yet */
+
+  /* start the first command in the DO phase */
+  state(conn, SSH_SFTP_QUOTE_INIT);
+
+  /* run the state-machine */
+  if(conn->data->state.used_interface == Curl_if_multi) {
+    result = ssh_multi_statemach(conn, dophase_done);
+  }
+  else {
+    result = ssh_easy_statemach(conn);
+    *dophase_done = TRUE; /* with the easy interface we are done here */
+  }
+  *connected = conn->bits.tcpconnect;
+
+  if(*dophase_done) {
+    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+  }
+
+  return result;
+}
+
+/* called from multi.c while DOing */
+static CURLcode sftp_doing(struct connectdata *conn,
+                           bool *dophase_done)
+{
+  CURLcode result;
+  result = ssh_multi_statemach(conn, dophase_done);
+
+  if(*dophase_done) {
+    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+  }
+  return result;
+}
+
+/* BLOCKING, but the function is using the state machine so the only reason
+   this is still blocking is that the multi interface code has no support for
+   disconnecting operations that takes a while */
+static CURLcode sftp_disconnect(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+
+  DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n"));
+
+  Curl_safefree(conn->data->state.proto.ssh);
+  conn->data->state.proto.ssh = NULL;
+
+  if(conn->proto.sshc.ssh_session) {
+    /* only if there's a session still around to use! */
+    state(conn, SSH_SFTP_SHUTDOWN);
+    result = ssh_easy_statemach(conn);
+  }
+
+  DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n"));
+
+  return result;
+
+}
+
+static CURLcode sftp_done(struct connectdata *conn, CURLcode status,
+                               bool premature)
+{
+  struct ssh_conn *sshc = &conn->proto.sshc;
+
+  if(status == CURLE_OK) {
+    /* Before we shut down, see if there are any post-quote commands to
+       send: */
+    if(!status && !premature && conn->data->set.postquote) {
+      sshc->nextstate = SSH_SFTP_CLOSE;
+      state(conn, SSH_SFTP_POSTQUOTE_INIT);
+    }
+    else
+      state(conn, SSH_SFTP_CLOSE);
+  }
+  return ssh_done(conn, status);
+}
+
+/* return number of sent bytes */
+ssize_t Curl_sftp_send(struct connectdata *conn, int sockindex,
+                       const void *mem, size_t len)
+{
+  ssize_t nwrite;   /* libssh2_sftp_write() used to return size_t in 0.14
+                       but is changed to ssize_t in 0.15. These days we don't
+                       support libssh2 0.15*/
+  (void)sockindex;
+
+  nwrite = libssh2_sftp_write(conn->proto.sshc.sftp_handle, mem, len);
+
+  ssh_block2waitfor(conn, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+
+  if(nwrite == LIBSSH2_ERROR_EAGAIN)
+    return 0;
+
+  return nwrite;
+}
+
+/*
+ * Return number of received (decrypted) bytes
+ */
+ssize_t Curl_sftp_recv(struct connectdata *conn, int sockindex,
+                       char *mem, size_t len)
+{
+  ssize_t nread;
+  (void)sockindex;
+
+  nread = libssh2_sftp_read(conn->proto.sshc.sftp_handle, mem, len);
+
+  ssh_block2waitfor(conn, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+
+  return nread;
+}
+
+/* The get_pathname() function is being borrowed from OpenSSH sftp.c
+   version 4.6p1. */
+/*
+ * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
+ *
+ * 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 THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
+ */
+static CURLcode
+get_pathname(const char **cpp, char **path)
+{
+  const char *cp = *cpp, *end;
+  char quot;
+  unsigned int i, j;
+  static const char WHITESPACE[] = " \t\r\n";
+
+  cp += strspn(cp, WHITESPACE);
+  if(!*cp) {
+    *cpp = cp;
+    *path = NULL;
+    return CURLE_QUOTE_ERROR;
+  }
+
+  *path = malloc(strlen(cp) + 1);
+  if(*path == NULL)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Check for quoted filenames */
+  if(*cp == '\"' || *cp == '\'') {
+    quot = *cp++;
+
+    /* Search for terminating quote, unescape some chars */
+    for (i = j = 0; i <= strlen(cp); i++) {
+      if(cp[i] == quot) {  /* Found quote */
+        i++;
+        (*path)[j] = '\0';
+        break;
+      }
+      if(cp[i] == '\0') {  /* End of string */
+        /*error("Unterminated quote");*/
+        goto fail;
+      }
+      if(cp[i] == '\\') {  /* Escaped characters */
+        i++;
+        if(cp[i] != '\'' && cp[i] != '\"' &&
+            cp[i] != '\\') {
+          /*error("Bad escaped character '\\%c'",
+              cp[i]);*/
+          goto fail;
+        }
+      }
+      (*path)[j++] = cp[i];
+    }
+
+    if(j == 0) {
+      /*error("Empty quotes");*/
+      goto fail;
+    }
+    *cpp = cp + i + strspn(cp + i, WHITESPACE);
+  }
+  else {
+    /* Read to end of filename */
+    end = strpbrk(cp, WHITESPACE);
+    if(end == NULL)
+      end = strchr(cp, '\0');
+    *cpp = end + strspn(end, WHITESPACE);
+
+    memcpy(*path, cp, end - cp);
+    (*path)[end - cp] = '\0';
+  }
+  return CURLE_OK;
+
+  fail:
+    Curl_safefree(*path);
+    *path = NULL;
+    return CURLE_QUOTE_ERROR;
+}
+
+
+static const char *sftp_libssh2_strerror(unsigned long err)
+{
+  switch (err) {
+    case LIBSSH2_FX_NO_SUCH_FILE:
+      return "No such file or directory";
+
+    case LIBSSH2_FX_PERMISSION_DENIED:
+      return "Permission denied";
+
+    case LIBSSH2_FX_FAILURE:
+      return "Operation failed";
+
+    case LIBSSH2_FX_BAD_MESSAGE:
+      return "Bad message from SFTP server";
+
+    case LIBSSH2_FX_NO_CONNECTION:
+      return "Not connected to SFTP server";
+
+    case LIBSSH2_FX_CONNECTION_LOST:
+      return "Connection to SFTP server lost";
+
+    case LIBSSH2_FX_OP_UNSUPPORTED:
+      return "Operation not supported by SFTP server";
+
+    case LIBSSH2_FX_INVALID_HANDLE:
+      return "Invalid handle";
+
+    case LIBSSH2_FX_NO_SUCH_PATH:
+      return "No such file or directory";
+
+    case LIBSSH2_FX_FILE_ALREADY_EXISTS:
+      return "File already exists";
+
+    case LIBSSH2_FX_WRITE_PROTECT:
+      return "File is write protected";
+
+    case LIBSSH2_FX_NO_MEDIA:
+      return "No media";
+
+    case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM:
+      return "Disk full";
+
+    case LIBSSH2_FX_QUOTA_EXCEEDED:
+      return "User quota exceeded";
+
+    case LIBSSH2_FX_UNKNOWN_PRINCIPLE:
+      return "Unknown principle";
+
+    case LIBSSH2_FX_LOCK_CONFlICT:
+      return "File lock conflict";
+
+    case LIBSSH2_FX_DIR_NOT_EMPTY:
+      return "Directory not empty";
+
+    case LIBSSH2_FX_NOT_A_DIRECTORY:
+      return "Not a directory";
+
+    case LIBSSH2_FX_INVALID_FILENAME:
+      return "Invalid filename";
+
+    case LIBSSH2_FX_LINK_LOOP:
+      return "Link points to itself";
+  }
+  return "Unknown error in libssh2";
+}
+
+#endif /* USE_LIBSSH2 */
diff --git a/lib/ssh.h b/lib/ssh.h
new file mode 100644
index 0000000..4e268c2
--- /dev/null
+++ b/lib/ssh.h
@@ -0,0 +1,187 @@
+#ifndef HEADER_CURL_SSH_H
+#define HEADER_CURL_SSH_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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"
+
+#ifdef HAVE_LIBSSH2_H
+#include <libssh2.h>
+#include <libssh2_sftp.h>
+#endif /* HAVE_LIBSSH2_H */
+
+/****************************************************************************
+ * SSH unique setup
+ ***************************************************************************/
+typedef enum {
+  SSH_NO_STATE = -1,  /* Used for "nextState" so say there is none */
+  SSH_STOP = 0,       /* do nothing state, stops the state machine */
+
+  SSH_S_STARTUP,      /* Session startup, First state in SSH-CONNECT */
+  SSH_HOSTKEY,        /* verify hostkey */
+  SSH_AUTHLIST,
+  SSH_AUTH_PKEY_INIT,
+  SSH_AUTH_PKEY,
+  SSH_AUTH_PASS_INIT,
+  SSH_AUTH_PASS,
+  SSH_AUTH_HOST_INIT,
+  SSH_AUTH_HOST,
+  SSH_AUTH_KEY_INIT,
+  SSH_AUTH_KEY,
+  SSH_AUTH_DONE,
+  SSH_SFTP_INIT,
+  SSH_SFTP_REALPATH,   /* Last state in SSH-CONNECT */
+
+  SSH_SFTP_QUOTE_INIT, /* First state in SFTP-DO */
+  SSH_SFTP_POSTQUOTE_INIT, /* (Possibly) First state in SFTP-DONE */
+  SSH_SFTP_QUOTE,
+  SSH_SFTP_NEXT_QUOTE,
+  SSH_SFTP_QUOTE_STAT,
+  SSH_SFTP_QUOTE_SETSTAT,
+  SSH_SFTP_QUOTE_SYMLINK,
+  SSH_SFTP_QUOTE_MKDIR,
+  SSH_SFTP_QUOTE_RENAME,
+  SSH_SFTP_QUOTE_RMDIR,
+  SSH_SFTP_QUOTE_UNLINK,
+  SSH_SFTP_TRANS_INIT,
+  SSH_SFTP_UPLOAD_INIT,
+  SSH_SFTP_CREATE_DIRS_INIT,
+  SSH_SFTP_CREATE_DIRS,
+  SSH_SFTP_CREATE_DIRS_MKDIR,
+  SSH_SFTP_READDIR_INIT,
+  SSH_SFTP_READDIR,
+  SSH_SFTP_READDIR_LINK,
+  SSH_SFTP_READDIR_BOTTOM,
+  SSH_SFTP_READDIR_DONE,
+  SSH_SFTP_DOWNLOAD_INIT,
+  SSH_SFTP_DOWNLOAD_STAT, /* Last state in SFTP-DO */
+  SSH_SFTP_CLOSE,    /* Last state in SFTP-DONE */
+  SSH_SFTP_SHUTDOWN, /* First state in SFTP-DISCONNECT */
+  SSH_SCP_TRANS_INIT, /* First state in SCP-DO */
+  SSH_SCP_UPLOAD_INIT,
+  SSH_SCP_DOWNLOAD_INIT,
+  SSH_SCP_DONE,
+  SSH_SCP_SEND_EOF,
+  SSH_SCP_WAIT_EOF,
+  SSH_SCP_WAIT_CLOSE,
+  SSH_SCP_CHANNEL_FREE,   /* Last state in SCP-DONE */
+  SSH_SESSION_DISCONNECT, /* First state in SCP-DISCONNECT */
+  SSH_SESSION_FREE,       /* Last state in SCP/SFTP-DISCONNECT */
+  SSH_QUIT,
+  SSH_LAST  /* never used */
+} sshstate;
+
+/* this struct is used in the HandleData struct which is part of the
+   SessionHandle, which means this is used on a per-easy handle basis.
+   Everything that is strictly related to a connection is banned from this
+   struct. */
+struct SSHPROTO {
+  char *path;                  /* the path we operate on */
+};
+
+/* ssh_conn is used for struct connection-oriented data in the connectdata
+   struct */
+struct ssh_conn {
+  const char *authlist;       /* List of auth. methods, managed by libssh2 */
+#ifdef USE_LIBSSH2
+  const char *passphrase;     /* pass-phrase to use */
+  char *rsa_pub;              /* path name */
+  char *rsa;                  /* path name */
+  bool authed;                /* the connection has been authenticated fine */
+  sshstate state;             /* always use ssh.c:state() to change state! */
+  sshstate nextstate;         /* the state to goto after stopping */
+  CURLcode actualcode;        /* the actual error code */
+  struct curl_slist *quote_item; /* for the quote option */
+  char *quote_path1;          /* two generic pointers for the QUOTE stuff */
+  char *quote_path2;
+  LIBSSH2_SFTP_ATTRIBUTES quote_attrs; /* used by the SFTP_QUOTE state */
+  char *homedir;              /* when doing SFTP we figure out home dir in the
+                                 connect phase */
+
+  /* Here's a set of struct members used by the SFTP_READDIR state */
+  LIBSSH2_SFTP_ATTRIBUTES readdir_attrs;
+  char *readdir_filename;
+  char *readdir_longentry;
+  int readdir_len, readdir_totalLen, readdir_currLen;
+  char *readdir_line;
+  char *readdir_linkPath;
+  /* end of READDIR stuff */
+
+  int secondCreateDirs;         /* counter use by the code to see if the
+                                   second attempt has been made to change
+                                   to/create a directory */
+  char *slash_pos;              /* used by the SFTP_CREATE_DIRS state */
+  LIBSSH2_SESSION *ssh_session; /* Secure Shell session */
+  LIBSSH2_CHANNEL *ssh_channel; /* Secure Shell channel handle */
+  LIBSSH2_SFTP *sftp_session;   /* SFTP handle */
+  LIBSSH2_SFTP_HANDLE *sftp_handle;
+  int orig_waitfor;             /* default READ/WRITE bits wait for */
+
+  /* note that HAVE_LIBSSH2_KNOWNHOST_API is a define set in the libssh2.h
+     header */
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+  LIBSSH2_KNOWNHOSTS *kh;
+#endif
+#endif /* USE_LIBSSH2 */
+};
+
+#ifdef USE_LIBSSH2
+
+#if !defined(LIBSSH2_VERSION_NUM) || (LIBSSH2_VERSION_NUM < 0x001000)
+#  error "SCP/SFTP protocols require libssh2 0.16 or later"
+#endif
+
+#if defined(LIBSSH2_VERSION_NUM) && (LIBSSH2_VERSION_NUM >= 0x010000)
+/* libssh2_sftp_seek64() has only ever been provided by libssh2 1.0 or
+   later */
+#  define HAVE_LIBSSH2_SFTP_SEEK64 1
+#else
+#  undef HAVE_LIBSSH2_SFTP_SEEK64
+#endif
+
+
+extern const struct Curl_handler Curl_handler_scp;
+extern const struct Curl_handler Curl_handler_sftp;
+
+ssize_t Curl_scp_send(struct connectdata *conn, int sockindex,
+                      const void *mem, size_t len);
+ssize_t Curl_scp_recv(struct connectdata *conn, int sockindex,
+                      char *mem, size_t len);
+
+ssize_t Curl_sftp_send(struct connectdata *conn, int sockindex,
+                       const void *mem, size_t len);
+ssize_t Curl_sftp_recv(struct connectdata *conn, int sockindex,
+                       char *mem, size_t len);
+
+#define Curl_ssh_enabled(conn,prot) (conn->protocol & prot)
+
+#else /* USE_LIBSSH2 */
+
+#define Curl_ssh_enabled(x,y) 0
+#define Curl_scp_send(a,b,c,d) 0
+#define Curl_sftp_send(a,b,c,d) 0
+#define Curl_scp_recv(a,b,c,d) 0
+#define Curl_sftp_recv(a,b,c,d) 0
+
+#endif /* USE_LIBSSH2 */
+
+#endif /* HEADER_CURL_SSH_H */
diff --git a/lib/sslgen.c b/lib/sslgen.c
new file mode 100644
index 0000000..df2a407
--- /dev/null
+++ b/lib/sslgen.c
@@ -0,0 +1,489 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+/* This file is for implementing all "generic" SSL functions that all libcurl
+   internals should use. It is then responsible for calling the proper
+   "backend" function.
+
+   SSL-functions in libcurl should call functions in this source file, and not
+   to any specific SSL-layer.
+
+   Curl_ssl_ - prefix for generic ones
+   Curl_ossl_ - prefix for OpenSSL ones
+   Curl_gtls_ - prefix for GnuTLS ones
+   Curl_nss_ - prefix for NSS ones
+
+   Note that this source code uses curlssl_* functions, and they are all
+   defines/macros #defined by the lib-specific header files.
+
+   "SSL/TLS Strong Encryption: An Introduction"
+   http://httpd.apache.org/docs-2.0/ssl/ssl_intro.html
+*/
+
+#include "setup.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#include "urldata.h"
+#define SSLGEN_C
+#include "sslgen.h" /* generic SSL protos etc */
+#include "ssluse.h" /* OpenSSL versions */
+#include "gtls.h"   /* GnuTLS versions */
+#include "nssg.h"   /* NSS versions */
+#include "qssl.h"   /* QSOSSL versions */
+#include "sendf.h"
+#include "rawstr.h"
+#include "url.h"
+#include "curl_memory.h"
+#include "progress.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+static bool safe_strequal(char* str1, char* str2)
+{
+  if(str1 && str2)
+    /* both pointers point to something then compare them */
+    return (bool)(0 != Curl_raw_equal(str1, str2));
+  else
+    /* if both pointers are NULL then treat them as equal */
+    return (bool)(!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->sessionid = source->sessionid;
+  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;
+  }
+  else
+    dest->CAfile = NULL;
+
+  if(source->CApath) {
+    dest->CApath = strdup(source->CApath);
+    if(!dest->CApath)
+      return FALSE;
+  }
+  else
+    dest->CApath = NULL;
+
+  if(source->cipher_list) {
+    dest->cipher_list = strdup(source->cipher_list);
+    if(!dest->cipher_list)
+      return FALSE;
+  }
+  else
+    dest->cipher_list = NULL;
+
+  if(source->egdsocket) {
+    dest->egdsocket = strdup(source->egdsocket);
+    if(!dest->egdsocket)
+      return FALSE;
+  }
+  else
+    dest->egdsocket = NULL;
+
+  if(source->random_file) {
+    dest->random_file = strdup(source->random_file);
+    if(!dest->random_file)
+      return FALSE;
+  }
+  else
+    dest->random_file = NULL;
+
+  return TRUE;
+}
+
+void Curl_free_ssl_config(struct ssl_config_data* sslc)
+{
+  Curl_safefree(sslc->CAfile);
+  Curl_safefree(sslc->CApath);
+  Curl_safefree(sslc->cipher_list);
+  Curl_safefree(sslc->egdsocket);
+  Curl_safefree(sslc->random_file);
+}
+
+#ifdef USE_SSL
+
+/* "global" init done? */
+static bool init_ssl=FALSE;
+
+/**
+ * Global SSL init
+ *
+ * @retval 0 error initializing SSL
+ * @retval 1 SSL initialized successfully
+ */
+int Curl_ssl_init(void)
+{
+  /* make sure this is only done once */
+  if(init_ssl)
+    return 1;
+  init_ssl = TRUE; /* never again */
+
+  return curlssl_init();
+}
+
+
+/* Global cleanup */
+void Curl_ssl_cleanup(void)
+{
+  if(init_ssl) {
+    /* only cleanup if we did a previous init */
+    curlssl_cleanup();
+    init_ssl = FALSE;
+  }
+}
+
+CURLcode
+Curl_ssl_connect(struct connectdata *conn, int sockindex)
+{
+  CURLcode res;
+  /* mark this is being ssl-enabled from here on. */
+  conn->ssl[sockindex].use = TRUE;
+  conn->ssl[sockindex].state = ssl_connection_negotiating;
+
+  res = curlssl_connect(conn, sockindex);
+
+  if(!res)
+    Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
+
+  return res;
+}
+
+CURLcode
+Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex,
+                             bool *done)
+{
+#ifdef curlssl_connect_nonblocking
+  CURLcode res;
+  /* mark this is being ssl requested from here on. */
+  conn->ssl[sockindex].use = TRUE;
+  res = curlssl_connect_nonblocking(conn, sockindex, done);
+  if(!res && *done == TRUE)
+    Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
+  return res;
+#else
+  *done = TRUE; /* fallback to BLOCKING */
+  conn->ssl[sockindex].use = TRUE;
+  return curlssl_connect(conn, sockindex);
+#endif /* non-blocking connect support */
+}
+
+/*
+ * Check if there's a session ID for the given connection in the cache, and if
+ * there's one suitable, it is provided. Returns TRUE when no entry matched.
+ */
+int Curl_ssl_getsessionid(struct connectdata *conn,
+                          void **ssl_sessionid,
+                          size_t *idsize) /* set 0 if unknown */
+{
+  struct curl_ssl_session *check;
+  struct SessionHandle *data = conn->data;
+  long i;
+
+  if(!conn->ssl_config.sessionid)
+    /* session ID re-use is disabled */
+    return TRUE;
+
+  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_raw_equal(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;
+      if(idsize)
+        *idsize = check->idsize;
+      return FALSE;
+    }
+  }
+  *ssl_sessionid = NULL;
+  return TRUE;
+}
+
+/*
+ * Kill a single session ID entry in the cache.
+ */
+static int kill_session(struct curl_ssl_session *session)
+{
+  if(session->sessionid) {
+    /* defensive check */
+
+    /* free the ID the SSL-layer specific way */
+    curlssl_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;
+}
+
+/*
+ * Delete the given session ID from the cache.
+ */
+void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid)
+{
+  int i;
+  for(i=0; i< conn->data->set.ssl.numsessions; i++) {
+    struct curl_ssl_session *check = &conn->data->state.session[i];
+
+    if (check->sessionid == ssl_sessionid) {
+      kill_session(check);
+      break;
+    }
+  }
+}
+
+/*
+ * Store session id in the session cache. The ID passed on to this function
+ * must already have been extracted and allocated the proper way for the SSL
+ * layer. Curl_XXXX_session_free() will be called to free/kill the session ID
+ * later on.
+ */
+CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
+                               void *ssl_sessionid,
+                               size_t idsize)
+{
+  long 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;
+
+  /* Even though session ID re-use might be disabled, that only disables USING
+     IT. We still store it here in case the re-using is again enabled for an
+     upcoming transfer */
+
+  clone_host = strdup(conn->host.name);
+  if(!clone_host)
+    return CURLE_OUT_OF_MEMORY; /* bail out */
+
+  /* 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_session(store);
+  else
+    store = &data->state.session[i]; /* use this slot */
+
+  /* now init the session struct wisely */
+  store->sessionid = ssl_sessionid;
+  store->idsize = idsize;
+  store->age = data->state.sessionage;    /* set current age */
+  if (store->name)
+    /* free it if there's one already present */
+    free(store->name);
+  store->name = clone_host;               /* clone host name */
+  store->remote_port = conn->remote_port; /* port number */
+
+  if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config))
+    return CURLE_OUT_OF_MEMORY;
+
+  return CURLE_OK;
+}
+
+
+void Curl_ssl_close_all(struct SessionHandle *data)
+{
+  long i;
+  /* kill the session ID cache */
+  if(data->state.session) {
+    for(i=0; i< data->set.ssl.numsessions; i++)
+      /* the single-killer function handles empty table slots */
+      kill_session(&data->state.session[i]);
+
+    /* free the cache data */
+    free(data->state.session);
+    data->state.session = NULL;
+  }
+
+  curlssl_close_all(data);
+}
+
+void Curl_ssl_close(struct connectdata *conn, int sockindex)
+{
+  DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
+  curlssl_close(conn, sockindex);
+}
+
+CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex)
+{
+  if(curlssl_shutdown(conn, sockindex))
+    return CURLE_SSL_SHUTDOWN_FAILED;
+
+  conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */
+  conn->ssl[sockindex].state = ssl_connection_none;
+
+  return CURLE_OK;
+}
+
+/* Selects an SSL crypto engine
+ */
+CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine)
+{
+  return curlssl_set_engine(data, engine);
+}
+
+/* Selects the default SSL crypto engine
+ */
+CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data)
+{
+  return curlssl_set_engine_default(data);
+}
+
+/* Return list of OpenSSL crypto engine names. */
+struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data)
+{
+  return curlssl_engines_list(data);
+}
+
+ssize_t Curl_ssl_send(struct connectdata *conn,
+                      int sockindex,
+                      const void *mem,
+                      size_t len,
+                      int *curlcode)
+{
+  return curlssl_send(conn, sockindex, mem, len, curlcode);
+}
+
+ssize_t Curl_ssl_recv(struct connectdata *conn,
+                      int sockindex,
+                      char *mem,
+                      size_t len,
+                      int *curlcode)
+{
+  return curlssl_recv(conn, sockindex, mem, len, curlcode);
+}
+
+
+/*
+ * This sets up a session ID cache to the specified size. Make sure this code
+ * is agnostic to what underlying SSL technology we use.
+ */
+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 = calloc(amount, sizeof(struct curl_ssl_session));
+  if(!session)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* 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;
+}
+
+size_t Curl_ssl_version(char *buffer, size_t size)
+{
+  return curlssl_version(buffer, size);
+}
+
+/*
+ * This function tries to determine connection status.
+ *
+ * Return codes:
+ *     1 means the connection is still in place
+ *     0 means the connection has been closed
+ *    -1 means the connection status is unknown
+ */
+int Curl_ssl_check_cxn(struct connectdata *conn)
+{
+  return curlssl_check_cxn(conn);
+}
+
+bool Curl_ssl_data_pending(const struct connectdata *conn,
+                           int connindex)
+{
+  return curlssl_data_pending(conn, connindex);
+}
+
+void Curl_ssl_free_certinfo(struct SessionHandle *data)
+{
+  int i;
+  struct curl_certinfo *ci = &data->info.certs;
+  if(ci->num_of_certs) {
+    /* free all individual lists used */
+    for(i=0; i<ci->num_of_certs; i++)
+      curl_slist_free_all(ci->certinfo[i]);
+    free(ci->certinfo); /* free the actual array too */
+    ci->num_of_certs = 0;
+  }
+}
+#endif /* USE_SSL */
diff --git a/lib/sslgen.h b/lib/sslgen.h
new file mode 100644
index 0000000..c56265e
--- /dev/null
+++ b/lib/sslgen.h
@@ -0,0 +1,114 @@
+#ifndef __SSLGEN_H
+#define __SSLGEN_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2008, 2010, 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.
+ *
+ ***************************************************************************/
+
+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);
+
+#ifdef USE_SSL
+int Curl_ssl_init(void);
+void Curl_ssl_cleanup(void);
+CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex);
+CURLcode Curl_ssl_connect_nonblocking(struct connectdata *conn,
+                                      int sockindex,
+                                      bool *done);
+/* tell the SSL stuff to close down all open information regarding
+   connections (and thus session ID caching etc) */
+void Curl_ssl_close_all(struct SessionHandle *data);
+void Curl_ssl_close(struct connectdata *conn, int sockindex);
+CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex);
+CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine);
+/* Sets engine as default for all SSL operations */
+CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data);
+struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data);
+
+/* If the write would block (EWOULDBLOCK) or fail, we we return -1.
+ * The error or -1 (for EWOULDBLOCK) is then stored in *curlcode.
+ * Otherwise we return the count of (non-SSL) bytes transfered.
+ */
+ssize_t Curl_ssl_send(struct connectdata *conn, /* connection data */
+                      int sockindex,            /* socketindex */
+                      const void *mem,          /* data to write */
+                      size_t len,               /* max amount to write */
+                      int *curlcode);           /* error to return,
+                                                   -1 means EWOULDBLOCK */
+
+/* If the read would block (EWOULDBLOCK) or fail, we we return -1.
+ * The error or -1 (for EWOULDBLOCK) is then stored in *curlcode.
+ * Otherwise we return the count of (non-SSL) bytes transfered.
+ */
+ssize_t Curl_ssl_recv(struct connectdata *conn, /* connection data */
+                      int sockindex,            /* socketindex */
+                      char *mem,                /* store read data here */
+                      size_t len,               /* max amount to read */
+                      int *curlcode);           /* error to return,
+                                                   -1 means EWOULDBLOCK */
+
+/* init the SSL session ID cache */
+CURLcode Curl_ssl_initsessions(struct SessionHandle *, long);
+size_t Curl_ssl_version(char *buffer, size_t size);
+bool Curl_ssl_data_pending(const struct connectdata *conn,
+                           int connindex);
+int Curl_ssl_check_cxn(struct connectdata *conn);
+void Curl_ssl_free_certinfo(struct SessionHandle *data);
+
+/* Functions to be used by SSL library adaptation functions */
+
+/* extract a session ID */
+int Curl_ssl_getsessionid(struct connectdata *conn,
+                          void **ssl_sessionid,
+                          size_t *idsize) /* set 0 if unknown */;
+/* add a new session ID */
+CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
+                               void *ssl_sessionid,
+                               size_t idsize);
+/* delete a session from the cache */
+void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid);
+
+#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */
+
+#else
+/* When SSL support is not present, just define away these function calls */
+#define Curl_ssl_init() 1
+#define Curl_ssl_cleanup() do { } while (0)
+#define Curl_ssl_connect(x,y) CURLE_FAILED_INIT
+#define Curl_ssl_close_all(x)
+#define Curl_ssl_close(x,y)
+#define Curl_ssl_shutdown(x,y) CURLE_FAILED_INIT
+#define Curl_ssl_set_engine(x,y) CURLE_FAILED_INIT
+#define Curl_ssl_set_engine_default(x) CURLE_FAILED_INIT
+#define Curl_ssl_engines_list(x) NULL
+#define Curl_ssl_send(a,b,c,d,e) -1
+#define Curl_ssl_recv(a,b,c,d,e) -1
+#define Curl_ssl_initsessions(x,y) CURLE_OK
+#define Curl_ssl_version(x,y) 0
+#define Curl_ssl_data_pending(x,y) 0
+#define Curl_ssl_check_cxn(x) 0
+#define Curl_ssl_free_certinfo(x)
+
+#endif
+
+#endif /* USE_SSL */
diff --git a/lib/ssluse.c b/lib/ssluse.c
new file mode 100644
index 0000000..d9cf382
--- /dev/null
+++ b/lib/ssluse.c
@@ -0,0 +1,2639 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all OpenSSL-specific code for the TLS/SSL layer. No code
+ * but sslgen.c should ever call or use these functions.
+ */
+
+/*
+ * The original SSLeay-using code for curl was written by Linas Vepstas and
+ * Sampo Kellomaki 1998.
+ */
+
+#include "setup.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.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"
+#include "strequal.h"
+#include "select.h"
+#include "sslgen.h"
+#include "rawstr.h"
+
+#define _MPRINTF_REPLACE /* use the internal *printf() functions */
+#include <curl/mprintf.h>
+
+#ifdef USE_SSLEAY
+
+#ifdef USE_OPENSSL
+#include <openssl/rand.h>
+#include <openssl/x509v3.h>
+#include <openssl/dsa.h>
+#include <openssl/dh.h>
+#else
+#include <rand.h>
+#include <x509v3.h>
+#endif
+
+#include "curl_memory.h"
+#include "easyif.h" /* for Curl_convert_from_utf8 prototype */
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#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
+#include <openssl/ui.h>
+#else
+/* ENGINE_load_private_key() takes three arguments */
+#undef HAVE_ENGINE_LOAD_FOUR_ARGS
+#endif
+
+#if (OPENSSL_VERSION_NUMBER >= 0x00903001L) && defined(HAVE_OPENSSL_PKCS12_H)
+/* OpenSSL has PKCS 12 support */
+#define HAVE_PKCS12_SUPPORT
+#else
+/* OpenSSL/SSLEay does not have PKCS12 support */
+#undef HAVE_PKCS12_SUPPORT
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x00906001L
+#define HAVE_ERR_ERROR_STRING_N 1
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x00909000L
+#define SSL_METHOD_QUAL const
+#else
+#define SSL_METHOD_QUAL
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x00907000L
+/* 0.9.6 didn't have X509_STORE_set_flags() */
+#define HAVE_X509_STORE_SET_FLAGS 1
+#else
+#define X509_STORE_set_flags(x,y)
+#endif
+
+/*
+ * Number of bytes to read from the random number seed file. This must be
+ * a finite value (because some entropy "files" like /dev/urandom have
+ * an infinite length), but must be large enough to provide enough
+ * entopy to properly seed OpenSSL's PRNG.
+ */
+#define RAND_LOAD_LENGTH 1024
+
+#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
+static char global_passwd[64];
+#endif
+
+static int passwd_callback(char *buf, int num, int verify
+#ifdef 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 (bool)(0 != RAND_status());
+}
+#else
+#define seed_enough(x) rand_enough(x)
+static bool rand_enough(int nread)
+{
+  /* this is a very silly decision to make */
+  return (bool)(nread > 500);
+}
+#endif
+
+static int ossl_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.str[STRING_SSL_RANDOM_FILE]?
+                             data->set.str[STRING_SSL_RANDOM_FILE]:
+                             RANDOM_FILE),
+                            RAND_LOAD_LENGTH);
+    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.str[STRING_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.str[STRING_SSL_EGDSOCKET]?
+                       data->set.str[STRING_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
+  /* if RAND_screen() is present, it was called during global init */
+  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, RAND_LOAD_LENGTH);
+    if(seed_enough(nread))
+      return nread;
+  }
+
+  infof(data, "libcurl is now using a weak random seed!\n");
+  return nread;
+}
+
+int Curl_ossl_seed(struct SessionHandle *data)
+{
+  /* we have the "SSL is seeded" boolean static to prevent multiple
+     time-consuming seedings in vain */
+  static bool ssl_seeded = FALSE;
+
+  if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
+     data->set.str[STRING_SSL_EGDSOCKET]) {
+    ossl_seed(data);
+    ssl_seeded = TRUE;
+  }
+  return 0;
+}
+
+
+#ifndef SSL_FILETYPE_ENGINE
+#define SSL_FILETYPE_ENGINE 42
+#endif
+#ifndef SSL_FILETYPE_PKCS12
+#define SSL_FILETYPE_PKCS12 43
+#endif
+static int do_file_type(const char *type)
+{
+  if(!type || !type[0])
+    return SSL_FILETYPE_PEM;
+  if(Curl_raw_equal(type, "PEM"))
+    return SSL_FILETYPE_PEM;
+  if(Curl_raw_equal(type, "DER"))
+    return SSL_FILETYPE_ASN1;
+  if(Curl_raw_equal(type, "ENG"))
+    return SSL_FILETYPE_ENGINE;
+  if(Curl_raw_equal(type, "P12"))
+    return SSL_FILETYPE_PKCS12;
+  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 = do_file_type(cert_type);
+
+  if(cert_file != NULL || file_type == SSL_FILETYPE_ENGINE) {
+    SSL *ssl;
+    X509 *x509;
+    int cert_done = 0;
+
+    if(data->set.str[STRING_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.str[STRING_KEY_PASSWD]);
+#endif
+      /* Set passwd callback: */
+      SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
+    }
+
+
+#define SSL_CLIENT_CERT_ERR \
+    "unable to use client certificate (no key found or wrong pass phrase?)"
+
+    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, SSL_CLIENT_CERT_ERR);
+        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, SSL_CLIENT_CERT_ERR);
+        return 0;
+      }
+      break;
+    case SSL_FILETYPE_ENGINE:
+#if defined(HAVE_OPENSSL_ENGINE_H) && defined(ENGINE_CTRL_GET_CMD_FROM_NAME)
+      {
+        if(data->state.engine) {
+          const char *cmd_name = "LOAD_CERT_CTRL";
+          struct {
+            const char *cert_id;
+            X509 *cert;
+          } params;
+
+          params.cert_id = cert_file;
+          params.cert = NULL;
+
+          /* Does the engine supports LOAD_CERT_CTRL ? */
+          if (!ENGINE_ctrl(data->state.engine, ENGINE_CTRL_GET_CMD_FROM_NAME,
+                           0, (void *)cmd_name, NULL)) {
+            failf(data, "ssl engine does not support loading certificates");
+            return 0;
+          }
+
+          /* Load the certificate from the engine */
+          if (!ENGINE_ctrl_cmd(data->state.engine, cmd_name,
+                               0, &params, NULL, 1)) {
+            failf(data, "ssl engine cannot load client cert with id"
+                  " '%s' [%s]", cert_file,
+                  ERR_error_string(ERR_get_error(), NULL));
+            return 0;
+          }
+
+          if (!params.cert) {
+            failf(data, "ssl engine didn't initialized the certificate "
+                  "properly.");
+            return 0;
+          }
+
+          if(SSL_CTX_use_certificate(ctx, params.cert) != 1) {
+            failf(data, "unable to set client certificate");
+            X509_free(params.cert);
+            return 0;
+          }
+          X509_free(params.cert); /* we don't need the handle any more... */
+        }
+        else {
+          failf(data, "crypto engine not set, can't load certificate");
+          return 0;
+        }
+      }
+      break;
+#else
+      failf(data, "file type ENG for certificate not implemented");
+      return 0;
+#endif
+
+    case SSL_FILETYPE_PKCS12:
+    {
+#ifdef HAVE_PKCS12_SUPPORT
+      FILE *f;
+      PKCS12 *p12;
+      EVP_PKEY *pri;
+      STACK_OF(X509) *ca = NULL;
+      int i;
+
+      f = fopen(cert_file,"rb");
+      if(!f) {
+        failf(data, "could not open PKCS12 file '%s'", cert_file);
+        return 0;
+      }
+      p12 = d2i_PKCS12_fp(f, NULL);
+      fclose(f);
+
+      if(!p12) {
+        failf(data, "error reading PKCS12 file '%s'", cert_file );
+        return 0;
+      }
+
+      PKCS12_PBE_add();
+
+      if(!PKCS12_parse(p12, data->set.str[STRING_KEY_PASSWD], &pri, &x509,
+                        &ca)) {
+        failf(data,
+              "could not parse PKCS12 file, check password, OpenSSL error %s",
+              ERR_error_string(ERR_get_error(), NULL) );
+        PKCS12_free(p12);
+        return 0;
+      }
+
+      PKCS12_free(p12);
+
+      if(SSL_CTX_use_certificate(ctx, x509) != 1) {
+        failf(data, SSL_CLIENT_CERT_ERR);
+        EVP_PKEY_free(pri);
+        X509_free(x509);
+        return 0;
+      }
+
+      if(SSL_CTX_use_PrivateKey(ctx, pri) != 1) {
+        failf(data, "unable to use private key from PKCS12 file '%s'",
+              cert_file);
+        EVP_PKEY_free(pri);
+        X509_free(x509);
+        return 0;
+      }
+
+      if (!SSL_CTX_check_private_key (ctx)) {
+        failf(data, "private key from PKCS12 file '%s' "
+              "does not match certificate in same file", cert_file);
+        EVP_PKEY_free(pri);
+        X509_free(x509);
+        return 0;
+      }
+      /* Set Certificate Verification chain */
+      if (ca && sk_X509_num(ca)) {
+        for (i = 0; i < sk_X509_num(ca); i++) {
+          if (!SSL_CTX_add_extra_chain_cert(ctx,sk_X509_value(ca, i))) {
+            failf(data, "cannot add certificate to certificate chain");
+            EVP_PKEY_free(pri);
+            X509_free(x509);
+            return 0;
+          }
+          if (!SSL_CTX_add_client_CA(ctx, sk_X509_value(ca, i))) {
+            failf(data, "cannot add certificate to client CA list");
+            EVP_PKEY_free(pri);
+            X509_free(x509);
+            return 0;
+          }
+        }
+      }
+
+      EVP_PKEY_free(pri);
+      X509_free(x509);
+      cert_done = 1;
+      break;
+#else
+      failf(data, "file type P12 for certificate not supported");
+      return 0;
+#endif
+    }
+    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(cert_done)
+        break;
+      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",
+              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(data->state.engine) {
+#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
+          UI_METHOD *ui_method = UI_OpenSSL();
+#endif
+          /* the typecast below was added to please mingw32 */
+          priv_key = (EVP_PKEY *)
+            ENGINE_load_private_key(data->state.engine,key_file,
+#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
+                                    ui_method,
+#endif
+                                    data->set.str[STRING_KEY_PASSWD]);
+          if(!priv_key) {
+            failf(data, "failed to load private key from crypto engine");
+            return 0;
+          }
+          if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) {
+            failf(data, "unable to set private key");
+            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");
+          return 0;
+        }
+      }
+      break;
+#else
+      failf(data, "file type ENG for private key not supported");
+      return 0;
+#endif
+    case SSL_FILETYPE_PKCS12:
+      if(!cert_done) {
+        failf(data, "file type P12 for private key not supported");
+        return 0;
+      }
+      break;
+    default:
+      failf(data, "not supported file type for private key");
+      return 0;
+    }
+
+    ssl=SSL_new(ctx);
+    if(NULL == ssl) {
+      failf(data,"unable to create an SSL structure");
+      return 0;
+    }
+
+    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;
+}
+
+/* returns non-zero on failure */
+static int x509_name_oneline(X509_NAME *a, char *buf, size_t size)
+{
+#if 0
+  return X509_NAME_oneline(a, buf, size);
+#else
+  BIO *bio_out = BIO_new(BIO_s_mem());
+  BUF_MEM *biomem;
+  int rc;
+
+  if(!bio_out)
+    return 1; /* alloc failed! */
+
+  rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC);
+  BIO_get_mem_ptr(bio_out, &biomem);
+
+  if((size_t)biomem->length < size)
+    size = biomem->length;
+  else
+    size--; /* don't overwrite the buffer end */
+
+  memcpy(buf, biomem->data, size);
+  buf[size]=0;
+
+  BIO_free(bio_out);
+
+  return !rc;
+#endif
+}
+
+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);
+  (void)x509_name_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
+  return ok;
+}
+
+/* Return error string for last OpenSSL error
+ */
+static char *SSL_strerror(unsigned long error, char *buf, size_t size)
+{
+#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(error, buf, size);
+#else
+  (void) size;
+  ERR_error_string(error, buf);
+#endif
+  return buf;
+}
+
+#endif /* USE_SSLEAY */
+
+#ifdef USE_SSLEAY
+/**
+ * Global SSL init
+ *
+ * @retval 0 error initializing SSL
+ * @retval 1 SSL initialized successfully
+ */
+int Curl_ossl_init(void)
+{
+#ifdef HAVE_ENGINE_LOAD_BUILTIN_ENGINES
+  ENGINE_load_builtin_engines();
+#endif
+
+  /* Lets get nice error messages */
+  SSL_load_error_strings();
+
+  /* Init the global ciphers and digests */
+  if(!SSLeay_add_ssl_algorithms())
+    return 0;
+
+  OpenSSL_add_all_algorithms();
+
+#ifdef HAVE_RAND_SCREEN
+  /* This one gets a random value by reading the currently shown screen.
+     RAND_screen() is not thread-safe according to OpenSSL devs - although not
+     mentioned in documentation. */
+  RAND_screen();
+#endif
+
+  return 1;
+}
+
+#endif /* USE_SSLEAY */
+
+#ifdef USE_SSLEAY
+
+/* Global cleanup */
+void Curl_ossl_cleanup(void)
+{
+  /* 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
+}
+
+/*
+ * This function uses SSL_peek to determine connection status.
+ *
+ * Return codes:
+ *     1 means the connection is still in place
+ *     0 means the connection has been closed
+ *    -1 means the connection status is unknown
+ */
+int Curl_ossl_check_cxn(struct connectdata *conn)
+{
+  int rc;
+  char buf;
+
+  rc = SSL_peek(conn->ssl[FIRSTSOCKET].handle, (void*)&buf, 1);
+  if(rc > 0)
+    return 1; /* connection still in place */
+
+  if(rc == 0)
+    return 0; /* connection has been closed */
+
+  return -1; /* connection status unknown */
+}
+
+/* Selects an OpenSSL crypto engine
+ */
+CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine)
+{
+#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
+  ENGINE *e;
+
+#if OPENSSL_VERSION_NUMBER >= 0x00909000L
+  e = ENGINE_by_id(engine);
+#else
+  /* avoid memory leak */
+  for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) {
+    const char *e_id = ENGINE_get_id(e);
+    if(!strcmp(engine, e_id))
+      break;
+  }
+#endif
+
+  if(!e) {
+    failf(data, "SSL Engine '%s' not found", engine);
+    return CURLE_SSL_ENGINE_NOTFOUND;
+  }
+
+  if(data->state.engine) {
+    ENGINE_finish(data->state.engine);
+    ENGINE_free(data->state.engine);
+    data->state.engine = NULL;
+  }
+  if(!ENGINE_init(e)) {
+    char buf[256];
+
+    ENGINE_free(e);
+    failf(data, "Failed to initialise SSL Engine '%s':\n%s",
+          engine, SSL_strerror(ERR_get_error(), buf, sizeof(buf)));
+    return CURLE_SSL_ENGINE_INITFAILED;
+  }
+  data->state.engine = e;
+  return CURLE_OK;
+#else
+  (void)engine;
+  failf(data, "SSL Engine not supported");
+  return CURLE_SSL_ENGINE_NOTFOUND;
+#endif
+}
+
+/* Sets engine as default for all SSL operations
+ */
+CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data)
+{
+#ifdef HAVE_OPENSSL_ENGINE_H
+  if(data->state.engine) {
+    if(ENGINE_set_default(data->state.engine, ENGINE_METHOD_ALL) > 0) {
+      infof(data,"set default crypto engine '%s'\n", ENGINE_get_id(data->state.engine));
+    }
+    else {
+      failf(data, "set default crypto engine '%s' failed", ENGINE_get_id(data->state.engine));
+      return CURLE_SSL_ENGINE_SETFAILED;
+    }
+  }
+#else
+  (void) data;
+#endif
+  return CURLE_OK;
+}
+
+/* Return list of OpenSSL crypto engine names.
+ */
+struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data)
+{
+  struct curl_slist *list = NULL;
+#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
+  struct curl_slist *beg = NULL;
+  ENGINE *e;
+
+  for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) {
+    list = curl_slist_append(list, ENGINE_get_id(e));
+    if(list == NULL) {
+      curl_slist_free_all(beg);
+      return NULL;
+    }
+    else if(beg == NULL) {
+      beg = list;
+    }
+  }
+#endif
+  (void) data;
+  return list;
+}
+
+
+/*
+ * This function is called when an SSL connection is closed.
+ */
+void Curl_ossl_close(struct connectdata *conn, int sockindex)
+{
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+  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;
+  }
+}
+
+/*
+ * This function is called to shut down the SSL layer but keep the
+ * socket open (CCC - Clear Command Channel)
+ */
+int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
+{
+  int retval = 0;
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+  struct SessionHandle *data = conn->data;
+  char buf[120]; /* We will use this for the OpenSSL error buffer, so it has
+                    to be at least 120 bytes long. */
+  unsigned long sslerror;
+  ssize_t nread;
+  int buffsize;
+  int err;
+  int done = 0;
+
+  /* This has only been tested on the proftpd server, and the mod_tls code
+     sends a close notify alert without waiting for a close notify alert in
+     response. Thus we wait for a close notify alert from the server, but
+     we do not send one. Let's hope other servers do the same... */
+
+  if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
+      (void)SSL_shutdown(connssl->handle);
+
+  if(connssl->handle) {
+    buffsize = (int)sizeof(buf);
+    while(!done) {
+      int what = Curl_socket_ready(conn->sock[sockindex],
+                             CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
+      if(what > 0) {
+        /* Something to read, let's do it and hope that it is the close
+           notify alert from the server */
+        nread = (ssize_t)SSL_read(conn->ssl[sockindex].handle, buf,
+                                  buffsize);
+        err = SSL_get_error(conn->ssl[sockindex].handle, (int)nread);
+
+        switch(err) {
+        case SSL_ERROR_NONE: /* this is not an error */
+        case SSL_ERROR_ZERO_RETURN: /* no more data */
+          /* This is the expected response. There was no data but only
+             the close notify alert */
+          done = 1;
+          break;
+        case SSL_ERROR_WANT_READ:
+          /* there's data pending, re-invoke SSL_read() */
+          infof(data, "SSL_ERROR_WANT_READ\n");
+          break;
+        case SSL_ERROR_WANT_WRITE:
+          /* SSL wants a write. Really odd. Let's bail out. */
+          infof(data, "SSL_ERROR_WANT_WRITE\n");
+          done = 1;
+          break;
+        default:
+          /* openssl/ssl.h says "look at error stack/return value/errno" */
+          sslerror = ERR_get_error();
+          failf(conn->data, "SSL read: %s, errno %d",
+                ERR_error_string(sslerror, buf),
+                SOCKERRNO);
+          done = 1;
+          break;
+        }
+      }
+      else if(0 == what) {
+        /* timeout */
+        failf(data, "SSL shutdown timeout");
+        done = 1;
+      }
+      else {
+        /* anything that gets here is fatally bad */
+        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+        retval = -1;
+        done = 1;
+      }
+    } /* while()-loop for the select() */
+
+    if(data->set.verbose) {
+#ifdef HAVE_SSL_GET_SHUTDOWN
+      switch(SSL_get_shutdown(connssl->handle)) {
+      case SSL_SENT_SHUTDOWN:
+        infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN\n");
+        break;
+      case SSL_RECEIVED_SHUTDOWN:
+        infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN\n");
+        break;
+      case SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN:
+        infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN|"
+              "SSL_RECEIVED__SHUTDOWN\n");
+        break;
+      }
+#endif
+    }
+
+    SSL_free (connssl->handle);
+    connssl->handle = NULL;
+  }
+  return retval;
+}
+
+void Curl_ossl_session_free(void *ptr)
+{
+  /* free the ID */
+  SSL_SESSION_free(ptr);
+}
+
+/*
+ * This function is called when the 'data' struct is going away. Close
+ * down everything and free all resources!
+ */
+int Curl_ossl_close_all(struct SessionHandle *data)
+{
+  /*
+    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);
+
+#ifdef HAVE_OPENSSL_ENGINE_H
+  if(data->state.engine) {
+    ENGINE_finish(data->state.engine);
+    ENGINE_free(data->state.engine);
+    data->state.engine = NULL;
+  }
+#else
+  (void)data;
+#endif
+  return 0;
+}
+
+static int asn1_output(const ASN1_UTCTIME *tm,
+                       char *buf,
+                       size_t sizeofbuf)
+{
+  const char *asn1_string;
+  int gmt=FALSE;
+  int i;
+  int year=0,month=0,day=0,hour=0,minute=0,second=0;
+
+  i=tm->length;
+  asn1_string=(const 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');
+
+  snprintf(buf, sizeofbuf,
+           "%04d-%02d-%02d %02d:%02d:%02d %s",
+           year+1900, month, day, hour, minute, second, (gmt?"GMT":""));
+
+  return 0;
+}
+
+/* ====================================================== */
+
+/*
+ * 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) {
+    char 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;
+      }
+      break;
+    }
+
+    if(Curl_raw_toupper(c) != Curl_raw_toupper(*hostname++))
+      break;
+  }
+  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_raw_equal(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)
+{
+  int matched = -1; /* -1 is no alternative match yet, 1 means match and 0
+                       means mismatch */
+  int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */
+  size_t 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
+  CURLcode res = CURLE_OK;
+
+#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 != 1); 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);
+        size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5);
+
+        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((altlen == strlen(altptr)) &&
+             /* if this isn't true, there was an embedded zero in the name
+                string and we cannot match it. */
+             cert_hostcheck(altptr, conn->host.name))
+            matched = 1;
+          else
+            matched = 0;
+          break;
+
+        case GEN_IPADD: /* IP address comparison */
+          /* compare alternative IP address if the data chunk is the same size
+             our server IP address is */
+          if((altlen == addrlen) && !memcmp(altptr, &addr, altlen))
+            matched = 1;
+          else
+            matched = 0;
+          break;
+        }
+      }
+    }
+    GENERAL_NAMES_free(altnames);
+  }
+
+  if(matched == 1)
+    /* an alternative name matched the server hostname */
+    infof(data, "\t subjectAltName: %s matched\n", conn->host.dispname);
+  else if(matched == 0) {
+    /* an alternative name field existed, but didn't match and then
+       we MUST fail */
+    infof(data, "\t subjectAltName does not match %s\n", conn->host.dispname);
+    res = CURLE_PEER_FAILED_VERIFICATION;
+  }
+  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) {
+        if(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 && ((int)strlen((char *)peer_CN) != j)) {
+          /* there was a terminating zero before the end of string, this
+             cannot match and we return failure! */
+          failf(data, "SSL: illegal cert name field");
+          res = CURLE_PEER_FAILED_VERIFICATION;
+        }
+      }
+    }
+
+    if(peer_CN == nulstr)
+       peer_CN = NULL;
+#ifdef CURL_DOES_CONVERSIONS
+    else {
+      /* convert peer_CN from UTF8 */
+      size_t rc;
+      rc = Curl_convert_from_utf8(data, peer_CN, strlen(peer_CN));
+      /* Curl_convert_from_utf8 calls failf if unsuccessful */
+      if(rc != CURLE_OK) {
+        OPENSSL_free(peer_CN);
+        return rc;
+      }
+    }
+#endif /* CURL_DOES_CONVERSIONS */
+
+    if(res)
+      /* error already detected, pass through */
+      ;
+    else if(!peer_CN) {
+      failf(data,
+            "SSL: unable to obtain common name from peer certificate");
+      res = CURLE_PEER_FAILED_VERIFICATION;
+    }
+    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);
+        res = CURLE_PEER_FAILED_VERIFICATION;
+      }
+      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);
+    }
+    if(peer_CN)
+      OPENSSL_free(peer_CN);
+  }
+  return res;
+}
+#endif /* USE_SSLEAY */
+
+/* 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;
+  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 = 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, (size_t)txt_len, NULL);
+
+  Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT :
+             CURLINFO_SSL_DATA_IN, (char *)buf, len, NULL);
+  (void) ssl;
+}
+#endif
+
+#ifdef USE_SSLEAY
+/* ====================================================== */
+
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+#  define use_sni(x)  sni = (x)
+#else
+#  define use_sni(x)  do { } while (0)
+#endif
+
+static CURLcode
+ossl_connect_step1(struct connectdata *conn,
+                   int sockindex)
+{
+  CURLcode retcode = CURLE_OK;
+
+  struct SessionHandle *data = conn->data;
+  SSL_METHOD_QUAL SSL_METHOD *req_method=NULL;
+  void *ssl_sessionid=NULL;
+  X509_LOOKUP *lookup=NULL;
+  curl_socket_t sockfd = conn->sock[sockindex];
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+  bool sni;
+#ifdef ENABLE_IPV6
+  struct in6_addr addr;
+#else
+  struct in_addr addr;
+#endif
+#endif
+
+  DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
+
+  /* Make funny stuff to get random input */
+  Curl_ossl_seed(data);
+
+  /* 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();
+    use_sni(TRUE);
+    break;
+  case CURL_SSLVERSION_TLSv1:
+    req_method = TLSv1_client_method();
+    use_sni(TRUE);
+    break;
+  case CURL_SSLVERSION_SSLv2:
+    req_method = SSLv2_client_method();
+    use_sni(FALSE);
+    break;
+  case CURL_SSLVERSION_SSLv3:
+    req_method = SSLv3_client_method();
+    use_sni(FALSE);
+    break;
+  }
+
+  if(connssl->ctx)
+    SSL_CTX_free(connssl->ctx);
+  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 && data->set.verbose) {
+    /* the SSL trace callback is only used for verbose logging so we only
+       inform about failures of setting it */
+    if(!SSL_CTX_callback_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK,
+                               (void (*)(void))ssl_tls_trace)) {
+      infof(data, "SSL: couldn't set callback!\n");
+    }
+    else if(!SSL_CTX_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK_ARG, 0,
+                          conn)) {
+      infof(data, "SSL: couldn't set callback argument!\n");
+    }
+  }
+#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
+     all 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."
+
+     The "-no_ticket" option was introduced in Openssl0.9.8j. It's a flag to
+     disable "rfc4507bis session ticket support".  rfc4507bis was later turned
+     into the proper RFC5077 it seems: http://tools.ietf.org/html/rfc5077
+
+     The enabled extension concerns the session management. I wonder how often
+     libcurl stops a connection and then resumes a TLS session. also, sending
+     the session data is some overhead. .I suggest that you just use your
+     proposed patch (which explicitly disables TICKET).
+
+     If someone writes an application with libcurl and openssl who wants to
+     enable the feature, one can do this in the SSL callback.
+
+  */
+#ifdef SSL_OP_NO_TICKET
+  /* expect older openssl releases to not have this define so only use it if
+     present */
+#define CURL_CTX_OPTIONS SSL_OP_ALL|SSL_OP_NO_TICKET
+#else
+#define CURL_CTX_OPTIONS SSL_OP_ALL
+#endif
+
+  SSL_CTX_set_options(connssl->ctx, CURL_CTX_OPTIONS);
+
+  /* disable SSLv2 in the default case (i.e. allow SSLv3 and TLSv1) */
+  if(data->set.ssl.version == CURL_SSLVERSION_DEFAULT)
+    SSL_CTX_set_options(connssl->ctx, SSL_OP_NO_SSLv2);
+
+#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.str[STRING_CERT] || data->set.str[STRING_CERT_TYPE]) {
+    if(!cert_stuff(conn,
+                   connssl->ctx,
+                   data->set.str[STRING_CERT],
+                   data->set.str[STRING_CERT_TYPE],
+                   data->set.str[STRING_KEY],
+                   data->set.str[STRING_KEY_TYPE])) {
+      /* failf() is already done in cert_stuff() */
+      return CURLE_SSL_CERTPROBLEM;
+    }
+  }
+
+  if(data->set.str[STRING_SSL_CIPHER_LIST]) {
+    if(!SSL_CTX_set_cipher_list(connssl->ctx,
+                                data->set.str[STRING_SSL_CIPHER_LIST])) {
+      failf(data, "failed setting cipher list");
+      return CURLE_SSL_CIPHER;
+    }
+  }
+
+  if(data->set.str[STRING_SSL_CAFILE] || data->set.str[STRING_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.str[STRING_SSL_CAFILE],
+                                       data->set.str[STRING_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.str[STRING_SSL_CAFILE]?
+              data->set.str[STRING_SSL_CAFILE]: "none",
+              data->set.str[STRING_SSL_CAPATH]?
+              data->set.str[STRING_SSL_CAPATH] : "none");
+        return CURLE_SSL_CACERT_BADFILE;
+      }
+      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.str[STRING_SSL_CAFILE] ? data->set.str[STRING_SSL_CAFILE]:
+          "none",
+          data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]:
+          "none");
+  }
+
+  if (data->set.str[STRING_SSL_CRLFILE]) {
+    /* tell SSL where to find CRL file that is used to check certificate
+     * revocation */
+    lookup=X509_STORE_add_lookup(connssl->ctx->cert_store,X509_LOOKUP_file());
+    if ( !lookup ||
+         (!X509_load_crl_file(lookup,data->set.str[STRING_SSL_CRLFILE],
+                              X509_FILETYPE_PEM)) ) {
+      failf(data,"error loading CRL file :\n"
+            "  CRLfile: %s\n",
+            data->set.str[STRING_SSL_CRLFILE]?
+            data->set.str[STRING_SSL_CRLFILE]: "none");
+      return CURLE_SSL_CRL_BADFILE;
+    }
+    else {
+      /* Everything is fine. */
+      infof(data, "successfully load CRL file:\n");
+      X509_STORE_set_flags(connssl->ctx->cert_store,
+                           X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
+    }
+    infof(data,
+          "  CRLfile: %s\n", data->set.str[STRING_SSL_CRLFILE] ?
+          data->set.str[STRING_SSL_CRLFILE]: "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 */
+  if(connssl->handle)
+    SSL_free(connssl->handle);
+  connssl->handle = SSL_new(connssl->ctx);
+  if(!connssl->handle) {
+    failf(data, "SSL: couldn't create a context (handle)!");
+    return CURLE_OUT_OF_MEMORY;
+  }
+  SSL_set_connect_state(connssl->handle);
+
+  connssl->server_cert = 0x0;
+
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+  if ((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) &&
+#ifdef ENABLE_IPV6
+      (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) &&
+#endif
+      sni &&
+      !SSL_set_tlsext_host_name(connssl->handle, conn->host.name))
+    infof(data, "WARNING: failed to configure server name indication (SNI) "
+          "TLS extension\n");
+#endif
+
+  /* Check if there's a cached ID we can/should use here! */
+  if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
+    /* we got a session id, use it! */
+    if(!SSL_set_session(connssl->handle, ssl_sessionid)) {
+      failf(data, "SSL: SSL_set_session failed: %s",
+            ERR_error_string(ERR_get_error(),NULL));
+      return CURLE_SSL_CONNECT_ERROR;
+    }
+    /* Informational message */
+    infof (data, "SSL re-using session ID\n");
+  }
+
+  /* pass the raw socket into the SSL layers */
+  if(!SSL_set_fd(connssl->handle, (int)sockfd)) {
+     failf(data, "SSL: SSL_set_fd failed: %s",
+           ERR_error_string(ERR_get_error(),NULL));
+     return CURLE_SSL_CONNECT_ERROR;
+  }
+
+  connssl->connecting_state = ssl_connect_2;
+  return CURLE_OK;
+}
+
+static CURLcode
+ossl_connect_step2(struct connectdata *conn, int sockindex)
+{
+  struct SessionHandle *data = conn->data;
+  int err;
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+  DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
+             || ssl_connect_2_reading == connssl->connecting_state
+             || ssl_connect_2_writing == connssl->connecting_state);
+
+  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) {
+      connssl->connecting_state = ssl_connect_2_reading;
+      return CURLE_OK;
+    }
+    else if(SSL_ERROR_WANT_WRITE == detail) {
+      connssl->connecting_state = ssl_connect_2_writing;
+      return CURLE_OK;
+    }
+    else {
+      /* untreated error */
+      unsigned long errdetail;
+      char error_buffer[256]; /* OpenSSL documents that this must be at least
+                                 256 bytes long. */
+      CURLcode rc;
+      const char *cert_problem = NULL;
+
+      connssl->connecting_state = ssl_connect_2; /* the connection failed,
+                                                    we're not waiting for
+                                                    anything else. */
+
+      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:%ld ",
+              conn->host.name, conn->port);
+        return rc;
+      }
+      /* Could be a CERT problem */
+
+      SSL_strerror(errdetail, error_buffer, sizeof(error_buffer));
+      failf(data, "%s%s", cert_problem ? cert_problem : "", error_buffer);
+      return rc;
+    }
+  }
+  else {
+    /* we have been connected fine, we're not waiting for anything else. */
+    connssl->connecting_state = ssl_connect_3;
+
+    /* Informational message */
+    infof (data, "SSL connection using %s\n",
+           SSL_get_cipher(connssl->handle));
+
+    return CURLE_OK;
+  }
+}
+
+static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len)
+{
+  int i, ilen;
+
+  if((ilen = (int)len) < 0)
+    return 1; /* buffer too big */
+
+  i = i2t_ASN1_OBJECT(buf, ilen, a);
+
+  if(i >= ilen)
+    return 1; /* buffer too small */
+
+  return 0;
+}
+
+static CURLcode push_certinfo_len(struct SessionHandle *data,
+                                  int certnum,
+                                  const char *label,
+                                  const char *value,
+                                  size_t valuelen)
+{
+  struct curl_certinfo *ci = &data->info.certs;
+  char *output;
+  struct curl_slist *nl;
+  CURLcode res = CURLE_OK;
+  size_t labellen = strlen(label);
+  size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */
+
+  output = malloc(outlen);
+  if(!output)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* sprintf the label and colon */
+  snprintf(output, outlen, "%s:", label);
+
+  /* memcpy the value (it might not be zero terminated) */
+  memcpy(&output[labellen+1], value, valuelen);
+
+  /* zero terminate the output */
+  output[labellen + 1 + valuelen] = 0;
+
+  /* TODO: we should rather introduce an internal API that can do the
+     equivalent of curl_slist_append but doesn't strdup() the given data as
+     like in this place the extra malloc/free is totally pointless */
+  nl = curl_slist_append(ci->certinfo[certnum], output);
+  if(!nl) {
+    curl_slist_free_all(ci->certinfo[certnum]);
+    res = CURLE_OUT_OF_MEMORY;
+  }
+  else
+    ci->certinfo[certnum] = nl;
+
+  free(output);
+
+  return res;
+}
+
+/* this is a convenience function for push_certinfo_len that takes a zero
+   terminated value */
+static CURLcode push_certinfo(struct SessionHandle *data,
+                              int certnum,
+                              const char *label,
+                              const char *value)
+{
+  size_t valuelen = strlen(value);
+
+  return push_certinfo_len(data, certnum, label, value, valuelen);
+}
+
+static void pubkey_show(struct SessionHandle *data,
+                        int num,
+                        const char *type,
+                        const char *name,
+                        unsigned char *raw,
+                        int len)
+{
+  char buffer[1024];
+  size_t left = sizeof(buffer);
+  int i;
+  char *ptr=buffer;
+  char namebuf[32];
+
+  snprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name);
+
+  for(i=0; i< len; i++) {
+    snprintf(ptr, left, "%02x:", raw[i]);
+    ptr += 3;
+    left -= 3;
+  }
+  infof(data, "   %s: %s\n", namebuf, buffer);
+  push_certinfo(data, num, namebuf, buffer);
+}
+
+#define print_pubkey_BN(_type, _name, _num)    \
+do {                              \
+  if (pubkey->pkey._type->_name != NULL) { \
+    int len = BN_num_bytes(pubkey->pkey._type->_name); \
+    if(len < (int)sizeof(buf)) {                       \
+      BN_bn2bin(pubkey->pkey._type->_name, (unsigned char*)buf); \
+      buf[len] = 0; \
+      pubkey_show(data, _num, #_type, #_name, (unsigned char*)buf, len); \
+    } \
+  } \
+} while (0)
+
+static int X509V3_ext(struct SessionHandle *data,
+                      int certnum,
+                      STACK_OF(X509_EXTENSION) *exts)
+{
+  int i;
+  size_t j;
+
+  if(sk_X509_EXTENSION_num(exts) <= 0)
+    /* no extensions, bail out */
+    return 1;
+
+  for (i=0; i<sk_X509_EXTENSION_num(exts); i++) {
+    ASN1_OBJECT *obj;
+    X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
+    BUF_MEM *biomem;
+    char buf[512];
+    char *ptr=buf;
+    char namebuf[128];
+    BIO *bio_out = BIO_new(BIO_s_mem());
+
+    if(!bio_out)
+      return 1;
+
+    obj = X509_EXTENSION_get_object(ext);
+
+    asn1_object_dump(obj, namebuf, sizeof(namebuf));
+
+    infof(data, "%s: %s\n", namebuf,
+          X509_EXTENSION_get_critical(ext)?"(critical)":"");
+
+    if(!X509V3_EXT_print(bio_out, ext, 0, 0))
+      M_ASN1_OCTET_STRING_print(bio_out, ext->value);
+
+    BIO_get_mem_ptr(bio_out, &biomem);
+
+    /* biomem->length bytes at biomem->data, this little loop here is only
+       done for the infof() call, we send the "raw" data to the certinfo
+       function */
+    for(j=0; j<(size_t)biomem->length; j++) {
+      const char *sep="";
+      if(biomem->data[j] == '\n') {
+        sep=", ";
+        j++; /* skip the newline */
+      };
+      while((biomem->data[j] == ' ') && (j<(size_t)biomem->length))
+        j++;
+      if(j<(size_t)biomem->length)
+        ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep, biomem->data[j]);
+    }
+    infof(data, "  %s\n", buf);
+
+    push_certinfo(data, certnum, namebuf, buf);
+
+    BIO_free(bio_out);
+
+  }
+  return 0; /* all is fine */
+}
+
+
+static void X509_signature(struct SessionHandle *data,
+                           int numcert,
+                           ASN1_STRING *sig)
+{
+  char buf[1024];
+  char *ptr = buf;
+  int i;
+  for (i=0; i<sig->length; i++)
+    ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%02x:", sig->data[i]);
+
+  infof(data, " Signature: %s\n", buf);
+  push_certinfo(data, numcert, "Signature", buf);
+}
+
+static void dumpcert(struct SessionHandle *data, X509 *x, int numcert)
+{
+  BIO *bio_out = BIO_new(BIO_s_mem());
+  BUF_MEM *biomem;
+
+  /* this outputs the cert in this 64 column wide style with newlines and
+     -----BEGIN CERTIFICATE----- texts and more */
+  PEM_write_bio_X509(bio_out, x);
+
+  BIO_get_mem_ptr(bio_out, &biomem);
+
+  infof(data, "%s\n", biomem->data);
+
+  push_certinfo_len(data, numcert, "Cert", biomem->data, biomem->length);
+
+  BIO_free(bio_out);
+
+}
+
+
+static int init_certinfo(struct SessionHandle *data,
+                         int num)
+{
+  struct curl_certinfo *ci = &data->info.certs;
+  struct curl_slist **table;
+
+  Curl_ssl_free_certinfo(data);
+
+  ci->num_of_certs = num;
+  table = calloc((size_t)num, sizeof(struct curl_slist *));
+  if(!table)
+    return 1;
+
+  ci->certinfo = table;
+  return 0;
+}
+
+static CURLcode get_cert_chain(struct connectdata *conn,
+                               struct ssl_connect_data *connssl)
+
+{
+  STACK_OF(X509) *sk;
+  int i;
+  char buf[512];
+  struct SessionHandle *data = conn->data;
+  int numcerts;
+
+  sk = SSL_get_peer_cert_chain(connssl->handle);
+
+  if(!sk)
+    return CURLE_OUT_OF_MEMORY;
+
+  numcerts = sk_X509_num(sk);
+
+  if(init_certinfo(data, numcerts))
+    return CURLE_OUT_OF_MEMORY;
+
+  infof(data, "--- Certificate chain\n");
+  for (i=0; i<numcerts; i++) {
+    long value;
+    ASN1_INTEGER *num;
+    ASN1_TIME *certdate;
+
+    /* get the certs in "importance order" */
+#if 0
+    X509 *x = sk_X509_value(sk, numcerts - i - 1);
+#else
+    X509 *x = sk_X509_value(sk, i);
+#endif
+
+    X509_CINF *cinf;
+    EVP_PKEY *pubkey=NULL;
+    int j;
+    char *ptr;
+
+    (void)x509_name_oneline(X509_get_subject_name(x), buf, sizeof(buf));
+    infof(data, "%2d Subject: %s\n",i,buf);
+    push_certinfo(data, i, "Subject", buf);
+
+    (void)x509_name_oneline(X509_get_issuer_name(x), buf, sizeof(buf));
+    infof(data, "   Issuer: %s\n",buf);
+    push_certinfo(data, i, "Issuer", buf);
+
+    value = X509_get_version(x);
+    infof(data, "   Version: %lu (0x%lx)\n", value+1, value);
+    snprintf(buf, sizeof(buf), "%lx", value);
+    push_certinfo(data, i, "Version", buf); /* hex */
+
+    num=X509_get_serialNumber(x);
+    if (num->length <= 4) {
+      value = ASN1_INTEGER_get(num);
+      infof(data,"   Serial Number: %ld (0x%lx)\n", value, value);
+      snprintf(buf, sizeof(buf), "%lx", value);
+    }
+    else {
+
+      ptr = buf;
+      *ptr++ = 0;
+      if(num->type == V_ASN1_NEG_INTEGER)
+        *ptr++='-';
+
+      for (j=0; j<num->length; j++) {
+        /* TODO: length restrictions */
+        snprintf(ptr, 3, "%02x%c",num->data[j],
+                 ((j+1 == num->length)?'\n':':'));
+        ptr += 3;
+      }
+      if(num->length)
+        infof(data,"   Serial Number: %s\n", buf);
+      else
+        buf[0]=0;
+    }
+    if(buf[0])
+      push_certinfo(data, i, "Serial Number", buf); /* hex */
+
+    cinf = x->cert_info;
+
+    j = asn1_object_dump(cinf->signature->algorithm, buf, sizeof(buf));
+    if(!j) {
+      infof(data, "   Signature Algorithm: %s\n", buf);
+      push_certinfo(data, i, "Signature Algorithm", buf);
+    }
+
+    certdate = X509_get_notBefore(x);
+    asn1_output(certdate, buf, sizeof(buf));
+    infof(data, "   Start date: %s\n", buf);
+    push_certinfo(data, i, "Start date", buf);
+
+    certdate = X509_get_notAfter(x);
+    asn1_output(certdate, buf, sizeof(buf));
+    infof(data, "   Expire date: %s\n", buf);
+    push_certinfo(data, i, "Expire date", buf);
+
+    j = asn1_object_dump(cinf->key->algor->algorithm, buf, sizeof(buf));
+    if(!j) {
+      infof(data, "   Public Key Algorithm: %s\n", buf);
+      push_certinfo(data, i, "Public Key Algorithm", buf);
+    }
+
+    pubkey = X509_get_pubkey(x);
+    if(!pubkey)
+      infof(data, "   Unable to load public key\n");
+    else {
+      switch(pubkey->type) {
+      case EVP_PKEY_RSA:
+        infof(data,  "   RSA Public Key (%d bits)\n",
+              BN_num_bits(pubkey->pkey.rsa->n));
+        snprintf(buf, sizeof(buf), "%d", BN_num_bits(pubkey->pkey.rsa->n));
+        push_certinfo(data, i, "RSA Public Key", buf);
+
+        print_pubkey_BN(rsa, n, i);
+        print_pubkey_BN(rsa, e, i);
+        print_pubkey_BN(rsa, d, i);
+        print_pubkey_BN(rsa, p, i);
+        print_pubkey_BN(rsa, q, i);
+        print_pubkey_BN(rsa, dmp1, i);
+        print_pubkey_BN(rsa, dmq1, i);
+        print_pubkey_BN(rsa, iqmp, i);
+        break;
+      case EVP_PKEY_DSA:
+        print_pubkey_BN(dsa, p, i);
+        print_pubkey_BN(dsa, q, i);
+        print_pubkey_BN(dsa, g, i);
+        print_pubkey_BN(dsa, priv_key, i);
+        print_pubkey_BN(dsa, pub_key, i);
+        break;
+      case EVP_PKEY_DH:
+        print_pubkey_BN(dh, p, i);
+        print_pubkey_BN(dh, g, i);
+        print_pubkey_BN(dh, priv_key, i);
+        print_pubkey_BN(dh, pub_key, i);
+        break;
+#if 0
+      case EVP_PKEY_EC: /* symbol not present in OpenSSL 0.9.6 */
+        /* left TODO */
+        break;
+#endif
+      }
+      EVP_PKEY_free(pubkey);
+    }
+
+    X509V3_ext(data, i, cinf->extensions);
+
+    X509_signature(data, i, x->signature);
+
+    dumpcert(data, x, i);
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Get the server cert, verify it and show it etc, only call failf() if the
+ * 'strict' argument is TRUE as otherwise all this is for informational
+ * purposes only!
+ *
+ * We check certificates to authenticate the server; otherwise we risk
+ * man-in-the-middle attack.
+ */
+static CURLcode servercert(struct connectdata *conn,
+                           struct ssl_connect_data *connssl,
+                           bool strict)
+{
+  CURLcode retcode = CURLE_OK;
+  int rc;
+  long lerr;
+  ASN1_TIME *certdate;
+  struct SessionHandle *data = conn->data;
+  X509 *issuer;
+  FILE *fp;
+  char buffer[256];
+
+  if(data->set.ssl.certinfo)
+    /* we've been asked to gather certificate info! */
+    (void)get_cert_chain(conn, connssl);
+
+  data->set.ssl.certverifyresult = !X509_V_OK;
+
+  connssl->server_cert = SSL_get_peer_certificate(connssl->handle);
+  if(!connssl->server_cert) {
+    if(strict)
+      failf(data, "SSL: couldn't get peer certificate!");
+    return CURLE_PEER_FAILED_VERIFICATION;
+  }
+  infof (data, "Server certificate:\n");
+
+  rc = x509_name_oneline(X509_get_subject_name(connssl->server_cert),
+                          buffer, sizeof(buffer));
+  if(rc) {
+    if(strict)
+      failf(data, "SSL: couldn't get X509-subject!");
+    X509_free(connssl->server_cert);
+    connssl->server_cert = NULL;
+    return CURLE_SSL_CONNECT_ERROR;
+  }
+  infof(data, "\t subject: %s\n", buffer);
+
+  certdate = X509_get_notBefore(connssl->server_cert);
+  asn1_output(certdate, buffer, sizeof(buffer));
+  infof(data, "\t start date: %s\n", buffer);
+
+  certdate = X509_get_notAfter(connssl->server_cert);
+  asn1_output(certdate, buffer, sizeof(buffer));
+  infof(data, "\t expire date: %s\n", buffer);
+
+  if(data->set.ssl.verifyhost) {
+    retcode = verifyhost(conn, connssl->server_cert);
+    if(retcode) {
+      X509_free(connssl->server_cert);
+      connssl->server_cert = NULL;
+      return retcode;
+    }
+  }
+
+  rc = x509_name_oneline(X509_get_issuer_name(connssl->server_cert),
+                         buffer, sizeof(buffer));
+  if(rc) {
+    if(strict)
+      failf(data, "SSL: couldn't get X509-issuer name!");
+    retcode = CURLE_SSL_CONNECT_ERROR;
+  }
+  else {
+    infof(data, "\t issuer: %s\n", buffer);
+
+    /* We could do all sorts of certificate verification stuff here before
+       deallocating the certificate. */
+
+    /* e.g. match issuer name with provided issuer certificate */
+    if (data->set.str[STRING_SSL_ISSUERCERT]) {
+      if (! (fp=fopen(data->set.str[STRING_SSL_ISSUERCERT],"r"))) {
+        if (strict)
+          failf(data, "SSL: Unable to open issuer cert (%s)\n",
+                data->set.str[STRING_SSL_ISSUERCERT]);
+        X509_free(connssl->server_cert);
+        connssl->server_cert = NULL;
+        return CURLE_SSL_ISSUER_ERROR;
+      }
+      issuer = PEM_read_X509(fp,NULL,ZERO_NULL,NULL);
+      if (!issuer) {
+        if (strict)
+          failf(data, "SSL: Unable to read issuer cert (%s)\n",
+                data->set.str[STRING_SSL_ISSUERCERT]);
+        X509_free(connssl->server_cert);
+        X509_free(issuer);
+        fclose(fp);
+        return CURLE_SSL_ISSUER_ERROR;
+      }
+      fclose(fp);
+      if (X509_check_issued(issuer,connssl->server_cert) != X509_V_OK) {
+        if (strict)
+          failf(data, "SSL: Certificate issuer check failed (%s)\n",
+                data->set.str[STRING_SSL_ISSUERCERT]);
+        X509_free(connssl->server_cert);
+        X509_free(issuer);
+        connssl->server_cert = NULL;
+        return CURLE_SSL_ISSUER_ERROR;
+      }
+      infof(data, "\t SSL certificate issuer check ok (%s)\n",
+            data->set.str[STRING_SSL_ISSUERCERT]);
+      X509_free(issuer);
+    }
+
+    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 earlier if verifypeer is set? */
+        if(strict)
+          failf(data, "SSL certificate verify result: %s (%ld)",
+                X509_verify_cert_error_string(lerr), lerr);
+        retcode = CURLE_PEER_FAILED_VERIFICATION;
+      }
+      else
+        infof(data, "\t SSL certificate verify result: %s (%ld),"
+              " continuing anyway.\n",
+              X509_verify_cert_error_string(lerr), lerr);
+    }
+    else
+      infof(data, "\t SSL certificate verify ok.\n");
+  }
+
+  X509_free(connssl->server_cert);
+  connssl->server_cert = NULL;
+  connssl->connecting_state = ssl_connect_done;
+
+  return retcode;
+}
+
+
+static CURLcode
+ossl_connect_step3(struct connectdata *conn,
+                   int sockindex)
+{
+  CURLcode retcode = CURLE_OK;
+  void *old_ssl_sessionid=NULL;
+  struct SessionHandle *data = conn->data;
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+  int incache;
+  SSL_SESSION *our_ssl_sessionid;
+
+  DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
+
+#ifdef HAVE_SSL_GET1_SESSION
+  our_ssl_sessionid = SSL_get1_session(connssl->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
+  our_ssl_sessionid = SSL_get_session(connssl->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
+
+  incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL));
+  if (incache) {
+    if (old_ssl_sessionid != our_ssl_sessionid) {
+      infof(data, "old SSL session ID is stale, removing\n");
+      Curl_ssl_delsessionid(conn, old_ssl_sessionid);
+      incache = FALSE;
+    }
+  }
+  if (!incache) {
+    retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
+                                    0 /* unknown size */);
+    if(retcode) {
+      failf(data, "failed to store ssl session");
+      return retcode;
+    }
+  }
+#ifdef HAVE_SSL_GET1_SESSION
+  else {
+    /* Session was incache, so refcount already incremented earlier.
+     * Avoid further increments with each SSL_get1_session() call.
+     * This does not free the session as refcount remains > 0
+     */
+    SSL_SESSION_free(our_ssl_sessionid);
+  }
+#endif
+
+  /*
+   * We check certificates to authenticate the server; otherwise we risk
+   * man-in-the-middle attack; NEVERTHELESS, if we're told explicitly not to
+   * verify the peer ignore faults and failures from the server cert
+   * operations.
+   */
+
+  if(!data->set.ssl.verifypeer)
+    (void)servercert(conn, connssl, FALSE);
+  else
+    retcode = servercert(conn, connssl, TRUE);
+
+  if(CURLE_OK == retcode)
+    connssl->connecting_state = ssl_connect_done;
+  return retcode;
+}
+
+static CURLcode
+ossl_connect_common(struct connectdata *conn,
+                    int sockindex,
+                    bool nonblocking,
+                    bool *done)
+{
+  CURLcode retcode;
+  struct SessionHandle *data = conn->data;
+  struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+  curl_socket_t sockfd = conn->sock[sockindex];
+  long timeout_ms;
+  int what;
+
+  if(ssl_connect_1==connssl->connecting_state) {
+    /* Find out how much more time we're allowed */
+    timeout_ms = Curl_timeleft(conn, NULL, TRUE);
+
+    if(timeout_ms < 0) {
+      /* no need to continue if time already is up */
+      failf(data, "SSL connection timeout");
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+    retcode = ossl_connect_step1(conn, sockindex);
+    if(retcode)
+      return retcode;
+  }
+
+  while(ssl_connect_2 == connssl->connecting_state ||
+        ssl_connect_2_reading == connssl->connecting_state ||
+        ssl_connect_2_writing == connssl->connecting_state) {
+
+    /* check allowed time left */
+    timeout_ms = Curl_timeleft(conn, NULL, TRUE);
+
+    if(timeout_ms < 0) {
+      /* no need to continue if time already is up */
+      failf(data, "SSL connection timeout");
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+
+    /* if ssl is expecting something, check if it's available. */
+    if(connssl->connecting_state == ssl_connect_2_reading
+        || connssl->connecting_state == ssl_connect_2_writing) {
+
+      curl_socket_t writefd = ssl_connect_2_writing==
+        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+      curl_socket_t readfd = ssl_connect_2_reading==
+        connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+
+      what = Curl_socket_ready(readfd, writefd,
+                               nonblocking?0:(int)timeout_ms);
+      if(what < 0) {
+        /* fatal error */
+        failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+        return CURLE_SSL_CONNECT_ERROR;
+      }
+      else if(0 == what) {
+        if(nonblocking) {
+          *done = FALSE;
+          return CURLE_OK;
+        }
+        else {
+          /* timeout */
+          failf(data, "SSL connection timeout");
+          return CURLE_OPERATION_TIMEDOUT;
+        }
+      }
+      /* socket is readable or writable */
+    }
+
+    retcode = ossl_connect_step2(conn, sockindex);
+    if(retcode || (data->state.used_interface == Curl_if_multi))
+      return retcode;
+
+  } /* repeat step2 until all transactions are done. */
+
+
+  if(ssl_connect_3==connssl->connecting_state) {
+    retcode = ossl_connect_step3(conn, sockindex);
+    if(retcode)
+      return retcode;
+  }
+
+  if(ssl_connect_done==connssl->connecting_state) {
+    connssl->state = ssl_connection_complete;
+    *done = TRUE;
+  }
+  else
+    *done = FALSE;
+
+  /* Reset our connect state machine */
+  connssl->connecting_state = ssl_connect_1;
+
+  return CURLE_OK;
+}
+
+CURLcode
+Curl_ossl_connect_nonblocking(struct connectdata *conn,
+                              int sockindex,
+                              bool *done)
+{
+  return ossl_connect_common(conn, sockindex, TRUE, done);
+}
+
+CURLcode
+Curl_ossl_connect(struct connectdata *conn,
+                  int sockindex)
+{
+  CURLcode retcode;
+  bool done = FALSE;
+
+  retcode = ossl_connect_common(conn, sockindex, FALSE, &done);
+  if(retcode)
+    return retcode;
+
+  DEBUGASSERT(done);
+
+  return CURLE_OK;
+}
+
+bool Curl_ossl_data_pending(const struct connectdata *conn,
+                            int connindex)
+{
+  if(conn->ssl[connindex].handle)
+    /* SSL is in use */
+    return (bool)(0 != SSL_pending(conn->ssl[connindex].handle));
+  else
+    return FALSE;
+}
+
+/* for documentation see Curl_ssl_send() in sslgen.h */
+ssize_t Curl_ossl_send(struct connectdata *conn,
+                       int sockindex,
+                       const void *mem,
+                       size_t len,
+                       int *curlcode)
+{
+  /* SSL_write() is said to return 'int' while write() and send() returns
+     'size_t' */
+  int err;
+  char error_buffer[120]; /* OpenSSL documents that this must be at least 120
+                             bytes long. */
+  unsigned long sslerror;
+  int memlen;
+  int rc;
+
+  memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
+  rc = SSL_write(conn->ssl[sockindex].handle, mem, memlen);
+
+  if(rc < 0) {
+    err = SSL_get_error(conn->ssl[sockindex].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. */
+      *curlcode = /* EWOULDBLOCK */ -1;
+      return -1;
+    case SSL_ERROR_SYSCALL:
+      failf(conn->data, "SSL_write() returned SYSCALL, errno = %d",
+            SOCKERRNO);
+      *curlcode = CURLE_SEND_ERROR;
+      return -1;
+    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",
+            ERR_error_string(sslerror, error_buffer));
+      *curlcode = CURLE_SEND_ERROR;
+      return -1;
+    }
+    /* a true error */
+    failf(conn->data, "SSL_write() return error %d", err);
+    *curlcode = CURLE_SEND_ERROR;
+    return -1;
+  }
+  return (ssize_t)rc; /* number of bytes */
+}
+
+/* for documentation see Curl_ssl_recv() in sslgen.h */
+ssize_t Curl_ossl_recv(struct connectdata *conn, /* connection data */
+                       int num,                  /* socketindex */
+                       char *buf,                /* store read data here */
+                       size_t buffersize,        /* max amount to read */
+                       int *curlcode)
+{
+  char error_buffer[120]; /* OpenSSL documents that this must be at
+                             least 120 bytes long. */
+  unsigned long sslerror;
+  ssize_t nread;
+  int buffsize;
+
+  buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
+  nread = (ssize_t)SSL_read(conn->ssl[num].handle, buf, buffsize);
+  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() */
+      *curlcode = -1;  /* EWOULDBLOCK */
+      return -1;
+    default:
+      /* openssl/ssl.h says "look at error stack/return value/errno" */
+      sslerror = ERR_get_error();
+      failf(conn->data, "SSL read: %s, errno %d",
+            ERR_error_string(sslerror, error_buffer),
+            SOCKERRNO);
+      *curlcode = CURLE_RECV_ERROR;
+      return -1;
+    }
+  }
+  return nread;
+}
+
+size_t Curl_ossl_version(char *buffer, size_t size)
+{
+#ifdef YASSL_VERSION
+  /* yassl provides an OpenSSL API compatiblity layer so it looks identical
+     to OpenSSL in all other aspects */
+  return snprintf(buffer, size, "yassl/%s", YASSL_VERSION);
+#else /* YASSL_VERSION */
+
+#if(SSLEAY_VERSION_NUMBER >= 0x905000)
+  {
+    char sub[2];
+    unsigned long ssleay_value;
+    sub[1]='\0';
+    ssleay_value=SSLeay();
+    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(buffer, size, "OpenSSL/%lx.%lx.%lx%s",
+                    (ssleay_value>>28)&0xf,
+                    (ssleay_value>>20)&0xff,
+                    (ssleay_value>>12)&0xff,
+                    sub);
+  }
+
+#else /* SSLEAY_VERSION_NUMBER is less than 0.9.5 */
+
+#if(SSLEAY_VERSION_NUMBER >= 0x900000)
+  return snprintf(buffer, size, "OpenSSL/%lx.%lx.%lx",
+                  (SSLEAY_VERSION_NUMBER>>28)&0xff,
+                  (SSLEAY_VERSION_NUMBER>>20)&0xff,
+                  (SSLEAY_VERSION_NUMBER>>12)&0xf);
+
+#else /* (SSLEAY_VERSION_NUMBER >= 0x900000) */
+  {
+    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(buffer, size, "SSL/%x.%x.%x%s",
+                    (SSLEAY_VERSION_NUMBER>>12)&0xff,
+                    (SSLEAY_VERSION_NUMBER>>8)&0xf,
+                    (SSLEAY_VERSION_NUMBER>>4)&0xf, sub);
+  }
+#endif /* (SSLEAY_VERSION_NUMBER >= 0x900000) */
+#endif /* SSLEAY_VERSION_NUMBER is less than 0.9.5 */
+
+#endif /* YASSL_VERSION */
+}
+#endif /* USE_SSLEAY */
diff --git a/lib/ssluse.h b/lib/ssluse.h
new file mode 100644
index 0000000..00357af
--- /dev/null
+++ b/lib/ssluse.h
@@ -0,0 +1,100 @@
+#ifndef __SSLUSE_H
+#define __SSLUSE_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+#ifdef USE_SSLEAY
+/*
+ * This header should only be needed to get included by sslgen.c and ssluse.c
+ */
+
+#include "urldata.h"
+CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex);
+CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn,
+                                       int sockindex,
+                                       bool *done);
+
+/* close a SSL connection */
+void Curl_ossl_close(struct connectdata *conn, int sockindex);
+
+/* tell OpenSSL to close down all open information regarding connections (and
+   thus session ID caching etc) */
+int Curl_ossl_close_all(struct SessionHandle *data);
+
+/* Sets an OpenSSL engine */
+CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine);
+
+/* function provided for the generic SSL-layer, called when a session id
+   should be freed */
+void Curl_ossl_session_free(void *ptr);
+
+/* Sets engine as default for all SSL operations */
+CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data);
+
+/* Build list of OpenSSL engines */
+struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data);
+
+int Curl_ossl_init(void);
+void Curl_ossl_cleanup(void);
+
+/* for documentation see Curl_ssl_send() in sslgen.h */
+ssize_t Curl_ossl_send(struct connectdata *conn,
+                       int sockindex,
+                       const void *mem,
+                       size_t len,
+                       int *curlcode);
+
+/* for documentation see Curl_ssl_recv() in sslgen.h */
+ssize_t Curl_ossl_recv(struct connectdata *conn, /* connection data */
+                       int num,                  /* socketindex */
+                       char *buf,                /* store read data here */
+                       size_t buffersize,        /* max amount to read */
+                       int *curlcode);
+
+size_t Curl_ossl_version(char *buffer, size_t size);
+int Curl_ossl_check_cxn(struct connectdata *cxn);
+int Curl_ossl_seed(struct SessionHandle *data);
+
+int Curl_ossl_shutdown(struct connectdata *conn, int sockindex);
+bool Curl_ossl_data_pending(const struct connectdata *conn,
+                            int connindex);
+
+/* API setup for OpenSSL */
+#define curlssl_init Curl_ossl_init
+#define curlssl_cleanup Curl_ossl_cleanup
+#define curlssl_connect Curl_ossl_connect
+#define curlssl_connect_nonblocking Curl_ossl_connect_nonblocking
+#define curlssl_session_free(x) Curl_ossl_session_free(x)
+#define curlssl_close_all Curl_ossl_close_all
+#define curlssl_close Curl_ossl_close
+#define curlssl_shutdown(x,y) Curl_ossl_shutdown(x,y)
+#define curlssl_set_engine(x,y) Curl_ossl_set_engine(x,y)
+#define curlssl_set_engine_default(x) Curl_ossl_set_engine_default(x)
+#define curlssl_engines_list(x) Curl_ossl_engines_list(x)
+#define curlssl_send Curl_ossl_send
+#define curlssl_recv Curl_ossl_recv
+#define curlssl_version Curl_ossl_version
+#define curlssl_check_cxn Curl_ossl_check_cxn
+#define curlssl_data_pending(x,y) Curl_ossl_data_pending(x,y)
+
+#endif /* USE_SSLEAY */
+#endif /* __SSLUSE_H */
diff --git a/lib/stamp-h1 b/lib/stamp-h1
new file mode 100644
index 0000000..8f5adb6
--- /dev/null
+++ b/lib/stamp-h1
@@ -0,0 +1 @@
+timestamp for lib/curl_config.h
diff --git a/lib/strdup.c b/lib/strdup.c
new file mode 100644
index 0000000..a3107cf
--- /dev/null
+++ b/lib/strdup.c
@@ -0,0 +1,49 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2008, 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 "strdup.h"
+
+#ifndef HAVE_STRDUP
+char *curlx_strdup(const char *str)
+{
+  size_t len;
+  char *newstr;
+
+  if(!str)
+    return (char *)NULL;
+
+  len = strlen(str);
+
+  if(len >= ((size_t)-1) / sizeof(char))
+    return (char *)NULL;
+
+  newstr = malloc((len+1)*sizeof(char));
+  if(!newstr)
+    return (char *)NULL;
+
+  memcpy(newstr,str,(len+1)*sizeof(char));
+
+  return newstr;
+
+}
+#endif
diff --git a/lib/strdup.h b/lib/strdup.h
new file mode 100644
index 0000000..4edbcd7
--- /dev/null
+++ b/lib/strdup.h
@@ -0,0 +1,30 @@
+#ifndef HEADER_CURL_STRDUP_H
+#define HEADER_CURL_STRDUP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+#ifndef HAVE_STRDUP
+extern char *curlx_strdup(const char *str);
+#endif
+
+#endif /* HEADER_CURL_STRDUP_H */
diff --git a/lib/strequal.c b/lib/strequal.c
new file mode 100644
index 0000000..f6bf5f3
--- /dev/null
+++ b/lib/strequal.c
@@ -0,0 +1,121 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 <string.h>
+#include <ctype.h>
+
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#include "strequal.h"
+
+int curl_strequal(const char *first, const char *second)
+{
+#if defined(HAVE_STRCASECMP)
+  return !(strcasecmp)(first, second);
+#elif defined(HAVE_STRCMPI)
+  return !(strcmpi)(first, second);
+#elif defined(HAVE_STRICMP)
+  return !(stricmp)(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_STRNCASECMP)
+  return !strncasecmp(first, second, max);
+#elif defined(HAVE_STRNCMPI)
+  return !strncmpi(first, second, max);
+#elif defined(HAVE_STRNICMP)
+  return !strnicmp(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
+}
+
+#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;
+  union {
+    ssize_t sig;
+     size_t uns;
+  } dlen;
+
+  /* Find the end of dst and adjust bytes left but don't go past end */
+  while(n-- != 0 && *d != '\0')
+    d++;
+  dlen.sig = d - dst;
+  n = siz - dlen.uns;
+
+  if(n == 0)
+    return(dlen.uns + strlen(s));
+  while(*s != '\0') {
+    if(n != 1) {
+      *d++ = *s;
+      n--;
+    }
+    s++;
+  }
+  *d = '\0';
+
+  return(dlen.uns + (s - src));     /* count does not include NUL */
+}
+#endif
diff --git a/lib/strequal.h b/lib/strequal.h
new file mode 100644
index 0000000..202c919
--- /dev/null
+++ b/lib/strequal.h
@@ -0,0 +1,35 @@
+#ifndef __STREQUAL_H
+#define __STREQUAL_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2008, 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 <curl/curl.h>
+
+#define strequal(a,b) curl_strequal(a,b)
+#define strnequal(a,b,c) curl_strnequal(a,b,c)
+
+#ifndef HAVE_STRLCAT
+#define strlcat(x,y,z) Curl_strlcat(x,y,z)
+#endif
+size_t strlcat(char *dst, const char *src, size_t siz);
+
+#endif
diff --git a/lib/strerror.c b/lib/strerror.c
new file mode 100644
index 0000000..673e89c
--- /dev/null
+++ b/lib/strerror.c
@@ -0,0 +1,769 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2004 - 2010, 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"
+
+#ifdef HAVE_STRERROR_R
+#  if (!defined(HAVE_POSIX_STRERROR_R) && \
+       !defined(HAVE_GLIBC_STRERROR_R) && \
+       !defined(HAVE_VXWORKS_STRERROR_R)) || \
+      (defined(HAVE_POSIX_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R)) || \
+      (defined(HAVE_GLIBC_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R)) || \
+      (defined(HAVE_POSIX_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R))
+#    error "strerror_r MUST be either POSIX-style, glibc-style or vxworks-style"
+#  endif
+#endif
+
+#include <curl/curl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef USE_LIBIDN
+#include <idna.h>
+#endif
+
+#include "strerror.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+
+const char *
+curl_easy_strerror(CURLcode error)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  switch (error) {
+  case CURLE_OK:
+    return "No error";
+
+  case CURLE_UNSUPPORTED_PROTOCOL:
+    return "Unsupported protocol";
+
+  case CURLE_FAILED_INIT:
+    return "Failed initialization";
+
+  case CURLE_URL_MALFORMAT:
+    return "URL using bad/illegal format or missing URL";
+
+  case CURLE_COULDNT_RESOLVE_PROXY:
+    return "Couldn't resolve proxy name";
+
+  case CURLE_COULDNT_RESOLVE_HOST:
+    return "Couldn't resolve host name";
+
+  case CURLE_COULDNT_CONNECT:
+    return "Couldn't connect to server";
+
+  case CURLE_FTP_WEIRD_SERVER_REPLY:
+    return "FTP: weird server reply";
+
+  case CURLE_REMOTE_ACCESS_DENIED:
+    return "Access denied to remote resource";
+
+  case CURLE_FTP_PRET_FAILED:
+    return "FTP: The server did not accept the PRET command.";
+
+  case CURLE_FTP_WEIRD_PASS_REPLY:
+    return "FTP: unknown PASS 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_COULDNT_SET_TYPE:
+    return "FTP: couldn't set file type";
+
+  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_QUOTE_ERROR:
+    return "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_UPLOAD_FAILED:
+    return "Upload failed (at start/before it took off)";
+
+  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_TIMEDOUT:
+    return "Timeout was reached";
+
+  case CURLE_FTP_PORT_FAILED:
+    return "FTP: command PORT failed";
+
+  case CURLE_FTP_COULDNT_USE_REST:
+    return "FTP: command REST failed";
+
+  case CURLE_RANGE_ERROR:
+    return "Requested range was not delivered by the server";
+
+  case CURLE_HTTP_POST_ERROR:
+    return "Internal problem setting up the POST";
+
+  case CURLE_SSL_CONNECT_ERROR:
+    return "SSL connect error";
+
+  case CURLE_BAD_DOWNLOAD_RESUME:
+    return "Couldn't resume 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_FUNCTION_NOT_FOUND:
+    return "A required function in the library was not found";
+
+  case CURLE_ABORTED_BY_CALLBACK:
+    return "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 telnet option";
+
+  case CURLE_TELNET_OPTION_SYNTAX :
+    return "Malformed telnet option";
+
+  case CURLE_PEER_FAILED_VERIFICATION:
+    return "SSL peer certificate or SSH remote key 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_SSL_ENGINE_INITFAILED:
+    return "Failed to initialise SSL crypto engine";
+
+  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_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 "Peer certificate cannot be authenticated with known CA certificates";
+
+  case CURLE_SSL_CACERT_BADFILE:
+    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_USE_SSL_FAILED:
+    return "Requested SSL level failed";
+
+  case CURLE_SSL_SHUTDOWN_FAILED:
+    return "Failed to shut down the SSL connection";
+
+  case CURLE_SSL_CRL_BADFILE:
+    return "Failed to load CRL file (path? access rights?, format?)";
+
+  case CURLE_SSL_ISSUER_ERROR:
+    return "Issuer check against peer certificate failed";
+
+  case CURLE_SEND_FAIL_REWIND:
+    return "Send failed since rewinding of the data stream failed";
+
+  case CURLE_LOGIN_DENIED:
+    return "Login denied";
+
+  case CURLE_TFTP_NOTFOUND:
+    return "TFTP: File Not Found";
+
+  case CURLE_TFTP_PERM:
+    return "TFTP: Access Violation";
+
+  case CURLE_REMOTE_DISK_FULL:
+    return "Disk full or allocation exceeded";
+
+  case CURLE_TFTP_ILLEGAL:
+    return "TFTP: Illegal operation";
+
+  case CURLE_TFTP_UNKNOWNID:
+    return "TFTP: Unknown transfer ID";
+
+  case CURLE_REMOTE_FILE_EXISTS:
+    return "Remote file already exists";
+
+  case CURLE_TFTP_NOSUCHUSER:
+    return "TFTP: No such user";
+
+  case CURLE_CONV_FAILED:
+    return "Conversion failed";
+
+  case CURLE_CONV_REQD:
+    return "Caller must register CURLOPT_CONV_ callback options";
+
+  case CURLE_REMOTE_FILE_NOT_FOUND:
+    return "Remote file not found";
+
+  case CURLE_SSH:
+    return "Error in the SSH layer";
+
+  case CURLE_AGAIN:
+    return "Socket not ready for send/recv";
+
+  case CURLE_RTSP_CSEQ_ERROR:
+    return "RTSP CSeq mismatch or invalid CSeq";
+
+  case CURLE_RTSP_SESSION_ERROR:
+    return "RTSP session error";
+
+    /* error codes not used by current libcurl */
+  case CURLE_OBSOLETE4:
+  case CURLE_OBSOLETE10:
+  case CURLE_OBSOLETE12:
+  case CURLE_OBSOLETE16:
+  case CURLE_OBSOLETE20:
+  case CURLE_OBSOLETE24:
+  case CURLE_OBSOLETE29:
+  case CURLE_OBSOLETE32:
+  case CURLE_OBSOLETE40:
+  case CURLE_OBSOLETE44:
+  case CURLE_OBSOLETE46:
+  case CURLE_OBSOLETE50:
+  case CURLE_OBSOLETE57:
+  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";
+#else
+  if(error == CURLE_OK)
+    return "No error";
+  else
+    return "Error";
+#endif
+}
+
+const char *
+curl_multi_strerror(CURLMcode error)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  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_BAD_SOCKET:
+    return "Invalid socket argument";
+
+  case CURLM_UNKNOWN_OPTION:
+    return "Unknown option";
+
+  case CURLM_LAST:
+    break;
+  }
+
+  return "Unknown error";
+#else
+  if(error == CURLM_OK)
+    return "No error";
+  else
+    return "Error";
+#endif
+}
+
+const char *
+curl_share_strerror(CURLSHcode error)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  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 "CURLSHcode unknown";
+#else
+  if(error == CURLSHE_OK)
+    return "No error";
+  else
+    return "Error";
+#endif
+}
+
+#ifdef USE_WINSOCK
+
+/* 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)
+{
+  const char *p;
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  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;
+#ifdef WSAEDISCON  /* missing in SalfordC! */
+  case WSAEDISCON:
+    p = "Disconnected";
+    break;
+#endif
+    /* Extended Winsock errors */
+  case WSASYSNOTREADY:
+    p = "Winsock library is not ready";
+    break;
+  case WSANOTINITIALISED:
+    p = "Winsock library not initialised";
+    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;
+  }
+#else
+  if(err == CURLE_OK)
+    return NULL;
+  else
+    p = "error";
+#endif
+  strncpy (buf, p, len);
+  buf [len-1] = '\0';
+  return buf;
+}
+#endif   /* USE_WINSOCK */
+
+/*
+ * 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" conversion 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;
+  int old_errno = ERRNO;
+
+  DEBUGASSERT(conn);
+  DEBUGASSERT(err >= 0);
+
+  buf = conn->syserr_buf;
+  max = sizeof(conn->syserr_buf)-1;
+  *buf = '\0';
+
+#ifdef USE_WINSOCK
+
+#ifdef _WIN32_WCE
+  {
+    wchar_t wbuf[256];
+    wbuf[0] = L'\0';
+
+    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
+                  LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL);
+    wcstombs(buf,wbuf,max);
+  }
+#else
+  /* '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, (DWORD)max, NULL))
+      snprintf(buf, max, "Unknown error %d (%#x)", err, err);
+  }
+#endif
+
+#else /* not USE_WINSOCK coming up */
+
+#if defined(HAVE_STRERROR_R) && defined(HAVE_POSIX_STRERROR_R)
+ /*
+  * The POSIX-style strerror_r() may set errno to ERANGE if insufficient
+  * storage is supplied via 'strerrbuf' and 'buflen' to hold the generated
+  * message string, or EINVAL if 'errnum' is not a valid error number.
+  */
+  if(0 != strerror_r(err, buf, max)) {
+    if('\0' == buf[0])
+      snprintf(buf, max, "Unknown error %d", err);
+  }
+#elif defined(HAVE_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R)
+ /*
+  * The glibc-style 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 non-NULL).
+  */
+  {
+    char buffer[256];
+    char *msg = strerror_r(err, buffer, sizeof(buffer));
+    if(msg)
+      strncpy(buf, msg, max);
+    else
+      snprintf(buf, max, "Unknown error %d", err);
+  }
+#elif defined(HAVE_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R)
+ /*
+  * The vxworks-style strerror_r() does use the buffer we pass to the function.
+  * The buffer size should be at least MAXERRSTR_SIZE (150) defined in rtsold.h
+  */
+  {
+    char buffer[256];
+    if(OK == strerror_r(err, buffer))
+      strncpy(buf, buffer, max);
+    else
+      snprintf(buf, max, "Unknown error %d", err);
+  }
+#else
+  {
+    char *msg = strerror(err);
+    if(msg)
+      strncpy(buf, msg, max);
+    else
+      snprintf(buf, max, "Unknown error %d", err);
+  }
+#endif
+
+#endif /* end of ! USE_WINSOCK */
+
+  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';
+
+  if(old_errno != ERRNO)
+    SET_ERRNO(old_errno);
+
+  return buf;
+}
+
+#ifdef USE_LIBIDN
+/*
+ * Return error-string for libidn status as returned from idna_to_ascii_lz().
+ */
+const char *Curl_idn_strerror (struct connectdata *conn, int err)
+{
+#ifdef HAVE_IDNA_STRERROR
+  (void)conn;
+  return idna_strerror((Idna_rc) err);
+#else
+  const char *str;
+  char *buf;
+  size_t max;
+
+  DEBUGASSERT(conn);
+
+  buf = conn->syserr_buf;
+  max = sizeof(conn->syserr_buf)-1;
+  *buf = '\0';
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  switch ((Idna_rc)err) {
+    case IDNA_SUCCESS:
+      str = "No error";
+      break;
+    case IDNA_STRINGPREP_ERROR:
+      str = "Error in string preparation";
+      break;
+    case IDNA_PUNYCODE_ERROR:
+      str = "Error in Punycode operation";
+      break;
+    case IDNA_CONTAINS_NON_LDH:
+      str = "Illegal ASCII characters";
+      break;
+    case IDNA_CONTAINS_MINUS:
+      str = "Contains minus";
+      break;
+    case IDNA_INVALID_LENGTH:
+      str = "Invalid output length";
+      break;
+    case IDNA_NO_ACE_PREFIX:
+      str = "No ACE prefix (\"xn--\")";
+      break;
+    case IDNA_ROUNDTRIP_VERIFY_ERROR:
+      str = "Round trip verify error";
+      break;
+    case IDNA_CONTAINS_ACE_PREFIX:
+      str = "Already have ACE prefix (\"xn--\")";
+      break;
+    case IDNA_ICONV_ERROR:
+      str = "Locale conversion failed";
+      break;
+    case IDNA_MALLOC_ERROR:
+      str = "Allocation failed";
+      break;
+    case IDNA_DLOPEN_ERROR:
+      str = "dlopen() error";
+      break;
+    default:
+      snprintf(buf, max, "error %d", err);
+      str = NULL;
+      break;
+  }
+#else
+  if((Idna_rc)err == IDNA_SUCCESS)
+    str = "No error";
+  else
+    str = "Error";
+#endif
+  if(str)
+    strncpy(buf, str, max);
+  buf[max] = '\0';
+  return (buf);
+#endif
+}
+#endif  /* USE_LIBIDN */
diff --git a/lib/strerror.h b/lib/strerror.h
new file mode 100644
index 0000000..7f2342a
--- /dev/null
+++ b/lib/strerror.h
@@ -0,0 +1,33 @@
+#ifndef __CURL_STRERROR_H
+#define __CURL_STRERROR_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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 "urldata.h"
+
+const char *Curl_strerror (struct connectdata *conn, int err);
+
+#ifdef USE_LIBIDN
+const char *Curl_idn_strerror (struct connectdata *conn, int err);
+#endif
+
+#endif
diff --git a/lib/strtok.c b/lib/strtok.c
new file mode 100644
index 0000000..91c2541
--- /dev/null
+++ b/lib/strtok.c
@@ -0,0 +1,67 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, 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"
+
+#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/lib/strtok.h b/lib/strtok.h
new file mode 100644
index 0000000..8baf779
--- /dev/null
+++ b/lib/strtok.h
@@ -0,0 +1,34 @@
+#ifndef HEADER_CURL_STRTOK_H
+#define HEADER_CURL_STRTOK_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 <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 /* HEADER_CURL_STRTOK_H */
diff --git a/lib/strtoofft.c b/lib/strtoofft.c
new file mode 100644
index 0000000..f75eb8a
--- /dev/null
+++ b/lib/strtoofft.c
@@ -0,0 +1,191 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, 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 "strtoofft.h"
+
+/*
+ * NOTE:
+ *
+ * In the ISO C standard (IEEE Std 1003.1), there is a strtoimax() function we
+ * could use in case strtoll() doesn't exist...  See
+ * http://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html
+ */
+
+#ifdef NEED_CURL_STRTOLL
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+/* Range tests can be used for alphanum decoding if characters are consecutive,
+   like in ASCII. Else an array is scanned. Determine this condition now. */
+
+#if('9' - '0') != 9 || ('Z' - 'A') != 25 || ('z' - 'a') != 25
+#include <string.h>
+
+#define NO_RANGE_TEST
+
+static const char valchars[] =
+            "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+#endif
+
+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(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 {
+    if(is_negative)
+      value = CURL_LLONG_MIN;
+    else
+      value = CURL_LLONG_MAX;
+
+    SET_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)
+{
+#ifndef NO_RANGE_TEST
+  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;
+  }
+#else
+  const char * cp;
+  int value;
+
+  cp = memchr(valchars, c, 10 + 26 + 26);
+
+  if(!cp)
+    return -1;
+
+  value = cp - valchars;
+
+  if(value >= 10 + 26)
+    value -= 26;                /* Lowercase. */
+#endif
+
+  if(value >= base) {
+    value = -1;
+  }
+
+  return value;
+}
+#endif  /* Only present if we need strtoll, but don't have it. */
diff --git a/lib/strtoofft.h b/lib/strtoofft.h
new file mode 100644
index 0000000..bf27a17
--- /dev/null
+++ b/lib/strtoofft.h
@@ -0,0 +1,63 @@
+#ifndef HEADER_CURL_STRTOOFFT_H
+#define HEADER_CURL_STRTOOFFT_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+/*
+ * Determine which string to integral data type conversion function we use
+ * to implement string conversion to our curl_off_t integral data type.
+ *
+ * Notice that curl_off_t might be 64 or 32 bit wide, and that it might use
+ * an undelying data type which might be 'long', 'int64_t', 'long long' or
+ * '__int64' and more remotely other data types.
+ *
+ * On systems where the size of curl_off_t is greater than the size of 'long'
+ * the conversion funtion to use is strtoll() if it is available, otherwise,
+ * we emulate its functionality with our own clone.
+ *
+ * On systems where the size of curl_off_t is smaller or equal than the size
+ * of 'long' the conversion funtion to use is strtol().
+ */
+
+#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
+#  ifdef HAVE_STRTOLL
+#    define curlx_strtoofft strtoll
+#  else
+#    if defined(_MSC_VER) && (_MSC_VER >= 1300) && (_INTEGRAL_MAX_BITS >= 64)
+       _CRTIMP __int64 __cdecl _strtoi64(const char *, char **, int);
+#      define curlx_strtoofft _strtoi64
+#    else
+       curl_off_t curlx_strtoll(const char *nptr, char **endptr, int base);
+#      define curlx_strtoofft curlx_strtoll
+#      define NEED_CURL_STRTOLL 1
+#    endif
+#  endif
+#else
+#  define curlx_strtoofft strtol
+#endif
+
+#define CURL_LLONG_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF)
+#define CURL_LLONG_MIN (-CURL_LLONG_MAX - CURL_OFF_T_C(1))
+
+#endif /* HEADER_CURL_STRTOOFFT_H */
diff --git a/lib/telnet.c b/lib/telnet.c
new file mode 100644
index 0000000..9409f49
--- /dev/null
+++ b/lib/telnet.c
@@ -0,0 +1,1519 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+#ifndef CURL_DISABLE_TELNET
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.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>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#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
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#endif  /* WIN32 */
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "telnet.h"
+#include "connect.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#define  TELOPTS
+#define  TELCMDS
+
+#include "arpa_telnet.h"
+#include "curl_memory.h"
+#include "select.h"
+#include "strequal.h"
+#include "rawstr.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 CURL_DISABLE_VERBOSE_STRINGS
+#define printoption(a,b,c,d)  do { } while(0)
+#endif
+
+#ifdef USE_WINSOCK
+typedef FARPROC WSOCK2_FUNC;
+static CURLcode check_wsock2 ( struct SessionHandle *data );
+#endif
+
+static
+CURLcode telrcv(struct connectdata *,
+                const unsigned char *inbuf, /* Data received from socket */
+                ssize_t count);             /* Number of bytes received */
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void printoption(struct SessionHandle *data,
+                        const char *direction,
+                        int cmd, int option);
+#endif
+
+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 *);
+
+static CURLcode telnet_do(struct connectdata *conn, bool *done);
+static CURLcode telnet_done(struct connectdata *conn,
+                                 CURLcode, bool premature);
+
+/* 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 */
+  unsigned char subbuffer[SUBBUFSIZE];
+  unsigned char *subpointer, *subend;      /* buffer for sub-options */
+
+  TelnetReceive telrcv_state;
+};
+
+
+/*
+ * TELNET protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_telnet = {
+  "TELNET",                             /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  telnet_do,                            /* do_it */
+  telnet_done,                          /* done */
+  ZERO_NULL,                            /* do_more */
+  ZERO_NULL,                            /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  PORT_TELNET,                          /* defport */
+  PROT_TELNET                           /* protocol */
+};
+
+
+#ifdef USE_WINSOCK
+static CURLcode
+check_wsock2 ( struct SessionHandle *data )
+{
+  int err;
+  WORD wVersionRequested;
+  WSADATA wsaData;
+
+  DEBUGASSERT(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 = calloc(1, sizeof(struct TELNET));
+  if(!tn)
+    return CURLE_OUT_OF_MEMORY;
+
+  conn->data->state.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->data->state.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);
+  }
+}
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+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))
+        infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
+      else
+        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)
+          infof(data, "%s %s %s\n", direction, fmt, opt);
+        else
+          infof(data, "%s %s %d\n", direction, fmt, option);
+      }
+      else
+        infof(data, "%s %d %d\n", direction, cmd, option);
+    }
+  }
+}
+#endif
+
+static void send_negotiation(struct connectdata *conn, int cmd, int option)
+{
+   unsigned char buf[3];
+   ssize_t bytes_written;
+   int err;
+   struct SessionHandle *data = conn->data;
+
+   buf[0] = CURL_IAC;
+   buf[1] = (unsigned char)cmd;
+   buf[2] = (unsigned char)option;
+
+   bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3);
+   if(bytes_written < 0) {
+     err = SOCKERRNO;
+     failf(data,"Sending data failed (%d)",err);
+   }
+
+   printoption(conn->data, "SENT", cmd, option);
+}
+
+static
+void set_remote_option(struct connectdata *conn, int option, int newstate)
+{
+  struct TELNET *tn = (struct TELNET *)conn->data->state.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->data->state.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->data->state.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->data->state.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->data->state.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->data->state.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)
+    {
+      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)
+        {
+          infof(data, "(terminated by ");
+          if(CURL_TELOPT_OK(i))
+            infof(data, "%s ", CURL_TELOPT(i));
+          else if(CURL_TELCMD_OK(i))
+            infof(data, "%s ", CURL_TELCMD(i));
+          else
+            infof(data, "%u ", i);
+          if(CURL_TELOPT_OK(j))
+            infof(data, "%s", CURL_TELOPT(j));
+          else if(CURL_TELCMD_OK(j))
+            infof(data, "%s", CURL_TELCMD(j));
+          else
+            infof(data, "%d", j);
+          infof(data, ", not IAC SE!) ");
+        }
+      }
+      length -= 2;
+    }
+    if(length < 1)
+    {
+      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:
+          infof(data, "%s", CURL_TELOPT(pointer[0]));
+          break;
+        default:
+          infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
+          break;
+      }
+    }
+    else
+      infof(data, "%d (unknown)", pointer[i]);
+
+    switch(pointer[1]) {
+      case CURL_TELQUAL_IS:
+        infof(data, " IS");
+        break;
+      case CURL_TELQUAL_SEND:
+        infof(data, " SEND");
+        break;
+      case CURL_TELQUAL_INFO:
+        infof(data, " INFO/REPLY");
+        break;
+      case CURL_TELQUAL_NAME:
+        infof(data, " NAME");
+        break;
+    }
+
+    switch(pointer[0]) {
+      case CURL_TELOPT_TTYPE:
+      case CURL_TELOPT_XDISPLOC:
+        pointer[length] = 0;
+        infof(data, " \"%s\"", &pointer[2]);
+        break;
+      case CURL_TELOPT_NEW_ENVIRON:
+        if(pointer[1] == CURL_TELQUAL_IS) {
+          infof(data, " ");
+          for(i = 3;i < length;i++) {
+            switch(pointer[i]) {
+              case CURL_NEW_ENV_VAR:
+                infof(data, ", ");
+                break;
+              case CURL_NEW_ENV_VALUE:
+                infof(data, " = ");
+                break;
+              default:
+                infof(data, "%c", pointer[i]);
+                break;
+            }
+          }
+        }
+        break;
+      default:
+        for (i = 2; i < length; i++)
+          infof(data, " %.2x", pointer[i]);
+        break;
+    }
+
+    if(direction)
+    {
+      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->data->state.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_raw_equal(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_raw_equal(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_raw_equal(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];
+  ssize_t bytes_written;
+  size_t len;
+  size_t tmplen;
+  int err;
+  char varname[128];
+  char varval[128];
+  struct SessionHandle *data = conn->data;
+  struct TELNET *tn = (struct TELNET *)data->state.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);
+      bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
+      if(bytes_written < 0) {
+        err = SOCKERRNO;
+        failf(data,"Sending data failed (%d)",err);
+      }
+      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);
+      bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
+      if(bytes_written < 0) {
+        err = SOCKERRNO;
+        failf(data,"Sending data failed (%d)",err);
+      }
+      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;
+      bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
+      if(bytes_written < 0) {
+        err = SOCKERRNO;
+        failf(data,"Sending data failed (%d)",err);
+      }
+      printsub(data, '>', &temp[2], len-2);
+      break;
+  }
+  return;
+}
+
+static
+CURLcode telrcv(struct connectdata *conn,
+                const unsigned char *inbuf, /* Data received from socket */
+                ssize_t count)              /* Number of bytes received */
+{
+  unsigned char c;
+  CURLcode result;
+  int in = 0;
+  int startwrite=-1;
+  struct SessionHandle *data = conn->data;
+  struct TELNET *tn = (struct TELNET *)data->state.proto.telnet;
+
+#define startskipping() \
+    if(startwrite >= 0) { \
+       result = Curl_client_write(conn, \
+                                  CLIENTWRITE_BODY, \
+                                  (char *)&inbuf[startwrite], \
+                                  in-startwrite); \
+      if(result != CURLE_OK) \
+        return result; \
+    } \
+    startwrite = -1
+
+#define writebyte() \
+    if(startwrite < 0) \
+      startwrite = in
+
+#define bufferflush() startskipping()
+
+  while(count--)
+  {
+    c = inbuf[in];
+
+    /*infof(data,"In rcv state %d char %d\n", tn->telrcv_state, c);*/
+    switch (tn->telrcv_state)
+    {
+      case CURL_TS_CR:
+        tn->telrcv_state = CURL_TS_DATA;
+        if(c == '\0')
+        {
+          startskipping();
+          break;   /* Ignore \0 after CR */
+        }
+        writebyte();
+        break;
+
+      case CURL_TS_DATA:
+        if(c == CURL_IAC)
+        {
+          tn->telrcv_state = CURL_TS_IAC;
+          startskipping();
+          break;
+        }
+        else if(c == '\r')
+        {
+          tn->telrcv_state = CURL_TS_CR;
+        }
+        writebyte();
+        break;
+
+      case CURL_TS_IAC:
+      process_iac:
+      DEBUGASSERT(startwrite < 0);
+      switch (c)
+      {
+        case CURL_WILL:
+          tn->telrcv_state = CURL_TS_WILL;
+          break;
+        case CURL_WONT:
+          tn->telrcv_state = CURL_TS_WONT;
+          break;
+        case CURL_DO:
+          tn->telrcv_state = CURL_TS_DO;
+          break;
+        case CURL_DONT:
+          tn->telrcv_state = CURL_TS_DONT;
+          break;
+        case CURL_SB:
+          CURL_SB_CLEAR(tn);
+          tn->telrcv_state = CURL_TS_SB;
+          break;
+        case CURL_IAC:
+          tn->telrcv_state = CURL_TS_DATA;
+          writebyte();
+          break;
+        case CURL_DM:
+        case CURL_NOP:
+        case CURL_GA:
+        default:
+          tn->telrcv_state = CURL_TS_DATA;
+          printoption(data, "RCVD", CURL_IAC, c);
+          break;
+      }
+      break;
+
+      case CURL_TS_WILL:
+        printoption(data, "RCVD", CURL_WILL, c);
+        tn->please_negotiate = 1;
+        rec_will(conn, c);
+        tn->telrcv_state = CURL_TS_DATA;
+        break;
+
+      case CURL_TS_WONT:
+        printoption(data, "RCVD", CURL_WONT, c);
+        tn->please_negotiate = 1;
+        rec_wont(conn, c);
+        tn->telrcv_state = CURL_TS_DATA;
+        break;
+
+      case CURL_TS_DO:
+        printoption(data, "RCVD", CURL_DO, c);
+        tn->please_negotiate = 1;
+        rec_do(conn, c);
+        tn->telrcv_state = CURL_TS_DATA;
+        break;
+
+      case CURL_TS_DONT:
+        printoption(data, "RCVD", CURL_DONT, c);
+        tn->please_negotiate = 1;
+        rec_dont(conn, c);
+        tn->telrcv_state = CURL_TS_DATA;
+        break;
+
+      case CURL_TS_SB:
+        if(c == CURL_IAC)
+        {
+          tn->telrcv_state = CURL_TS_SE;
+        }
+        else
+        {
+          CURL_SB_ACCUM(tn,c);
+        }
+        break;
+
+      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, 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, CURL_IAC);
+          CURL_SB_ACCUM(tn, CURL_SE);
+          tn->subpointer -= 2;
+          CURL_SB_TERM(tn);
+          suboption(conn);   /* handle sub-option */
+          tn->telrcv_state = CURL_TS_DATA;
+        }
+        break;
+    }
+    ++in;
+  }
+  bufferflush();
+  return CURLE_OK;
+}
+
+/* Escape and send a telnet data block */
+/* TODO: write large chunks of data instead of one byte at a time */
+static CURLcode send_telnet_data(struct connectdata *conn,
+                                 char *buffer, ssize_t nread)
+{
+  unsigned char outbuf[2];
+  ssize_t bytes_written, total_written;
+  int out_count;
+  CURLcode rc = CURLE_OK;
+
+  while(rc == CURLE_OK && nread--) {
+    outbuf[0] = *buffer++;
+    out_count = 1;
+    if(outbuf[0] == CURL_IAC)
+      outbuf[out_count++] = CURL_IAC;
+
+    total_written = 0;
+    do {
+      /* Make sure socket is writable to avoid EWOULDBLOCK condition */
+      struct pollfd pfd[1];
+      pfd[0].fd = conn->sock[FIRSTSOCKET];
+      pfd[0].events = POLLOUT;
+      switch (Curl_poll(pfd, 1, -1)) {
+        case -1:                    /* error, abort writing */
+        case 0:                     /* timeout (will never happen) */
+          rc = CURLE_SEND_ERROR;
+          break;
+        default:                    /* write! */
+          bytes_written = 0;
+          rc = Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf+total_written,
+                          out_count-total_written, &bytes_written);
+          total_written += bytes_written;
+          break;
+      }
+    /* handle partial write */
+    } while (rc == CURLE_OK && total_written < out_count);
+  }
+  return rc;
+}
+
+static CURLcode telnet_done(struct connectdata *conn,
+                                 CURLcode status, bool premature)
+{
+  struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet;
+  (void)status; /* unused */
+  (void)premature; /* not used */
+
+  curl_slist_free_all(tn->telnet_vars);
+
+  free(conn->data->state.proto.telnet);
+  conn->data->state.proto.telnet = NULL;
+
+  return CURLE_OK;
+}
+
+static CURLcode telnet_do(struct connectdata *conn, bool *done)
+{
+  CURLcode code;
+  struct SessionHandle *data = conn->data;
+  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+#ifdef USE_WINSOCK
+  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;
+  int err;
+#else
+  int interval_ms;
+  struct pollfd pfd[2];
+#endif
+  int ret;
+  ssize_t nread;
+  struct timeval now;
+  bool keepon = TRUE;
+  char *buf = data->state.buffer;
+  struct TELNET *tn;
+
+  *done = TRUE; /* unconditionally */
+
+  code = init_telnet(conn);
+  if(code)
+    return code;
+
+  tn = (struct TELNET *)data->state.proto.telnet;
+
+  code = check_telnet_options(conn);
+  if(code)
+    return code;
+
+#ifdef USE_WINSOCK
+  /*
+  ** 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)", ERRNO);
+    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)",
+          ERRNO);
+    FreeLibrary(wsock2);
+    return CURLE_FAILED_INIT;
+  }
+
+  /* And WSACloseEvent */
+  close_event_func = GetProcAddress(wsock2,"WSACloseEvent");
+  if(close_event_func == NULL) {
+    failf(data,"failed to find WSACloseEvent function (%d)",
+          ERRNO);
+    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)",
+          ERRNO);
+    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)",
+          ERRNO);
+    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)", SOCKERRNO);
+    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 CURLE_OK;
+  }
+
+  /* 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 = 1000;
+  }
+
+  /* Keep on listening and act on events */
+  while(keepon) {
+    waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
+    switch(waitret) {
+    case WAIT_TIMEOUT:
+    {
+      for(;;) {
+        if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) {
+          keepon = FALSE;
+          code = CURLE_READ_ERROR;
+          break;
+        }
+
+        if(!readfile_read)
+          break;
+
+        if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
+                     &readfile_read, NULL)) {
+          keepon = FALSE;
+          code = CURLE_READ_ERROR;
+          break;
+        }
+
+        code = send_telnet_data(conn, buf, readfile_read);
+        if(code) {
+          keepon = FALSE;
+          break;
+        }
+      }
+    }
+    break;
+
+    case WAIT_OBJECT_0 + 1:
+    {
+      if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
+                   &readfile_read, NULL)) {
+        keepon = FALSE;
+        code = CURLE_READ_ERROR;
+        break;
+      }
+
+      code = send_telnet_data(conn, buf, readfile_read);
+      if(code) {
+        keepon = FALSE;
+        break;
+      }
+    }
+    break;
+
+    case WAIT_OBJECT_0:
+
+      if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) {
+        if((err = SOCKERRNO) != EINPROGRESS) {
+          infof(data,"WSAEnumNetworkEvents failed (%d)", err);
+          keepon = FALSE;
+          code = CURLE_READ_ERROR;
+        }
+        break;
+      }
+      if(events.lNetworkEvents & FD_READ) {
+        /* read data from network */
+        ret = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
+        /* returned sub-zero, this would've blocked. Loop again */
+        if(ret < 0)
+          break;
+        /* returned not-zero, this an error */
+        else if(ret) {
+          keepon = FALSE;
+          code = (CURLcode)ret;
+          break;
+        }
+        /* returned zero but actually received 0 or less here,
+           the server closed the connection and we bail out */
+        else if(nread <= 0) {
+          keepon = FALSE;
+          break;
+        }
+
+        code = telrcv(conn, (unsigned char *)buf, nread);
+        if(code) {
+          keepon = FALSE;
+          break;
+        }
+
+        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;
+
+    }
+
+    if(data->set.timeout) {
+      now = Curl_tvnow();
+      if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
+        failf(data, "Time-out");
+        code = CURLE_OPERATION_TIMEDOUT;
+        keepon = FALSE;
+      }
+    }
+  }
+
+  /* We called WSACreateEvent, so call WSACloseEvent */
+  if(close_event_func(event_handle) == FALSE) {
+    infof(data,"WSACloseEvent failed (%d)", SOCKERRNO);
+  }
+
+  /* "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;
+
+  /* We called LoadLibrary, so call FreeLibrary */
+  if(!FreeLibrary(wsock2))
+    infof(data,"FreeLibrary(wsock2) failed (%d)", ERRNO);
+#else
+  pfd[0].fd = sockfd;
+  pfd[0].events = POLLIN;
+  pfd[1].fd = 0;
+  pfd[1].events = POLLIN;
+  interval_ms = 1 * 1000;
+
+  while(keepon) {
+    switch (Curl_poll(pfd, 2, interval_ms)) {
+    case -1:                    /* error, stop reading */
+      keepon = FALSE;
+      continue;
+    case 0:                     /* timeout */
+      break;
+    default:                    /* read! */
+      if(pfd[1].revents & POLLIN) { /* read from stdin */
+        nread = read(0, buf, 255);
+        code = send_telnet_data(conn, buf, nread);
+        if(code) {
+          keepon = FALSE;
+          break;
+        }
+      }
+
+      if(pfd[0].revents & POLLIN) {
+        /* read data from network */
+        ret = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
+        /* returned sub-zero, this would've blocked. Loop again */
+        if(ret < 0)
+          break;
+        /* returned not-zero, this an error */
+        else if(ret) {
+          keepon = FALSE;
+          code = (CURLcode)ret;
+          break;
+        }
+        /* returned zero but actually received 0 or less here,
+           the server closed the connection and we bail out */
+        else if(nread <= 0) {
+          keepon = FALSE;
+          break;
+        }
+
+        code = telrcv(conn, (unsigned char *)buf, nread);
+        if(code) {
+          keepon = FALSE;
+          break;
+        }
+
+        /* 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) {
+      now = Curl_tvnow();
+      if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
+        failf(data, "Time-out");
+        code = CURLE_OPERATION_TIMEDOUT;
+        keepon = FALSE;
+      }
+    }
+  }
+#endif
+  /* mark this as "no further transfer wanted" */
+  Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+
+  return code;
+}
+#endif
diff --git a/lib/telnet.h b/lib/telnet.h
new file mode 100644
index 0000000..f00f7fd
--- /dev/null
+++ b/lib/telnet.h
@@ -0,0 +1,28 @@
+#ifndef __TELNET_H
+#define __TELNET_H
+
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, 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.
+ *
+ ***************************************************************************/
+#ifndef CURL_DISABLE_TELNET
+extern const struct Curl_handler Curl_handler_telnet;
+#endif
+#endif
diff --git a/lib/tftp.c b/lib/tftp.c
new file mode 100644
index 0000000..dc21c54
--- /dev/null
+++ b/lib/tftp.c
@@ -0,0 +1,1493 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+#ifndef CURL_DISABLE_TFTP
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.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>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#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
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#endif /* WIN32 */
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "tftp.h"
+#include "progress.h"
+#include "connect.h"
+#include "strerror.h"
+#include "sockaddr.h" /* required for Curl_sockaddr_storage */
+#include "multiif.h"
+#include "url.h"
+#include "rawstr.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+#include "select.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* RFC2348 allows the block size to be negotiated */
+#define TFTP_BLKSIZE_DEFAULT 512
+#define TFTP_BLKSIZE_MIN 8
+#define TFTP_BLKSIZE_MAX 65464
+#define TFTP_OPTION_BLKSIZE "blksize"
+#define TFTP_OPTION_TSIZE "tsize"
+#define TFTP_OPTION_INTERVAL "interval"
+
+typedef enum {
+  TFTP_MODE_NETASCII=0,
+  TFTP_MODE_OCTET
+} tftp_mode_t;
+
+typedef enum {
+  TFTP_STATE_START=0,
+  TFTP_STATE_RX,
+  TFTP_STATE_TX,
+  TFTP_STATE_FIN
+} tftp_state_t;
+
+typedef enum {
+  TFTP_EVENT_NONE = -1,
+  TFTP_EVENT_INIT = 0,
+  TFTP_EVENT_RRQ = 1,
+  TFTP_EVENT_WRQ = 2,
+  TFTP_EVENT_DATA = 3,
+  TFTP_EVENT_ACK = 4,
+  TFTP_EVENT_ERROR = 5,
+  TFTP_EVENT_OACK = 6,
+  TFTP_EVENT_TIMEOUT
+} tftp_event_t;
+
+typedef enum {
+  TFTP_ERR_UNDEF=0,
+  TFTP_ERR_NOTFOUND,
+  TFTP_ERR_PERM,
+  TFTP_ERR_DISKFULL,
+  TFTP_ERR_ILLEGAL,
+  TFTP_ERR_UNKNOWNID,
+  TFTP_ERR_EXISTS,
+  TFTP_ERR_NOSUCHUSER,  /* This will never be triggered by this code */
+
+  /* The remaining error codes are internal to curl */
+  TFTP_ERR_NONE = -100,
+  TFTP_ERR_TIMEOUT,
+  TFTP_ERR_NORESPONSE
+} tftp_error_t;
+
+typedef struct tftp_packet {
+  unsigned char *data;
+} tftp_packet_t;
+
+typedef struct tftp_state_data {
+  tftp_state_t    state;
+  tftp_mode_t     mode;
+  tftp_error_t    error;
+  tftp_event_t    event;
+  struct connectdata      *conn;
+  curl_socket_t   sockfd;
+  int             retries;
+  int             retry_time;
+  int             retry_max;
+  time_t          start_time;
+  time_t          max_time;
+  time_t          rx_time;
+  unsigned short  block;
+  struct Curl_sockaddr_storage   local_addr;
+  struct Curl_sockaddr_storage   remote_addr;
+  curl_socklen_t  remote_addrlen;
+  int             rbytes;
+  int             sbytes;
+  int             blksize;
+  int             requested_blksize;
+  tftp_packet_t   rpacket;
+  tftp_packet_t   spacket;
+} tftp_state_data_t;
+
+
+/* Forward declarations */
+static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) ;
+static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) ;
+static CURLcode tftp_connect(struct connectdata *conn, bool *done);
+static CURLcode tftp_disconnect(struct connectdata *conn);
+static CURLcode tftp_do(struct connectdata *conn, bool *done);
+static CURLcode tftp_done(struct connectdata *conn,
+                               CURLcode, bool premature);
+static CURLcode tftp_setup_connection(struct connectdata * conn);
+static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done);
+static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done);
+static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks,
+                        int numsocks);
+static CURLcode tftp_translate_code(tftp_error_t error);
+
+
+/*
+ * TFTP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_tftp = {
+  "TFTP",                               /* scheme */
+  tftp_setup_connection,                /* setup_connection */
+  tftp_do,                              /* do_it */
+  tftp_done,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  tftp_connect,                         /* connect_it */
+  tftp_multi_statemach,                 /* connecting */
+  tftp_doing,                           /* doing */
+  tftp_getsock,                         /* proto_getsock */
+  tftp_getsock,                         /* doing_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  tftp_disconnect,                      /* disconnect */
+  PORT_TFTP,                            /* defport */
+  PROT_TFTP                             /* protocol */
+};
+
+/**********************************************************
+ *
+ * tftp_set_timeouts -
+ *
+ * Set timeouts based on state machine state.
+ * Use user provided connect timeouts until DATA or ACK
+ * packet is received, then use user-provided transfer timeouts
+ *
+ *
+ **********************************************************/
+static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
+{
+  time_t maxtime, timeout;
+  long timeout_ms;
+  bool start = (bool)(state->state == TFTP_STATE_START);
+
+  time(&state->start_time);
+
+  /* Compute drop-dead time */
+  timeout_ms = Curl_timeleft(state->conn, NULL, start);
+
+  if(timeout_ms < 0) {
+    /* time-out, bail out, go home */
+    failf(state->conn->data, "Connection time-out");
+    return CURLE_OPERATION_TIMEDOUT;
+  }
+
+  if(start) {
+
+    maxtime = (time_t)(timeout_ms + 500) / 1000;
+    state->max_time = state->start_time+maxtime;
+
+    /* Set per-block timeout to total */
+    timeout = maxtime ;
+
+    /* Average restart after 5 seconds */
+    state->retry_max = (int)timeout/5;
+
+    if(state->retry_max < 1)
+      /* avoid division by zero below */
+      state->retry_max = 1;
+
+    /* Compute the re-start interval to suit the timeout */
+    state->retry_time = (int)timeout/state->retry_max;
+    if(state->retry_time<1)
+      state->retry_time=1;
+
+  }
+  else {
+    if(timeout_ms > 0)
+      maxtime = (time_t)(timeout_ms + 500) / 1000;
+    else
+      maxtime = 3600;
+
+    state->max_time = state->start_time+maxtime;
+
+    /* Set per-block timeout to 10% of total */
+    timeout = maxtime/10 ;
+
+    /* Average reposting an ACK after 15 seconds */
+    state->retry_max = (int)timeout/15;
+  }
+  /* But bound the total number */
+  if(state->retry_max<3)
+    state->retry_max=3;
+
+  if(state->retry_max>50)
+    state->retry_max=50;
+
+  /* Compute the re-ACK interval to suit the timeout */
+  state->retry_time = (int)(timeout/state->retry_max);
+  if(state->retry_time<1)
+    state->retry_time=1;
+
+  infof(state->conn->data,
+        "set timeouts for state %d; Total %ld, retry %d maxtry %d\n",
+        (int)state->state, (long)(state->max_time-state->start_time),
+        state->retry_time, state->retry_max);
+
+  /* init RX time */
+  time(&state->rx_time);
+
+  return CURLE_OK;
+}
+
+/**********************************************************
+ *
+ * tftp_set_send_first
+ *
+ * Event handler for the START state
+ *
+ **********************************************************/
+
+static void setpacketevent(tftp_packet_t *packet, unsigned short num)
+{
+  packet->data[0] = (unsigned char)(num >> 8);
+  packet->data[1] = (unsigned char)(num & 0xff);
+}
+
+
+static void setpacketblock(tftp_packet_t *packet, unsigned short num)
+{
+  packet->data[2] = (unsigned char)(num >> 8);
+  packet->data[3] = (unsigned char)(num & 0xff);
+}
+
+static unsigned short getrpacketevent(const tftp_packet_t *packet)
+{
+  return (unsigned short)((packet->data[0] << 8) | packet->data[1]);
+}
+
+static unsigned short getrpacketblock(const tftp_packet_t *packet)
+{
+  return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
+}
+
+static size_t Curl_strnlen(const char *string, size_t maxlen)
+{
+  const char *end = memchr (string, '\0', maxlen);
+  return end ? (size_t) (end - string) : maxlen;
+}
+
+static const char *tftp_option_get(const char *buf, size_t len,
+                                   const char **option, const char **value)
+{
+  size_t loc;
+
+  loc = Curl_strnlen( buf, len );
+  loc++; /* NULL term */
+
+  if (loc >= len)
+    return NULL;
+  *option = buf;
+
+  loc += Curl_strnlen( buf+loc, len-loc );
+  loc++; /* NULL term */
+
+  if (loc > len)
+    return NULL;
+  *value = &buf[strlen(*option) + 1];
+
+  return &buf[loc];
+}
+
+static CURLcode tftp_parse_option_ack(tftp_state_data_t *state,
+                                      const char *ptr, int len)
+{
+  const char *tmp = ptr;
+  struct SessionHandle *data = state->conn->data;
+
+  /* if OACK doesn't contain blksize option, the default (512) must be used */
+  state->blksize = TFTP_BLKSIZE_DEFAULT;
+
+  while (tmp < ptr + len) {
+    const char *option, *value;
+
+    tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value);
+    if(tmp == NULL) {
+      failf(data, "Malformed ACK packet, rejecting");
+      return CURLE_TFTP_ILLEGAL;
+    }
+
+    infof(data, "got option=(%s) value=(%s)\n", option, value);
+
+    if(checkprefix(option, TFTP_OPTION_BLKSIZE)) {
+      long blksize;
+
+      blksize = strtol( value, NULL, 10 );
+
+      if(!blksize) {
+        failf(data, "invalid blocksize value in OACK packet");
+        return CURLE_TFTP_ILLEGAL;
+      }
+      else if(blksize > TFTP_BLKSIZE_MAX) {
+        failf(data, "%s (%d)", "blksize is larger than max supported",
+                TFTP_BLKSIZE_MAX);
+        return CURLE_TFTP_ILLEGAL;
+      }
+      else if(blksize < TFTP_BLKSIZE_MIN) {
+        failf(data, "%s (%d)", "blksize is smaller than min supported",
+                TFTP_BLKSIZE_MIN);
+        return CURLE_TFTP_ILLEGAL;
+      }
+      else if (blksize > state->requested_blksize) {
+        /* could realloc pkt buffers here, but the spec doesn't call out
+         * support for the server requesting a bigger blksize than the client
+         * requests */
+        failf(data, "%s (%ld)",
+                "server requested blksize larger than allocated", blksize);
+        return CURLE_TFTP_ILLEGAL;
+      }
+
+      state->blksize = (int)blksize;
+      infof(data, "%s (%d) %s (%d)\n", "blksize parsed from OACK",
+        state->blksize, "requested", state->requested_blksize);
+    }
+    else if(checkprefix(option, TFTP_OPTION_TSIZE)) {
+      long tsize = 0;
+
+      tsize = strtol( value, NULL, 10 );
+      infof(data, "%s (%ld)\n", "tsize parsed from OACK", tsize);
+
+      /* tsize should be ignored on upload: Who cares about the size of the
+         remote file? */
+      if (!data->set.upload) {
+        if(!tsize) {
+          failf(data, "invalid tsize -:%s:- value in OACK packet", value);
+          return CURLE_TFTP_ILLEGAL;
+        }
+        Curl_pgrsSetDownloadSize(data, tsize);
+      }
+    }
+  }
+
+  return CURLE_OK;
+}
+
+static size_t tftp_option_add(tftp_state_data_t *state, size_t csize,
+                              char *buf, const char *option)
+{
+  if( ( strlen(option) + csize + 1 ) > (size_t)state->blksize )
+    return 0;
+  strcpy(buf, option);
+  return( strlen(option) + 1 );
+}
+
+static CURLcode tftp_connect_for_tx(tftp_state_data_t *state,
+                                    tftp_event_t event)
+{
+  CURLcode res;
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  struct SessionHandle *data = state->conn->data;
+
+  infof(data, "%s\n", "Connected for transmit");
+#endif
+  state->state = TFTP_STATE_TX;
+  res = tftp_set_timeouts(state);
+  if(res != CURLE_OK)
+    return(res);
+  return tftp_tx(state, event);
+}
+
+static CURLcode tftp_connect_for_rx(tftp_state_data_t *state,
+                                    tftp_event_t event)
+{
+  CURLcode res;
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  struct SessionHandle *data = state->conn->data;
+
+  infof(data, "%s\n", "Connected for receive");
+#endif
+  state->state = TFTP_STATE_RX;
+  res = tftp_set_timeouts(state);
+  if(res != CURLE_OK)
+    return(res);
+  return tftp_rx(state, event);
+}
+
+static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
+{
+  size_t sbytes;
+  ssize_t senddata;
+  const char *mode = "octet";
+  char *filename;
+  char buf[64];
+  struct SessionHandle *data = state->conn->data;
+  CURLcode res = CURLE_OK;
+
+  /* Set ascii mode if -B flag was used */
+  if(data->set.prefer_ascii)
+    mode = "netascii";
+
+  switch(event) {
+
+  case TFTP_EVENT_INIT:    /* Send the first packet out */
+  case TFTP_EVENT_TIMEOUT: /* Resend the first packet out */
+    /* Increment the retry counter, quit if over the limit */
+    state->retries++;
+    if(state->retries>state->retry_max) {
+      state->error = TFTP_ERR_NORESPONSE;
+      state->state = TFTP_STATE_FIN;
+      return res;
+    }
+
+    if(data->set.upload) {
+      /* If we are uploading, send an WRQ */
+      setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
+      state->conn->data->req.upload_fromhere =
+        (char *)state->spacket.data+4;
+      if(data->set.infilesize != -1)
+        Curl_pgrsSetUploadSize(data, data->set.infilesize);
+    }
+    else {
+      /* If we are downloading, send an RRQ */
+      setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
+    }
+    /* As RFC3617 describes the separator slash is not actually part of the
+       file name so we skip the always-present first letter of the path
+       string. */
+    filename = curl_easy_unescape(data, &state->conn->data->state.path[1], 0,
+                                  NULL);
+    if(!filename)
+      return CURLE_OUT_OF_MEMORY;
+
+    snprintf((char *)state->spacket.data+2,
+             state->blksize,
+             "%s%c%s%c", filename, '\0',  mode, '\0');
+    sbytes = 4 + strlen(filename) + strlen(mode);
+
+    /* add tsize option */
+    if(data->set.upload && (data->set.infilesize != -1))
+      snprintf( buf, sizeof(buf), "%" FORMAT_OFF_T, data->set.infilesize );
+    else
+      strcpy(buf, "0"); /* the destination is large enough */
+
+    sbytes += tftp_option_add(state, sbytes,
+                              (char *)state->spacket.data+sbytes,
+                              TFTP_OPTION_TSIZE);
+    sbytes += tftp_option_add(state, sbytes,
+                              (char *)state->spacket.data+sbytes, buf);
+    /* add blksize option */
+    snprintf( buf, sizeof(buf), "%d", state->requested_blksize );
+    sbytes += tftp_option_add(state, sbytes,
+                              (char *)state->spacket.data+sbytes,
+                              TFTP_OPTION_BLKSIZE);
+    sbytes += tftp_option_add(state, sbytes,
+                              (char *)state->spacket.data+sbytes, buf );
+    /* add timeout option, this is the max time the session may live */
+    snprintf( buf, sizeof(buf), "%d", state->retry_time*state->retry_max );
+    sbytes += tftp_option_add(state, sbytes,
+                              (char *)state->spacket.data+sbytes,
+                              TFTP_OPTION_INTERVAL);
+    sbytes += tftp_option_add(state, sbytes,
+                              (char *)state->spacket.data+sbytes, buf );
+
+    senddata = sendto(state->sockfd, (void *)state->spacket.data,
+                    sbytes, 0,
+                    state->conn->ip_addr->ai_addr,
+                    state->conn->ip_addr->ai_addrlen);
+    if(senddata != (ssize_t)sbytes) {
+      failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+    }
+    Curl_safefree(filename);
+    break;
+
+  case TFTP_EVENT_OACK:
+    if(data->set.upload) {
+      res = tftp_connect_for_tx(state, event);
+    }
+    else {
+      res = tftp_connect_for_rx(state, event);
+    }
+    break;
+
+  case TFTP_EVENT_ACK: /* Connected for transmit */
+    res = tftp_connect_for_tx(state, event);
+    break;
+
+  case TFTP_EVENT_DATA: /* Connected for receive */
+    res = tftp_connect_for_rx(state, event);
+    break;
+
+  case TFTP_EVENT_ERROR:
+    state->state = TFTP_STATE_FIN;
+    break;
+
+  default:
+    failf(state->conn->data, "tftp_send_first: internal error");
+    break;
+  }
+  return res;
+}
+
+/**********************************************************
+ *
+ * tftp_rx
+ *
+ * Event handler for the RX state
+ *
+ **********************************************************/
+static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
+{
+  ssize_t sbytes;
+  int rblock;
+  struct SessionHandle *data = state->conn->data;
+
+  switch(event) {
+
+  case TFTP_EVENT_DATA:
+    /* Is this the block we expect? */
+    rblock = getrpacketblock(&state->rpacket);
+    if((state->block+1) != rblock) {
+      /* No, log it, up the retry count and fail if over the limit */
+      infof(data,
+            "Received unexpected DATA packet block %d\n", rblock);
+      state->retries++;
+      if(state->retries>state->retry_max) {
+        failf(data, "tftp_rx: giving up waiting for block %d",
+              state->block+1);
+        return CURLE_TFTP_ILLEGAL;
+      }
+    }
+    /* This is the expected block.  Reset counters and ACK it. */
+    state->block = (unsigned short)rblock;
+    state->retries = 0;
+    setpacketevent(&state->spacket, TFTP_EVENT_ACK);
+    setpacketblock(&state->spacket, state->block);
+    sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+                    4, SEND_4TH_ARG,
+                    (struct sockaddr *)&state->remote_addr,
+                    state->remote_addrlen);
+    if(sbytes < 0) {
+      failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+      return CURLE_SEND_ERROR;
+    }
+
+    /* Check if completed (That is, a less than full packet is received) */
+    if(state->rbytes < (ssize_t)state->blksize+4){
+      state->state = TFTP_STATE_FIN;
+    }
+    else {
+      state->state = TFTP_STATE_RX;
+    }
+    time(&state->rx_time);
+    break;
+
+  case TFTP_EVENT_OACK:
+    /* ACK option acknowledgement so we can move on to data */
+    state->block = 0;
+    state->retries = 0;
+    setpacketevent(&state->spacket, TFTP_EVENT_ACK);
+    setpacketblock(&state->spacket, state->block);
+    sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+                    4, SEND_4TH_ARG,
+                    (struct sockaddr *)&state->remote_addr,
+                    state->remote_addrlen);
+    if(sbytes < 0) {
+      failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+      return CURLE_SEND_ERROR;
+    }
+
+    /* we're ready to RX data */
+    state->state = TFTP_STATE_RX;
+    time(&state->rx_time);
+    break;
+
+  case TFTP_EVENT_TIMEOUT:
+    /* Increment the retry count and fail if over the limit */
+    state->retries++;
+    infof(data,
+          "Timeout waiting for block %d ACK.  Retries = %d\n",
+          state->block+1, state->retries);
+    if(state->retries > state->retry_max) {
+      state->error = TFTP_ERR_TIMEOUT;
+      state->state = TFTP_STATE_FIN;
+    }
+    else {
+      /* Resend the previous ACK */
+      sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+                      4, SEND_4TH_ARG,
+                      (struct sockaddr *)&state->remote_addr,
+                      state->remote_addrlen);
+      /* Check all sbytes were sent */
+      if(sbytes<0) {
+        failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+        return CURLE_SEND_ERROR;
+      }
+    }
+    break;
+
+  case TFTP_EVENT_ERROR:
+    setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
+    setpacketblock(&state->spacket, state->block);
+    sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+                    4, SEND_4TH_ARG,
+                    (struct sockaddr *)&state->remote_addr,
+                    state->remote_addrlen);
+    /* don't bother with the return code, but if the socket is still up we
+     * should be a good TFTP client and let the server know we're done */
+    state->state = TFTP_STATE_FIN;
+    break;
+
+  default:
+    failf(data, "%s", "tftp_rx: internal error");
+    return CURLE_TFTP_ILLEGAL; /* not really the perfect return code for
+                                  this */
+  }
+  return CURLE_OK;
+}
+
+/**********************************************************
+ *
+ * tftp_tx
+ *
+ * Event handler for the TX state
+ *
+ **********************************************************/
+static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
+{
+  struct SessionHandle *data = state->conn->data;
+  ssize_t sbytes;
+  int rblock;
+  CURLcode res = CURLE_OK;
+  struct SingleRequest *k = &data->req;
+
+  switch(event) {
+
+  case TFTP_EVENT_ACK:
+  case TFTP_EVENT_OACK:
+    if (event == TFTP_EVENT_ACK) {
+       /* Ack the packet */
+       rblock = getrpacketblock(&state->rpacket);
+
+       if(rblock != state->block) {
+          /* This isn't the expected block.  Log it and up the retry counter */
+          infof(data, "Received ACK for block %d, expecting %d\n",
+                rblock, state->block);
+          state->retries++;
+          /* Bail out if over the maximum */
+          if(state->retries>state->retry_max) {
+             failf(data, "tftp_tx: giving up waiting for block %d ack",
+                   state->block);
+             res = CURLE_SEND_ERROR;
+          }
+          else {
+             /* Re-send the data packet */
+             sbytes = sendto(state->sockfd, (void *)&state->spacket,
+                             4+state->sbytes, SEND_4TH_ARG,
+                             (struct sockaddr *)&state->remote_addr,
+                             state->remote_addrlen);
+             /* Check all sbytes were sent */
+             if(sbytes<0) {
+                failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+                res = CURLE_SEND_ERROR;
+             }
+          }
+          return res;
+       }
+       /* This is the expected packet.  Reset the counters and send the next
+          block */
+       time(&state->rx_time);
+       state->block++;
+    }
+    else {
+       state->block = 1; /* first data block is 1 when using OACK */
+    }
+    state->retries = 0;
+    setpacketevent(&state->spacket, TFTP_EVENT_DATA);
+    setpacketblock(&state->spacket, state->block);
+    if(state->block > 1 && state->sbytes < (int)state->blksize) {
+      state->state = TFTP_STATE_FIN;
+      return CURLE_OK;
+    }
+    res = Curl_fillreadbuffer(state->conn, (size_t)state->blksize,
+                              &state->sbytes);
+    if(res)
+      return res;
+    sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+                    4+state->sbytes, SEND_4TH_ARG,
+                    (struct sockaddr *)&state->remote_addr,
+                    state->remote_addrlen);
+    /* Check all sbytes were sent */
+    if(sbytes<0) {
+      failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+      return CURLE_SEND_ERROR;
+    }
+    /* Update the progress meter */
+    k->writebytecount += state->sbytes;
+    Curl_pgrsSetUploadCounter(data, k->writebytecount);
+    break;
+
+  case TFTP_EVENT_TIMEOUT:
+    /* Increment the retry counter and log the timeout */
+    state->retries++;
+    infof(data, "Timeout waiting for block %d ACK. "
+          " Retries = %d\n", state->block+1, state->retries);
+    /* Decide if we've had enough */
+    if(state->retries > state->retry_max) {
+      state->error = TFTP_ERR_TIMEOUT;
+      state->state = TFTP_STATE_FIN;
+    }
+    else {
+      /* Re-send the data packet */
+      sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+                      4+state->sbytes, SEND_4TH_ARG,
+                      (struct sockaddr *)&state->remote_addr,
+                      state->remote_addrlen);
+      /* Check all sbytes were sent */
+      if(sbytes<0) {
+        failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+        return CURLE_SEND_ERROR;
+      }
+      /* since this was a re-send, we remain at the still byte position */
+      Curl_pgrsSetUploadCounter(data, k->writebytecount);
+    }
+    break;
+
+  case TFTP_EVENT_ERROR:
+    state->state = TFTP_STATE_FIN;
+    setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
+    setpacketblock(&state->spacket, state->block);
+    sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+                    4, SEND_4TH_ARG,
+                    (struct sockaddr *)&state->remote_addr,
+                    state->remote_addrlen);
+    /* don't bother with the return code, but if the socket is still up we
+     * should be a good TFTP client and let the server know we're done */
+    state->state = TFTP_STATE_FIN;
+    break;
+
+  default:
+    failf(data, "tftp_tx: internal error, event: %i", (int)(event));
+    break;
+  }
+
+  return res;
+}
+
+/**********************************************************
+ *
+ * tftp_translate_code
+ *
+ * Translate internal error codes to CURL error codes
+ *
+ **********************************************************/
+static CURLcode tftp_translate_code(tftp_error_t error)
+{
+  CURLcode code = CURLE_OK;
+
+  if(error != TFTP_ERR_NONE) {
+    switch(error) {
+    case TFTP_ERR_NOTFOUND:
+      code = CURLE_TFTP_NOTFOUND;
+      break;
+    case TFTP_ERR_PERM:
+      code = CURLE_TFTP_PERM;
+      break;
+    case TFTP_ERR_DISKFULL:
+      code = CURLE_REMOTE_DISK_FULL;
+      break;
+    case TFTP_ERR_UNDEF:
+    case TFTP_ERR_ILLEGAL:
+      code = CURLE_TFTP_ILLEGAL;
+      break;
+    case TFTP_ERR_UNKNOWNID:
+      code = CURLE_TFTP_UNKNOWNID;
+      break;
+    case TFTP_ERR_EXISTS:
+      code = CURLE_REMOTE_FILE_EXISTS;
+      break;
+    case TFTP_ERR_NOSUCHUSER:
+      code = CURLE_TFTP_NOSUCHUSER;
+      break;
+    case TFTP_ERR_TIMEOUT:
+      code = CURLE_OPERATION_TIMEDOUT;
+      break;
+    case TFTP_ERR_NORESPONSE:
+      code = CURLE_COULDNT_CONNECT;
+      break;
+    default:
+      code= CURLE_ABORTED_BY_CALLBACK;
+      break;
+    }
+  }
+  else {
+    code = CURLE_OK;
+  }
+
+  return(code);
+}
+
+/**********************************************************
+ *
+ * tftp_state_machine
+ *
+ * The tftp state machine event dispatcher
+ *
+ **********************************************************/
+static CURLcode tftp_state_machine(tftp_state_data_t *state,
+                                   tftp_event_t event)
+{
+  CURLcode res = CURLE_OK;
+  struct SessionHandle *data = state->conn->data;
+  switch(state->state) {
+  case TFTP_STATE_START:
+    DEBUGF(infof(data, "TFTP_STATE_START\n"));
+    res = tftp_send_first(state, event);
+    break;
+  case TFTP_STATE_RX:
+    DEBUGF(infof(data, "TFTP_STATE_RX\n"));
+    res = tftp_rx(state, event);
+    break;
+  case TFTP_STATE_TX:
+    DEBUGF(infof(data, "TFTP_STATE_TX\n"));
+    res = tftp_tx(state, event);
+    break;
+  case TFTP_STATE_FIN:
+    infof(data, "%s\n", "TFTP finished");
+    break;
+  default:
+    DEBUGF(infof(data, "STATE: %d\n", state->state));
+    failf(data, "%s", "Internal state machine error");
+    res = CURLE_TFTP_ILLEGAL;
+    break;
+  }
+  return res;
+}
+
+/**********************************************************
+ *
+ * tftp_disconnect
+ *
+ * The disconnect callback
+ *
+ **********************************************************/
+static CURLcode tftp_disconnect(struct connectdata *conn)
+{
+  tftp_state_data_t *state = conn->proto.tftpc;
+
+  /* done, free dynamically allocated pkt buffers */
+  if(state) {
+    Curl_safefree(state->rpacket.data);
+    Curl_safefree(state->spacket.data);
+    free(state);
+  }
+
+  return CURLE_OK;
+}
+
+/**********************************************************
+ *
+ * tftp_connect
+ *
+ * The connect callback
+ *
+ **********************************************************/
+static CURLcode tftp_connect(struct connectdata *conn, bool *done)
+{
+  CURLcode code;
+  tftp_state_data_t *state;
+  int blksize, rc;
+
+  blksize = TFTP_BLKSIZE_DEFAULT;
+
+  /* If there already is a protocol-specific struct allocated for this
+     sessionhandle, deal with it */
+  Curl_reset_reqproto(conn);
+
+  state = conn->proto.tftpc = calloc(1, sizeof(tftp_state_data_t));
+  if(!state)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* alloc pkt buffers based on specified blksize */
+  if(conn->data->set.tftp_blksize) {
+    blksize = (int)conn->data->set.tftp_blksize;
+    if(blksize > TFTP_BLKSIZE_MAX || blksize < TFTP_BLKSIZE_MIN )
+      return CURLE_TFTP_ILLEGAL;
+  }
+
+  if(!state->rpacket.data) {
+    state->rpacket.data = calloc(1, blksize + 2 + 2);
+
+    if(!state->rpacket.data)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  if(!state->spacket.data) {
+    state->spacket.data = calloc(1, blksize + 2 + 2);
+
+    if(!state->spacket.data)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  conn->bits.close = TRUE; /* we don't keep TFTP connections up bascially
+                              because there's none or very little gain for UDP
+                           */
+
+  state->conn = conn;
+  state->sockfd = state->conn->sock[FIRSTSOCKET];
+  state->state = TFTP_STATE_START;
+  state->error = TFTP_ERR_NONE;
+  state->blksize = TFTP_BLKSIZE_DEFAULT;
+  state->requested_blksize = blksize;
+
+  ((struct sockaddr *)&state->local_addr)->sa_family =
+    (unsigned short)(conn->ip_addr->ai_family);
+
+  tftp_set_timeouts(state);
+
+  if(!conn->bits.bound) {
+    /* If not already bound, bind to any interface, random UDP port. If it is
+     * reused or a custom local port was desired, this has already been done!
+     *
+     * We once used the size of the local_addr struct as the third argument
+     * for bind() to better work with IPv6 or whatever size the struct could
+     * have, but we learned that at least Tru64, AIX and IRIX *requires* the
+     * size of that argument to match the exact size of a 'sockaddr_in' struct
+     * when running IPv4-only.
+     *
+     * Therefore we use the size from the address we connected to, which we
+     * assume uses the same IP version and thus hopefully this works for both
+     * IPv4 and IPv6...
+     */
+    rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
+              conn->ip_addr->ai_addrlen);
+    if(rc) {
+      failf(conn->data, "bind() failed; %s",
+            Curl_strerror(conn, SOCKERRNO));
+      return CURLE_COULDNT_CONNECT;
+    }
+    conn->bits.bound = TRUE;
+  }
+
+  Curl_pgrsStartNow(conn->data);
+
+  *done = TRUE;
+  code = CURLE_OK;
+  return(code);
+}
+
+/**********************************************************
+ *
+ * tftp_done
+ *
+ * The done callback
+ *
+ **********************************************************/
+static CURLcode tftp_done(struct connectdata *conn, CURLcode status,
+                               bool premature)
+{
+  CURLcode code = CURLE_OK;
+  tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
+
+  (void)status; /* unused */
+  (void)premature; /* not used */
+
+  Curl_pgrsDone(conn);
+
+  /* If we have encountered an error */
+  code = tftp_translate_code(state->error);
+
+  return code;
+}
+
+/**********************************************************
+ *
+ * tftp_getsock
+ *
+ * The getsock callback
+ *
+ **********************************************************/
+static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks,
+                       int numsocks)
+{
+  if(!numsocks)
+    return GETSOCK_BLANK;
+
+  socks[0] = conn->sock[FIRSTSOCKET];
+
+  return GETSOCK_READSOCK(0);
+}
+
+/**********************************************************
+ *
+ * tftp_receive_packet
+ *
+ * Called once select fires and data is ready on the socket
+ *
+ **********************************************************/
+static CURLcode tftp_receive_packet(struct connectdata *conn)
+{
+  struct Curl_sockaddr_storage fromaddr;
+  curl_socklen_t        fromlen;
+  CURLcode              result = CURLE_OK;
+  struct SessionHandle  *data = conn->data;
+  tftp_state_data_t     *state = (tftp_state_data_t *)conn->proto.tftpc;
+  struct SingleRequest  *k = &data->req;
+
+  /* Receive the packet */
+  fromlen = sizeof(fromaddr);
+  state->rbytes = (int)recvfrom(state->sockfd,
+                                   (void *)state->rpacket.data,
+                                   state->blksize+4,
+                                   0,
+                                   (struct sockaddr *)&fromaddr,
+                                   &fromlen);
+  if(state->remote_addrlen==0) {
+    memcpy(&state->remote_addr, &fromaddr, fromlen);
+    state->remote_addrlen = fromlen;
+  }
+
+  /* Sanity check packet length */
+  if(state->rbytes < 4) {
+    failf(data, "Received too short packet");
+    /* Not a timeout, but how best to handle it? */
+    state->event = TFTP_EVENT_TIMEOUT;
+  }
+  else {
+    /* The event is given by the TFTP packet time */
+    state->event = (tftp_event_t)getrpacketevent(&state->rpacket);
+
+    switch(state->event) {
+    case TFTP_EVENT_DATA:
+      /* Don't pass to the client empty or retransmitted packets */
+      if(state->rbytes > 4 &&
+          ((state->block+1) == getrpacketblock(&state->rpacket))) {
+        result = Curl_client_write(conn, CLIENTWRITE_BODY,
+                                 (char *)state->rpacket.data+4,
+                                 state->rbytes-4);
+        if(result) {
+          tftp_state_machine(state, TFTP_EVENT_ERROR);
+          return result;
+        }
+        k->bytecount += state->rbytes-4;
+        Curl_pgrsSetDownloadCounter(data, (curl_off_t) k->bytecount);
+      }
+      break;
+    case TFTP_EVENT_ERROR:
+      state->error = (tftp_error_t)getrpacketblock(&state->rpacket);
+      infof(data, "%s\n", (const char *)state->rpacket.data+4);
+      break;
+    case TFTP_EVENT_ACK:
+      break;
+    case TFTP_EVENT_OACK:
+      result = tftp_parse_option_ack(state,
+                                   (const char *)state->rpacket.data+2,
+                                   state->rbytes-2);
+      if(result)
+        return result;
+      break;
+    case TFTP_EVENT_RRQ:
+    case TFTP_EVENT_WRQ:
+    default:
+      failf(data, "%s", "Internal error: Unexpected packet");
+      break;
+    }
+
+    /* Update the progress meter */
+    if(Curl_pgrsUpdate(conn)) {
+      tftp_state_machine(state, TFTP_EVENT_ERROR);
+      return CURLE_ABORTED_BY_CALLBACK;
+    }
+  }
+  return result;
+}
+
+/**********************************************************
+ *
+ * tftp_state_timeout
+ *
+ * Check if timeouts have been reached
+ *
+ **********************************************************/
+static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event)
+{
+  time_t                current;
+  tftp_state_data_t     *state = (tftp_state_data_t *)conn->proto.tftpc;
+
+  if (event)
+    *event = TFTP_EVENT_NONE;
+
+  time(&current);
+  if(current > state->max_time) {
+    DEBUGF(infof(conn->data, "timeout: %ld > %ld\n",
+                 (long)current, (long)state->max_time));
+    state->error = TFTP_ERR_TIMEOUT;
+    state->state = TFTP_STATE_FIN;
+    return(0);
+  }
+  else if (current > state->rx_time+state->retry_time) {
+    if (event)
+      *event = TFTP_EVENT_TIMEOUT;
+    time(&state->rx_time); /* update even though we received nothing */
+    return(state->max_time-current);
+  }
+  else {
+    return(state->max_time-current);
+  }
+}
+
+
+/**********************************************************
+ *
+ * tftp_easy_statemach
+ *
+ * Handle easy request until completion
+ *
+ **********************************************************/
+static CURLcode tftp_easy_statemach(struct connectdata *conn)
+{
+  int                   rc;
+  int                   check_time = 0;
+  CURLcode              result = CURLE_OK;
+  struct SessionHandle  *data = conn->data;
+  tftp_state_data_t     *state = (tftp_state_data_t *)conn->proto.tftpc;
+  int                   fd_read;
+  long                  timeout_ms;
+  struct SingleRequest  *k = &data->req;
+  struct timeval        transaction_start = Curl_tvnow();
+
+  k->start = transaction_start;
+  k->now = transaction_start;
+
+  /* Run the TFTP State Machine */
+  for(; (state->state != TFTP_STATE_FIN) && (result == CURLE_OK); ) {
+
+    timeout_ms = state->retry_time * 1000;
+
+    if (data->set.upload) {
+      if (data->set.max_send_speed &&
+          (data->progress.ulspeed > data->set.max_send_speed)) {
+        fd_read = CURL_SOCKET_BAD;
+        timeout_ms = Curl_sleep_time(data->set.max_send_speed,
+                                     data->progress.ulspeed, state->blksize);
+      }
+      else {
+        fd_read = state->sockfd;
+      }
+    }
+    else {
+      if (data->set.max_recv_speed &&
+          (data->progress.dlspeed > data->set.max_recv_speed)) {
+        fd_read = CURL_SOCKET_BAD;
+        timeout_ms = Curl_sleep_time(data->set.max_recv_speed,
+                                     data->progress.dlspeed, state->blksize);
+      }
+      else {
+        fd_read = state->sockfd;
+      }
+    }
+
+    if(data->set.timeout) {
+      timeout_ms = data->set.timeout - Curl_tvdiff(k->now, k->start);
+      if (timeout_ms > state->retry_time * 1000)
+        timeout_ms = state->retry_time * 1000;
+      else if(timeout_ms < 0)
+        timeout_ms = 0;
+    }
+
+
+    /* Wait until ready to read or timeout occurs */
+    rc = Curl_socket_ready(fd_read, CURL_SOCKET_BAD, (int)(timeout_ms));
+
+    k->now = Curl_tvnow();
+
+    /* Force a progress callback if it's been too long */
+    if (Curl_tvdiff(k->now, k->start) >= data->set.timeout) {
+       if(Curl_pgrsUpdate(conn)) {
+          tftp_state_machine(state, TFTP_EVENT_ERROR);
+          return CURLE_ABORTED_BY_CALLBACK;
+       }
+       k->start = k->now;
+    }
+
+    if(rc == -1) {
+      /* bail out */
+      int error = SOCKERRNO;
+      failf(data, "%s", Curl_strerror(conn, error));
+      state->event = TFTP_EVENT_ERROR;
+    }
+    else {
+
+      if(rc==0) {
+        /* A timeout occured, but our timeout is variable, so maybe
+           just continue? */
+        long rtms = state->retry_time * 1000;
+        if (Curl_tvdiff(k->now, transaction_start) > rtms) {
+          state->event = TFTP_EVENT_TIMEOUT;
+          /* Force a look at transfer timeouts */
+          check_time = 1;
+        }
+        else {
+          continue; /* skip state machine */
+        }
+      }
+      else {
+        result = tftp_receive_packet(conn);
+        if (result == CURLE_OK)
+           transaction_start = Curl_tvnow();
+
+        if(k->bytecountp)
+          *k->bytecountp = k->bytecount; /* read count */
+        if(k->writebytecountp)
+          *k->writebytecountp = k->writebytecount; /* write count */
+      }
+    }
+
+    if(check_time) {
+      tftp_state_timeout(conn, NULL);
+      check_time = 0;
+    }
+
+    if(result)
+      return(result);
+
+    result = tftp_state_machine(state, state->event);
+  }
+
+  /* Tell curl we're done */
+  result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+
+  return(result);
+}
+
+/**********************************************************
+ *
+ * tftp_multi_statemach
+ *
+ * Handle single RX socket event and return
+ *
+ **********************************************************/
+static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done)
+{
+  int                   rc;
+  tftp_event_t          event;
+  CURLcode              result = CURLE_OK;
+  struct SessionHandle  *data = conn->data;
+  tftp_state_data_t     *state = (tftp_state_data_t *)conn->proto.tftpc;
+  long                  timeout_ms = tftp_state_timeout(conn, &event);
+
+  *done = FALSE;
+
+  if(timeout_ms <= 0) {
+    failf(data, "TFTP response timeout");
+    return CURLE_OPERATION_TIMEDOUT;
+  }
+  else if (event != TFTP_EVENT_NONE) {
+    result = tftp_state_machine(state, event);
+    if(result != CURLE_OK)
+      return(result);
+    *done = (bool)(state->state == TFTP_STATE_FIN);
+    if(*done)
+      /* Tell curl we're done */
+      result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+  }
+  else {
+    /* no timeouts to handle, check our socket */
+    rc = Curl_socket_ready(state->sockfd, CURL_SOCKET_BAD, 0);
+
+    if(rc == -1) {
+      /* bail out */
+      int error = SOCKERRNO;
+      failf(data, "%s", Curl_strerror(conn, error));
+      state->event = TFTP_EVENT_ERROR;
+    }
+    else if(rc != 0) {
+      result = tftp_receive_packet(conn);
+      if(result != CURLE_OK)
+        return(result);
+      result = tftp_state_machine(state, state->event);
+      if(result != CURLE_OK)
+        return(result);
+      *done = (bool)(state->state == TFTP_STATE_FIN);
+      if(*done)
+        /* Tell curl we're done */
+        result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+    }
+    /* if rc == 0, then select() timed out */
+  }
+
+  return result;
+}
+
+/**********************************************************
+ *
+ * tftp_doing
+ *
+ * Called from multi.c while DOing
+ *
+ **********************************************************/
+static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done)
+{
+  CURLcode result;
+  result = tftp_multi_statemach(conn, dophase_done);
+
+  if(*dophase_done) {
+    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+  }
+  return result;
+}
+
+/**********************************************************
+ *
+ * tftp_peform
+ *
+ * Entry point for transfer from tftp_do, sarts state mach
+ *
+ **********************************************************/
+static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done)
+{
+  CURLcode              result = CURLE_OK;
+  tftp_state_data_t     *state = (tftp_state_data_t *)conn->proto.tftpc;
+
+  *dophase_done = FALSE;
+
+  result = tftp_state_machine(state, TFTP_EVENT_INIT);
+
+  if(state->state == TFTP_STATE_FIN || result != CURLE_OK)
+    return(result);
+
+  if(conn->data->state.used_interface == Curl_if_multi)
+    tftp_multi_statemach(conn, dophase_done);
+  else {
+    result = tftp_easy_statemach(conn);
+    *dophase_done = TRUE; /* with the easy interface we are done here */
+  }
+
+  if(*dophase_done)
+    DEBUGF(infof(conn->data, "DO phase is complete\n"));
+
+  return result;
+}
+
+
+/**********************************************************
+ *
+ * tftp_do
+ *
+ * The do callback
+ *
+ * This callback initiates the TFTP transfer
+ *
+ **********************************************************/
+
+static CURLcode tftp_do(struct connectdata *conn, bool *done)
+{
+  tftp_state_data_t     *state;
+  CURLcode              code;
+
+  *done = FALSE;
+
+  /*
+    Since connections can be re-used between SessionHandles, this might be a
+    connection already existing but on a fresh SessionHandle struct so we must
+    make sure we have a good 'struct TFTP' to play with. For new connections,
+    the struct TFTP is allocated and setup in the tftp_connect() function.
+  */
+  Curl_reset_reqproto(conn);
+
+  if(!conn->proto.tftpc) {
+    code = tftp_connect(conn, done);
+    if(code)
+      return code;
+  }
+  state = (tftp_state_data_t *)conn->proto.tftpc;
+
+  code = tftp_perform(conn, done);
+
+  /* If tftp_perform() returned an error, use that for return code. If it
+     was OK, see if tftp_translate_code() has an error. */
+  if (code == CURLE_OK) 
+    /* If we have encountered an internal tftp error, translate it. */
+    code = tftp_translate_code(state->error);
+
+  return code;
+}
+
+static CURLcode tftp_setup_connection(struct connectdata * conn)
+{
+  struct SessionHandle *data = conn->data;
+  char * type;
+  char command;
+
+  conn->socktype = SOCK_DGRAM;   /* UDP datagram based */
+
+  /* TFTP URLs support an extension like ";mode=<typecode>" that
+   * we'll try to get now! */
+  type = strstr(data->state.path, ";mode=");
+
+  if(!type)
+    type = strstr(conn->host.rawalloc, ";mode=");
+
+  if(type) {
+    *type = 0;                   /* it was in the middle of the hostname */
+    command = Curl_raw_toupper(type[6]);
+
+    switch (command) {
+    case 'A': /* ASCII mode */
+    case 'N': /* NETASCII mode */
+      data->set.prefer_ascii = TRUE;
+      break;
+
+    case 'O': /* octet mode */
+    case 'I': /* binary mode */
+    default:
+      /* switch off ASCII */
+      data->set.prefer_ascii = FALSE;
+      break;
+    }
+  }
+
+  return CURLE_OK;
+}
+#endif
diff --git a/lib/tftp.h b/lib/tftp.h
new file mode 100644
index 0000000..b2d67b2
--- /dev/null
+++ b/lib/tftp.h
@@ -0,0 +1,28 @@
+#ifndef __TFTP_H
+#define __TFTP_H
+
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, 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.
+ *
+ ***************************************************************************/
+#ifndef CURL_DISABLE_TFTP
+extern const struct Curl_handler Curl_handler_tftp;
+#endif
+#endif
diff --git a/lib/timeval.c b/lib/timeval.c
new file mode 100644
index 0000000..cb39308
--- /dev/null
+++ b/lib/timeval.c
@@ -0,0 +1,131 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2008, 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 "timeval.h"
+
+#if defined(WIN32) && !defined(MSDOS)
+
+struct timeval curlx_tvnow(void)
+{
+  /*
+  ** GetTickCount() is available on _all_ Windows versions from W95 up
+  ** to nowadays. Returns milliseconds elapsed since last system boot,
+  ** increases monotonically and wraps once 49.7 days have elapsed.
+  */
+  struct timeval now;
+  DWORD milliseconds = GetTickCount();
+  now.tv_sec = milliseconds / 1000;
+  now.tv_usec = (milliseconds % 1000) * 1000;
+  return now;
+}
+
+#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC)
+
+struct timeval curlx_tvnow(void)
+{
+  /*
+  ** clock_gettime() is granted to be increased monotonically when the
+  ** monotonic clock is queried. Time starting point is unspecified, it
+  ** could be the system start-up time, the Epoch, or something else,
+  ** in any case the time starting point does not change once that the
+  ** system has started up.
+  */
+  struct timeval now;
+  struct timespec tsnow;
+  if(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow)) {
+    now.tv_sec = tsnow.tv_sec;
+    now.tv_usec = tsnow.tv_nsec / 1000;
+  }
+  /*
+  ** Even when the configure process has truly detected monotonic clock
+  ** availability, it might happen that it is not actually available at
+  ** run-time. When this occurs simply fallback to other time source.
+  */
+#ifdef HAVE_GETTIMEOFDAY
+  else
+    (void)gettimeofday(&now, NULL);
+#else
+  else {
+    now.tv_sec = (long)time(NULL);
+    now.tv_usec = 0;
+  }
+#endif
+  return now;
+}
+
+#elif defined(HAVE_GETTIMEOFDAY)
+
+struct timeval curlx_tvnow(void)
+{
+  /*
+  ** gettimeofday() is not granted to be increased monotonically, due to
+  ** clock drifting and external source time synchronization it can jump
+  ** forward or backward in time.
+  */
+  struct timeval now;
+  (void)gettimeofday(&now, NULL);
+  return now;
+}
+
+#else
+
+struct timeval curlx_tvnow(void)
+{
+  /*
+  ** time() returns the value of time in seconds since the Epoch.
+  */
+  struct timeval now;
+  now.tv_sec = (long)time(NULL);
+  now.tv_usec = 0;
+  return now;
+}
+
+#endif
+
+/*
+ * 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/lib/timeval.h b/lib/timeval.h
new file mode 100644
index 0000000..bc79a45
--- /dev/null
+++ b/lib/timeval.h
@@ -0,0 +1,57 @@
+#ifndef __TIMEVAL_H
+#define __TIMEVAL_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, 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.
+ *
+ ***************************************************************************/
+
+/*
+ * 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"
+
+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/lib/transfer.c b/lib/transfer.c
new file mode 100644
index 0000000..2d50405
--- /dev/null
+++ b/lib/transfer.c
@@ -0,0 +1,2250 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+/* -- WIN32 approved -- */
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "strtoofft.h"
+#include "strequal.h"
+#include "rawstr.h"
+
+#ifdef WIN32
+#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
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#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
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifndef HAVE_SOCKET
+#error "We can't compile without socket() support!"
+#endif
+
+#endif  /* WIN32 */
+
+#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 "http.h"
+#include "url.h"
+#include "getinfo.h"
+#include "sslgen.h"
+#include "http_digest.h"
+#include "http_ntlm.h"
+#include "http_negotiate.h"
+#include "share.h"
+#include "curl_memory.h"
+#include "select.h"
+#include "multiif.h"
+#include "easyif.h" /* for Curl_convert_to_network prototype */
+#include "rtsp.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 */
+
+/*
+ * 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;
+#ifdef CURL_DOES_CONVERSIONS
+  bool sending_http_headers = FALSE;
+
+  if((conn->protocol&(PROT_HTTP|PROT_RTSP)) &&
+     (data->state.proto.http->sending == HTTPSEND_REQUEST)) {
+    /* We're sending the HTTP request headers, not the data.
+       Remember that so we don't re-translate them into garbage. */
+    sending_http_headers = TRUE;
+  }
+#endif
+
+  if(data->req.upload_chunky) {
+    /* if chunked Transfer-Encoding */
+    buffersize -= (8 + 2 + 2);   /* 32bit hex + CRLF + CRLF */
+    data->req.upload_fromhere += (8 + 2); /* 32bit hex + CRLF */
+  }
+
+  /* this function returns a size_t, so we typecast to int to prevent warnings
+     with picky compilers */
+  nread = (int)conn->fread_func(data->req.upload_fromhere, 1,
+                                buffersize, conn->fread_in);
+
+  if(nread == CURL_READFUNC_ABORT) {
+    failf(data, "operation aborted by callback");
+    *nreadp = 0;
+    return CURLE_ABORTED_BY_CALLBACK;
+  }
+  else if(nread == CURL_READFUNC_PAUSE) {
+    struct SingleRequest *k = &data->req;
+    /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */
+    k->keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */
+    if(data->req.upload_chunky) {
+      /* Back out the preallocation done above */
+      data->req.upload_fromhere -= (8 + 2);
+    }
+    *nreadp = 0;
+    return CURLE_OK; /* nothing was read */
+  }
+  else if((size_t)nread > buffersize) {
+    /* the read function returned a too large value */
+    *nreadp = 0;
+    failf(data, "read function returned funny value");
+    return CURLE_READ_ERROR;
+  }
+
+  if(!data->req.forbidchunk && data->req.upload_chunky) {
+    /* if chunked Transfer-Encoding
+     *    build chunk:
+     *
+     *        <HEX SIZE> CRLF
+     *        <DATA> CRLF
+     */
+    /* On non-ASCII platforms the <DATA> may or may not be
+       translated based on set.prefer_ascii while the protocol
+       portion must always be translated to the network encoding.
+       To further complicate matters, line end conversion might be
+       done later on, so we need to prevent CRLFs from becoming
+       CRCRLFs if that's the case.  To do this we use bare LFs
+       here, knowing they'll become CRLFs later on.
+     */
+
+    char hexbuffer[11];
+    const char *endofline_native;
+    const char *endofline_network;
+    int hexlen;
+#ifdef CURL_DO_LINEEND_CONV
+    if((data->set.crlf) || (data->set.prefer_ascii)) {
+#else
+    if(data->set.crlf) {
+#endif /* CURL_DO_LINEEND_CONV */
+      /* \n will become \r\n later on */
+      endofline_native  = "\n";
+      endofline_network = "\x0a";
+    } else {
+      endofline_native  = "\r\n";
+      endofline_network = "\x0d\x0a";
+    }
+    hexlen = snprintf(hexbuffer, sizeof(hexbuffer),
+                      "%x%s", nread, endofline_native);
+
+    /* move buffer pointer */
+    data->req.upload_fromhere -= hexlen;
+    nread += hexlen;
+
+    /* copy the prefix to the buffer, leaving out the NUL */
+    memcpy(data->req.upload_fromhere, hexbuffer, hexlen);
+
+    /* always append ASCII CRLF to the data */
+    memcpy(data->req.upload_fromhere + nread,
+           endofline_network,
+           strlen(endofline_network));
+
+#ifdef CURL_DOES_CONVERSIONS
+    CURLcode res;
+    int length;
+    if(data->set.prefer_ascii) {
+      /* translate the protocol and data */
+      length = nread;
+    } else {
+      /* just translate the protocol portion */
+      length = strlen(hexbuffer);
+    }
+    res = Curl_convert_to_network(data, data->req.upload_fromhere, length);
+    /* Curl_convert_to_network calls failf if unsuccessful */
+    if(res != CURLE_OK) {
+      return(res);
+    }
+#endif /* CURL_DOES_CONVERSIONS */
+
+    if((nread - hexlen) == 0) {
+      /* mark this as done once this chunk is transfered */
+      data->req.upload_done = TRUE;
+    }
+
+    nread+=(int)strlen(endofline_native); /* for the added end of line */
+  }
+#ifdef CURL_DOES_CONVERSIONS
+  else if((data->set.prefer_ascii) && (!sending_http_headers)) {
+    CURLcode res;
+    res = Curl_convert_to_network(data, data->req.upload_fromhere, nread);
+    /* Curl_convert_to_network calls failf if unsuccessful */
+    if(res != CURLE_OK)
+      return(res);
+  }
+#endif /* CURL_DOES_CONVERSIONS */
+
+  *nreadp = nread;
+
+  return CURLE_OK;
+}
+
+
+/*
+ * Curl_readrewind() rewinds the read stream. This is typically used for HTTP
+ * POST/PUT with multi-pass authentication when a sending was denied and a
+ * resend is necessary.
+ */
+CURLcode Curl_readrewind(struct connectdata *conn)
+{
+  struct SessionHandle *data = conn->data;
+
+  conn->bits.rewindaftersend = FALSE; /* we rewind now */
+
+  /* explicitly switch off sending data on this connection now since we are
+     about to restart a new transfer and thus we want to avoid inadvertently
+     sending more data on the existing connection until the next transfer
+     starts */
+  data->req.keepon &= ~KEEP_SEND;
+
+  /* We have sent away data. If not using CURLOPT_POSTFIELDS or
+     CURLOPT_HTTPPOST, call app to rewind
+  */
+  if(data->set.postfields ||
+     (data->set.httpreq == HTTPREQ_POST_FORM))
+    ; /* do nothing */
+  else {
+    if(data->set.seek_func) {
+      int err;
+
+      err = (data->set.seek_func)(data->set.seek_client, 0, SEEK_SET);
+      if(err) {
+        failf(data, "seek callback returned error %d", (int)err);
+        return CURLE_SEND_FAIL_REWIND;
+      }
+    }
+    else if(data->set.ioctl_func) {
+      curlioerr err;
+
+      err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD,
+                                   data->set.ioctl_client);
+      infof(data, "the ioctl callback returned %d\n", (int)err);
+
+      if(err) {
+        /* FIXME: convert to a human readable error message */
+        failf(data, "ioctl callback returned error %d", (int)err);
+        return CURLE_SEND_FAIL_REWIND;
+      }
+    }
+    else {
+      /* If no CURLOPT_READFUNCTION is used, we know that we operate on a
+         given FILE * stream and we can actually attempt to rewind that
+         ourself with fseek() */
+      if(data->set.fread_func == (curl_read_callback)fread) {
+        if(-1 != fseek(data->set.in, 0, SEEK_SET))
+          /* successful rewind */
+          return CURLE_OK;
+      }
+
+      /* no callback set or failure above, makes us fail at once */
+      failf(data, "necessary data rewind wasn't possible");
+      return CURLE_SEND_FAIL_REWIND;
+    }
+  }
+  return CURLE_OK;
+}
+
+static int data_pending(const struct connectdata *conn)
+{
+  /* in the case of libssh2, we can never be really sure that we have emptied
+     its internal buffers so we MUST always try until we get EAGAIN back */
+  return conn->protocol&(PROT_SCP|PROT_SFTP) ||
+    Curl_ssl_data_pending(conn, FIRSTSOCKET);
+}
+
+static void read_rewind(struct connectdata *conn,
+                        size_t thismuch)
+{
+  DEBUGASSERT(conn->read_pos >= thismuch);
+
+  conn->read_pos -= thismuch;
+  conn->bits.stream_was_rewound = TRUE;
+
+#ifdef DEBUGBUILD
+  {
+    char buf[512 + 1];
+    size_t show;
+
+    show = CURLMIN(conn->buf_len - conn->read_pos, sizeof(buf)-1);
+    if(conn->master_buffer) {
+        memcpy(buf, conn->master_buffer + conn->read_pos, show);
+        buf[show] = '\0';
+    }
+    else {
+        buf[0] = '\0';
+    }
+
+    DEBUGF(infof(conn->data,
+                 "Buffer after stream rewind (read_pos = %zu): [%s]",
+                 conn->read_pos, buf));
+  }
+#endif
+}
+
+
+/*
+ * Go ahead and do a read if we have a readable socket or if
+ * the stream was rewound (in which case we have data in a
+ * buffer)
+ */
+static CURLcode readwrite_data(struct SessionHandle *data,
+                               struct connectdata *conn,
+                               struct SingleRequest *k,
+                               int *didwhat, bool *done)
+{
+  CURLcode result = CURLE_OK;
+  ssize_t nread; /* number of bytes read */
+  size_t excess = 0; /* excess bytes read */
+  bool is_empty_data = FALSE;
+#ifndef CURL_DISABLE_RTSP
+  bool readmore = FALSE; /* used by RTP to signal for more data */
+#endif
+
+  *done = FALSE;
+
+  /* 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;
+    size_t bytestoread = buffersize;
+    int readrc;
+
+    if(k->size != -1 && !k->header) {
+      /* make sure we don't read "too much" if we can help it since we
+         might be pipelining and then someone else might want to read what
+         follows! */
+      curl_off_t totalleft = k->size - k->bytecount;
+      if(totalleft < (curl_off_t)bytestoread)
+        bytestoread = (size_t)totalleft;
+    }
+
+    if(bytestoread) {
+      /* receive data from the network! */
+      readrc = Curl_read(conn, conn->sockfd, k->buf, bytestoread, &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;
+    }
+    else {
+      /* read nothing but since we wanted nothing we consider this an OK
+         situation to proceed from */
+      nread = 0;
+    }
+
+    if((k->bytecount == 0) && (k->writebytecount == 0)) {
+      Curl_pgrsTime(data, TIMER_STARTTRANSFER);
+      if(k->exp100 > EXP100_SEND_DATA)
+        /* set time stamp to compare with when waiting for the 100 */
+        k->start100 = Curl_tvnow();
+    }
+
+    *didwhat |= KEEP_RECV;
+    /* indicates data of zero size, i.e. empty file */
+    is_empty_data = (bool)((nread == 0) && (k->bodywrites == 0));
+
+    /* NUL terminate, allowing string ops to be used */
+    if(0 < nread || is_empty_data) {
+      k->buf[nread] = 0;
+    }
+    else if(0 >= nread) {
+      /* if we receive 0 or less here, the server closed the connection
+         and we bail out from this! */
+      DEBUGF(infof(data, "nread <= 0, server closed connection, bailing\n"));
+      k->keepon &= ~KEEP_RECV;
+      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;
+
+#ifndef CURL_DISABLE_RTSP
+    /* Check for RTP at the beginning of the data */
+    if(conn->protocol & PROT_RTSP) {
+      result = Curl_rtsp_rtp_readwrite(data, conn, &nread, &readmore);
+      if(result)
+        return result;
+      if(readmore)
+        break;
+    }
+#endif
+
+#ifndef CURL_DISABLE_HTTP
+    /* 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;
+      result = Curl_http_readwrite_headers(data, conn, &nread, &stop_reading);
+      if(result)
+        return result;
+
+#ifndef CURL_DISABLE_RTSP
+      /* Check for RTP after the headers if there is no Content */
+      if(k->maxdownload <= 0 && nread > 0 && (conn->protocol & PROT_RTSP)) {
+        result = Curl_rtsp_rtp_readwrite(data, conn, &nread, &readmore);
+        if(result)
+          return result;
+        if(readmore)
+          break;
+      }
+#endif
+
+      if(stop_reading)
+        /* We've stopped dealing with input, get out of the do-while loop */
+        break;
+    }
+#endif /* CURL_DISABLE_HTTP */
+
+
+    /* 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 || is_empty_data)) {
+
+
+#ifndef CURL_DISABLE_HTTP
+      if(0 == k->bodywrites && !is_empty_data) {
+        /* These checks are only made the first time we are about to
+           write a piece of the body */
+        if(conn->protocol&(PROT_HTTP|PROT_RTSP)) {
+          /* HTTP-only checks */
+
+          if(data->req.newurl) {
+            if(conn->bits.close) {
+              /* Abort after the headers if "follow Location" is set
+                 and we're set to close anyway. */
+              k->keepon &= ~KEEP_RECV;
+              *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->state.resume_from && !k->content_range &&
+             (data->set.httpreq==HTTPREQ_GET) &&
+             !k->ignorebody) {
+            /* 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_RANGE_ERROR;
+          }
+
+          if(data->set.timecondition && !data->state.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;
+                  data->info.timecond = 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;
+                  data->info.timecond = 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 */
+#endif /* CURL_DISABLE_HTTP */
+      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,
+                     (size_t)k->hbuflen, conn);
+          if(k->badheader == HEADER_PARTHEADER)
+            Curl_debug(data, CURLINFO_DATA_IN,
+                       k->str, (size_t)nread, conn);
+        }
+        else
+          Curl_debug(data, CURLINFO_DATA_IN,
+                     k->str, (size_t)nread, conn);
+      }
+
+#ifndef CURL_DISABLE_HTTP
+      if(k->chunk) {
+        /*
+         * 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", (int)res);
+          return CURLE_RECV_ERROR;
+        }
+        else if(CHUNKE_STOP == res) {
+          size_t dataleft;
+          /* we're done reading chunks! */
+          k->keepon &= ~KEEP_RECV; /* read no more */
+
+          /* There are now possibly N number of bytes at the end of the
+             str buffer that weren't written to the client.
+
+             We DO care about this data if we are pipelining.
+             Push it back to be read on the next pass. */
+
+          dataleft = conn->chunk.dataleft;
+          if(dataleft != 0) {
+            infof(conn->data, "Leftovers after chunking. "
+                  " Rewinding %zu bytes\n",dataleft);
+            read_rewind(conn, dataleft);
+          }
+        }
+        /* If it returned OK, we just keep going */
+      }
+#endif   /* CURL_DISABLE_HTTP */
+
+      /* Account for body content stored in the header buffer */
+      if(k->badheader && !k->ignorebody) {
+        DEBUGF(infof(data, "Increasing bytecount by %zu from hbuflen\n",
+                     k->hbuflen));
+        k->bytecount += k->hbuflen;
+      }
+
+      if((-1 != k->maxdownload) &&
+         (k->bytecount + nread >= k->maxdownload)) {
+
+        excess = (size_t)(k->bytecount + nread - k->maxdownload);
+        if(excess > 0 && !k->ignorebody) {
+          if(conn->data->multi && Curl_multi_canPipeline(conn->data->multi)) {
+            /* The 'excess' amount below can't be more than BUFSIZE which
+               always will fit in a size_t */
+            infof(data,
+                "Rewinding stream by : %zu"
+                " bytes on url %s (size = %" FORMAT_OFF_T
+                ", maxdownload = %" FORMAT_OFF_T
+                ", bytecount = %" FORMAT_OFF_T ", nread = %zd)\n",
+                excess, data->state.path,
+                k->size, k->maxdownload, k->bytecount, nread);
+            read_rewind(conn, excess);
+          }
+          else {
+            infof(data,
+                "Excess found in a non pipelined read:"
+                " excess = %zu"
+                ", size = %" FORMAT_OFF_T
+                ", maxdownload = %" FORMAT_OFF_T
+                ", bytecount = %" FORMAT_OFF_T "\n",
+                excess, k->size, k->maxdownload, k->bytecount);
+          }
+        }
+
+        nread = (ssize_t) (k->maxdownload - k->bytecount);
+        if(nread < 0 ) /* this should be unusual */
+          nread = 0;
+
+        k->keepon &= ~KEEP_RECV; /* we're done reading */
+      }
+
+      k->bytecount += nread;
+
+      Curl_pgrsSetDownloadCounter(data, k->bytecount);
+
+      if(!k->chunk && (nread || k->badheader || is_empty_data)) {
+        /* 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 */
+
+          /* Don't let excess data pollute body writes */
+          if(k->maxdownload == -1 || (curl_off_t)k->hbuflen <= k->maxdownload)
+            result = Curl_client_write(conn, CLIENTWRITE_BODY,
+                data->state.headerbuff,
+                k->hbuflen);
+          else
+            result = Curl_client_write(conn, CLIENTWRITE_BODY,
+                data->state.headerbuff,
+                (size_t)k->maxdownload);
+
+          if(result)
+            return result;
+        }
+        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 (conn->data->set.http_ce_skip ?
+                  IDENTITY : 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) {
+
+#ifndef CURL_DISABLE_POP3
+              if(conn->protocol&PROT_POP3)
+                result = Curl_pop3_write(conn, k->str, nread);
+              else
+#endif /* CURL_DISABLE_POP3 */
+
+              result = Curl_client_write(conn, CLIENTWRITE_BODY, k->str,
+                                         nread);
+            }
+#ifdef HAVE_LIBZ
+            break;
+
+          case DEFLATE:
+            /* Assume CLIENTWRITE_BODY; headers are not encoded. */
+            if(!k->ignorebody)
+              result = Curl_unencode_deflate_write(conn, k, nread);
+            break;
+
+          case GZIP:
+            /* Assume CLIENTWRITE_BODY; headers are not encoded. */
+            if(!k->ignorebody)
+              result = Curl_unencode_gzip_write(conn, 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 ) */
+
+#ifndef CURL_DISABLE_RTSP
+    if(excess > 0 && !conn->bits.stream_was_rewound &&
+        (conn->protocol & PROT_RTSP)) {
+      /* Check for RTP after the content if there is unrewound excess */
+
+      /* Parse the excess data */
+      k->str += nread;
+      nread = excess;
+
+      result = Curl_rtsp_rtp_readwrite(data, conn, &nread, &readmore);
+      if(result)
+        return result;
+
+      if(readmore)
+        k->keepon |= KEEP_RECV; /* we're not done reading */
+        break;
+    }
+#endif
+
+    if(is_empty_data) {
+      /* if we received nothing, the server closed the connection and we
+         are done */
+      k->keepon &= ~KEEP_RECV;
+    }
+
+  } while(data_pending(conn));
+
+  if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) &&
+     conn->bits.close ) {
+    /* When we've read the entire thing and the close bit is set, the server
+       may now close the connection. If there's now any kind of sending going
+       on from our side, we need to stop that immediately. */
+    infof(data, "we are done reading and this is set to close, stop send\n");
+    k->keepon &= ~KEEP_SEND; /* no writing anymore either */
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Send data to upload to the server, when the socket is writable.
+ */
+static CURLcode readwrite_upload(struct SessionHandle *data,
+                                 struct connectdata *conn,
+                                 struct SingleRequest *k,
+                                 int *didwhat)
+{
+  ssize_t i, si;
+  ssize_t bytes_written;
+  CURLcode result;
+  ssize_t nread; /* number of bytes read */
+  bool sending_http_headers = FALSE;
+
+  if((k->bytecount == 0) && (k->writebytecount == 0))
+    Curl_pgrsTime(data, TIMER_STARTTRANSFER);
+
+  *didwhat |= KEEP_SEND;
+
+  /*
+   * 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 == data->req.upload_present) {
+      /* init the "upload from here" pointer */
+      data->req.upload_fromhere = k->uploadbuf;
+
+      if(!k->upload_done) {
+        /* HTTP pollution, this should be written nicer to become more
+           protocol agnostic. */
+        int fillcount;
+
+        if((k->exp100 == EXP100_SENDING_REQUEST) &&
+           (data->state.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->exp100 = EXP100_AWAITING_CONTINUE; /* wait for the header */
+          k->keepon &= ~KEEP_SEND;         /* disable writing */
+          k->start100 = Curl_tvnow();       /* timeout count starts now */
+          *didwhat &= ~KEEP_SEND;  /* we didn't write anything actually */
+          break;
+        }
+
+        if(conn->protocol&(PROT_HTTP|PROT_RTSP)) {
+          if(data->state.proto.http->sending == HTTPSEND_REQUEST)
+            /* We're sending the HTTP request headers, not the data.
+               Remember that so we don't change the line endings. */
+            sending_http_headers = TRUE;
+          else
+            sending_http_headers = FALSE;
+        }
+
+        result = Curl_fillreadbuffer(conn, BUFSIZE, &fillcount);
+        if(result)
+          return result;
+
+        nread = (ssize_t)fillcount;
+      }
+      else
+        nread = 0; /* we're done uploading/reading */
+
+      if(!nread && (k->keepon & KEEP_SEND_PAUSE)) {
+        /* this is a paused transfer */
+        break;
+      }
+      else if(nread<=0) {
+        /* done */
+        k->keepon &= ~KEEP_SEND; /* we're done writing */
+
+        if(conn->bits.rewindaftersend) {
+          result = Curl_readrewind(conn);
+          if(result)
+            return result;
+        }
+        break;
+      }
+
+      /* store number of bytes available for upload */
+      data->req.upload_present = nread;
+
+#ifndef CURL_DISABLE_SMTP
+      if(conn->protocol & PROT_SMTP) {
+        result = Curl_smtp_escape_eob(conn, nread);
+        if(result)
+          return result;
+      }
+      else
+#endif /* CURL_DISABLE_SMTP */
+
+      /* convert LF to CRLF if so asked */
+      if((!sending_http_headers) &&
+#ifdef CURL_DO_LINEEND_CONV
+        /* always convert if we're FTPing in ASCII mode */
+         ((data->set.crlf) || (data->set.prefer_ascii))) {
+#else
+         (data->set.crlf)) {
+#endif
+        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;
+        }
+        /*
+         * ASCII/EBCDIC Note: This is presumably a text (not binary)
+         * transfer so the data should already be in ASCII.
+         * That means the hex values for ASCII CR (0x0d) & LF (0x0a)
+         * must be used instead of the escape sequences \r & \n.
+         */
+        for(i = 0, si = 0; i < nread; i++, si++) {
+          if(data->req.upload_fromhere[i] == 0x0a) {
+            data->state.scratch[si++] = 0x0d;
+            data->state.scratch[si] = 0x0a;
+            if(!data->set.crlf) {
+              /* we're here only because FTP is in ASCII mode...
+                 bump infilesize for the LF we just added */
+              data->set.infilesize++;
+            }
+          }
+          else
+            data->state.scratch[si] = data->req.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 */
+          data->req.upload_fromhere = data->state.scratch;
+
+          /* set the new amount too */
+          data->req.upload_present = nread;
+        }
+      }
+    } /* if 0 == data->req.upload_present */
+    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 */
+                        data->req.upload_fromhere, /* buffer pointer */
+                        data->req.upload_present,  /* buffer size */
+                        &bytes_written);           /* actually sent */
+
+    if(result)
+      return result;
+
+    if(data->set.verbose)
+      /* show the data before we change the pointer upload_fromhere */
+      Curl_debug(data, CURLINFO_DATA_OUT, data->req.upload_fromhere,
+                 (size_t)bytes_written, conn);
+
+    if(data->req.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 */
+      data->req.upload_present -= bytes_written;
+
+      /* advance the pointer where to find the buffer when the next send
+         is to happen */
+      data->req.upload_fromhere += bytes_written;
+    }
+    else {
+      /* we've uploaded that buffer now */
+      data->req.upload_fromhere = k->uploadbuf;
+      data->req.upload_present = 0; /* no more bytes left */
+
+      if(k->upload_done) {
+        /* switch off writing, we're done! */
+        k->keepon &= ~KEEP_SEND; /* we're done writing */
+      }
+    }
+
+    k->writebytecount += bytes_written;
+    Curl_pgrsSetUploadCounter(data, k->writebytecount);
+
+  } while(0); /* just to break out from! */
+
+  return CURLE_OK;
+}
+
+/*
+ * 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 SessionHandle *data = conn->data;
+  struct SingleRequest *k = &data->req;
+  CURLcode result;
+  int didwhat=0;
+
+  curl_socket_t fd_read;
+  curl_socket_t fd_write;
+  int select_res = conn->cselect_bits;
+
+  conn->cselect_bits = 0;
+
+  /* only use the proper socket if the *_HOLD bit is not set simultaneously as
+     then we are in rate limiting state in that transfer direction */
+
+  if((k->keepon & KEEP_RECVBITS) == KEEP_RECV)
+    fd_read = conn->sockfd;
+  else
+    fd_read = CURL_SOCKET_BAD;
+
+  if((k->keepon & KEEP_SENDBITS) == KEEP_SEND)
+    fd_write = conn->writesockfd;
+  else
+    fd_write = CURL_SOCKET_BAD;
+
+  if(!select_res) /* Call for select()/poll() only, if read/write/error
+                     status is not known. */
+    select_res = Curl_socket_ready(fd_read, fd_write, 0);
+
+  if(select_res == CURL_CSELECT_ERR) {
+    failf(data, "select/poll returned error");
+    return CURLE_SEND_ERROR;
+  }
+
+  /* We go ahead and do a read if we have a readable socket or if
+     the stream was rewound (in which case we have data in a
+     buffer) */
+  if((k->keepon & KEEP_RECV) &&
+     ((select_res & CURL_CSELECT_IN) || conn->bits.stream_was_rewound)) {
+
+    result = readwrite_data(data, conn, k, &didwhat, done);
+    if(result || *done)
+      return result;
+  }
+
+  /* If we still have writing to do, we check if we have a writable socket. */
+  if((k->keepon & KEEP_SEND) && (select_res & CURL_CSELECT_OUT)) {
+    /* write */
+
+    result = readwrite_upload(data, conn, k, &didwhat);
+    if(result)
+      return result;
+  }
+
+  k->now = Curl_tvnow();
+  if(didwhat) {
+    /* Update read/write counters */
+    if(k->bytecountp)
+      *k->bytecountp = k->bytecount; /* read count */
+    if(k->writebytecountp)
+      *k->writebytecountp = k->writebytecount; /* write count */
+  }
+  else {
+    /* no read no write, this is a timeout? */
+    if(k->exp100 == EXP100_AWAITING_CONTINUE) {
+      /* This should allow some time for the header to arrive, but only a
+         very short time as otherwise it'll be too much wasted time 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->exp100 = EXP100_SEND_DATA;
+        k->keepon |= KEEP_SEND;
+        infof(data, "Done waiting for 100-continue\n");
+      }
+    }
+  }
+
+  if(Curl_pgrsUpdate(conn))
+    result = CURLE_ABORTED_BY_CALLBACK;
+  else
+    result = Curl_speedcheck(data, k->now);
+  if(result)
+    return result;
+
+  if(k->keepon) {
+    if(data->set.timeout &&
+       (Curl_tvdiff(k->now, k->start) >= data->set.timeout)) {
+      if(k->size != -1) {
+        failf(data, "Operation timed out after %ld milliseconds with %"
+              FORMAT_OFF_T " out of %" FORMAT_OFF_T " bytes received",
+              Curl_tvdiff(k->now, k->start), k->bytecount, k->size);
+      } else {
+        failf(data, "Operation timed out after %ld milliseconds with %"
+              FORMAT_OFF_T " bytes received",
+              Curl_tvdiff(k->now, k->start), k->bytecount);
+      }
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+  }
+  else {
+    /*
+     * The transfer has been performed. Just make some general checks before
+     * returning.
+     */
+
+    if(!(data->set.opt_no_body) && (k->size != -1) &&
+       (k->bytecount != k->size) &&
+#ifdef CURL_DO_LINEEND_CONV
+       /* Most FTP servers don't adjust their file SIZE response for CRLFs,
+          so we'll check to see if the discrepancy can be explained
+          by the number of CRLFs we've changed to LFs.
+       */
+       (k->bytecount != (k->size + data->state.crlf_conversions)) &&
+#endif /* CURL_DO_LINEEND_CONV */
+       !data->req.newurl) {
+      failf(data, "transfer closed with %" FORMAT_OFF_T
+            " bytes remaining to read",
+            k->size - k->bytecount);
+      return CURLE_PARTIAL_FILE;
+    }
+    else if(!(data->set.opt_no_body) &&
+            k->chunk &&
+            (conn->chunk.state != CHUNK_STOP)) {
+      /*
+       * In chunked mode, return an error if the connection is closed prior to
+       * the empty (terminiating) chunk is read.
+       *
+       * The condition above used to check for
+       * conn->proto.http->chunk.datasize != 0 which is true after reading
+       * *any* chunk, not just the empty chunk.
+       *
+       */
+      failf(data, "transfer closed with outstanding read data remaining");
+      return CURLE_PARTIAL_FILE;
+    }
+    if(Curl_pgrsUpdate(conn))
+      return CURLE_ABORTED_BY_CALLBACK;
+  }
+
+  /* Now update the "done" boolean we return */
+  *done = (bool)(0 == (k->keepon&(KEEP_RECV|KEEP_SEND|
+                                  KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)));
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_single_getsock() gets called by the multi interface code when the app
+ * has requested to get the sockets 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.
+ */
+int Curl_single_getsock(const struct connectdata *conn,
+                        curl_socket_t *sock, /* points to numsocks number
+                                                of sockets */
+                        int numsocks)
+{
+  const struct SessionHandle *data = conn->data;
+  int bitmap = GETSOCK_BLANK;
+  unsigned sockindex = 0;
+
+  if(conn->handler->perform_getsock)
+    return conn->handler->perform_getsock(conn, sock, numsocks);
+
+  if(numsocks < 2)
+    /* simple check but we might need two slots */
+    return GETSOCK_BLANK;
+
+  /* don't include HOLD and PAUSE connections */
+  if((data->req.keepon & KEEP_RECVBITS) == KEEP_RECV) {
+
+    DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD);
+
+    bitmap |= GETSOCK_READSOCK(sockindex);
+    sock[sockindex] = conn->sockfd;
+  }
+
+  /* don't include HOLD and PAUSE connections */
+  if((data->req.keepon & KEEP_SENDBITS) == KEEP_SEND) {
+
+    if((conn->sockfd != conn->writesockfd) ||
+       !(data->req.keepon & KEEP_RECV)) {
+      /* only if they are not the same socket or we didn't have a readable
+         one, we increase index */
+      if(data->req.keepon & KEEP_RECV)
+        sockindex++; /* increase index if we need two entries */
+
+      DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD);
+
+      sock[sockindex] = conn->writesockfd;
+    }
+
+    bitmap |= GETSOCK_WRITESOCK(sockindex);
+  }
+
+  return bitmap;
+}
+
+/*
+ * Determine optimum sleep time based on configured rate, current rate,
+ * and packet size.
+ * Returns value in mili-seconds.
+ *
+ * The basic idea is to adjust the desired rate up/down in this method
+ * based on whether we are running too slow or too fast.  Then, calculate
+ * how many miliseconds to wait for the next packet to achieve this new
+ * rate.
+ */
+long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps,
+                             int pkt_size)
+{
+  curl_off_t min_sleep = 0;
+  curl_off_t rv = 0;
+
+  if (rate_bps == 0)
+    return 0;
+
+  /* If running faster than about .1% of the desired speed, slow
+   * us down a bit.  Use shift instead of division as the 0.1%
+   * cutoff is arbitrary anyway.
+   */
+  if (cur_rate_bps > (rate_bps + (rate_bps >> 10))) {
+    /* running too fast, decrease target rate by 1/64th of rate */
+    rate_bps -= rate_bps >> 6;
+    min_sleep = 1;
+  }
+  else if (cur_rate_bps < (rate_bps - (rate_bps >> 10))) {
+    /* running too slow, increase target rate by 1/64th of rate */
+    rate_bps += rate_bps >> 6;
+  }
+
+  /* Determine number of miliseconds to wait until we do
+   * the next packet at the adjusted rate.  We should wait
+   * longer when using larger packets, for instance.
+   */
+  rv = ((curl_off_t)((pkt_size * 8) * 1000) / rate_bps);
+
+  /* Catch rounding errors and always slow down at least 1ms if
+   * we are running too fast.
+   */
+  if (rv < min_sleep)
+    rv = min_sleep;
+
+  /* Bound value to fit in 'long' on 32-bit platform.  That's
+   * plenty long enough anyway!
+   */
+  if(rv > 0x7fffffff)
+    rv = 0x7fffffff;
+  
+  return (long)rv;
+}
+
+
+/*
+ * 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_setup_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.
+ *
+ */
+
+static CURLcode
+Transfer(struct connectdata *conn)
+{
+  CURLcode result;
+  struct SessionHandle *data = conn->data;
+  struct SingleRequest *k = &data->req;
+  bool done=FALSE;
+  bool first=TRUE;
+  int timeout_ms;
+  int buffersize;
+  int totmp;
+
+  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(!k->getheader && data->set.opt_no_body)
+    return CURLE_OK;
+
+  while(!done) {
+    curl_socket_t fd_read = conn->sockfd;
+    curl_socket_t fd_write = conn->writesockfd;
+    int keepon = k->keepon;
+    timeout_ms = 1000;
+
+    if(conn->waitfor) {
+      /* if waitfor is set, get the RECV and SEND bits from that but keep the
+         other bits */
+      keepon &= ~ (KEEP_RECV|KEEP_SEND);
+      keepon |= conn->waitfor & (KEEP_RECV|KEEP_SEND);
+    }
+
+    /* limit-rate logic: if speed exceeds threshold, then do not include fd in
+       select set. The current speed is recalculated in each Curl_readwrite()
+       call */
+    if((keepon & KEEP_SEND) &&
+        (!data->set.max_send_speed ||
+         (data->progress.ulspeed < data->set.max_send_speed) )) {
+      k->keepon &= ~KEEP_SEND_HOLD;
+    }
+    else {
+      if (data->set.upload && data->set.max_send_speed &&
+          (data->progress.ulspeed > data->set.max_send_speed) ) {
+        /* calculate upload rate-limitation timeout. */
+        buffersize = (int)(data->set.buffer_size ?
+                           data->set.buffer_size : BUFSIZE);
+        totmp = (int)Curl_sleep_time(data->set.max_send_speed,
+                                     data->progress.ulspeed, buffersize);
+        if (totmp < timeout_ms)
+          timeout_ms = totmp;
+      }
+      fd_write = CURL_SOCKET_BAD;
+      if(keepon & KEEP_SEND)
+        k->keepon |= KEEP_SEND_HOLD; /* hold it */
+    }
+
+    if((keepon & KEEP_RECV) &&
+        (!data->set.max_recv_speed ||
+         (data->progress.dlspeed < data->set.max_recv_speed)) ) {
+      k->keepon &= ~KEEP_RECV_HOLD;
+    }
+    else {
+      if ((!data->set.upload) && data->set.max_recv_speed &&
+          (data->progress.dlspeed > data->set.max_recv_speed)) {
+        /* Calculate download rate-limitation timeout. */
+        buffersize = (int)(data->set.buffer_size ?
+                           data->set.buffer_size : BUFSIZE);
+        totmp = (int)Curl_sleep_time(data->set.max_recv_speed,
+                                     data->progress.dlspeed, buffersize);
+        if (totmp < timeout_ms)
+          timeout_ms = totmp;
+      }
+      fd_read = CURL_SOCKET_BAD;
+      if(keepon & KEEP_RECV)
+        k->keepon |= KEEP_RECV_HOLD; /* hold it */
+    }
+
+    /* pause logic. Don't check descriptors for paused connections */
+    if(k->keepon & KEEP_RECV_PAUSE)
+      fd_read = CURL_SOCKET_BAD;
+    if(k->keepon & KEEP_SEND_PAUSE)
+      fd_write = CURL_SOCKET_BAD;
+
+    /* The *_HOLD and *_PAUSE logic is necessary since even though there might
+       be no traffic during the select interval, we still call
+       Curl_readwrite() for the timeout case and if we limit transfer speed we
+       must make sure that this function doesn't transfer anything while in
+       HOLD status.
+
+       The no timeout for the first round is for the protocols for which data
+       has already been slurped off the socket and thus waiting for action
+       won't work since it'll wait even though there is already data present
+       to work with. */
+    if(first &&
+       ((fd_read != CURL_SOCKET_BAD) || (fd_write != CURL_SOCKET_BAD)))
+      /* if this is the first lap and one of the file descriptors is fine
+         to work with, skip the timeout */
+      timeout_ms = 0;
+    else {
+      if(data->set.timeout) {
+        totmp = (int)(data->set.timeout - Curl_tvdiff(k->now, k->start));
+        if(totmp < 0)
+          return CURLE_OPERATION_TIMEDOUT;
+      }
+      else
+        totmp = 1000;
+
+      if (totmp < timeout_ms)
+        timeout_ms = totmp;
+    }
+
+    switch (Curl_socket_ready(fd_read, fd_write, timeout_ms)) {
+    case -1: /* select() error, stop reading */
+#ifdef EINTR
+      /* The EINTR is not serious, and it seems you might get this more
+         often when using the lib in a multi-threaded environment! */
+      if(SOCKERRNO == EINTR)
+        continue;
+#endif
+      return CURLE_RECV_ERROR;  /* indicate a network problem */
+    case 0:  /* timeout */
+    default: /* readable descriptors */
+
+      result = Curl_readwrite(conn, &done);
+      /* "done" signals to us if the transfer(s) are ready */
+      break;
+    }
+    if(result)
+      return result;
+
+    first = FALSE; /* not the first lap anymore */
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * Curl_pretransfer() is called immediately before a transfer starts.
+ */
+CURLcode Curl_pretransfer(struct SessionHandle *data)
+{
+  CURLcode res;
+  if(!data->change.url) {
+    /* we can't do anything without URL */
+    failf(data, "No URL set!");
+    return CURLE_URL_MALFORMAT;
+  }
+
+  /* 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. */
+  res = Curl_ssl_initsessions(data, data->set.ssl.numsessions);
+  if(res)
+    return res;
+
+  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.httpversion = 0; /* don't assume any particular server version */
+
+  data->state.ssl_connect_retry = FALSE;
+
+  data->state.authproblem = FALSE;
+  data->state.authhost.want = data->set.httpauth;
+  data->state.authproxy.want = data->set.proxyauth;
+  Curl_safefree(data->info.wouldredirect);
+  data->info.wouldredirect = NULL;
+
+  /* If there is a list of cookie files to read, do it now! */
+  if(data->change.cookielist) {
+    Curl_cookie_loadfiles(data);
+  }
+
+ /* 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
+
+  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");
+
+  return CURLE_OK;
+}
+
+#ifndef CURL_DISABLE_HTTP
+/*
+ * strlen_url() returns the length of the given URL if the spaces within the
+ * URL were properly URL encoded.
+ */
+static size_t strlen_url(const char *url)
+{
+  const char *ptr;
+  size_t newlen=0;
+  bool left=TRUE; /* left side of the ? */
+
+  for(ptr=url; *ptr; ptr++) {
+    switch(*ptr) {
+    case '?':
+      left=FALSE;
+      /* fall through */
+    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, const char *url)
+{
+  /* we must add this with whitespace-replacing */
+  bool left=TRUE;
+  const char *iptr;
+  char *optr = output;
+  for(iptr = url;    /* read from here */
+      *iptr;         /* until zero byte */
+      iptr++) {
+    switch(*iptr) {
+    case '?':
+      left=FALSE;
+      /* fall through */
+    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 */
+
+}
+
+/*
+ * Returns true if the given URL is absolute (as opposed to relative)
+ */
+static bool is_absolute_url(const char *url)
+{
+  char prot[16]; /* URL protocol string storage */
+  char letter;   /* used for a silly sscanf */
+
+  return (bool)(2 == sscanf(url, "%15[^?&/:]://%c", prot, &letter));
+}
+
+/*
+ * Concatenate a relative URL to a base URL making it absolute.
+ * URL-encodes any spaces.
+ * The returned pointer must be freed by the caller unless NULL
+ * (returns NULL on out of memory).
+ */
+static char *concat_url(const char *base, const char *relurl)
+{
+  /***
+   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 *newest;
+  char *protsep;
+  char *pathsep;
+  size_t newlen;
+
+  const char *useurl = relurl;
+  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(base);
+
+  if(!url_clone)
+    return NULL; /* 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('/' != relurl[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 = strchr(protsep, '?');
+    if(pathsep)
+      *pathsep=0;
+
+    /* we have a relative path to append to the last slash if there's one
+       available, or if the new URL is just a query string (starts with a
+       '?')  we append the new one at the end of the entire currently worked
+       out URL */
+    if(useurl[0] != '?') {
+      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) {
+      /* When people use badly formatted URLs, such as
+         "http://www.url.com?dir=/home/daniel" we must not use the first
+         slash, if there's a ?-letter before it! */
+      char *sep = strchr(protsep, '?');
+      if(sep && (sep < pathsep))
+        pathsep = sep;
+      *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 = malloc( urllen + 1 + /* possible slash */
+                         newlen + 1 /* zero byte */);
+
+  if(!newest) {
+    free(url_clone); /* don't leak this */
+    return NULL;
+  }
+
+  /* copy over the root url part */
+  memcpy(newest, url_clone, urllen);
+
+  /* check if we need to append a slash */
+  if(('/' == useurl[0]) || (protsep && !*protsep) || ('?' == useurl[0]))
+    ;
+  else
+    newest[urllen++]='/';
+
+  /* then append the new piece on the right side */
+  strcpy_url(&newest[urllen], useurl);
+
+  free(url_clone);
+
+  return newest;
+}
+#endif /* CURL_DISABLE_HTTP */
+
+/*
+ * 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 */
+                     followtype type) /* see transfer.h */
+{
+#ifdef CURL_DISABLE_HTTP
+  (void)data;
+  (void)newurl;
+  (void)type;
+  /* Location: following will not happen when HTTP is disabled */
+  return CURLE_TOO_MANY_REDIRECTS;
+#else
+
+  /* Location: redirect */
+  bool disallowport = FALSE;
+
+  if(type == FOLLOW_REDIR) {
+    if((data->set.maxredirs != -1) &&
+        (data->set.followlocation >= data->set.maxredirs)) {
+      failf(data,"Maximum (%ld) 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);
+      if (!data->change.referer) {
+        data->change.referer_alloc = FALSE;
+        return CURLE_OUT_OF_MEMORY;
+      }
+      data->change.referer_alloc = TRUE; /* yes, free this later */
+    }
+  }
+
+  if(!is_absolute_url(newurl))  {
+    /***
+     *DANG* this is an RFC 2068 violation. The URL is supposed
+     to be absolute and this doesn't seem to be that!
+     */
+    char *absolute = concat_url(data->change.url, newurl);
+    if (!absolute)
+      return CURLE_OUT_OF_MEMORY;
+    free(newurl);
+    newurl = absolute;
+  }
+  else {
+    /* This is an absolute URL, don't allow the custom port number */
+    disallowport = TRUE;
+
+    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". */
+      char *newest;
+      size_t newlen = strlen_url(newurl);
+
+      newest = malloc(newlen+1); /* get memory for this */
+      if (!newest)
+        return CURLE_OUT_OF_MEMORY;
+      strcpy_url(newest, newurl); /* create a space-free URL */
+
+      free(newurl); /* that was no good */
+      newurl = newest; /* use this instead now */
+    }
+
+  }
+
+  if(type == FOLLOW_FAKE) {
+    /* we're only figuring out the new url if we would've followed locations
+       but now we're done so we can get out! */
+    data->info.wouldredirect = newurl;
+    return CURLE_OK;
+  }
+
+  if(disallowport)
+    data->state.allow_port = FALSE;
+
+  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! */
+
+  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-Authenticate, we keep on moving and do the
+       Authorization: XXXX header in the HTTP request code snippet */
+    /* 407 - Act on a Proxy-Authenticate, 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.
+     *
+     * This behaviour can be overridden with CURLOPT_POSTREDIR.
+     */
+    if( (data->set.httpreq == HTTPREQ_POST
+         || data->set.httpreq == HTTPREQ_POST_FORM)
+        && !data->set.post301) {
+      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.
+
+    This behaviour can be overriden with CURLOPT_POSTREDIR
+    */
+    if( (data->set.httpreq == HTTPREQ_POST
+         || data->set.httpreq == HTTPREQ_POST_FORM)
+        && !data->set.post302) {
+      infof(data,
+            "Violate RFC 2616/10.3.3 and switch from POST to GET\n");
+      data->set.httpreq = HTTPREQ_GET;
+    }
+    break;
+
+  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;
+#endif /* CURL_DISABLE_HTTP */
+}
+
+static CURLcode
+connect_host(struct SessionHandle *data,
+             struct connectdata **conn)
+{
+  CURLcode res = CURLE_OK;
+
+  bool async;
+  bool protocol_done=TRUE; /* will be TRUE always since this is only used
+                                within the easy interface */
+  Curl_pgrsTime(data, TIMER_STARTSINGLE);
+  res = Curl_connect(data, conn, &async, &protocol_done);
+
+  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, &protocol_done);
+    else
+      /* if we can't resolve, we kill this "connection" now */
+      (void)Curl_disconnect(*conn);
+  }
+
+  return res;
+}
+
+CURLcode
+Curl_reconnect_request(struct connectdata **connp)
+{
+  CURLcode result = CURLE_OK;
+  struct connectdata *conn = *connp;
+  struct SessionHandle *data = conn->data;
+
+  /* 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, FALSE); /* we are so done with this */
+
+  /* conn may no longer be a good pointer */
+
+  /*
+   * According to bug report #1330310. We need to check for CURLE_SEND_ERROR
+   * here as well. I figure this could happen when the request failed on a FTP
+   * connection and thus Curl_done() itself tried to use the connection
+   * (again). Slight Lack of feedback in the report, but I don't think this
+   * extra check can do much harm.
+   */
+  if((CURLE_OK == result) || (CURLE_SEND_ERROR == result)) {
+    bool async;
+    bool protocol_done = TRUE;
+
+    /* Now, redo the connect and get a new connection */
+    result = Curl_connect(data, connp, &async, &protocol_done);
+    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, &protocol_done);
+        if(result)
+          return result;
+      }
+    }
+  }
+
+  return result;
+}
+
+/* Returns CURLE_OK *and* sets '*url' if a request retry is wanted.
+
+   NOTE: that the *url is malloc()ed. */
+CURLcode Curl_retry_request(struct connectdata *conn,
+                            char **url)
+{
+  struct SessionHandle *data = conn->data;
+
+  *url = NULL;
+
+  /* if we're talking upload, we can't do the checks below, unless the protocol
+     is HTTP as when uploading over HTTP we will still get a response */
+  if(data->set.upload && !(conn->protocol&(PROT_HTTP|PROT_RTSP)))
+    return CURLE_OK;
+
+  if(/* workaround for broken TLS servers */ data->state.ssl_connect_retry ||
+      ((data->req.bytecount +
+        data->req.headerbytecount == 0) &&
+        conn->bits.reuse &&
+        !data->set.opt_no_body &&
+        data->set.rtspreq != RTSPREQ_RECEIVE)) {
+    /* We got no data, we attempted to re-use a connection and yet we want a
+       "body". 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(conn->data, "Connection died, retrying a fresh connect\n");
+    *url = strdup(conn->data->change.url);
+    if(!*url)
+      return CURLE_OUT_OF_MEMORY;
+
+    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! */
+  }
+  return CURLE_OK;
+}
+
+/*
+ * 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! */
+  followtype follow = FOLLOW_NONE;
+
+  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.
+   */
+
+  for(;;) {
+    res = connect_host(data, &conn);   /* primary connection */
+
+    if(res == CURLE_OK) {
+      bool do_done;
+      if(data->set.connect_only) {
+        /* keep connection open for application to use the socket */
+        conn->bits.close = FALSE;
+        res = Curl_done(&conn, CURLE_OK, FALSE);
+        break;
+      }
+      res = Curl_do(&conn, &do_done);
+
+      if(res == CURLE_OK) {
+        res = Transfer(conn); /* now fetch that URL please */
+        if((res == CURLE_OK) || (res == CURLE_RECV_ERROR)) {
+          bool retry = FALSE;
+          CURLcode rc = Curl_retry_request(conn, &newurl);
+          if(rc)
+            res = rc;
+          else
+            retry = (bool)(newurl?TRUE:FALSE);
+
+          if(retry) {
+            res = CURLE_OK;
+            follow = FOLLOW_RETRY;
+            if (!newurl)
+              res = CURLE_OUT_OF_MEMORY;
+          }
+          else if (res == CURLE_OK) {
+            /*
+             * We must duplicate the new URL here as the connection data may
+             * be free()ed in the Curl_done() function. We prefer the newurl
+             * one since that's used for redirects or just further requests
+             * for retries or multi-stage HTTP auth methods etc.
+             */
+            if(data->req.newurl) {
+              follow = FOLLOW_REDIR;
+              newurl = strdup(data->req.newurl);
+              if (!newurl)
+                res = CURLE_OUT_OF_MEMORY;
+            }
+            else if(data->req.location) {
+              follow = FOLLOW_FAKE;
+              newurl = strdup(data->req.location);
+              if (!newurl)
+                res = CURLE_OUT_OF_MEMORY;
+            }
+          }
+
+          /* in the above cases where 'newurl' gets assigned, we have a fresh
+           * allocated memory pointed to */
+        }
+        if(res != CURLE_OK) {
+          /* The transfer phase returned error, we mark the connection to get
+           * closed to prevent being re-used. This is because 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, FALSE);
+
+        if(CURLE_OK == res)
+          res = res2;
+      }
+      else if(conn)
+        /* Curl_do() failed, clean up left-overs in the done-call, but note
+           that at some cases the conn pointer is NULL when Curl_do() failed
+           and the connection cache is very small so only call Curl_done() if
+           conn is still "alive".
+        */
+        res2 = Curl_done(&conn, res, FALSE);
+
+      /*
+       * Important: 'conn' cannot be used here, since it may have been closed
+       * in 'Curl_done' or other functions.
+       */
+
+      if((res == CURLE_OK) && follow) {
+        res = Curl_follow(data, newurl, follow);
+        if(CURLE_OK == res) {
+          /* if things went fine, Curl_follow() freed or otherwise took
+             responsibility for the newurl pointer */
+          newurl = NULL;
+          if(follow >= FOLLOW_RETRY) {
+            follow = FOLLOW_NONE;
+            continue;
+          }
+          /* else we break out of the loop below */
+        }
+      }
+    }
+    break; /* it only reaches here when this shouldn't loop */
+
+  } /* loop if Location: */
+
+  if(newurl)
+    free(newurl);
+
+  if(res && !data->state.errorbuf) {
+    /*
+     * As an extra precaution: if no error string has been set and there was
+     * an error, use the strerror() string or if things are so bad that not
+     * even that is good, set a bad string that mentions the error code.
+     */
+    const char *str = curl_easy_strerror(res);
+    if(!str)
+      failf(data, "unspecified error %d", (int)res);
+    else
+      failf(data, "%s", str);
+  }
+
+  /* run post-transfer unconditionally, 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_setup_transfer() is called to setup some basic properties for the
+ * upcoming transfer.
+ */
+CURLcode
+Curl_setup_transfer(
+  struct connectdata *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 SessionHandle *data;
+  struct SingleRequest *k;
+
+  DEBUGASSERT(conn != NULL);
+
+  data = conn->data;
+  k = &data->req;
+
+  DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
+
+  /* now copy all input parameters */
+  conn->sockfd = sockindex == -1 ?
+      CURL_SOCKET_BAD : conn->sock[sockindex];
+  conn->writesockfd = writesockindex == -1 ?
+      CURL_SOCKET_BAD:conn->sock[writesockindex];
+  k->getheader = getheader;
+
+  k->size = size;
+  k->bytecountp = bytecountp;
+  k->writebytecountp = writecountp;
+
+  /* The code sequence below is placed in this function just because all
+     necessary input is not always known in do_complete() as this function may
+     be called after that */
+
+  if(!k->getheader) {
+    k->header = FALSE;
+    if(size > 0)
+      Curl_pgrsSetDownloadSize(data, size);
+  }
+  /* we want header and/or body, if neither then don't do this! */
+  if(k->getheader || !data->set.opt_no_body) {
+
+    if(conn->sockfd != CURL_SOCKET_BAD) {
+      k->keepon |= KEEP_RECV;
+    }
+
+    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->state.expect100header) &&
+         (data->state.proto.http->sending == HTTPSEND_BODY)) {
+        /* wait with write until we either got 100-continue or a timeout */
+        k->exp100 = EXP100_AWAITING_CONTINUE;
+        k->start100 = k->start;
+      }
+      else {
+        if(data->state.expect100header)
+          /* when we've sent off the rest of the headers, we must await a
+             100-continue but first finish sending the request */
+          k->exp100 = EXP100_SENDING_REQUEST;
+
+        /* enable the write bit when we're not waiting for continue */
+        k->keepon |= KEEP_SEND;
+      }
+    } /* if(conn->writesockfd != CURL_SOCKET_BAD) */
+  } /* if(k->getheader || !data->set.opt_no_body) */
+
+  return CURLE_OK;
+}
diff --git a/lib/transfer.h b/lib/transfer.h
new file mode 100644
index 0000000..4c2bc9e
--- /dev/null
+++ b/lib/transfer.h
@@ -0,0 +1,67 @@
+#ifndef __TRANSFER_H
+#define __TRANSFER_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+CURLcode Curl_perform(struct SessionHandle *data);
+CURLcode Curl_pretransfer(struct SessionHandle *data);
+CURLcode Curl_second_connect(struct connectdata *conn);
+CURLcode Curl_posttransfer(struct SessionHandle *data);
+
+typedef enum {
+  FOLLOW_NONE,  /* not used within the function, just a placeholder to
+                   allow initing to this */
+  FOLLOW_FAKE,  /* only records stuff, not actually following */
+  FOLLOW_RETRY, /* set if this is a request retry as opposed to a real
+                          redirect following */
+  FOLLOW_REDIR, /* a full true redirect */
+  FOLLOW_LAST   /* never used */
+} followtype;
+
+CURLcode Curl_follow(struct SessionHandle *data, char *newurl, followtype type);
+
+
+CURLcode Curl_readwrite(struct connectdata *conn, bool *done);
+int Curl_single_getsock(const struct connectdata *conn,
+                        curl_socket_t *socks,
+                        int numsocks);
+CURLcode Curl_readrewind(struct connectdata *conn);
+CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp);
+CURLcode Curl_reconnect_request(struct connectdata **connp);
+CURLcode Curl_retry_request(struct connectdata *conn, char **url);
+
+/* This sets up a forthcoming transfer */
+CURLcode
+Curl_setup_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 */
+);
+
+long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps,
+                     int pkt_size);
+
+#endif
diff --git a/lib/url.c b/lib/url.c
new file mode 100644
index 0000000..357f213
--- /dev/null
+++ b/lib/url.c
@@ -0,0 +1,5322 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+/* -- WIN32 approved -- */
+
+#include "setup.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+#ifdef WIN32
+#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
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#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
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#ifndef HAVE_SOCKET
+#error "We can't compile without socket() support!"
+#endif
+
+#endif  /* WIN32 */
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifdef USE_LIBIDN
+#include <idna.h>
+#include <tld.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  /* USE_LIBIDN */
+
+#include "urldata.h"
+#include "netrc.h"
+
+#include "formdata.h"
+#include "sslgen.h"
+#include "hostip.h"
+#include "transfer.h"
+#include "sendf.h"
+#include "progress.h"
+#include "cookie.h"
+#include "strequal.h"
+#include "strerror.h"
+#include "escape.h"
+#include "strtok.h"
+#include "share.h"
+#include "content_encoding.h"
+#include "http_digest.h"
+#include "http_negotiate.h"
+#include "select.h"
+#include "multiif.h"
+#include "easyif.h"
+#include "speedcheck.h"
+#include "rawstr.h"
+#include "warnless.h"
+
+/* And now for the protocols */
+#include "ftp.h"
+#include "dict.h"
+#include "telnet.h"
+#include "tftp.h"
+#include "http.h"
+#include "file.h"
+#include "curl_ldap.h"
+#include "ssh.h"
+#include "imap.h"
+#include "url.h"
+#include "connect.h"
+#include "inet_ntop.h"
+#include "http_ntlm.h"
+#include "socks.h"
+#include "rtsp.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* Local static prototypes */
+static long ConnectionKillOne(struct SessionHandle *data);
+static void conn_free(struct connectdata *conn);
+static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke);
+
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+#define verboseconnect(x)  do { } while (0)
+#endif
+
+
+/*
+ * Protocol table.
+ */
+
+static const struct Curl_handler * const protocols[] = {
+
+#ifndef CURL_DISABLE_HTTP
+  &Curl_handler_http,
+#endif
+
+#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
+  &Curl_handler_https,
+#endif
+
+#ifndef CURL_DISABLE_FTP
+  &Curl_handler_ftp,
+#endif
+
+#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)
+  &Curl_handler_ftps,
+#endif
+
+#ifndef CURL_DISABLE_TELNET
+  &Curl_handler_telnet,
+#endif
+
+#ifndef CURL_DISABLE_DICT
+  &Curl_handler_dict,
+#endif
+
+#ifndef CURL_DISABLE_LDAP
+  &Curl_handler_ldap,
+#endif
+
+#if !defined(CURL_DISABLE_LDAP) && defined(HAVE_LDAP_SSL)
+  &Curl_handler_ldaps,
+#endif
+
+#ifndef CURL_DISABLE_FILE
+  &Curl_handler_file,
+#endif
+
+#ifndef CURL_DISABLE_TFTP
+  &Curl_handler_tftp,
+#endif
+
+#ifdef USE_LIBSSH2
+  &Curl_handler_scp,
+  &Curl_handler_sftp,
+#endif
+
+#ifndef CURL_DISABLE_IMAP
+  &Curl_handler_imap,
+#ifdef USE_SSL
+  &Curl_handler_imaps,
+#endif
+#endif
+
+#ifndef CURL_DISABLE_POP3
+  &Curl_handler_pop3,
+#ifdef USE_SSL
+  &Curl_handler_pop3s,
+#endif
+#endif
+
+#ifndef CURL_DISABLE_SMTP
+  &Curl_handler_smtp,
+#ifdef USE_SSL
+  &Curl_handler_smtps,
+#endif
+#endif
+
+#ifndef CURL_DISABLE_RTSP
+  &Curl_handler_rtsp,
+#endif
+
+  (struct Curl_handler *) NULL
+};
+
+/*
+ * Dummy handler for undefined protocol schemes.
+ */
+
+static const struct Curl_handler Curl_handler_dummy = {
+  "<no protocol>",                      /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  ZERO_NULL,                            /* do_it */
+  ZERO_NULL,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  ZERO_NULL,                            /* connect_it */
+  ZERO_NULL,                            /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  0,                                    /* defport */
+  0                                     /* protocol */
+};
+
+void Curl_safefree(void *ptr)
+{
+  if(ptr)
+    free(ptr);
+}
+
+static void close_connections(struct SessionHandle *data)
+{
+  /* Loop through all open connections and kill them one by one */
+  long i;
+  do {
+    i = ConnectionKillOne(data);
+  } while(i != -1L);
+}
+
+void Curl_freeset(struct SessionHandle * data)
+{
+  /* Free all dynamic strings stored in the data->set substructure. */
+  enum dupstring i;
+  for(i=(enum dupstring)0; i < STRING_LAST; i++)
+    Curl_safefree(data->set.str[i]);
+}
+
+static CURLcode setstropt(char **charp, char * s)
+{
+  /* Release the previous storage at `charp' and replace by a dynamic storage
+     copy of `s'. Return CURLE_OK or CURLE_OUT_OF_MEMORY. */
+
+  if(*charp) {
+    free(*charp);
+    *charp = (char *) NULL;
+  }
+
+  if(s) {
+    s = strdup(s);
+
+    if(!s)
+      return CURLE_OUT_OF_MEMORY;
+
+    *charp = s;
+  }
+
+  return CURLE_OK;
+}
+
+static CURLcode setstropt_userpwd(char *option, char **user_storage,
+                                  char **pwd_storage)
+{
+  char* separator;
+  CURLcode result = CURLE_OK;
+
+  if(!option) {
+    /* we treat a NULL passed in as a hint to clear existing info */
+    Curl_safefree(*user_storage);
+    *user_storage = (char *) NULL;
+    Curl_safefree(*pwd_storage);
+    *pwd_storage = (char *) NULL;
+    return CURLE_OK;
+  }
+
+  separator = strchr(option, ':');
+  if (separator != NULL) {
+
+    /* store username part of option */
+    char * p;
+    size_t username_len = (size_t)(separator-option);
+    p = malloc(username_len+1);
+    if(!p)
+      result = CURLE_OUT_OF_MEMORY;
+    else {
+      memcpy(p, option, username_len);
+      p[username_len] = '\0';
+      Curl_safefree(*user_storage);
+      *user_storage = p;
+    }
+
+    /* store password part of option */
+    if (result == CURLE_OK) {
+      result = setstropt(pwd_storage, separator+1);
+    }
+  }
+  else {
+    result = setstropt(user_storage, option);
+  }
+  return result;
+}
+
+CURLcode Curl_dupset(struct SessionHandle * dst, struct SessionHandle * src)
+{
+  CURLcode r = CURLE_OK;
+  enum dupstring i;
+
+  /* Copy src->set into dst->set first, then deal with the strings
+     afterwards */
+  dst->set = src->set;
+
+  /* clear all string pointers first */
+  memset(dst->set.str, 0, STRING_LAST * sizeof(char *));
+
+  /* duplicate all strings */
+  for(i=(enum dupstring)0; i< STRING_LAST; i++) {
+    r = setstropt(&dst->set.str[i], src->set.str[i]);
+    if(r != CURLE_OK)
+      break;
+  }
+
+  /* If a failure occurred, freeing has to be performed externally. */
+  return r;
+}
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+static void flush_cookies(struct SessionHandle *data, int cleanup)
+{
+  if(data->set.str[STRING_COOKIEJAR]) {
+    if(data->change.cookielist) {
+      /* If there is a list of cookie files to read, do it first so that
+         we have all the told files read before we write the new jar.
+         Curl_cookie_loadfiles() LOCKS and UNLOCKS the share itself! */
+      Curl_cookie_loadfiles(data);
+    }
+
+    Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+
+    /* if we have a destination file for all the cookies to get dumped to */
+    if(Curl_cookie_output(data->cookies, data->set.str[STRING_COOKIEJAR]))
+      infof(data, "WARNING: failed to save cookies in %s\n",
+            data->set.str[STRING_COOKIEJAR]);
+  }
+  else {
+    if(cleanup && data->change.cookielist)
+      /* since nothing is written, we can just free the list of cookie file
+         names */
+      curl_slist_free_all(data->change.cookielist); /* clean up list */
+    Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+  }
+
+  if(cleanup && (!data->share || (data->cookies != data->share->cookies))) {
+    Curl_cookie_cleanup(data->cookies);
+  }
+  Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+}
+#endif
+
+/*
+ * 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)
+{
+  struct Curl_multi *m = data->multi;
+
+#ifdef DEBUGBUILD
+  /* only for debugging, scan through all connections and see if there's a
+     pipe reference still identifying this handle */
+
+  if(data->state.connc && data->state.connc->type == CONNCACHE_MULTI) {
+    struct conncache *c = data->state.connc;
+    long i;
+    struct curl_llist *pipeline;
+    struct curl_llist_element *curr;
+    struct connectdata *connptr;
+
+    for(i=0; i< c->num; i++) {
+      connptr = c->connects[i];
+      if(!connptr)
+        continue;
+
+      pipeline = connptr->send_pipe;
+      if(pipeline) {
+        for (curr = pipeline->head; curr; curr=curr->next) {
+          if(data == (struct SessionHandle *) curr->ptr) {
+            fprintf(stderr,
+                    "problem we %p are still in send pipe for %p done %d\n",
+                    data, connptr, (int)connptr->bits.done);
+          }
+        }
+      }
+      pipeline = connptr->recv_pipe;
+      if(pipeline) {
+        for (curr = pipeline->head; curr; curr=curr->next) {
+          if(data == (struct SessionHandle *) curr->ptr) {
+            fprintf(stderr,
+                    "problem we %p are still in recv pipe for %p done %d\n",
+                    data, connptr, (int)connptr->bits.done);
+          }
+        }
+      }
+      pipeline = connptr->done_pipe;
+      if(pipeline) {
+        for (curr = pipeline->head; curr; curr=curr->next) {
+          if(data == (struct SessionHandle *) curr->ptr) {
+            fprintf(stderr,
+                    "problem we %p are still in done pipe for %p done %d\n",
+                    data, connptr, (int)connptr->bits.done);
+          }
+        }
+      }
+      pipeline = connptr->pend_pipe;
+      if(pipeline) {
+        for (curr = pipeline->head; curr; curr=curr->next) {
+          if(data == (struct SessionHandle *) curr->ptr) {
+            fprintf(stderr,
+                    "problem we %p are still in pend pipe for %p done %d\n",
+                    data, connptr, (int)connptr->bits.done);
+          }
+        }
+      }
+    }
+  }
+#endif
+
+  if(m)
+    /* This handle is still part of a multi handle, take care of this first
+       and detach this handle from there. */
+    Curl_multi_rmeasy(data->multi, data);
+
+  data->magic = 0; /* force a clear AFTER the possibly enforced removal from
+                      the multi handle, since that function uses the magic
+                      field! */
+
+  if(data->state.connc) {
+
+    if(data->state.connc->type == CONNCACHE_PRIVATE) {
+      /* close all connections still alive that are in the private connection
+         cache, as we no longer have the pointer left to the shared one. */
+      close_connections(data);
+
+      /* free the connection cache if allocated privately */
+      Curl_rm_connc(data->state.connc);
+    }
+  }
+
+  if(data->state.shared_conn) {
+    /* marked to be used by a pending connection so we can't kill this handle
+       just yet */
+    data->state.closed = TRUE;
+    return CURLE_OK;
+  }
+
+  if(data->dns.hostcachetype == HCACHE_PRIVATE) {
+    Curl_hash_destroy(data->dns.hostcache);
+    data->dns.hostcachetype = HCACHE_NONE;
+    data->dns.hostcache = NULL;
+  }
+
+  if(data->state.rangestringalloc)
+    free(data->state.range);
+
+  /* Free the pathbuffer */
+  Curl_safefree(data->state.pathbuffer);
+  Curl_safefree(data->state.proto.generic);
+
+  /* Close down all open SSL info and sessions */
+  Curl_ssl_close_all(data);
+  Curl_safefree(data->state.first_host);
+  Curl_safefree(data->state.scratch);
+  Curl_ssl_free_certinfo(data);
+
+  if(data->change.referer_alloc)
+    free(data->change.referer);
+
+  if(data->change.url_alloc)
+    free(data->change.url);
+
+  Curl_safefree(data->state.headerbuff);
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+  flush_cookies(data, 1);
+#endif
+
+  Curl_digest_cleanup(data);
+
+  Curl_safefree(data->info.contenttype);
+  Curl_safefree(data->info.wouldredirect);
+
+  /* this destroys the channel and we cannot use it anymore after this */
+  ares_destroy(data->state.areschannel);
+
+#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
+  /* close iconv conversion descriptors */
+  if(data->inbound_cd != (iconv_t)-1) {
+     iconv_close(data->inbound_cd);
+  }
+  if(data->outbound_cd != (iconv_t)-1) {
+     iconv_close(data->outbound_cd);
+  }
+  if(data->utf8_cd != (iconv_t)-1) {
+     iconv_close(data->utf8_cd);
+  }
+#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
+
+  /* No longer a dirty share, if it exists */
+  if(data->share) {
+    Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
+    data->share->dirty--;
+    Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
+  }
+
+  Curl_freeset(data);
+  free(data);
+  return CURLE_OK;
+}
+
+/* create a connection cache of a private or multi type */
+struct conncache *Curl_mk_connc(int type,
+                                long amount) /* set -1 to use default */
+{
+  /* It is subject for debate how many default connections to have for a multi
+     connection cache... */
+
+  struct conncache *c;
+  long default_amount;
+  long max_amount = (long)(((size_t)INT_MAX) / sizeof(struct connectdata *));
+
+  if(type == CONNCACHE_PRIVATE) {
+    default_amount = (amount < 1L) ? 5L : amount;
+  }
+  else {
+    default_amount = (amount < 1L) ? 10L : amount;
+  }
+
+  if(default_amount > max_amount)
+    default_amount = max_amount;
+
+  c = calloc(1, sizeof(struct conncache));
+  if(!c)
+    return NULL;
+
+  c->connects = calloc((size_t)default_amount, sizeof(struct connectdata *));
+  if(!c->connects) {
+    free(c);
+    return NULL;
+  }
+
+  c->num = default_amount;
+
+  return c;
+}
+
+/* Change number of entries of a connection cache */
+CURLcode Curl_ch_connc(struct SessionHandle *data,
+                       struct conncache *c,
+                       long newamount)
+{
+  long i;
+  struct connectdata **newptr;
+  long max_amount = (long)(((size_t)INT_MAX) / sizeof(struct connectdata *));
+
+  if(newamount < 1)
+    newamount = 1; /* we better have at least one entry */
+
+  if(!c) {
+    /* we get a NULL pointer passed in as connection cache, which means that
+       there is no cache created for this SessionHandle just yet, we create a
+       brand new with the requested size.
+    */
+    data->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, newamount);
+    if(!data->state.connc)
+      return CURLE_OUT_OF_MEMORY;
+    return CURLE_OK;
+  }
+
+  if(newamount < c->num) {
+    /* 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!
+
+       NOTE: for conncache_multi cases we must make sure that we only
+       close handles not in use.
+    */
+    for(i=newamount; i< c->num; i++)
+      Curl_disconnect(c->connects[i]);
+
+    /* If the most recent connection is no longer valid, mark it
+       invalid. */
+    if(data->state.lastconnect <= newamount)
+      data->state.lastconnect = -1;
+  }
+  if(newamount > 0) {
+    if(newamount > max_amount)
+      newamount = max_amount;
+    newptr = realloc(c->connects, sizeof(struct connectdata *) * newamount);
+    if(!newptr)
+      /* we closed a few connections in vain, but so what? */
+      return CURLE_OUT_OF_MEMORY;
+
+    /* nullify the newly added pointers */
+    for(i=c->num; i<newamount; i++)
+      newptr[i] = NULL;
+
+    c->connects = newptr;
+    c->num = newamount;
+  }
+  /* we no longer support less than 1 as size for the connection cache, and
+     I'm not sure it ever worked to set it to zero */
+  return CURLE_OK;
+}
+
+/* Free a connection cache. This is called from Curl_close() and
+   curl_multi_cleanup(). */
+void Curl_rm_connc(struct conncache *c)
+{
+  if(c->connects) {
+    long i;
+    for(i = 0; i < c->num; ++i)
+      conn_free(c->connects[i]);
+
+    free(c->connects);
+  }
+
+  free(c);
+}
+
+/*
+ * Initialize the UserDefined fields within a SessionHandle.
+ * This may be safely called on a new or existing SessionHandle.
+ */
+CURLcode Curl_init_userdefined(struct UserDefined *set)
+{
+  CURLcode res = CURLE_OK;
+
+  set->out = stdout; /* default output to stdout */
+  set->in  = stdin;  /* default input from stdin */
+  set->err  = stderr;  /* default stderr to stderr */
+
+  /* use fwrite as default function to store output */
+  set->fwrite_func = (curl_write_callback)fwrite;
+
+  /* use fread as default function to read input */
+  set->fread_func = (curl_read_callback)fread;
+
+  set->seek_func = ZERO_NULL;
+  set->seek_client = ZERO_NULL;
+
+  /* conversion callbacks for non-ASCII hosts */
+  set->convfromnetwork = ZERO_NULL;
+  set->convtonetwork   = ZERO_NULL;
+  set->convfromutf8    = ZERO_NULL;
+
+  set->infilesize = -1;      /* we don't know any size */
+  set->postfieldsize = -1;   /* unknown size */
+  set->maxredirs = -1;       /* allow any amount by default */
+
+  set->httpreq = HTTPREQ_GET; /* Default HTTP request */
+  set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */
+  set->ftp_use_epsv = TRUE;   /* FTP defaults to EPSV operations */
+  set->ftp_use_eprt = TRUE;   /* FTP defaults to EPRT operations */
+  set->ftp_use_pret = FALSE;  /* mainly useful for drftpd servers */
+  set->ftp_filemethod = FTPFILE_MULTICWD;
+
+  set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
+
+  /* Set the default size of the SSL session ID cache */
+  set->ssl.numsessions = 5;
+
+  set->proxyport = CURL_DEFAULT_PROXY_PORT; /* from url.h */
+  set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
+  set->httpauth = CURLAUTH_BASIC;  /* defaults to basic */
+  set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */
+
+  /* make libcurl quiet by default: */
+  set->hide_progress = TRUE;  /* CURLOPT_NOPROGRESS changes these */
+
+  /*
+   * libcurl 7.10 introduced SSL verification *by default*! This needs to be
+   * switched off unless wanted.
+   */
+  set->ssl.verifypeer = TRUE;
+  set->ssl.verifyhost = 2;
+  set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth
+                                                      type */
+  set->ssl.sessionid = TRUE; /* session ID caching enabled by default */
+
+  set->new_file_perms = 0644;    /* Default permissions */
+  set->new_directory_perms = 0755; /* Default permissions */
+
+  /* for the *protocols fields we don't use the CURLPROTO_ALL convenience
+     define since we internally only use the lower 16 bits for the passed
+     in bitmask to not conflict with the private bits */
+  set->allowed_protocols = PROT_EXTMASK;
+  set->redir_protocols =
+    PROT_EXTMASK & ~(CURLPROTO_FILE|CURLPROTO_SCP); /* not FILE or SCP */
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+  /*
+   * disallow unprotected protection negotiation NEC reference implementation
+   * seem not to follow rfc1961 section 4.3/4.4
+   */
+  set->socks5_gssapi_nec = FALSE;
+  /* set default gssapi service name */
+  res = setstropt(&set->str[STRING_SOCKS5_GSSAPI_SERVICE],
+                  (char *) CURL_DEFAULT_SOCKS5_GSSAPI_SERVICE);
+  if (res != CURLE_OK)
+    return res;
+#endif
+
+  /* This is our preferred CA cert bundle/path since install time */
+#if defined(CURL_CA_BUNDLE)
+  res = setstropt(&set->str[STRING_SSL_CAFILE], (char *) CURL_CA_BUNDLE);
+#elif defined(CURL_CA_PATH)
+  res = setstropt(&set->str[STRING_SSL_CAPATH], (char *) CURL_CA_PATH);
+#endif
+
+  return res;
+}
+
+/**
+ * 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;
+#ifdef USE_ARES
+  int status;
+#endif
+
+  /* Very simple start-up: alloc the struct, init it with zeroes and return */
+  data = calloc(1, sizeof(struct SessionHandle));
+  if(!data) {
+    /* this is a very serious error */
+    DEBUGF(fprintf(stderr, "Error: calloc of SessionHandle failed\n"));
+    return CURLE_OUT_OF_MEMORY;
+  }
+
+  data->magic = CURLEASY_MAGIC_NUMBER;
+
+#ifdef USE_ARES
+  if((status = ares_init(&data->state.areschannel)) != ARES_SUCCESS) {
+    DEBUGF(fprintf(stderr, "Error: ares_init failed\n"));
+    free(data);
+    if(status == ARES_ENOMEM)
+      return CURLE_OUT_OF_MEMORY;
+    else
+      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 = malloc(HEADERSIZE);
+  if(!data->state.headerbuff) {
+    DEBUGF(fprintf(stderr, "Error: malloc of headerbuff failed\n"));
+    res = CURLE_OUT_OF_MEMORY;
+  }
+  else {
+    Curl_easy_initHandleData(data);
+    res = Curl_init_userdefined(&data->set);
+
+    data->state.headersize=HEADERSIZE;
+
+#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
+    /* conversion descriptors for iconv calls */
+    data->outbound_cd = (iconv_t)-1;
+    data->inbound_cd  = (iconv_t)-1;
+    data->utf8_cd     = (iconv_t)-1;
+#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
+
+    /* most recent connection is not yet defined */
+    data->state.lastconnect = -1;
+
+    data->progress.flags |= PGRS_HIDE;
+    data->state.current_speed = -1; /* init to negative == impossible */
+
+    /* This no longer creates a connection cache here. It is instead made on
+       the first call to curl_easy_perform() or when the handle is added to a
+       multi stack. */
+  }
+
+  if(res) {
+    ares_destroy(data->state.areschannel);
+    if(data->state.headerbuff)
+      free(data->state.headerbuff);
+    Curl_freeset(data);
+    free(data);
+    data = NULL;
+  }
+  else
+    *curl = data;
+
+  return res;
+}
+
+CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
+                     va_list param)
+{
+  char *argptr;
+  CURLcode result = CURLE_OK;
+#ifndef CURL_DISABLE_HTTP
+  curl_off_t bigsize;
+#endif
+
+  switch(option) {
+  case CURLOPT_DNS_CACHE_TIMEOUT:
+    data->set.dns_cache_timeout = va_arg(param, long);
+    break;
+  case CURLOPT_DNS_USE_GLOBAL_CACHE:
+  {
+    /* remember we want this enabled */
+    long use_cache = va_arg(param, long);
+    data->set.global_dns_cache = (bool)(0 != use_cache);
+  }
+  break;
+  case CURLOPT_SSL_CIPHER_LIST:
+    /* set a list of cipher we want to use in the SSL connection */
+    result = setstropt(&data->set.str[STRING_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.
+     */
+    result = setstropt(&data->set.str[STRING_SSL_RANDOM_FILE],
+                       va_arg(param, char *));
+    break;
+  case CURLOPT_EGDSOCKET:
+    /*
+     * The Entropy Gathering Daemon socket pathname
+     */
+    result = setstropt(&data->set.str[STRING_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.
+     */
+    result = Curl_ch_connc(data, data->state.connc, va_arg(param, long));
+    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 = (bool)(0 != va_arg(param, long));
+    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 = (bool)(0 != va_arg(param, long));
+    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 = (bool)(0 != va_arg(param, long));
+    break;
+  case CURLOPT_HEADER:
+    /*
+     * Set to include the header in the general data output stream.
+     */
+    data->set.include_header = (bool)(0 != va_arg(param, long));
+    break;
+  case CURLOPT_NOPROGRESS:
+    /*
+     * Shut off the internal supported progress meter
+     */
+    data->set.hide_progress = (bool)(0 != va_arg(param, long));
+    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 = (bool)(0 != va_arg(param, long));
+    break;
+  case CURLOPT_FAILONERROR:
+    /*
+     * Don't output the >=300 error code HTML-page, but instead only
+     * return error.
+     */
+    data->set.http_fail_on_error = (bool)(0 != va_arg(param, long));
+    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 = (bool)(0 != va_arg(param, long));
+    if(data->set.upload) {
+      /* If this is HTTP, PUT is what's needed to "upload" */
+      data->set.httpreq = HTTPREQ_PUT;
+      data->set.opt_no_body = FALSE; /* this is implied */
+    }
+    else
+      /* In HTTP, the opposite of upload is GET (unless NOBODY is true as
+         then this can be changed to HEAD later on) */
+      data->set.httpreq = HTTPREQ_GET;
+    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 = (bool)(0 != va_arg(param, long));
+    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 = (int)va_arg(param, long);
+    break;
+  case CURLOPT_SERVER_RESPONSE_TIMEOUT:
+    /*
+     * Option that specifies how quickly an server response must be obtained
+     * before it is considered failure. For pingpong protocols.
+     */
+    data->set.server_response_timeout = va_arg( param , long ) * 1000;
+    break;
+  case CURLOPT_TFTP_BLKSIZE:
+    /*
+     * TFTP option that specifies the block size to use for data transmission
+     */
+    data->set.tftp_blksize = va_arg(param, long);
+    break;
+  case CURLOPT_DIRLISTONLY:
+    /*
+     * An option that changes the command to one that asks for a list
+     * only, no file info details.
+     */
+    data->set.ftp_list_only = (bool)(0 != va_arg(param, long));
+    break;
+  case CURLOPT_APPEND:
+    /*
+     * We want to upload and append to an existing file.
+     */
+    data->set.ftp_append = (bool)(0 != va_arg(param, long));
+    break;
+  case CURLOPT_FTP_FILEMETHOD:
+    /*
+     * How do access files over FTP.
+     */
+    data->set.ftp_filemethod = (curl_ftpfile)va_arg(param, long);
+    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
+     */
+    result = setstropt(&data->set.str[STRING_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.prefer_ascii = (bool)(0 != va_arg(param, long));
+    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 = (bool)(0 != va_arg(param, long));
+    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.
+     *
+     */
+    argptr = va_arg(param, char *);
+    result = setstropt(&data->set.str[STRING_ENCODING],
+                       (argptr && !*argptr)?
+                       (char *) ALL_CONTENT_ENCODINGS: argptr);
+    break;
+
+  case CURLOPT_FOLLOWLOCATION:
+    /*
+     * Follow Location: header hints on a HTTP-server.
+     */
+    data->set.http_follow_location = (bool)(0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_UNRESTRICTED_AUTH:
+    /*
+     * Send authentication (user+password) when following locations, even when
+     * hostname changed.
+     */
+    data->set.http_disable_hostname_check_before_authentication =
+      (bool)(0 != va_arg(param, long));
+    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_POSTREDIR:
+  {
+    /*
+     * Set the behaviour of POST when redirecting
+     * CURL_REDIR_GET_ALL - POST is changed to GET after 301 and 302
+     * CURL_REDIR_POST_301 - POST is kept as POST after 301
+     * CURL_REDIR_POST_302 - POST is kept as POST after 302
+     * CURL_REDIR_POST_ALL - POST is kept as POST after 301 and 302
+     * other - POST is kept as POST after 301 and 302
+     */
+    long postRedir = va_arg(param, long);
+    data->set.post301 = (bool)((postRedir & CURL_REDIR_POST_301)?TRUE:FALSE);
+    data->set.post302 = (bool)((postRedir & CURL_REDIR_POST_302)?TRUE:FALSE);
+  }
+  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;
+      data->set.opt_no_body = FALSE; /* this is implied */
+    }
+    else
+      data->set.httpreq = HTTPREQ_GET;
+    break;
+
+  case CURLOPT_COPYPOSTFIELDS:
+    /*
+     * A string with POST data. Makes curl HTTP POST. Even if it is NULL.
+     * If needed, CURLOPT_POSTFIELDSIZE must have been set prior to
+     *  CURLOPT_COPYPOSTFIELDS and not altered later.
+     */
+    argptr = va_arg(param, char *);
+
+    if(!argptr || data->set.postfieldsize == -1)
+      result = setstropt(&data->set.str[STRING_COPYPOSTFIELDS], argptr);
+    else {
+      /*
+       *  Check that requested length does not overflow the size_t type.
+       */
+
+      if((data->set.postfieldsize < 0) ||
+         ((sizeof(curl_off_t) != sizeof(size_t)) &&
+          (data->set.postfieldsize > (curl_off_t)((size_t)-1))))
+        result = CURLE_OUT_OF_MEMORY;
+      else {
+        char * p;
+
+        (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+
+        /* Allocate even when size == 0. This satisfies the need of possible
+           later address compare to detect the COPYPOSTFIELDS mode, and
+           to mark that postfields is used rather than read function or
+           form data.
+        */
+        p = malloc((size_t)(data->set.postfieldsize?
+                            data->set.postfieldsize:1));
+
+        if(!p)
+          result = CURLE_OUT_OF_MEMORY;
+        else {
+          if(data->set.postfieldsize)
+            memcpy(p, argptr, (size_t)data->set.postfieldsize);
+
+          data->set.str[STRING_COPYPOSTFIELDS] = p;
+        }
+      }
+    }
+
+    data->set.postfields = data->set.str[STRING_COPYPOSTFIELDS];
+    data->set.httpreq = HTTPREQ_POST;
+    break;
+
+  case CURLOPT_POSTFIELDS:
+    /*
+     * Like above, but use static data instead of copying it.
+     */
+    data->set.postfields = va_arg(param, void *);
+    /* Release old copied data. */
+    (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+    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.
+     */
+    bigsize = va_arg(param, long);
+
+    if(data->set.postfieldsize < bigsize &&
+       data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
+      /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
+      (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+      data->set.postfields = NULL;
+    }
+
+    data->set.postfieldsize = bigsize;
+    break;
+
+  case CURLOPT_POSTFIELDSIZE_LARGE:
+    /*
+     * The size of the POSTFIELD data to prevent libcurl to do strlen() to
+     * figure it out. Enables binary posts.
+     */
+    bigsize = va_arg(param, curl_off_t);
+
+    if(data->set.postfieldsize < bigsize &&
+       data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
+      /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
+      (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+      data->set.postfields = NULL;
+    }
+
+    data->set.postfieldsize = bigsize;
+    break;
+
+  case CURLOPT_HTTPPOST:
+    /*
+     * Set to make us do HTTP POST
+     */
+    data->set.httppost = va_arg(param, struct curl_httppost *);
+    data->set.httpreq = HTTPREQ_POST_FORM;
+    data->set.opt_no_body = FALSE; /* this is implied */
+    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;
+    }
+    result = setstropt(&data->set.str[STRING_SET_REFERER],
+                       va_arg(param, char *));
+    data->change.referer = data->set.str[STRING_SET_REFERER];
+    break;
+
+  case CURLOPT_USERAGENT:
+    /*
+     * String to use in the HTTP User-Agent field
+     */
+    result = setstropt(&data->set.str[STRING_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;
+
+#if !defined(CURL_DISABLE_COOKIES)
+  case CURLOPT_COOKIE:
+    /*
+     * Cookie string to send to the remote server in the request.
+     */
+    result = setstropt(&data->set.str[STRING_COOKIE],
+                       va_arg(param, char *));
+    break;
+
+  case CURLOPT_COOKIEFILE:
+    /*
+     * Set cookie file to read and parse. Can be used multiple times.
+     */
+    argptr = (char *)va_arg(param, void *);
+    if(argptr) {
+      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, argptr);
+
+      if(!cl)
+        return CURLE_OUT_OF_MEMORY;
+
+      data->change.cookielist = cl; /* store the list for later use */
+    }
+    break;
+
+  case CURLOPT_COOKIEJAR:
+    /*
+     * Set cookie file name to dump all cookies to when we're done.
+     */
+    result = setstropt(&data->set.str[STRING_COOKIEJAR],
+                       va_arg(param, char *));
+
+    /*
+     * 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)(0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_COOKIELIST:
+    argptr = va_arg(param, char *);
+
+    if(argptr == NULL)
+      break;
+
+    if(Curl_raw_equal(argptr, "ALL")) {
+      /* clear all cookies */
+      Curl_cookie_clearall(data->cookies);
+      break;
+    }
+    else if(Curl_raw_equal(argptr, "SESS")) {
+      /* clear session cookies */
+      Curl_cookie_clearsess(data->cookies);
+      break;
+    }
+    else if(Curl_raw_equal(argptr, "FLUSH")) {
+      /* flush cookies to file */
+      flush_cookies(data, 0);
+      break;
+    }
+
+    if(!data->cookies)
+      /* if cookie engine was not running, activate it */
+      data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE);
+
+    argptr = strdup(argptr);
+    if(!argptr) {
+      result = CURLE_OUT_OF_MEMORY;
+      break;
+    }
+
+    if(checkprefix("Set-Cookie:", argptr))
+      /* HTTP Header format line */
+      Curl_cookie_add(data, data->cookies, TRUE, argptr + 11, NULL, NULL);
+
+    else
+      /* Netscape format line */
+      Curl_cookie_add(data, data->cookies, FALSE, argptr, NULL, NULL);
+
+    free(argptr);
+    break;
+#endif /* CURL_DISABLE_COOKIES */
+
+  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 */
+      data->set.opt_no_body = FALSE; /* this is implied */
+    }
+    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_CUSTOMREQUEST:
+    /*
+     * Set a custom string to use as request
+     */
+    result = setstropt(&data->set.str[STRING_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_HTTPAUTH:
+    /*
+     * Set HTTP Authentication type BITMASK.
+     */
+  {
+    long auth = va_arg(param, long);
+
+    /* the DIGEST_IE bit is only used to set a special marker, for all the
+       rest we need to handle it as normal DIGEST */
+    data->state.authhost.iestyle = (bool)((auth & CURLAUTH_DIGEST_IE)?
+                                          TRUE:FALSE);
+
+    if(auth & CURLAUTH_DIGEST_IE) {
+      auth |= CURLAUTH_DIGEST; /* set standard digest bit */
+      auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
+    }
+
+    /* switch off bits we can't support */
+#ifndef USE_NTLM
+    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;
+
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_HTTPPROXYTUNNEL:
+    /*
+     * Tunnel operations through the proxy instead of normal proxy use
+     */
+    data->set.tunnel_thru_httpproxy = (bool)(0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_PROXYPORT:
+    /*
+     * Explicitly set HTTP proxy port number.
+     */
+    data->set.proxyport = va_arg(param, long);
+    break;
+
+  case CURLOPT_PROXYAUTH:
+    /*
+     * Set HTTP Authentication type BITMASK.
+     */
+  {
+    long auth = va_arg(param, long);
+
+    /* the DIGEST_IE bit is only used to set a special marker, for all the
+       rest we need to handle it as normal DIGEST */
+    data->state.authproxy.iestyle = (bool)((auth & CURLAUTH_DIGEST_IE)?
+                                           TRUE:FALSE);
+
+    if(auth & CURLAUTH_DIGEST_IE) {
+      auth |= CURLAUTH_DIGEST; /* set standard digest bit */
+      auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
+    }
+    /* switch off bits we can't support */
+#ifndef USE_NTLM
+    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_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.
+     */
+    result = setstropt(&data->set.str[STRING_PROXY],
+                       va_arg(param, char *));
+    break;
+
+  case CURLOPT_PROXYTYPE:
+    /*
+     * Set proxy type. HTTP/HTTP_1_0/SOCKS4/SOCKS4a/SOCKS5/SOCKS5_HOSTNAME
+     */
+    data->set.proxytype = (curl_proxytype)va_arg(param, long);
+    break;
+
+  case CURLOPT_PROXY_TRANSFER_MODE:
+    /*
+     * set transfer mode (;type=<a|i>) when doing FTP via an HTTP proxy
+     */
+    switch (va_arg(param, long)) {
+    case 0:
+      data->set.proxy_transfer_mode = FALSE;
+      break;
+    case 1:
+      data->set.proxy_transfer_mode = TRUE;
+      break;
+    default:
+      /* reserve other values for future use */
+      result = CURLE_FAILED_INIT;
+      break;
+    }
+    break;
+#endif
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+  case CURLOPT_SOCKS5_GSSAPI_SERVICE:
+    /*
+     * Set gssapi service name
+     */
+    result = setstropt(&data->set.str[STRING_SOCKS5_GSSAPI_SERVICE],
+                       va_arg(param, char *));
+    break;
+
+  case CURLOPT_SOCKS5_GSSAPI_NEC:
+    /*
+     * set flag for nec socks5 support
+     */
+    data->set.socks5_gssapi_nec = (bool)(0 != va_arg(param, long));
+    break;
+#endif
+
+  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
+     */
+    result = setstropt(&data->set.str[STRING_FTPPORT],
+                       va_arg(param, char *));
+    data->set.ftp_use_port = (bool)(NULL != data->set.str[STRING_FTPPORT]);
+    break;
+
+  case CURLOPT_FTP_USE_EPRT:
+    data->set.ftp_use_eprt = (bool)(0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_FTP_USE_EPSV:
+    data->set.ftp_use_epsv = (bool)(0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_FTP_USE_PRET:
+    data->set.ftp_use_pret = (bool)(0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_FTP_SSL_CCC:
+    data->set.ftp_ccc = (curl_ftpccc)va_arg(param, long);
+    break;
+
+  case CURLOPT_FTP_SKIP_PASV_IP:
+    /*
+     * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the
+     * bypass of the IP address in PASV responses.
+     */
+    data->set.ftp_skip_ip = (bool)(0 != va_arg(param, long));
+    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_MAX_SEND_SPEED_LARGE:
+    /*
+     * When transfer uploads are faster then CURLOPT_MAX_SEND_SPEED_LARGE
+     * bytes per second the transfer is throttled..
+     */
+    data->set.max_send_speed=va_arg(param, curl_off_t);
+    break;
+  case CURLOPT_MAX_RECV_SPEED_LARGE:
+    /*
+     * When receiving data faster than CURLOPT_MAX_RECV_SPEED_LARGE bytes per
+     * second the transfer is throttled..
+     */
+    data->set.max_recv_speed=va_arg(param, curl_off_t);
+    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;
+    }
+    result = setstropt(&data->set.str[STRING_SET_URL],
+                       va_arg(param, char *));
+    data->change.url = data->set.str[STRING_SET_URL];
+    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) * 1000L;
+    break;
+
+  case CURLOPT_TIMEOUT_MS:
+    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) * 1000L;
+    break;
+
+  case CURLOPT_CONNECTTIMEOUT_MS:
+    data->set.connecttimeout = va_arg(param, long);
+    break;
+
+  case CURLOPT_USERPWD:
+    /*
+     * user:password to use in the operation
+     */
+    result = setstropt_userpwd(va_arg(param, char *),
+                               &data->set.str[STRING_USERNAME],
+                               &data->set.str[STRING_PASSWORD]);
+    break;
+  case CURLOPT_USERNAME:
+    /*
+     * authentication user name to use in the operation
+     */
+    result = setstropt(&data->set.str[STRING_USERNAME],
+                       va_arg(param, char *));
+    break;
+  case CURLOPT_PASSWORD:
+    /*
+     * authentication password to use in the operation
+     */
+    result = setstropt(&data->set.str[STRING_PASSWORD],
+                       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;
+
+#ifndef CURL_DISABLE_PROXY
+  case CURLOPT_PROXYUSERPWD:
+    /*
+     * user:password needed to use the proxy
+     */
+    result = setstropt_userpwd(va_arg(param, char *),
+                               &data->set.str[STRING_PROXYUSERNAME],
+                               &data->set.str[STRING_PROXYPASSWORD]);
+    break;
+  case CURLOPT_PROXYUSERNAME:
+    /*
+     * authentication user name to use in the operation
+     */
+    result = setstropt(&data->set.str[STRING_PROXYUSERNAME],
+                       va_arg(param, char *));
+    break;
+  case CURLOPT_PROXYPASSWORD:
+    /*
+     * authentication password to use in the operation
+     */
+    result = setstropt(&data->set.str[STRING_PROXYPASSWORD],
+                       va_arg(param, char *));
+    break;
+  case CURLOPT_NOPROXY:
+    /*
+     * proxy exception list
+     */
+    result = setstropt(&data->set.str[STRING_NOPROXY],
+                       va_arg(param, char *));
+    break;
+#endif
+
+  case CURLOPT_RANGE:
+    /*
+     * What range of the file you want to transfer
+     */
+    result = setstropt(&data->set.str[STRING_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_func = va_arg(param, curl_write_callback);
+    if(!data->set.fwrite_func)
+      /* When set to NULL, reset to our internal default function */
+      data->set.fwrite_func = (curl_write_callback)fwrite;
+    break;
+  case CURLOPT_READFUNCTION:
+    /*
+     * Read data callback
+     */
+    data->set.fread_func = va_arg(param, curl_read_callback);
+    if(!data->set.fread_func)
+      /* When set to NULL, reset to our internal default function */
+      data->set.fread_func = (curl_read_callback)fread;
+    break;
+  case CURLOPT_SEEKFUNCTION:
+    /*
+     * Seek callback. Might be NULL.
+     */
+    data->set.seek_func = va_arg(param, curl_seek_callback);
+    break;
+  case CURLOPT_SEEKDATA:
+    /*
+     * Seek control callback. Might be NULL.
+     */
+    data->set.seek_client = va_arg(param, void *);
+    break;
+  case CURLOPT_CONV_FROM_NETWORK_FUNCTION:
+    /*
+     * "Convert from network encoding" callback
+     */
+    data->set.convfromnetwork = va_arg(param, curl_conv_callback);
+    break;
+  case CURLOPT_CONV_TO_NETWORK_FUNCTION:
+    /*
+     * "Convert to network encoding" callback
+     */
+    data->set.convtonetwork = va_arg(param, curl_conv_callback);
+    break;
+  case CURLOPT_CONV_FROM_UTF8_FUNCTION:
+    /*
+     * "Convert from UTF-8 encoding" callback
+     */
+    data->set.convfromutf8 = va_arg(param, curl_conv_callback);
+    break;
+  case CURLOPT_IOCTLFUNCTION:
+    /*
+     * I/O control callback. Might be NULL.
+     */
+    data->set.ioctl_func = va_arg(param, curl_ioctl_callback);
+    break;
+  case CURLOPT_IOCTLDATA:
+    /*
+     * I/O control data pointer. Might be NULL.
+     */
+    data->set.ioctl_client = va_arg(param, void *);
+    break;
+  case CURLOPT_SSLCERT:
+    /*
+     * String that holds file name of the SSL certificate to use
+     */
+    result = setstropt(&data->set.str[STRING_CERT],
+                       va_arg(param, char *));
+    break;
+  case CURLOPT_SSLCERTTYPE:
+    /*
+     * String that holds file type of the SSL certificate to use
+     */
+    result = setstropt(&data->set.str[STRING_CERT_TYPE],
+                       va_arg(param, char *));
+    break;
+  case CURLOPT_SSLKEY:
+    /*
+     * String that holds file name of the SSL key to use
+     */
+    result = setstropt(&data->set.str[STRING_KEY],
+                       va_arg(param, char *));
+    break;
+  case CURLOPT_SSLKEYTYPE:
+    /*
+     * String that holds file type of the SSL key to use
+     */
+    result = setstropt(&data->set.str[STRING_KEY_TYPE],
+                       va_arg(param, char *));
+    break;
+  case CURLOPT_KEYPASSWD:
+    /*
+     * String that holds the SSL or SSH private key password.
+     */
+    result = setstropt(&data->set.str[STRING_KEY_PASSWD],
+                       va_arg(param, char *));
+    break;
+  case CURLOPT_SSLENGINE:
+    /*
+     * String that holds the SSL crypto engine.
+     */
+    argptr = va_arg(param, char *);
+    if(argptr && argptr[0])
+      result = Curl_ssl_set_engine(data, argptr);
+    break;
+
+  case CURLOPT_SSLENGINE_DEFAULT:
+    /*
+     * flag to set engine as default.
+     */
+    result = Curl_ssl_set_engine_default(data);
+    break;
+  case CURLOPT_CRLF:
+    /*
+     * Kludgy option to enable CRLF conversions. Subject for removal.
+     */
+    data->set.crlf = (bool)(0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_INTERFACE:
+    /*
+     * Set what interface or address/hostname to bind the socket to when
+     * performing an operation and thus what from-IP your connection will use.
+     */
+    result = setstropt(&data->set.str[STRING_DEVICE],
+                       va_arg(param, char *));
+    break;
+  case CURLOPT_LOCALPORT:
+    /*
+     * Set what local port to bind the socket to when performing an operation.
+     */
+    data->set.localport = (unsigned short) va_arg(param, long);
+    break;
+  case CURLOPT_LOCALPORTRANGE:
+    /*
+     * Set number of local ports to try, starting with CURLOPT_LOCALPORT.
+     */
+    data->set.localportrange = (int) va_arg(param, long);
+    break;
+  case CURLOPT_KRBLEVEL:
+    /*
+     * A string that defines the kerberos security level.
+     */
+    result = setstropt(&data->set.str[STRING_KRB_LEVEL],
+                       va_arg(param, char *));
+    data->set.krb = (bool)(NULL != data->set.str[STRING_KRB_LEVEL]);
+    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;
+#ifdef USE_SSLEAY
+    /* since these two options are only possible to use on an OpenSSL-
+       powered libcurl we #ifdef them on this condition so that libcurls
+       built against other SSL libs will return a proper error when trying
+       to set this option! */
+  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_CERTINFO:
+    data->set.ssl.certinfo = (bool)(0 != va_arg(param, long));
+    break;
+#endif
+  case CURLOPT_CAINFO:
+    /*
+     * Set CA info for SSL connection. Specify file name of the CA certificate
+     */
+    result = setstropt(&data->set.str[STRING_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. */
+    result = setstropt(&data->set.str[STRING_SSL_CAPATH],
+                       va_arg(param, char *));
+    break;
+  case CURLOPT_CRLFILE:
+    /*
+     * Set CRL file info for SSL connection. Specify file name of the CRL
+     * to check certificates revocation
+     */
+    result = setstropt(&data->set.str[STRING_SSL_CRLFILE],
+                       va_arg(param, char *));
+    break;
+  case CURLOPT_ISSUERCERT:
+    /*
+     * Set Issuer certificate file
+     * to check certificates issuer
+     */
+    result = setstropt(&data->set.str[STRING_SSL_ISSUERCERT],
+                       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 = (bool)(0 != va_arg(param, long));
+    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->dns.hostcachetype == HCACHE_SHARED) {
+        data->dns.hostcache = NULL;
+        data->dns.hostcachetype = HCACHE_NONE;
+      }
+
+      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 the private one if any */
+        if(data->dns.hostcachetype == HCACHE_PRIVATE)
+          Curl_hash_destroy(data->dns.hostcache);
+
+        data->dns.hostcache = data->share->hostcache;
+        data->dns.hostcachetype = HCACHE_SHARED;
+      }
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+      if(data->share->cookies) {
+        /* use shared cookie list, first free own one if any */
+        if(data->cookies)
+          Curl_cookie_cleanup(data->cookies);
+        /* enable cookies since we now use a share that uses cookies! */
+        data->cookies = data->share->cookies;
+      }
+#endif   /* CURL_DISABLE_HTTP */
+      Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
+
+    }
+    /* check for host cache not needed,
+     * it will be done by curl_easy_perform */
+  }
+  break;
+
+  case CURLOPT_PRIVATE:
+    /*
+     * Set private data pointer.
+     */
+    data->set.private_data = va_arg(param, void *);
+    break;
+
+  case CURLOPT_MAXFILESIZE:
+    /*
+     * Set the maximum size of a file to download.
+     */
+    data->set.max_filesize = va_arg(param, long);
+    break;
+
+  case CURLOPT_USE_SSL:
+    /*
+     * Make transfers attempt to use SSL/TLS.
+     */
+    data->set.ftp_ssl = (curl_usessl)va_arg(param, long);
+    break;
+
+  case CURLOPT_FTPSSLAUTH:
+    /*
+     * Set a specific auth for FTP-SSL transfers.
+     */
+    data->set.ftpsslauth = (curl_ftpauth)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)(0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_FTP_ACCOUNT:
+    result = setstropt(&data->set.str[STRING_FTP_ACCOUNT],
+                       va_arg(param, char *));
+    break;
+
+  case CURLOPT_IGNORE_CONTENT_LENGTH:
+    data->set.ignorecl = (bool)(0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_CONNECT_ONLY:
+    /*
+     * No data transfer, set up connection and let application use the socket
+     */
+    data->set.connect_only = (bool)(0 != va_arg(param, long));
+    break;
+
+  case CURLOPT_FTP_ALTERNATIVE_TO_USER:
+    result = setstropt(&data->set.str[STRING_FTP_ALTERNATIVE_TO_USER],
+                       va_arg(param, char *));
+    break;
+
+  case CURLOPT_SOCKOPTFUNCTION:
+    /*
+     * socket callback function: called after socket() but before connect()
+     */
+    data->set.fsockopt = va_arg(param, curl_sockopt_callback);
+    break;
+
+  case CURLOPT_SOCKOPTDATA:
+    /*
+     * socket callback data pointer. Might be NULL.
+     */
+    data->set.sockopt_client = va_arg(param, void *);
+    break;
+
+  case CURLOPT_OPENSOCKETFUNCTION:
+    /*
+     * open/create socket callback function: called instead of socket(),
+     * before connect()
+     */
+    data->set.fopensocket = va_arg(param, curl_opensocket_callback);
+    break;
+
+  case CURLOPT_OPENSOCKETDATA:
+    /*
+     * socket callback data pointer. Might be NULL.
+     */
+    data->set.opensocket_client = va_arg(param, void *);
+    break;
+
+  case CURLOPT_SSL_SESSIONID_CACHE:
+    data->set.ssl.sessionid = (bool)(0 != va_arg(param, long));
+    break;
+
+#ifdef USE_LIBSSH2
+    /* we only include SSH options if explicitly built to support SSH */
+  case CURLOPT_SSH_AUTH_TYPES:
+    data->set.ssh_auth_types = va_arg(param, long);
+    break;
+
+  case CURLOPT_SSH_PUBLIC_KEYFILE:
+    /*
+     * Use this file instead of the $HOME/.ssh/id_dsa.pub file
+     */
+    result = setstropt(&data->set.str[STRING_SSH_PUBLIC_KEY],
+                       va_arg(param, char *));
+    break;
+
+  case CURLOPT_SSH_PRIVATE_KEYFILE:
+    /*
+     * Use this file instead of the $HOME/.ssh/id_dsa file
+     */
+    result = setstropt(&data->set.str[STRING_SSH_PRIVATE_KEY],
+                       va_arg(param, char *));
+    break;
+  case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5:
+    /*
+     * Option to allow for the MD5 of the host public key to be checked
+     * for validation purposes.
+     */
+    result = setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5],
+                       va_arg(param, char *));
+    break;
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+  case CURLOPT_SSH_KNOWNHOSTS:
+    /*
+     * Store the file name to read known hosts from.
+     */
+    result = setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS],
+                       va_arg(param, char *));
+    break;
+
+  case CURLOPT_SSH_KEYFUNCTION:
+    /* setting to NULL is fine since the ssh.c functions themselves will
+       then rever to use the internal default */
+    data->set.ssh_keyfunc = va_arg(param, curl_sshkeycallback);
+    break;
+
+  case CURLOPT_SSH_KEYDATA:
+    /*
+     * Custom client data to pass to the SSH keyfunc callback
+     */
+    data->set.ssh_keyfunc_userp = va_arg(param, void *);
+    break;
+#endif /* HAVE_LIBSSH2_KNOWNHOST_API */
+
+#endif /* USE_LIBSSH2 */
+
+  case CURLOPT_HTTP_TRANSFER_DECODING:
+    /*
+     * disable libcurl transfer encoding is used
+     */
+    data->set.http_te_skip = (bool)(0 == va_arg(param, long));
+    break;
+
+  case CURLOPT_HTTP_CONTENT_DECODING:
+    /*
+     * raw data passed to the application when content encoding is used
+     */
+    data->set.http_ce_skip = (bool)(0 == va_arg(param, long));
+    break;
+
+  case CURLOPT_NEW_FILE_PERMS:
+    /*
+     * Uses these permissions instead of 0644
+     */
+    data->set.new_file_perms = va_arg(param, long);
+    break;
+
+  case CURLOPT_NEW_DIRECTORY_PERMS:
+    /*
+     * Uses these permissions instead of 0755
+     */
+    data->set.new_directory_perms = va_arg(param, long);
+    break;
+
+  case CURLOPT_ADDRESS_SCOPE:
+    /*
+     * We always get longs when passed plain numericals, but for this value we
+     * know that an unsigned int will always hold the value so we blindly
+     * typecast to this type
+     */
+    data->set.scope = (unsigned int) va_arg(param, long);
+    break;
+
+  case CURLOPT_PROTOCOLS:
+    /* set the bitmask for the protocols that are allowed to be used for the
+       transfer, which thus helps the app which takes URLs from users or other
+       external inputs and want to restrict what protocol(s) to deal
+       with. Defaults to CURLPROTO_ALL. */
+    data->set.allowed_protocols = va_arg(param, long) & PROT_EXTMASK;
+    break;
+
+  case CURLOPT_REDIR_PROTOCOLS:
+    /* set the bitmask for the protocols that libcurl is allowed to follow to,
+       as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs
+       to be set in both bitmasks to be allowed to get redirected to. Defaults
+       to all protocols except FILE and SCP. */
+    data->set.redir_protocols = va_arg(param, long) & PROT_EXTMASK;
+    break;
+
+  case CURLOPT_MAIL_FROM:
+    result = setstropt(&data->set.str[STRING_MAIL_FROM],
+                       va_arg(param, char *));
+    break;
+
+  case CURLOPT_MAIL_RCPT:
+    /* get a list of mail recipients */
+    data->set.mail_rcpt = va_arg(param, struct curl_slist *);
+    break;
+
+  case CURLOPT_RTSP_REQUEST:
+    {
+      /*
+       * Set the RTSP request method (OPTIONS, SETUP, PLAY, etc...)
+       * Would this be better if the RTSPREQ_* were just moved into here?
+       */
+      long curl_rtspreq = va_arg(param, long);
+      Curl_RtspReq rtspreq = RTSPREQ_NONE;
+      switch(curl_rtspreq) {
+        case CURL_RTSPREQ_OPTIONS:
+          rtspreq = RTSPREQ_OPTIONS;
+          break;
+
+        case CURL_RTSPREQ_DESCRIBE:
+          rtspreq = RTSPREQ_DESCRIBE;
+          break;
+
+        case CURL_RTSPREQ_ANNOUNCE:
+          rtspreq = RTSPREQ_ANNOUNCE;
+          break;
+
+        case CURL_RTSPREQ_SETUP:
+          rtspreq = RTSPREQ_SETUP;
+          break;
+
+        case CURL_RTSPREQ_PLAY:
+          rtspreq = RTSPREQ_PLAY;
+          break;
+
+        case CURL_RTSPREQ_PAUSE:
+          rtspreq = RTSPREQ_PAUSE;
+          break;
+
+        case CURL_RTSPREQ_TEARDOWN:
+          rtspreq = RTSPREQ_TEARDOWN;
+          break;
+
+        case CURL_RTSPREQ_GET_PARAMETER:
+          rtspreq = RTSPREQ_GET_PARAMETER;
+          break;
+
+        case CURL_RTSPREQ_SET_PARAMETER:
+          rtspreq = RTSPREQ_SET_PARAMETER;
+          break;
+
+        case CURL_RTSPREQ_RECORD:
+          rtspreq = RTSPREQ_RECORD;
+          break;
+
+        case CURL_RTSPREQ_RECEIVE:
+          rtspreq = RTSPREQ_RECEIVE;
+          break;
+        default:
+          rtspreq = RTSPREQ_NONE;
+      }
+
+      data->set.rtspreq = rtspreq;
+    break;
+    }
+
+
+  case CURLOPT_RTSP_SESSION_ID:
+    /*
+     * Set the RTSP Session ID manually. Useful if the application is
+     * resuming a previously established RTSP session
+     */
+    result = setstropt(&data->set.str[STRING_RTSP_SESSION_ID],
+                       va_arg(param, char *));
+    break;
+
+  case CURLOPT_RTSP_STREAM_URI:
+    /*
+     * Set the Stream URI for the RTSP request. Unless the request is
+     * for generic server options, the application will need to set this.
+     */
+    result = setstropt(&data->set.str[STRING_RTSP_STREAM_URI],
+                       va_arg(param, char *));
+    break;
+
+  case CURLOPT_RTSP_TRANSPORT:
+    /*
+     * The content of the Transport: header for the RTSP request
+     */
+    result = setstropt(&data->set.str[STRING_RTSP_TRANSPORT],
+                       va_arg(param, char *));
+    break;
+
+  case CURLOPT_RTSP_CLIENT_CSEQ:
+    /*
+     * Set the CSEQ number to issue for the next RTSP request. Useful if the
+     * application is resuming a previously broken connection. The CSEQ
+     * will increment from this new number henceforth.
+     */
+    data->state.rtsp_next_client_CSeq = va_arg(param, long);
+    break;
+
+  case CURLOPT_RTSP_SERVER_CSEQ:
+    /* Same as the above, but for server-initiated requests */
+    data->state.rtsp_next_client_CSeq = va_arg(param, long);
+    break;
+
+  case CURLOPT_INTERLEAVEDATA:
+    data->set.rtp_out = va_arg(param, void *);
+    break;
+  case CURLOPT_INTERLEAVEFUNCTION:
+    /* Set the user defined RTP write function */
+    data->set.fwrite_rtp = va_arg(param, curl_write_callback);
+    break;
+  default:
+    /* unknown tag and its companion, just ignore: */
+    result = CURLE_FAILED_INIT; /* correct this */
+    break;
+  }
+
+  return result;
+}
+
+static void conn_free(struct connectdata *conn)
+{
+  if(!conn)
+    return;
+
+  /* close the SSL stuff before we close any sockets since they will/may
+     write to the sockets */
+  Curl_ssl_close(conn, FIRSTSOCKET);
+  Curl_ssl_close(conn, SECONDARYSOCKET);
+
+  /* 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);
+  Curl_safefree(conn->allocptr.rtsp_transport);
+  Curl_safefree(conn->trailer);
+  Curl_safefree(conn->host.rawalloc); /* host name buffer */
+  Curl_safefree(conn->proxy.rawalloc); /* proxy name buffer */
+  Curl_safefree(conn->master_buffer);
+
+  Curl_llist_destroy(conn->send_pipe, NULL);
+  Curl_llist_destroy(conn->recv_pipe, NULL);
+  Curl_llist_destroy(conn->pend_pipe, NULL);
+  Curl_llist_destroy(conn->done_pipe, NULL);
+
+  /* possible left-overs from the async name resolvers */
+#if defined(CURLRES_THREADED)
+  Curl_destroy_thread_data(&conn->async);
+#elif defined(CURLRES_ASYNCH)
+  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 */
+}
+
+CURLcode Curl_disconnect(struct connectdata *conn)
+{
+  struct SessionHandle *data;
+  if(!conn)
+    return CURLE_OK; /* this is closed and fine already */
+  data = conn->data;
+
+  if(!data) {
+    DEBUGF(infof(data, "DISCONNECT without easy handle, ignoring\n"));
+    return CURLE_OK;
+  }
+
+  if(conn->dns_entry != NULL) {
+    Curl_resolv_unlock(data, conn->dns_entry);
+    conn->dns_entry = NULL;
+  }
+
+#if defined(DEBUGBUILD) && 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_expire(data, 0); /* shut off timers */
+  Curl_hostcache_prune(data); /* kill old DNS cache entries */
+
+  {
+    int has_host_ntlm = (conn->ntlm.state != NTLMSTATE_NONE);
+    int has_proxy_ntlm = (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. */
+
+    if (has_host_ntlm) {
+      data->state.authhost.done = FALSE;
+      data->state.authhost.picked =
+        data->state.authhost.want;
+    }
+
+    if (has_proxy_ntlm) {
+      data->state.authproxy.done = FALSE;
+      data->state.authproxy.picked =
+        data->state.authproxy.want;
+    }
+
+    if (has_host_ntlm || has_proxy_ntlm) {
+      data->state.authproblem = FALSE;
+
+      Curl_ntlm_cleanup(conn);
+    }
+  }
+
+  /* Cleanup possible redirect junk */
+  if(data->req.newurl) {
+    free(data->req.newurl);
+    data->req.newurl = NULL;
+  }
+
+  if(conn->handler->disconnect)
+    /* This is set if protocol-specific cleanups should be made */
+    conn->handler->disconnect(conn);
+
+  if(-1 != conn->connectindex) {
+    /* unlink ourselves! */
+    infof(data, "Closing connection #%ld\n", conn->connectindex);
+    if(data->state.connc)
+      /* only clear the table entry if we still know in which cache we
+         used to be in */
+      data->state.connc->connects[conn->connectindex] = NULL;
+  }
+
+#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, FIRSTSOCKET);
+
+  /* Indicate to all handles on the pipe that we're dead */
+  if(Curl_isPipeliningEnabled(data)) {
+    signalPipeClose(conn->send_pipe, TRUE);
+    signalPipeClose(conn->recv_pipe, TRUE);
+    signalPipeClose(conn->pend_pipe, TRUE);
+    signalPipeClose(conn->done_pipe, FALSE);
+  }
+
+  conn_free(conn);
+  data->state.current_conn = NULL;
+
+  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;
+
+  sval = Curl_socket_ready(sock, CURL_SOCKET_BAD, 0);
+  if(sval == 0)
+    /* timeout */
+    ret_val = FALSE;
+
+  return ret_val;
+}
+
+#ifndef CURL_DISABLE_RTSP
+/*
+ * The server may send us RTP data at any point, and RTSPREQ_RECEIVE does not
+ * want to block the application forever while receiving a stream. Therefore,
+ * we cannot assume that an RTSP socket is dead just because it is readable.
+ *
+ * Instead, if it is readable, run Curl_getconnectinfo() to peek at the socket
+ * and distinguish between closed and data.
+ */
+static bool RTSPConnIsDead(struct connectdata *check)
+{
+  int sval;
+  bool ret_val = TRUE;
+
+  sval = Curl_socket_ready(check->sock[FIRSTSOCKET], CURL_SOCKET_BAD, 0);
+  if(sval == 0) {
+    /* timeout */
+    ret_val = FALSE;
+  }
+  else if (sval & CURL_CSELECT_ERR) {
+    /* socket is in an error state */
+    ret_val = TRUE;
+  }
+  else if (sval & CURL_CSELECT_IN) {
+    /* readable with no error. could be closed or could be alive */
+    long connectinfo = 0;
+    Curl_getconnectinfo(check->data, &connectinfo, &check);
+    if(connectinfo != -1) {
+      ret_val = FALSE;
+    }
+  }
+
+  return ret_val;
+}
+#endif /* CURL_DISABLE_RTSP */
+
+static bool IsPipeliningPossible(const struct SessionHandle *handle)
+{
+  if(handle->multi && Curl_multi_canPipeline(handle->multi) &&
+      (handle->set.httpreq == HTTPREQ_GET ||
+       handle->set.httpreq == HTTPREQ_HEAD) &&
+      handle->set.httpversion != CURL_HTTP_VERSION_1_0)
+    return TRUE;
+
+  return FALSE;
+}
+
+bool Curl_isPipeliningEnabled(const struct SessionHandle *handle)
+{
+  if(handle->multi && Curl_multi_canPipeline(handle->multi))
+    return TRUE;
+
+  return FALSE;
+}
+
+CURLcode Curl_addHandleToPipeline(struct SessionHandle *data,
+                                  struct curl_llist *pipeline)
+{
+#ifdef DEBUGBUILD
+  if(!IsPipeliningPossible(data)) {
+    /* when not pipelined, there MUST be no handle in the list already */
+    if(pipeline->head)
+      infof(data, "PIPE when no PIPE supposed!\n");
+  }
+#endif
+  if(!Curl_llist_insert_next(pipeline, pipeline->tail, data))
+    return CURLE_OUT_OF_MEMORY;
+  return CURLE_OK;
+}
+
+int Curl_removeHandleFromPipeline(struct SessionHandle *handle,
+                                  struct curl_llist *pipeline)
+{
+  struct curl_llist_element *curr;
+
+  curr = pipeline->head;
+  while(curr) {
+    if(curr->ptr == handle) {
+      Curl_llist_remove(pipeline, curr, NULL);
+      return 1; /* we removed a handle */
+    }
+    curr = curr->next;
+  }
+
+  return 0;
+}
+
+#if 0 /* this code is saved here as it is useful for debugging purposes */
+static void Curl_printPipeline(struct curl_llist *pipeline)
+{
+  struct curl_llist_element *curr;
+
+  curr = pipeline->head;
+  while(curr) {
+    struct SessionHandle *data = (struct SessionHandle *) curr->ptr;
+    infof(data, "Handle in pipeline: %s\n", data->state.path);
+    curr = curr->next;
+  }
+}
+#endif
+
+static struct SessionHandle* gethandleathead(struct curl_llist *pipeline)
+{
+  struct curl_llist_element *curr = pipeline->head;
+  if(curr) {
+    return (struct SessionHandle *) curr->ptr;
+  }
+
+  return NULL;
+}
+
+/* remove the specified connection from all (possible) pipelines and related
+   queues */
+void Curl_getoff_all_pipelines(struct SessionHandle *data,
+                               struct connectdata *conn)
+{
+  bool recv_head = (bool)(conn->readchannel_inuse &&
+    (gethandleathead(conn->recv_pipe) == data));
+
+  bool send_head = (bool)(conn->writechannel_inuse &&
+    (gethandleathead(conn->send_pipe) == data));
+
+  if(Curl_removeHandleFromPipeline(data, conn->recv_pipe) && recv_head)
+    conn->readchannel_inuse = FALSE;
+  if(Curl_removeHandleFromPipeline(data, conn->send_pipe) && send_head)
+    conn->writechannel_inuse = FALSE;
+  Curl_removeHandleFromPipeline(data, conn->pend_pipe);
+  Curl_removeHandleFromPipeline(data, conn->done_pipe);
+}
+
+static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke)
+{
+  struct curl_llist_element *curr;
+
+  if(!pipeline)
+    return;
+
+  curr = pipeline->head;
+  while(curr) {
+    struct curl_llist_element *next = curr->next;
+    struct SessionHandle *data = (struct SessionHandle *) curr->ptr;
+
+#ifdef DEBUGBUILD /* debug-only code */
+    if(data->magic != CURLEASY_MAGIC_NUMBER) {
+      /* MAJOR BADNESS */
+      infof(data, "signalPipeClose() found BAAD easy handle\n");
+    }
+#endif
+
+    if (pipe_broke)
+       data->state.pipe_broke = TRUE;
+    Curl_multi_handlePipeBreak(data);
+    Curl_llist_remove(pipeline, curr, NULL);
+    curr = next;
+  }
+}
+
+
+/*
+ * Given one filled in connection struct (named needle), this function should
+ * detect if there already is one that has all the significant details
+ * exactly the same and thus should be used instead.
+ *
+ * If there is a match, this function returns TRUE - and has marked the
+ * connection as 'in-use'. It must later be called with ConnectionDone() to
+ * return back to 'idle' (unused) state.
+ */
+static bool
+ConnectionExists(struct SessionHandle *data,
+                 struct connectdata *needle,
+                 struct connectdata **usethis)
+{
+  long i;
+  struct connectdata *check;
+  bool canPipeline = IsPipeliningPossible(data);
+
+  for(i=0; i< data->state.connc->num; i++) {
+    bool match = FALSE;
+    size_t pipeLen = 0;
+    /*
+     * Note that if we use a HTTP proxy, we check connections to that
+     * proxy and not to the actual remote server.
+     */
+    check = data->state.connc->connects[i];
+    if(!check)
+      /* NULL pointer means not filled-in entry */
+      continue;
+
+    pipeLen = check->send_pipe->size + check->recv_pipe->size;
+
+    if(check->connectindex == -1) {
+      check->connectindex = i; /* Set this appropriately since it might have
+                                  been set to -1 when the easy was removed
+                                  from the multi */
+    }
+
+    if(!pipeLen && !check->inuse) {
+      /* The check for a dead socket makes sense only if there are no
+         handles in pipeline and the connection isn't already marked in
+         use */
+      bool dead;
+#ifndef CURL_DISABLE_RTSP
+      if(check->protocol & PROT_RTSP)
+        /* RTSP is a special case due to RTP interleaving */
+        dead = RTSPConnIsDead(check);
+      else
+#endif /*CURL_DISABLE_RTSP*/
+        dead = SocketIsDead(check->sock[FIRSTSOCKET]);
+
+      if(dead) {
+        check->data = data;
+        infof(data, "Connection #%ld seems to be dead!\n", i);
+
+        Curl_disconnect(check); /* disconnect resources */
+        data->state.connc->connects[i]=NULL; /* nothing here */
+
+        continue;
+      }
+    }
+
+    if(canPipeline) {
+      /* Make sure the pipe has only GET requests */
+      struct SessionHandle* sh = gethandleathead(check->send_pipe);
+      struct SessionHandle* rh = gethandleathead(check->recv_pipe);
+      if(sh) {
+        if(!IsPipeliningPossible(sh))
+          continue;
+      }
+      else if(rh) {
+        if(!IsPipeliningPossible(rh))
+          continue;
+      }
+
+#ifdef DEBUGBUILD
+      if(pipeLen > MAX_PIPELINE_LENGTH) {
+        infof(data, "BAD! Connection #%ld has too big pipeline!\n",
+              check->connectindex);
+      }
+#endif
+    }
+    else {
+      if(pipeLen > 0) {
+        /* can only happen within multi handles, and means that another easy
+           handle is using this connection */
+        continue;
+      }
+
+#ifdef CURLRES_ASYNCH
+      /* ip_addr_str[0] is NUL only if the resolving of the name hasn't
+         completed yet and until then we don't re-use this connection */
+      if(!check->ip_addr_str[0]) {
+        infof(data,
+              "Connection #%ld hasn't finished name resolve, can't reuse\n",
+              check->connectindex);
+        continue;
+      }
+#endif
+
+      if((check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) || check->bits.close) {
+        /* Don't pick a connection that hasn't connected yet or that is going
+           to get closed. */
+        infof(data, "Connection #%ld isn't open enough, can't reuse\n",
+              check->connectindex);
+#ifdef DEBUGBUILD
+        if(check->recv_pipe->size > 0) {
+          infof(data, "BAD! Unconnected #%ld has a non-empty recv pipeline!\n",
+                check->connectindex);
+        }
+#endif
+        continue;
+      }
+    }
+
+    if((needle->protocol&PROT_SSL) != (check->protocol&PROT_SSL))
+      /* don't do mixed SSL and non-SSL connections */
+      continue;
+
+    if(needle->protocol&PROT_SSL) {
+      if((data->set.ssl.verifypeer != check->verifypeer) ||
+         (data->set.ssl.verifyhost != check->verifyhost))
+        continue;
+    }
+
+    if(needle->bits.proxy != check->bits.proxy)
+      /* don't do mixed proxy and non-proxy connections */
+      continue;
+
+    if(!canPipeline && check->inuse)
+      /* this request can't be pipelined but the checked connection is already
+         in use so we skip it */
+      continue;
+
+    if(!needle->bits.httpproxy || needle->protocol&PROT_SSL ||
+       (needle->bits.httpproxy && check->bits.httpproxy &&
+        needle->bits.tunnel_proxy && check->bits.tunnel_proxy &&
+        Curl_raw_equal(needle->proxy.name, check->proxy.name) &&
+        (needle->port == check->port))) {
+      /* The requested connection does not use a HTTP proxy or it uses SSL or
+         it is a non-SSL protocol tunneled over the same http proxy name and
+         port number */
+
+      if(Curl_raw_equal(needle->handler->scheme, check->handler->scheme) &&
+         Curl_raw_equal(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)) {
+            DEBUGF(infof(data,
+                         "Connection #%ld has different SSL parameters, "
+                         "can't reuse\n",
+                         check->connectindex));
+            continue;
+          }
+          else if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) {
+            DEBUGF(infof(data,
+                         "Connection #%ld has not started ssl connect, "
+                         "can't reuse\n",
+                         check->connectindex));
+            continue;
+          }
+        }
+        if((needle->protocol & PROT_FTP) ||
+           ((needle->protocol & PROT_HTTP) &&
+            (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 host, port and type? */
+      if(check->bits.proxy &&
+         (needle->proxytype == check->proxytype) &&
+         (needle->bits.tunnel_proxy == check->bits.tunnel_proxy) &&
+         Curl_raw_equal(needle->proxy.name, check->proxy.name) &&
+         needle->port == check->port) {
+        /* This is the same proxy connection, use it! */
+        match = TRUE;
+      }
+    }
+
+    if(match) {
+      check->inuse = TRUE; /* mark this as being in use so that no other
+                              handle in a multi stack may nick it */
+
+      *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; data->state.connc && (i< data->state.connc->num); i++) {
+    conn = data->state.connc->connects[i];
+
+    if(!conn || conn->inuse)
+      continue;
+
+    /* Set higher score for the age passed since the connection was used */
+    score = Curl_tvdiff(now, conn->now);
+
+    if(score > highscore) {
+      highscore = score;
+      connindex = i;
+    }
+  }
+  if(connindex >= 0) {
+    /* Set the connection's owner correctly */
+    conn = data->state.connc->connects[connindex];
+    conn->data = data;
+
+    /* the winner gets the honour of being disconnected */
+    (void)Curl_disconnect(conn);
+
+    /* clean the array entry */
+    data->state.connc->connects[connindex] = NULL;
+  }
+
+  return connindex; /* return the available index or -1 */
+}
+
+/* this connection can now be marked 'idle' */
+static void
+ConnectionDone(struct connectdata *conn)
+{
+  conn->inuse = FALSE;
+}
+
+/*
+ * 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.connc->num; i++) {
+    if(!data->state.connc->connects[i])
+      break;
+  }
+  if(i == data->state.connc->num) {
+    /* there was no room available, kill one */
+    i = ConnectionKillOne(data);
+    if(-1 != i)
+      infof(data, "Connection (#%ld) was killed to make room (holds %ld)\n",
+            i, data->state.connc->num);
+    else
+      infof(data, "This connection did not fit in the connection cache\n");
+  }
+
+  conn->connectindex = i; /* Make the child know where the pointer to this
+                             particular data is stored. But note that this -1
+                             if this is not within the cache and this is
+                             probably not checked for everywhere (yet). */
+  conn->inuse = TRUE;
+  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.
+
+       TODO: make sure we really can work with more handles than positions in
+       the cache, or possibly we should (allow to automatically) resize the
+       connection cache when we add more easy handles to a multi handle!
+    */
+    data->state.connc->connects[i] = conn; /* fill in this */
+    conn->data = data;
+  }
+
+  return i;
+}
+
+/* after a TCP connection to the proxy has been verified, this function does
+   the next magic step.
+
+   Note: this function (and its sub-functions) calls failf()
+
+*/
+CURLcode Curl_connected_proxy(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct SessionHandle *data = conn->data;
+
+  if(conn->bits.tcpconnect)
+    /* allow this to get called again from the multi interface when TCP is
+       found connected in the state machine, even though it has already been
+       called if the connection happened "instantly" */
+    return CURLE_OK;
+
+  switch(data->set.proxytype) {
+#ifndef CURL_DISABLE_PROXY
+  case CURLPROXY_SOCKS5:
+  case CURLPROXY_SOCKS5_HOSTNAME:
+    result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd,
+                         conn->host.name, conn->remote_port,
+                         FIRSTSOCKET, conn);
+    break;
+  case CURLPROXY_SOCKS4:
+    result = Curl_SOCKS4(conn->proxyuser, conn->host.name,
+                         conn->remote_port, FIRSTSOCKET, conn, FALSE);
+    break;
+  case CURLPROXY_SOCKS4A:
+    result = Curl_SOCKS4(conn->proxyuser, conn->host.name,
+                         conn->remote_port, FIRSTSOCKET, conn, TRUE);
+    break;
+#endif /* CURL_DISABLE_PROXY */
+  case CURLPROXY_HTTP:
+  case CURLPROXY_HTTP_1_0:
+    /* do nothing here. handled later. */
+    break;
+  default:
+    break;
+  } /* switch proxytype */
+
+  return result;
+}
+
+static CURLcode ConnectPlease(struct SessionHandle *data,
+                              struct connectdata *conn,
+                              bool *connected)
+{
+  CURLcode result;
+  Curl_addrinfo *addr;
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  char *hostname = conn->bits.proxy?conn->proxy.name:conn->host.name;
+
+  infof(data, "About to connect() to %s%s port %ld (#%ld)\n",
+        conn->bits.proxy?"proxy ":"",
+        hostname, conn->port, conn->connectindex);
+#else
+  (void)data;
+#endif
+
+  /*************************************************************
+   * Connect to server/proxy
+   *************************************************************/
+  result= Curl_connecthost(conn,
+                           conn->dns_entry,
+                           &conn->sock[FIRSTSOCKET],
+                           &addr,
+                           connected);
+  if(CURLE_OK == result) {
+    /* All is cool, we store the current information */
+    conn->ip_addr = addr;
+
+    if(*connected)
+      result = Curl_connected_proxy(conn);
+  }
+
+  if(result)
+    *connected = FALSE; /* mark it as not connected */
+
+  return result;
+}
+
+/*
+ * verboseconnect() displays verbose information after a connect
+ */
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void verboseconnect(struct connectdata *conn)
+{
+  infof(conn->data, "Connected to %s (%s) port %ld (#%ld)\n",
+        conn->bits.proxy ? conn->proxy.dispname : conn->host.dispname,
+        conn->ip_addr_str, conn->port, conn->connectindex);
+}
+#endif
+
+int Curl_protocol_getsock(struct connectdata *conn,
+                          curl_socket_t *socks,
+                          int numsocks)
+{
+  if(conn->handler->proto_getsock)
+    return conn->handler->proto_getsock(conn, socks, numsocks);
+  return GETSOCK_BLANK;
+}
+
+int Curl_doing_getsock(struct connectdata *conn,
+                       curl_socket_t *socks,
+                       int numsocks)
+{
+  if(conn && conn->handler->doing_getsock)
+    return conn->handler->doing_getsock(conn, socks, numsocks);
+  return GETSOCK_BLANK;
+}
+
+/*
+ * We are doing protocol-specific connecting and this is being called over and
+ * over from the multi interface until the connection phase is done on
+ * protocol layer.
+ */
+
+CURLcode Curl_protocol_connecting(struct connectdata *conn,
+                                  bool *done)
+{
+  CURLcode result=CURLE_OK;
+
+  if(conn && conn->handler->connecting) {
+    *done = FALSE;
+    result = conn->handler->connecting(conn, done);
+  }
+  else
+    *done = TRUE;
+
+  return result;
+}
+
+/*
+ * We are DOING this is being called over and over from the multi interface
+ * until the DOING phase is done on protocol layer.
+ */
+
+CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done)
+{
+  CURLcode result=CURLE_OK;
+
+  if(conn && conn->handler->doing) {
+    *done = FALSE;
+    result = conn->handler->doing(conn, done);
+  }
+  else
+    *done = TRUE;
+
+  return result;
+}
+
+/*
+ * We have discovered that the TCP connection has been successful, we can now
+ * proceed with some action.
+ *
+ */
+CURLcode Curl_protocol_connect(struct connectdata *conn,
+                               bool *protocol_done)
+{
+  CURLcode result=CURLE_OK;
+  struct SessionHandle *data = conn->data;
+
+  *protocol_done = FALSE;
+
+  if(conn->bits.tcpconnect && conn->bits.protoconnstart) {
+    /* 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. Note that we don't know if the protocol is actually done.
+
+       Unless this protocol doesn't have any protocol-connect callback, as
+       then we know we're done. */
+    if(!conn->handler->connecting)
+      *protocol_done = TRUE;
+
+    return CURLE_OK;
+  }
+
+  if(!conn->bits.tcpconnect) {
+
+    Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
+
+    if(data->set.verbose)
+      verboseconnect(conn);
+  }
+
+  if(!conn->bits.protoconnstart) {
+    if(conn->handler->connect_it) {
+      /* 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->handler->connect_it(conn, protocol_done);
+    }
+    else
+      *protocol_done = TRUE;
+
+    /* it has started, possibly even completed but that knowledge isn't stored
+       in this bit! */
+    if(!result)
+      conn->bits.protoconnstart = TRUE;
+  }
+
+  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;
+}
+
+/*
+ * Check if characters in hostname is allowed in Top Level Domain.
+ */
+static bool tld_check_name(struct SessionHandle *data,
+                           const char *ace_hostname)
+{
+  size_t err_pos;
+  char *uc_name = NULL;
+  int rc;
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  const char *tld_errmsg = "<no msg>";
+#else
+  (void)data;
+#endif
+
+  /* Convert (and downcase) ACE-name back into locale's character set */
+  rc = idna_to_unicode_lzlz(ace_hostname, &uc_name, 0);
+  if(rc != IDNA_SUCCESS)
+    return FALSE;
+
+  rc = tld_check_lz(uc_name, &err_pos, NULL);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+#ifdef HAVE_TLD_STRERROR
+  if(rc != TLD_SUCCESS)
+    tld_errmsg = tld_strerror((Tld_rc)rc);
+#endif
+  if(rc == TLD_INVALID)
+    infof(data, "WARNING: %s; pos %u = `%c'/0x%02X\n",
+          tld_errmsg, err_pos, uc_name[err_pos],
+          uc_name[err_pos] & 255);
+  else if(rc != TLD_SUCCESS)
+    infof(data, "WARNING: TLD check for %s failed; %s\n",
+          uc_name, tld_errmsg);
+#endif /* CURL_DISABLE_VERBOSE_STRINGS */
+  if(uc_name)
+     idn_free(uc_name);
+  if(rc != TLD_SUCCESS)
+    return FALSE;
+
+  return TRUE;
+}
+#endif
+
+/*
+ * Perform any necessary IDN conversion of hostname
+ */
+static void fix_hostname(struct SessionHandle *data,
+                         struct connectdata *conn, struct hostname *host)
+{
+#ifndef USE_LIBIDN
+  (void)data;
+  (void)conn;
+#elif defined(CURL_DISABLE_VERBOSE_STRINGS)
+  (void)conn;
+#endif
+
+  /* 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;
+    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; %s\n",
+            host->name, Curl_idn_strerror(conn,rc));
+    else {
+      /* tld_check_name() displays a warning if the host name contains
+         "illegal" characters for this TLD */
+      (void)tld_check_name(data, ace_hostname);
+
+      host->encalloc = ace_hostname;
+      /* change the name pointer to point to the encoded hostname */
+      host->name = host->encalloc;
+    }
+  }
+#endif
+}
+
+/*
+ * Allocate and initialize a new connectdata object.
+ */
+static struct connectdata *allocate_conn(void)
+{
+  struct connectdata *conn;
+
+  conn = calloc(1, sizeof(struct connectdata));
+  if(!conn)
+    return NULL;
+
+  conn->handler = &Curl_handler_dummy;  /* Be sure we have a handler defined
+                                           already from start to avoid NULL
+                                           situations and checks */
+
+  /* and we setup a few fields in case we end up actually using this struct */
+
+  conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD;     /* no file descriptor */
+  conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
+  conn->connectindex = -1;    /* no index */
+  conn->port = -1; /* unknown at this point */
+
+  /* Default protocol-independent behavior doesn't support persistent
+     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;
+
+  /* Store creation time to help future close decision making */
+  conn->created = Curl_tvnow();
+
+  return conn;
+}
+
+static CURLcode findprotocol(struct SessionHandle *data,
+                             struct connectdata *conn,
+                             const char *protostr)
+{
+  const struct Curl_handler * const *pp;
+  const struct Curl_handler *p;
+
+  /* Scan protocol handler table and match against 'protostr' to set a few
+     variables based on the URL. Now that the handler may be changed later
+     when the protocol specific setup function is called. */
+  for (pp = protocols; (p = *pp) != NULL; pp++) {
+    if(Curl_raw_equal(p->scheme, protostr)) {
+      /* Protocol found in table. Check if allowed */
+      if(!(data->set.allowed_protocols & p->protocol))
+        /* nope, get out */
+        break;
+
+      /* it is allowed for "normal" request, now do an extra check if this is
+         the result of a redirect */
+      if(data->state.this_is_a_follow &&
+         !(data->set.redir_protocols & p->protocol))
+        /* nope, get out */
+        break;
+
+      /* Perform setup complement if some. */
+      conn->handler = p;
+      conn->protocol |= p->protocol;
+
+      /* 'port' and 'remote_port' are set in setup_connection_internals() */
+      return CURLE_OK;
+    }
+  }
+
+
+  /* The protocol was not found in the table, but we don't have to assign it
+     to anything since it is already assigned to a dummy-struct in the
+     create_conn() function when the connectdata struct is allocated. */
+  failf(data, "Protocol %s not supported or disabled in " LIBCURL_NAME,
+        protostr);
+
+  return CURLE_UNSUPPORTED_PROTOCOL;
+}
+
+/*
+ * Parse URL and fill in the relevant members of the connection struct.
+ */
+static CURLcode parseurlandfillconn(struct SessionHandle *data,
+                                    struct connectdata *conn,
+                                    bool *prot_missing)
+{
+  char *at;
+  char *fragment;
+  char *path = data->state.path;
+  char *query;
+  int rc;
+  char protobuf[16];
+  const char *protop;
+
+  *prot_missing = FALSE;
+
+  /*************************************************************
+   * 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]",
+                  protobuf, path)) &&
+     Curl_raw_equal(protobuf, "file")) {
+    if(path[0] == '/' && 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(path, path + 2, strlen(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(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(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 preceding 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(path, ptr, strlen(ptr)+1);
+      }
+    }
+
+    protop = "file"; /* protocol string */
+  }
+  else {
+    /* clear path */
+    path[0]=0;
+
+    if(2 > sscanf(data->change.url,
+                   "%15[^\n:]://%[^\n/]%[^\n]",
+                   protobuf,
+                   conn->host.name, path)) {
+
+      /*
+       * The URL was badly formatted, let's try the browser-style _without_
+       * protocol specified like 'http://'.
+       */
+      rc = sscanf(data->change.url, "%[^\n/]%[^\n]", conn->host.name, path);
+      if(1 > rc) {
+        /*
+         * We couldn't even get this format.
+         * djgpp 2.04 has a sscanf() bug where 'conn->host.name' is
+         * assigned, but the return value is EOF!
+         */
+#if defined(__DJGPP__) && (DJGPP_MINOR == 4)
+        if (!(rc == -1 && *conn->host.name))
+#endif
+        {
+          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("FTP.", conn->host.name))
+        protop = "ftp";
+      else if(checkprefix("DICT.", conn->host.name))
+        protop = "DICT";
+      else if(checkprefix("LDAP.", conn->host.name))
+        protop = "LDAP";
+      else if(checkprefix("IMAP.", conn->host.name))
+        protop = "IMAP";
+      else {
+        protop = "http";
+      }
+
+      *prot_missing = TRUE; /* not given in URL */
+    }
+    else
+      protop = protobuf;
+  }
+
+  /* We search for '?' in the host name (but only on the right side of a
+   * @-letter to allow ?-letters in username and password) to handle things
+   * like http://example.com?param= (notice the missing '/').
+   */
+  at = strchr(conn->host.name, '@');
+  if(at)
+    query = strchr(at+1, '?');
+  else
+    query = strchr(conn->host.name, '?');
+
+  if(query) {
+    /* We must insert a slash before the '?'-letter in the URL. If the URL had
+       a slash after the '?', that is where the path currently begins and the
+       '?string' is still part of the host name.
+
+       We must move the trailing part from the host name and put it first in
+       the path. And have it all prefixed with a slash.
+    */
+
+    size_t hostlen = strlen(query);
+    size_t pathlen = strlen(path);
+
+    /* move the existing path plus the zero byte forward, to make room for
+       the host-name part */
+    memmove(path+hostlen+1, path, pathlen+1);
+
+     /* now copy the trailing host part in front of the existing path */
+    memcpy(path+1, query, hostlen);
+
+    path[0]='/'; /* prepend the missing slash */
+
+    *query=0; /* now cut off the hostname at the ? */
+  }
+  else if(!path[0]) {
+    /* if there's no path set, use a single slash */
+    strcpy(path, "/");
+  }
+
+  /* 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(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(&path[1], path, strlen(path)+1);
+    path[0] = '/';
+  }
+
+  if (conn->host.name[0] == '[') {
+    /* This looks like an IPv6 address literal.  See if there is an address
+       scope.  */
+    char *percent = strstr (conn->host.name, "%25");
+    if (percent) {
+      char *endp;
+      unsigned long scope = strtoul (percent + 3, &endp, 10);
+      if (*endp == ']') {
+        /* The address scope was well formed.  Knock it out of the
+           hostname. */
+        memmove(percent, endp, strlen(endp)+1);
+        if (!data->state.this_is_a_follow)
+          /* Don't honour a scope given in a Location: header */
+          conn->scope = (unsigned int)scope;
+      } else
+        infof(data, "Invalid IPv6 address format\n");
+    }
+  }
+
+  if(data->set.scope)
+    /* Override any scope that was set above.  */
+    conn->scope = data->set.scope;
+
+  /* Remove the fragment part of the path. Per RFC 2396, this is always the
+     last part of the URI. We are looking for the first '#' so that we deal
+     gracefully with non conformant URI such as http://example.com#foo#bar. */
+  fragment = strchr(path, '#');
+  if(fragment)
+    *fragment = 0;
+
+  /*
+   * So if the URL was A://B/C#D,
+   *   protop is A
+   *   conn->host.name is B
+   *   data->state.path is /C
+   */
+
+  return findprotocol(data, conn, protop);
+}
+
+static void llist_dtor(void *user, void *element)
+{
+  (void)user;
+  (void)element;
+  /* Do nothing */
+}
+
+/*
+ * If we're doing a resumed transfer, we need to setup our stuff
+ * properly.
+ */
+static CURLcode setup_range(struct SessionHandle *data)
+{
+  struct UrlState *s = &data->state;
+  s->resume_from = data->set.set_resume_from;
+  if(s->resume_from || data->set.str[STRING_SET_RANGE]) {
+    if(s->rangestringalloc)
+      free(s->range);
+
+    if(s->resume_from)
+      s->range = aprintf("%" FORMAT_OFF_TU "-", s->resume_from);
+    else
+      s->range = strdup(data->set.str[STRING_SET_RANGE]);
+
+    s->rangestringalloc = (bool)(s->range?TRUE:FALSE);
+
+    if(!s->range)
+      return CURLE_OUT_OF_MEMORY;
+
+    /* tell ourselves to fetch this range */
+    s->use_range = TRUE;        /* enable range download */
+  }
+  else
+    s->use_range = FALSE; /* disable range download */
+
+  return CURLE_OK;
+}
+
+
+/***************************************************************
+* Setup connection internals specific to the requested protocol.
+* This MUST get called after proxy magic has been figured out.
+***************************************************************/
+static CURLcode setup_connection_internals(struct connectdata *conn)
+{
+  const struct Curl_handler * p;
+  CURLcode result;
+
+  conn->socktype = SOCK_STREAM; /* most of them are TCP streams */
+
+  /* Scan protocol handler table. */
+
+  /* Perform setup complement if some. */
+  p = conn->handler;
+
+  if(p->setup_connection) {
+    result = (*p->setup_connection)(conn);
+
+    if(result != CURLE_OK)
+      return result;
+
+    p = conn->handler;              /* May have changed. */
+  }
+
+  if(conn->port < 0)
+    /* we check for -1 here since if proxy was detected already, this
+       was very likely already set to the proxy port */
+    conn->port = p->defport;
+  conn->remote_port = (unsigned short)p->defport;
+  conn->protocol |= p->protocol;
+
+  return CURLE_OK;
+}
+
+#ifndef CURL_DISABLE_PROXY
+/****************************************************************
+* Checks if the host is in the noproxy list. returns true if it matches
+* and therefore the proxy should NOT be used.
+****************************************************************/
+static bool check_noproxy(const char* name, const char* no_proxy)
+{
+  /* 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)
+   */
+  size_t tok_start;
+  size_t tok_end;
+  const char* separator = ", ";
+  size_t no_proxy_len;
+  size_t namelen;
+  char *endptr;
+
+  if(no_proxy && no_proxy[0]) {
+    if(Curl_raw_equal("*", no_proxy)) {
+      return TRUE;
+    }
+
+    /* NO_PROXY was specified and it wasn't just an asterisk */
+
+    no_proxy_len = strlen(no_proxy);
+    endptr = strchr(name, ':');
+    if(endptr)
+      namelen = endptr - name;
+    else
+      namelen = strlen(name);
+
+    for (tok_start = 0; tok_start < no_proxy_len; tok_start = tok_end + 1) {
+      while (tok_start < no_proxy_len &&
+             strchr(separator, no_proxy[tok_start]) != NULL) {
+        /* Look for the beginning of the token. */
+        ++tok_start;
+      }
+
+      if(tok_start == no_proxy_len)
+        break; /* It was all trailing separator chars, no more tokens. */
+
+      for (tok_end = tok_start; tok_end < no_proxy_len &&
+             strchr(separator, no_proxy[tok_end]) == NULL; ++tok_end) {
+        /* Look for the end of the token. */
+      }
+
+      /* To match previous behaviour, where it was necessary to specify
+       * ".local.com" to prevent matching "notlocal.com", we will leave
+       * the '.' off.
+       */
+      if(no_proxy[tok_start] == '.')
+        ++tok_start;
+
+      if((tok_end - tok_start) <= namelen) {
+        /* Match the last part of the name to the domain we are checking. */
+        const char *checkn = name + namelen - (tok_end - tok_start);
+        if(Curl_raw_nequal(no_proxy + tok_start, checkn,
+                           tok_end - tok_start)) {
+          if((tok_end - tok_start) == namelen || *(checkn - 1) == '.') {
+            /* We either have an exact match, or the previous character is a .
+             * so it is within the same domain, so no proxy for this host.
+             */
+            return TRUE;
+          }
+        }
+      } /* if((tok_end - tok_start) <= namelen) */
+    } /* for (tok_start = 0; tok_start < no_proxy_len;
+         tok_start = tok_end + 1) */
+  } /* NO_PROXY was specified and it wasn't just an asterisk */
+
+  return FALSE;
+}
+
+/****************************************************************
+* Detect what (if any) proxy to use. Remember that this selects a host
+* name and is not limited to HTTP proxies only.
+* The returned pointer must be freed by the caller (unless NULL)
+****************************************************************/
+static char *detect_proxy(struct connectdata *conn)
+{
+  char *proxy = NULL;
+
+#ifndef CURL_DISABLE_HTTP
+  /* 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/
+   * 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=NULL;
+  char proxy_env[128];
+
+  no_proxy=curl_getenv("no_proxy");
+  if(!no_proxy)
+    no_proxy=curl_getenv("NO_PROXY");
+
+  if(!check_noproxy(conn->host.name, no_proxy)) {
+    /* It was not listed as without proxy */
+    const char *protop = conn->handler->scheme;
+    char *envp = proxy_env;
+    char *prox;
+
+    /* Now, build <protocol>_proxy and check for such a one to use */
+    while(*protop)
+      *envp++ = (char)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 && !Curl_raw_equal("http_proxy", proxy_env)) {
+      /* There was no lowercase variable, try the uppercase version: */
+      Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
+      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(!check_noproxy(conn->host.name, no_proxy)) - it wasn't specified
+       non-proxy */
+  if(no_proxy)
+    free(no_proxy);
+
+#else /* !CURL_DISABLE_HTTP */
+
+  (void)conn;
+#endif /* CURL_DISABLE_HTTP */
+
+  return proxy;
+}
+
+/*
+ * If this is supposed to use a proxy, we need to figure out the proxy
+ * host name, so that we can re-use an existing connection
+ * that may exist registered to the same proxy host.
+ * proxy will be freed before this function returns.
+ */
+static CURLcode parse_proxy(struct SessionHandle *data,
+                            struct connectdata *conn, char *proxy)
+{
+  char *prox_portno;
+  char *endofprot;
+
+  /* We use 'proxyptr' to point to the proxy name from now on... */
+  char *proxyptr;
+  char *portptr;
+  char *atsign;
+
+  /* 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.
+   */
+
+  /* Skip the protocol part if present */
+  endofprot = strstr(proxy, "://");
+  if(endofprot)
+    proxyptr = endofprot+3;
+  else
+    proxyptr = proxy;
+
+  /* Is there a username and password given in this proxy url? */
+  atsign = strchr(proxyptr, '@');
+  if(atsign) {
+    char proxyuser[MAX_CURL_USER_LENGTH];
+    char proxypasswd[MAX_CURL_PASSWORD_LENGTH];
+    proxypasswd[0] = 0;
+
+    if(1 <= sscanf(proxyptr,
+                   "%" MAX_CURL_USER_LENGTH_TXT"[^:@]:"
+                   "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]",
+                   proxyuser, proxypasswd)) {
+      CURLcode res = CURLE_OK;
+
+      /* found user and password, rip them out.  note that we are
+         unescaping them, as there is otherwise no way to have a
+         username or password with reserved characters like ':' in
+         them. */
+      Curl_safefree(conn->proxyuser);
+      conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL);
+
+      if(!conn->proxyuser)
+        res = CURLE_OUT_OF_MEMORY;
+      else {
+        Curl_safefree(conn->proxypasswd);
+        conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL);
+
+        if(!conn->proxypasswd)
+          res = CURLE_OUT_OF_MEMORY;
+      }
+
+      if(CURLE_OK == res) {
+        conn->bits.proxy_user_passwd = TRUE; /* enable it */
+        atsign = strdup(atsign+1); /* the right side of the @-letter */
+
+        if(atsign) {
+          free(proxy); /* free the former proxy string */
+          proxy = proxyptr = atsign; /* now use this instead */
+        }
+        else
+          res = CURLE_OUT_OF_MEMORY;
+      }
+
+      if(res) {
+        free(proxy); /* free the allocated proxy string */
+        return res;
+      }
+    }
+  }
+
+  /* start scanning for port number at this point */
+  portptr = proxyptr;
+
+  /* detect and extract RFC2732-style IPv6-addresses */
+  if(*proxyptr == '[') {
+    char *ptr = ++proxyptr; /* advance beyond the initial bracket */
+    while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '%') ||
+                   (*ptr == '.')))
+      ptr++;
+    if(*ptr == ']') {
+      /* yeps, it ended nicely with a bracket as well */
+      *ptr++ = 0;
+    } else
+      infof(data, "Invalid IPv6 address format\n");
+    portptr = ptr;
+    /* Note that if this didn't end with a bracket, we still advanced the
+     * proxyptr first, but I can't see anything wrong with that as no host
+     * name nor a numeric can legally start with a bracket.
+     */
+  }
+
+  /* Get port number off proxy.server.com:1080 */
+  prox_portno = strchr(portptr, ':');
+  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 {
+    /* without a port number after the host name, some people seem to use
+       a slash so we strip everything from the first slash */
+    atsign = strchr(proxyptr, '/');
+    if(atsign)
+      *atsign = 0x0; /* cut off path part from host name */
+
+    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(proxy);
+  if(!conn->proxy.rawalloc)
+    return CURLE_OUT_OF_MEMORY;
+
+  return CURLE_OK;
+}
+
+/*
+ * Extract the user and password from the authentication string
+ */
+static CURLcode parse_proxy_auth(struct SessionHandle *data,
+                                 struct connectdata *conn)
+{
+  char proxyuser[MAX_CURL_USER_LENGTH]="";
+  char proxypasswd[MAX_CURL_PASSWORD_LENGTH]="";
+
+  if(data->set.str[STRING_PROXYUSERNAME] != NULL) {
+    strncpy(proxyuser, data->set.str[STRING_PROXYUSERNAME],
+            MAX_CURL_USER_LENGTH);
+    proxyuser[MAX_CURL_USER_LENGTH-1] = '\0';   /*To be on safe side*/
+  }
+  if(data->set.str[STRING_PROXYPASSWORD] != NULL) {
+    strncpy(proxypasswd, data->set.str[STRING_PROXYPASSWORD],
+            MAX_CURL_PASSWORD_LENGTH);
+    proxypasswd[MAX_CURL_PASSWORD_LENGTH-1] = '\0'; /*To be on safe side*/
+  }
+
+  conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL);
+  if(!conn->proxyuser)
+    return CURLE_OUT_OF_MEMORY;
+
+  conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL);
+  if(!conn->proxypasswd)
+    return CURLE_OUT_OF_MEMORY;
+
+  return CURLE_OK;
+}
+#endif /* CURL_DISABLE_PROXY */
+
+/*
+ *
+ * Parse a user name and password in the URL and strip it out of the host name
+ *
+ * Inputs: data->set.use_netrc (CURLOPT_NETRC)
+ *         conn->host.name
+ *
+ * Outputs: (almost :- all currently undefined)
+ *          conn->bits.user_passwd  - non-zero if non-default passwords exist
+ *          user                    - non-zero length if defined
+ *          passwd                  -   ditto
+ *          conn->host.name         - remove user name and password
+ */
+static CURLcode parse_url_userpass(struct SessionHandle *data,
+                                   struct connectdata *conn,
+                                   char *user, char *passwd)
+{
+  /* 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.
+   */
+
+  char *ptr=strchr(conn->host.name, '@');
+  char *userpass = conn->host.name;
+
+  user[0] =0;   /* to make everything well-defined */
+  passwd[0]=0;
+
+  /* We will now try to extract the
+   * possible user+password pair in a string like:
+   * ftp://user:password@ftp.my.site:8021/README */
+  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 :-(
+     */
+
+    conn->bits.userpwd_in_url = 1;
+    if(data->set.use_netrc != CURL_NETRC_REQUIRED) {
+      /* We could use the one in the URL */
+
+      conn->bits.user_passwd = TRUE; /* enable user+password */
+
+      if(*userpass != ':') {
+        /* the name is given, get user+password */
+        sscanf(userpass, "%" MAX_CURL_USER_LENGTH_TXT "[^:@]:"
+               "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]",
+               user, passwd);
+      }
+      else
+        /* no name given, get the password only */
+        sscanf(userpass, ":%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", passwd);
+
+      if(user[0]) {
+        char *newname=curl_easy_unescape(data, user, 0, NULL);
+        if(!newname)
+          return CURLE_OUT_OF_MEMORY;
+        if(strlen(newname) < MAX_CURL_USER_LENGTH)
+          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_easy_unescape(data, passwd, 0, NULL);
+        if(!newpasswd)
+          return CURLE_OUT_OF_MEMORY;
+        if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH)
+          strcpy(passwd, newpasswd);
+
+        free(newpasswd);
+      }
+    }
+  }
+  return CURLE_OK;
+}
+
+/*************************************************************
+ * Figure out the remote port number and fix it in the URL
+ *
+ * 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.
+ *
+ * The port number embedded in the URL is replaced, if necessary.
+ *************************************************************/
+static CURLcode parse_remote_port(struct SessionHandle *data,
+                                  struct connectdata *conn)
+{
+  char *portptr;
+  char endbracket;
+
+  /* Note that at this point, the IPv6 address cannot contain any scope
+     suffix as that has already been removed in the parseurlandfillconn()
+     function */
+  if((1 == sscanf(conn->host.name, "[%*45[0123456789abcdefABCDEF:.]%c",
+                  &endbracket)) &&
+     (']' == endbracket)) {
+    /* this is a RFC2732-style specified IP-address */
+    conn->bits.ipv6_ip = TRUE;
+
+    conn->host.name++; /* skip over the starting bracket */
+    portptr = strchr(conn->host.name, ']');
+    if(portptr) {
+      *portptr++ = '\0'; /* zero terminate, killing the bracket */
+      if(':' != *portptr)
+        portptr = NULL; /* no port number available */
+    }
+  }
+  else
+    portptr = strrchr(conn->host.name, ':');
+
+  if(data->set.use_port && data->state.allow_port) {
+    /* if set, we use this and ignore the port possibly given in the URL */
+    conn->remote_port = (unsigned short)data->set.use_port;
+    if(portptr)
+      *portptr = '\0'; /* cut off the name there anyway - if there was a port
+                      number - since the port number is to be ignored! */
+    if(conn->bits.httpproxy) {
+      /* we need to create new URL with the new port number */
+      char *url;
+      /* FTPS connections have the FTP bit set too, so they match as well */
+      bool isftp = (bool)(0 != (conn->protocol & PROT_FTP));
+
+      /*
+       * This synthesized URL isn't always right--suffixes like ;type=A
+       * are stripped off. It would be better to work directly from the
+       * original URL and simply replace the port part of it.
+       */
+      url = aprintf("%s://%s%s%s:%hu%s%s", conn->handler->scheme,
+                    conn->bits.ipv6_ip?"[":"", conn->host.name,
+                    conn->bits.ipv6_ip?"]":"", conn->remote_port,
+                    isftp?"/":"", data->state.path);
+      if(!url)
+        return CURLE_OUT_OF_MEMORY;
+
+      if(data->change.url_alloc)
+        free(data->change.url);
+
+      data->change.url = url;
+      data->change.url_alloc = TRUE;
+    }
+  }
+  else if(portptr) {
+    /* no CURLOPT_PORT given, extract the one from the URL */
+
+    char *rest;
+    unsigned long port;
+
+    port=strtoul(portptr+1, &rest, 10);  /* Port number must be decimal */
+
+    if(rest != (portptr+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;
+      }
+
+      *portptr = '\0'; /* cut off the name there */
+      conn->remote_port = curlx_ultous(port);
+    }
+  }
+  return CURLE_OK;
+}
+
+/*
+ * Override a user name and password from the URL with that in the
+ * CURLOPT_USERPWD option or a .netrc file, if applicable.
+ */
+static void override_userpass(struct SessionHandle *data,
+                              struct connectdata *conn,
+                              char *user, char *passwd)
+{
+  if(data->set.str[STRING_USERNAME] != NULL) {
+    strncpy(user, data->set.str[STRING_USERNAME], MAX_CURL_USER_LENGTH);
+    user[MAX_CURL_USER_LENGTH-1] = '\0';   /*To be on safe side*/
+  }
+  if(data->set.str[STRING_PASSWORD] != NULL) {
+    strncpy(passwd, data->set.str[STRING_PASSWORD], MAX_CURL_PASSWORD_LENGTH);
+    passwd[MAX_CURL_PASSWORD_LENGTH-1] = '\0'; /*To be on safe side*/
+  }
+
+  conn->bits.netrc = FALSE;
+  if(data->set.use_netrc != CURL_NETRC_IGNORED) {
+    if(Curl_parsenetrc(conn->host.name,
+                       user, passwd,
+                       data->set.str[STRING_NETRC_FILE])) {
+      infof(data, "Couldn't find host %s in the "
+            DOT_CHAR "netrc file; using defaults\n",
+            conn->host.name);
+    }
+    else {
+      /* set bits.netrc TRUE to remember that we got the name from a .netrc
+         file, so that it is safe to use even if we followed a Location: to a
+         different host or similar. */
+      conn->bits.netrc = TRUE;
+
+      conn->bits.user_passwd = TRUE; /* enable user+password */
+    }
+  }
+}
+
+/*
+ * Set password so it's available in the connection.
+ */
+static CURLcode set_userpass(struct connectdata *conn,
+                             const char *user, const char *passwd)
+{
+  /* If our protocol needs a password and we have none, use the defaults */
+  if( (conn->protocol & (PROT_FTP|PROT_IMAP)) &&
+       !conn->bits.user_passwd) {
+
+    conn->user = strdup(CURL_DEFAULT_USER);
+    if(conn->user)
+      conn->passwd = strdup(CURL_DEFAULT_PASSWORD);
+    else
+      conn->passwd = NULL;
+    /* 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);
+    if(conn->user)
+      conn->passwd = strdup(passwd);
+    else
+      conn->passwd = NULL;
+  }
+  if(!conn->user || !conn->passwd)
+    return CURLE_OUT_OF_MEMORY;
+
+  return CURLE_OK;
+}
+
+/*************************************************************
+ * Resolve the address of the server or proxy
+ *************************************************************/
+static CURLcode resolve_server(struct SessionHandle *data,
+                               struct connectdata *conn,
+                               bool *async)
+{
+  CURLcode result=CURLE_OK;
+  long shortest = 0; /* default to no timeout */
+
+  /*************************************************************
+   * Set timeout if that is being used
+   *************************************************************/
+  if(data->set.timeout || data->set.connecttimeout) {
+
+    /* 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. */
+
+    shortest = data->set.timeout; /* default to this timeout value */
+    if(shortest && data->set.connecttimeout &&
+       (data->set.connecttimeout < shortest))
+      /* if both are set, pick the shortest */
+      shortest = data->set.connecttimeout;
+    else if(!shortest)
+      /* if timeout is not set, use the connect timeout */
+      shortest = data->set.connecttimeout;
+  /* 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. */
+  }
+
+  /*************************************************************
+   * Resolve the name of the server or proxy
+   *************************************************************/
+  if(conn->bits.reuse) {
+    /* We're reusing the connection - no need to resolve anything */
+    *async = FALSE;
+
+    if(conn->bits.proxy)
+      fix_hostname(data, conn, &conn->host);
+  }
+  else {
+    /* this is a fresh connect */
+    int rc;
+    struct Curl_dns_entry *hostaddr;
+
+    /* set a pointer to the hostname we display */
+    fix_hostname(data, conn, &conn->host);
+
+    if(!conn->proxy.name || !*conn->proxy.name) {
+      /* 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_timeout(conn, conn->host.name, (int)conn->port,
+                               &hostaddr, shortest);
+      if(rc == CURLRESOLV_PENDING)
+        *async = TRUE;
+
+      else if (rc == CURLRESOLV_TIMEDOUT)
+        result = CURLE_OPERATION_TIMEDOUT;
+
+      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(data, conn, &conn->proxy);
+
+      /* resolve proxy */
+      rc = Curl_resolv_timeout(conn, conn->proxy.name, (int)conn->port,
+                               &hostaddr, shortest);
+
+      if(rc == CURLRESOLV_PENDING)
+        *async = TRUE;
+
+      else if (rc == CURLRESOLV_TIMEDOUT)
+        result = CURLE_OPERATION_TIMEDOUT;
+
+      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 */
+      }
+    }
+    DEBUGASSERT(conn->dns_entry == NULL);
+    conn->dns_entry = hostaddr;
+  }
+
+  return result;
+}
+
+/*
+ * Cleanup the connection just allocated before we can move along and use the
+ * previously existing one.  All relevant data is copied over and old_conn is
+ * ready for freeing once this function returns.
+ */
+static void reuse_conn(struct connectdata *old_conn,
+                       struct connectdata *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(&old_conn->ssl_config);
+
+  conn->data = old_conn->data;
+
+  /* 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;
+  if(conn->bits.user_passwd) {
+    /* use the new user name and password though */
+    Curl_safefree(conn->user);
+    Curl_safefree(conn->passwd);
+    conn->user = old_conn->user;
+    conn->passwd = old_conn->passwd;
+    old_conn->user = NULL;
+    old_conn->passwd = NULL;
+  }
+
+  conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd;
+  if(conn->bits.proxy_user_passwd) {
+    /* use the new proxy user name and proxy password though */
+    Curl_safefree(conn->proxyuser);
+    Curl_safefree(conn->proxypasswd);
+    conn->proxyuser = old_conn->proxyuser;
+    conn->proxypasswd = old_conn->proxypasswd;
+    old_conn->proxyuser = NULL;
+    old_conn->proxypasswd = NULL;
+  }
+
+  /* host can change, when doing keepalive with a proxy ! */
+  if(conn->bits.proxy) {
+    free(conn->host.rawalloc);
+    conn->host=old_conn->host;
+  }
+  else
+    free(old_conn->host.rawalloc); /* free the newly allocated name buffer */
+
+  /* re-use init */
+  conn->bits.reuse = TRUE; /* yes, we're re-using here */
+
+  Curl_safefree(old_conn->user);
+  Curl_safefree(old_conn->passwd);
+  Curl_safefree(old_conn->proxyuser);
+  Curl_safefree(old_conn->proxypasswd);
+  Curl_llist_destroy(old_conn->send_pipe, NULL);
+  Curl_llist_destroy(old_conn->recv_pipe, NULL);
+  Curl_llist_destroy(old_conn->pend_pipe, NULL);
+  Curl_llist_destroy(old_conn->done_pipe, NULL);
+  Curl_safefree(old_conn->master_buffer);
+}
+
+/**
+ * create_conn() 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 async is set TRUE when an async DNS resolution is pending
+ * @see setup_conn()
+ *
+ * *NOTE* this function assigns the conn->data pointer!
+ */
+
+static CURLcode create_conn(struct SessionHandle *data,
+                            struct connectdata **in_connect,
+                            bool *async)
+{
+  CURLcode result=CURLE_OK;
+  struct connectdata *conn;
+  struct connectdata *conn_temp = NULL;
+  size_t urllen;
+  char user[MAX_CURL_USER_LENGTH];
+  char passwd[MAX_CURL_PASSWORD_LENGTH];
+  bool reuse;
+  char *proxy = NULL;
+  bool prot_missing = FALSE;
+
+  *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 = allocate_conn();
+
+  /* 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;
+
+  if(!conn)
+    return CURLE_OUT_OF_MEMORY;
+
+  conn->data = data; /* Setup the association between this connection
+                        and the SessionHandle */
+
+  conn->proxytype = data->set.proxytype; /* type */
+
+#ifdef CURL_DISABLE_PROXY
+
+  conn->bits.proxy = FALSE;
+  conn->bits.httpproxy = FALSE;
+  conn->bits.proxy_user_passwd = FALSE;
+  conn->bits.tunnel_proxy = FALSE;
+
+#else /* CURL_DISABLE_PROXY */
+
+  conn->bits.proxy = (bool)(data->set.str[STRING_PROXY] &&
+                            *data->set.str[STRING_PROXY]);
+  conn->bits.httpproxy = (bool)(conn->bits.proxy &&
+                                (conn->proxytype == CURLPROXY_HTTP ||
+                                 conn->proxytype == CURLPROXY_HTTP_1_0));
+  conn->bits.proxy_user_passwd =
+    (bool)(NULL != data->set.str[STRING_PROXYUSERNAME]);
+  conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
+
+#endif /* CURL_DISABLE_PROXY */
+
+  conn->bits.user_passwd = (bool)(NULL != data->set.str[STRING_USERNAME]);
+  conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
+  conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
+
+  conn->verifypeer = data->set.ssl.verifypeer;
+  conn->verifyhost = data->set.ssl.verifyhost;
+
+  if(data->multi && Curl_multi_canPipeline(data->multi) &&
+      !conn->master_buffer) {
+    /* Allocate master_buffer to be used for pipelining */
+    conn->master_buffer = calloc(BUFSIZE, sizeof (char));
+    if(!conn->master_buffer)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Initialize the pipeline lists */
+  conn->send_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
+  conn->recv_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
+  conn->pend_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
+  conn->done_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
+  if(!conn->send_pipe || !conn->recv_pipe || !conn->pend_pipe ||
+    !conn->done_pipe)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* 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;
+
+  /*
+   * We malloc() the buffers below urllen+2 to make room for to possibilities:
+   * 1 - an extra terminating zero
+   * 2 - an extra slash (in case a syntax like "www.host.com?moo" is used)
+   */
+
+  Curl_safefree(data->state.pathbuffer);
+  data->state.pathbuffer = malloc(urllen+2);
+  if(NULL == data->state.pathbuffer)
+    return CURLE_OUT_OF_MEMORY; /* really bad error */
+  data->state.path = data->state.pathbuffer;
+
+  conn->host.rawalloc = malloc(urllen+2);
+  if(NULL == conn->host.rawalloc)
+    return CURLE_OUT_OF_MEMORY;
+
+  conn->host.name = conn->host.rawalloc;
+  conn->host.name[0] = 0;
+
+  result = parseurlandfillconn(data, conn, &prot_missing);
+  if(result != CURLE_OK) {
+      return result;
+  }
+
+  /*************************************************************
+   * No protocol part in URL was used, add it!
+   *************************************************************/
+  if(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->handler->scheme, data->change.url);
+
+    if(!reurl) {
+      Curl_safefree(proxy);
+      return CURLE_OUT_OF_MEMORY;
+    }
+
+    data->change.url = reurl;
+    data->change.url_alloc = TRUE; /* free this later */
+  }
+
+  /*************************************************************
+   * Parse a user name and password in the URL and strip it out
+   * of the host name
+   *************************************************************/
+  result = parse_url_userpass(data, conn, user, passwd);
+  if(result != CURLE_OK)
+    return result;
+
+#ifndef CURL_DISABLE_PROXY
+  /*************************************************************
+   * Extract the user and password from the authentication string
+   *************************************************************/
+  if(conn->bits.proxy_user_passwd) {
+    result = parse_proxy_auth(data, conn);
+    if(result != CURLE_OK)
+        return result;
+  }
+
+  /*************************************************************
+   * Detect what (if any) proxy to use
+   *************************************************************/
+  if(data->set.str[STRING_PROXY]) {
+    proxy = strdup(data->set.str[STRING_PROXY]);
+    /* if global proxy is set, this is it */
+    if(NULL == proxy) {
+      failf(data, "memory shortage");
+      return CURLE_OUT_OF_MEMORY;
+    }
+  }
+
+  if(data->set.str[STRING_NOPROXY] &&
+     check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY])) {
+    if(proxy) {
+      free(proxy);  /* proxy is in exception list */
+      proxy = NULL;
+    }
+  }
+  else if(!proxy)
+    proxy = detect_proxy(conn);
+
+  if(proxy && !*proxy) {
+    free(proxy);  /* Don't bother with an empty proxy string */
+    proxy = NULL;
+  }
+  /* proxy must be freed later unless NULL */
+  if(proxy && *proxy) {
+    long bits = conn->protocol & (PROT_HTTPS|PROT_SSL);
+
+    if((conn->proxytype == CURLPROXY_HTTP) ||
+       (conn->proxytype == CURLPROXY_HTTP_1_0)) {
+      /* force this connection's protocol to become HTTP */
+      conn->protocol = PROT_HTTP | bits;
+      conn->bits.httpproxy = TRUE;
+    }
+    conn->bits.proxy = TRUE;
+  }
+  else {
+    /* we aren't using the proxy after all... */
+    conn->bits.proxy = FALSE;
+    conn->bits.httpproxy = FALSE;
+    conn->bits.proxy_user_passwd = FALSE;
+    conn->bits.tunnel_proxy = FALSE;
+  }
+
+  /***********************************************************************
+   * If this is supposed to use a proxy, we need to figure out the proxy
+   * host name, so that we can re-use an existing connection
+   * that may exist registered to the same proxy host.
+   ***********************************************************************/
+  if(proxy) {
+    result = parse_proxy(data, conn, proxy);
+    /* parse_proxy has freed the proxy string, so don't try to use it again */
+    proxy = NULL;
+    if(result != CURLE_OK)
+      return result;
+  }
+#endif /* CURL_DISABLE_PROXY */
+
+  /*************************************************************
+   * Setup internals depending on protocol. Needs to be done after
+   * we figured out what/if proxy to use.
+   *************************************************************/
+  result = setup_connection_internals(conn);
+  if(result != CURLE_OK) {
+    Curl_safefree(proxy);
+    return result;
+  }
+
+  /***********************************************************************
+   * file: is a special case in that it doesn't need a network connection
+   ***********************************************************************/
+#ifndef CURL_DISABLE_FILE
+  if(conn->protocol & PROT_FILE) {
+    bool done;
+    /* this is supposed to be the connect function so we better at least check
+       that the file is present here! */
+    DEBUGASSERT(conn->handler->connect_it);
+    result = conn->handler->connect_it(conn, &done);
+
+    /* Setup a "faked" transfer that'll do nothing */
+    if(CURLE_OK == result) {
+      conn->data = data;
+      conn->bits.tcpconnect = TRUE; /* we are "connected */
+
+      ConnectionStore(data, conn);
+
+      /*
+       * Setup whatever necessary for a resumed transfer
+       */
+      result = setup_range(data);
+      if(result) {
+        DEBUGASSERT(conn->handler->done);
+        /* we ignore the return code for the protocol-specific DONE */
+        (void)conn->handler->done(conn, result, FALSE);
+        return result;
+      }
+
+      result = Curl_setup_transfer(conn, -1, -1, FALSE,
+                                   NULL, /* no download */
+                                   -1, NULL); /* no upload */
+    }
+
+    return result;
+  }
+#endif
+
+  /*************************************************************
+   * If the protocol 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;
+
+  /*************************************************************
+   * Figure out the remote port number and fix it in the URL
+   *************************************************************/
+  result = parse_remote_port(data, conn);
+  if(result != CURLE_OK)
+    return result;
+
+  /*************************************************************
+   * Check for an overridden user name and password, then set it
+   * for use
+   *************************************************************/
+  override_userpass(data, conn, user, passwd);
+  result = set_userpass(conn, user, passwd);
+  if(result != CURLE_OK)
+    return result;
+
+  /* Get a cloned copy of the SSL config situation stored in the
+     connection struct. But to get this going nicely, we must first make
+     sure that the strings in the master copy are pointing to the correct
+     strings in the session handle strings array!
+
+     Keep in mind that the pointers in the master copy are pointing to strings
+     that will be freed as part of the SessionHandle struct, but all cloned
+     copies will be separately allocated.
+  */
+  data->set.ssl.CApath = data->set.str[STRING_SSL_CAPATH];
+  data->set.ssl.CAfile = data->set.str[STRING_SSL_CAFILE];
+  data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE];
+  data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT];
+  data->set.ssl.random_file = data->set.str[STRING_SSL_RANDOM_FILE];
+  data->set.ssl.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
+  data->set.ssl.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST];
+
+  if(!Curl_clone_ssl_config(&data->set.ssl, &conn->ssl_config))
+    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.
+   *************************************************************/
+
+  /* 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.
+     */
+    reuse_conn(conn, conn_temp);
+    free(conn);          /* we don't need this anymore */
+    conn = conn_temp;
+    *in_connect = conn;
+    infof(data, "Re-using existing connection! (#%ld) with host %s\n",
+          conn->connectindex,
+          conn->proxy.name?conn->proxy.dispname:conn->host.dispname);
+    /* copy this IP address to the common buffer for the easy handle so that
+       the address can actually survice the removal of this connection. strcpy
+       is safe since the target buffer is big enough to hold the largest
+       possible IP address */
+    strcpy(data->info.ip, conn->ip_addr_str);
+
+  }
+  else {
+    /*
+     * This is a brand new connection, so let's store it in the connection
+     * cache of ours!
+     */
+    ConnectionStore(data, conn);
+  }
+
+  /*
+   * Setup whatever necessary for a resumed transfer
+   */
+  result = setup_range(data);
+  if(result)
+    return result;
+
+  /* Continue connectdata initialization here. */
+
+  /*
+   * Inherit the proper values from the urldata struct AFTER we have arranged
+   * the persistent connection stuff
+   */
+  conn->fread_func = data->set.fread_func;
+  conn->fread_in = data->set.in;
+  conn->seek_func = data->set.seek_func;
+  conn->seek_client = data->set.seek_client;
+
+  /*************************************************************
+   * Resolve the address of the server or proxy
+   *************************************************************/
+  result = resolve_server(data, conn, async);
+
+  return result;
+}
+
+/* setup_conn() is called after the name resolve initiated in
+ * create_conn() is all done.
+ *
+ * setup_conn() also handles reused connections
+ *
+ * conn->data MUST already have been setup fine (in create_conn)
+ */
+
+static CURLcode setup_conn(struct connectdata *conn,
+                           bool *protocol_done)
+{
+  CURLcode result=CURLE_OK;
+  struct SessionHandle *data = conn->data;
+
+  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 */
+    *protocol_done = TRUE;
+    return result;
+  }
+  *protocol_done = FALSE; /* default to not done */
+
+  /* set proxy_connect_closed to false unconditionally already here since it
+     is used strictly to provide extra information to a parent function in the
+     case of proxy CONNECT failures and we must make sure we don't have it
+     lingering set from a previous invoke */
+  conn->bits.proxy_connect_closed = FALSE;
+
+  /*
+   * Set user-agent. Used for HTTP, but since we can attempt to tunnel
+   * basically anything through a http proxy we can't limit this based on
+   * protocol.
+   */
+  if(data->set.str[STRING_USERAGENT]) {
+    Curl_safefree(conn->allocptr.uagent);
+    conn->allocptr.uagent =
+      aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]);
+    if(!conn->allocptr.uagent)
+      return CURLE_OUT_OF_MEMORY;
+  }
+
+  data->req.headerbytecount = 0;
+
+#ifdef CURL_DO_LINEEND_CONV
+  data->state.crlf_conversions = 0; /* reset CRLF conversion counter */
+#endif /* CURL_DO_LINEEND_CONV */
+
+  for(;;) {
+    /* loop for CURL_SERVER_CLOSED_CONNECTION */
+
+    if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
+      /* Try to connect only if not already connected */
+      bool connected = FALSE;
+
+      result = ConnectPlease(data, conn, &connected);
+
+      if(connected) {
+        result = Curl_protocol_connect(conn, protocol_done);
+        if(CURLE_OK == result)
+          conn->bits.tcpconnect = TRUE;
+      }
+      else
+        conn->bits.tcpconnect = FALSE;
+
+      /* if the connection was closed by the server while exchanging
+         authentication informations, retry with the new set
+         authentication information */
+      if(conn->bits.proxy_connect_closed) {
+        /* reset the error buffer */
+        if(data->set.errorbuffer)
+          data->set.errorbuffer[0] = '\0';
+        data->state.errorbuf = FALSE;
+        continue;
+      }
+
+      if(CURLE_OK != result)
+        return result;
+    }
+    else {
+      Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
+      Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
+      conn->bits.tcpconnect = TRUE;
+      *protocol_done = TRUE;
+      if(data->set.verbose)
+        verboseconnect(conn);
+    }
+    /* Stop the loop now */
+    break;
+  }
+
+  conn->now = Curl_tvnow(); /* time this *after* the connect is done, we
+                               set this here perhaps a second time */
+
+#ifdef __EMX__
+  /*
+   * This 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 result;
+}
+
+CURLcode Curl_connect(struct SessionHandle *data,
+                      struct connectdata **in_connect,
+                      bool *asyncp,
+                      bool *protocol_done)
+{
+  CURLcode code;
+
+  *asyncp = FALSE; /* assume synchronous resolves by default */
+
+  /* call the stuff that needs to be called */
+  code = create_conn(data, in_connect, asyncp);
+
+  if(CURLE_OK == code) {
+    /* no error */
+    if((*in_connect)->send_pipe->size || (*in_connect)->recv_pipe->size)
+      /* pipelining */
+      *protocol_done = TRUE;
+    else if (!*asyncp) {
+      /* DNS resolution is done: that's either because this is a reused
+         connection, in which case DNS was unnecessary, or because DNS
+         really did finish already (synch resolver/fast async resolve) */
+      code = setup_conn(*in_connect, protocol_done);
+    }
+  }
+
+  if(code && *in_connect) {
+    /* We're not allowed to return failure with memory left allocated
+       in the connectdata struct, free those here */
+    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.
+
+   Note: this function disconnects and frees the conn data in case of
+   resolve failure */
+CURLcode Curl_async_resolved(struct connectdata *conn,
+                             bool *protocol_done)
+{
+#ifdef CURLRES_ASYNCH
+  CURLcode code;
+
+  if(conn->async.dns) {
+    conn->dns_entry = conn->async.dns;
+    conn->async.dns = NULL;
+  }
+
+  code = setup_conn(conn, protocol_done);
+
+  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;
+  (void)protocol_done;
+  return CURLE_OK;
+#endif
+}
+
+
+CURLcode Curl_done(struct connectdata **connp,
+                   CURLcode status,  /* an error if this is called after an
+                                        error was detected */
+                   bool premature)
+{
+  CURLcode result;
+  struct connectdata *conn;
+  struct SessionHandle *data;
+
+  DEBUGASSERT(*connp);
+
+  conn = *connp;
+  data = conn->data;
+
+  Curl_expire(data, 0); /* stop timer */
+
+  if(conn->bits.done)
+    /* Stop if Curl_done() has already been called */
+    return CURLE_OK;
+
+  Curl_getoff_all_pipelines(data, conn);
+
+  if((conn->send_pipe->size + conn->recv_pipe->size != 0 &&
+      !data->set.reuse_forbid &&
+      !conn->bits.close))
+    /* Stop if pipeline is not empty and we do not have to close
+       connection. */
+    return CURLE_OK;
+
+  conn->bits.done = TRUE; /* called just now! */
+
+  /* Cleanup possible redirect junk */
+  if(data->req.newurl) {
+    free(data->req.newurl);
+    data->req.newurl = NULL;
+  }
+  if(data->req.location) {
+    free(data->req.location);
+    data->req.location = NULL;
+  }
+
+  if(conn->dns_entry) {
+    Curl_resolv_unlock(data, conn->dns_entry); /* done with this */
+    conn->dns_entry = NULL;
+  }
+
+  /* this calls the protocol-specific function pointer previously set */
+  if(conn->handler->done)
+    result = conn->handler->done(conn, status, premature);
+  else
+    result = CURLE_OK;
+
+  Curl_pgrsDone(conn); /* done with the operation */
+
+  /* if the transfer was completed in a paused state there can be buffered
+     data left to write and then kill */
+  if(data->state.tempwrite) {
+    free(data->state.tempwrite);
+    data->state.tempwrite = NULL;
+  }
+
+  /* for ares-using, make sure all possible outstanding requests are properly
+     cancelled before we proceed */
+  ares_cancel(data->state.areschannel);
+
+  /* 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 premature is TRUE, it means this connection was said to be DONE before
+     the entire request operation is complete and thus we can't know in what
+     state it is for re-using, so we're forced to close it. In a perfect world
+     we can add code that keep track of if we really must close it here or not,
+     but currently we have no such detail knowledge.
+
+     connectindex == -1 here means that the connection has no spot in the
+     connection cache and thus we must disconnect it here.
+  */
+  if(data->set.reuse_forbid || conn->bits.close || premature ||
+     (-1 == conn->connectindex)) {
+    CURLcode res2 = Curl_disconnect(conn); /* close the connection */
+
+    /* 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 {
+    ConnectionDone(conn); /* the connection is no longer in use */
+
+    /* remember the most recently used connection */
+    data->state.lastconnect = conn->connectindex;
+
+    infof(data, "Connection #%ld to host %s left intact\n",
+          conn->connectindex,
+          conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
+  }
+
+  *connp = NULL; /* to make the caller of this function better detect that
+                    this was either closed or handed over to the connection
+                    cache here, and therefore cannot be used from this point on
+                 */
+
+  return result;
+}
+
+/*
+ * do_init() inits the readwrite session. This is inited each time (in the DO
+ * function before the protocol-specific DO functions are invoked) for a
+ * transfer, sometimes multiple times on the same SessionHandle. Make sure
+ * nothing in here depends on stuff that are setup dynamically for the
+ * transfer.
+ */
+
+static CURLcode do_init(struct connectdata *conn)
+{
+  struct SessionHandle *data = conn->data;
+  struct SingleRequest *k = &data->req;
+
+  conn->bits.done = FALSE; /* Curl_done() is not called yet */
+  conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to use */
+  data->state.expect100header = FALSE;
+
+  if(data->set.opt_no_body)
+    /* in HTTP lingo, no body means using the HEAD request... */
+    data->set.httpreq = HTTPREQ_HEAD;
+  else if(HTTPREQ_HEAD == data->set.httpreq)
+    /* ... but if unset there really is no perfect method that is the
+       "opposite" of HEAD but in reality most people probably think GET
+       then. The important thing is that we can't let it remain HEAD if the
+       opt_no_body is set FALSE since then we'll behave wrong when getting
+       HTTP. */
+    data->set.httpreq = HTTPREQ_GET;
+
+  /* NB: the content encoding software depends on this initialization */
+  Curl_easy_initHandleData(data);
+
+  k->start = Curl_tvnow(); /* start time */
+  k->now = k->start;   /* current time is now */
+  k->header = TRUE; /* assume header */
+
+  k->bytecount = 0;
+
+  k->buf = data->state.buffer;
+  k->uploadbuf = data->state.uploadbuffer;
+  k->hbufp = data->state.headerbuff;
+  k->ignorebody=FALSE;
+
+  Curl_pgrsTime(data, TIMER_PRETRANSFER);
+  Curl_speedinit(data);
+
+  Curl_pgrsSetUploadCounter(data, 0);
+  Curl_pgrsSetDownloadCounter(data, 0);
+
+  return CURLE_OK;
+}
+
+/*
+ * do_complete is called when the DO actions are complete.
+ *
+ * We init chunking and trailer bits to their default values here immediately
+ * before receiving any header data for the current request in the pipeline.
+ */
+static void do_complete(struct connectdata *conn)
+{
+  conn->data->req.chunk=FALSE;
+  conn->data->req.trailerhdrpresent=FALSE;
+
+  conn->data->req.maxfd = (conn->sockfd>conn->writesockfd?
+                               conn->sockfd:conn->writesockfd)+1;
+}
+
+CURLcode Curl_do(struct connectdata **connp, bool *done)
+{
+  CURLcode result=CURLE_OK;
+  struct connectdata *conn = *connp;
+  struct SessionHandle *data = conn->data;
+
+  /* setup and init stuff before DO starts, in preparing for the transfer */
+  do_init(conn);
+
+  if(conn->handler->do_it) {
+    /* generic protocol-specific function pointer set in curl_connect() */
+    result = conn->handler->do_it(conn, done);
+
+    /* This was formerly done in transfer.c, but we better do it here */
+    if((CURLE_SEND_ERROR == result) && conn->bits.reuse) {
+        /*
+         * If the connection is using an easy handle, call reconnect
+         * to re-establish the connection.  Otherwise, let the multi logic
+         * figure out how to re-establish the connection.
+         */
+        if(!data->multi) {
+          result = Curl_reconnect_request(connp);
+
+          if(result == CURLE_OK) {
+            /* ... finally back to actually retry the DO phase */
+            result = conn->handler->do_it(conn, done);
+          }
+        }
+        else {
+          return result;
+        }
+    }
+
+    if((result == CURLE_OK) && *done)
+      /* do_complete must be called after the protocol-specific DO function */
+      do_complete(conn);
+  }
+  return result;
+}
+
+CURLcode Curl_do_more(struct connectdata *conn)
+{
+  CURLcode result=CURLE_OK;
+
+  if(conn->handler->do_more)
+    result = conn->handler->do_more(conn);
+
+  if(result == CURLE_OK)
+    /* do_complete must be called after the protocol-specific DO function */
+    do_complete(conn);
+
+  return result;
+}
+
+/* Called on connect, and if there's already a protocol-specific struct
+   allocated for a different connection, this frees it that it can be setup
+   properly later on. */
+void Curl_reset_reqproto(struct connectdata *conn)
+{
+  struct SessionHandle *data = conn->data;
+  if(data->state.proto.generic && data->state.current_conn != conn) {
+    free(data->state.proto.generic);
+    data->state.proto.generic = NULL;
+  }
+  data->state.current_conn = conn;
+}
diff --git a/lib/url.h b/lib/url.h
new file mode 100644
index 0000000..cb3dd2f
--- /dev/null
+++ b/lib/url.h
@@ -0,0 +1,89 @@
+#ifndef __URL_H
+#define __URL_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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 <stdarg.h> /* to make sure we have ap_list */
+
+/*
+ * Prototypes for library-wide functions provided by url.c
+ */
+
+CURLcode Curl_open(struct SessionHandle **curl);
+CURLcode Curl_init_userdefined(struct UserDefined *set);
+CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
+                     va_list arg);
+CURLcode Curl_dupset(struct SessionHandle * dst, struct SessionHandle * src);
+void Curl_freeset(struct SessionHandle * data);
+CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */
+CURLcode Curl_connect(struct SessionHandle *, struct connectdata **,
+                      bool *async, bool *protocol_connect);
+CURLcode Curl_async_resolved(struct connectdata *conn,
+                             bool *protocol_connect);
+CURLcode Curl_do(struct connectdata **, bool *done);
+CURLcode Curl_do_more(struct connectdata *);
+CURLcode Curl_done(struct connectdata **, CURLcode, bool premature);
+CURLcode Curl_disconnect(struct connectdata *);
+CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done);
+CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done);
+CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done);
+void Curl_safefree(void *ptr);
+
+/* create a connection cache */
+struct conncache *Curl_mk_connc(int type, long amount);
+/* free a connection cache */
+void Curl_rm_connc(struct conncache *c);
+/* Change number of entries of a connection cache */
+CURLcode Curl_ch_connc(struct SessionHandle *data,
+                       struct conncache *c,
+                       long newamount);
+
+int Curl_protocol_getsock(struct connectdata *conn,
+                          curl_socket_t *socks,
+                          int numsocks);
+int Curl_doing_getsock(struct connectdata *conn,
+                       curl_socket_t *socks,
+                       int numsocks);
+
+bool Curl_isPipeliningEnabled(const struct SessionHandle *handle);
+CURLcode Curl_addHandleToPipeline(struct SessionHandle *handle,
+                                  struct curl_llist *pipeline);
+int Curl_removeHandleFromPipeline(struct SessionHandle *handle,
+                                  struct curl_llist *pipeline);
+/* remove the specified connection from all (possible) pipelines and related
+   queues */
+void Curl_getoff_all_pipelines(struct SessionHandle *data,
+                               struct connectdata *conn);
+
+void Curl_close_connections(struct SessionHandle *data);
+
+/* Called on connect, and if there's already a protocol-specific struct
+   allocated for a different connection, this frees it that it can be setup
+   properly later on. */
+void Curl_reset_reqproto(struct connectdata *conn);
+
+#define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */
+#define CURL_DEFAULT_SOCKS5_GSSAPI_SERVICE "rcmd" /* default socks5 gssapi service */
+
+CURLcode Curl_connected_proxy(struct connectdata *conn);
+
+#endif
diff --git a/lib/urldata.h b/lib/urldata.h
new file mode 100644
index 0000000..ad172d6
--- /dev/null
+++ b/lib/urldata.h
@@ -0,0 +1,1427 @@
+#ifndef __URLDATA_H
+#define __URLDATA_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+/* This file is for lib internal stuff */
+
+#include "setup.h"
+
+#define PORT_FTP 21
+#define PORT_FTPS 990
+#define PORT_TELNET 23
+#define PORT_HTTP 80
+#define PORT_HTTPS 443
+#define PORT_DICT 2628
+#define PORT_LDAP 389
+#define PORT_LDAPS 636
+#define PORT_TFTP 69
+#define PORT_SSH 22
+#define PORT_IMAP 143
+#define PORT_IMAPS 993
+#define PORT_POP3 110
+#define PORT_POP3S 995
+#define PORT_SMTP 25
+#define PORT_SMTPS 465 /* sometimes called SSMTP */
+#define PORT_RTSP 554
+
+#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 "ftp@example.com"
+
+/* length of longest IPv6 address string including the trailing null */
+#define MAX_IPADR_LEN sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")
+
+/* Default FTP/IMAP etc response timeout in milliseconds.
+   Symbian OS panics when given a timeout much greater than 1/2 hour.
+*/
+#define RESP_TIMEOUT (1800*1000)
+
+#include "cookie.h"
+#include "formdata.h"
+
+#ifdef USE_SSLEAY
+#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
+#ifdef HAVE_OPENSSL_PKCS12_H
+#include <openssl/pkcs12.h>
+#endif
+#else /* SSLeay-style includes */
+#include "rsa.h"
+#include "crypto.h"
+#include "x509.h"
+#include "pem.h"
+#include "ssl.h"
+#include "err.h"
+#ifdef HAVE_OPENSSL_ENGINE_H
+#include <engine.h>
+#endif
+#ifdef HAVE_OPENSSL_PKCS12_H
+#include <pkcs12.h>
+#endif
+#endif /* USE_OPENSSL */
+#ifdef USE_GNUTLS
+#error Configuration error; cannot use GnuTLS *and* OpenSSL.
+#endif
+#endif /* USE_SSLEAY */
+
+#ifdef USE_GNUTLS
+#include <gnutls/gnutls.h>
+#endif
+
+#ifdef USE_NSS
+#include <nspr.h>
+#include <pk11pub.h>
+#endif
+
+#ifdef USE_QSOSSL
+#include <qsossl.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#include "timeval.h"
+
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>               /* for content-encoding */
+#ifdef __SYMBIAN32__
+/* zlib pollutes the namespace with this definition */
+#undef WIN32
+#endif
+#endif
+
+#ifdef USE_ARES
+#  if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
+     (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__))
+#    define CARES_STATICLIB
+#  endif
+#  include <ares.h>
+#endif
+
+#include <curl/curl.h>
+
+#include "http_chunks.h" /* for the structs and enum stuff */
+#include "hostip.h"
+#include "hash.h"
+#include "splay.h"
+
+#include "imap.h"
+#include "pop3.h"
+#include "smtp.h"
+#include "ftp.h"
+#include "file.h"
+#include "ssh.h"
+#include "http.h"
+#include "rtsp.h"
+
+#ifdef HAVE_GSSAPI
+# ifdef HAVE_GSSGNU
+#  include <gss.h>
+# elif defined HAVE_GSSMIT
+#  include <gssapi/gssapi.h>
+#  include <gssapi/gssapi_generic.h>
+# else
+#  include <gssapi.h>
+# endif
+#endif
+
+#ifdef HAVE_LIBSSH2_H
+#include <libssh2.h>
+#include <libssh2_sftp.h>
+#endif /* HAVE_LIBSSH2_H */
+
+/* Download buffer size, keep it fairly big for speed reasons */
+#undef BUFSIZE
+#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
+
+#define CURLEASY_MAGIC_NUMBER 0xc0dedbadU
+
+/* Some convenience macros to get the larger/smaller value out of two given.
+   We prefix with CURL to prevent name collisions. */
+#define CURLMAX(x,y) ((x)>(y)?(x):(y))
+#define CURLMIN(x,y) ((x)<(y)?(x):(y))
+
+
+#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
+/* Types needed for krb4/5-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,
+  prot_cmd
+};
+#endif
+
+/* enum for the nonblocking SSL connection state machine */
+typedef enum {
+  ssl_connect_1,
+  ssl_connect_2,
+  ssl_connect_2_reading,
+  ssl_connect_2_writing,
+  ssl_connect_3,
+  ssl_connect_done
+} ssl_connect_state;
+
+typedef enum {
+  ssl_connection_none,
+  ssl_connection_negotiating,
+  ssl_connection_complete
+} ssl_connection_state;
+
+/* struct for data related to each SSL connection */
+struct ssl_connect_data {
+  /* Use ssl encrypted communications TRUE/FALSE, not necessarily using it atm
+     but at least asked to or meaning to use it. See 'state' for the exact
+     current state of the connection. */
+  bool use;
+  ssl_connection_state state;
+#ifdef USE_SSLEAY
+  /* these ones requires specific SSL-types */
+  SSL_CTX* ctx;
+  SSL*     handle;
+  X509*    server_cert;
+  ssl_connect_state connecting_state;
+#endif /* USE_SSLEAY */
+#ifdef USE_GNUTLS
+  gnutls_session session;
+  gnutls_certificate_credentials cred;
+#endif /* USE_GNUTLS */
+#ifdef USE_NSS
+  PRFileDesc *handle;
+  char *client_nickname;
+  struct SessionHandle *data;
+#ifdef HAVE_PK11_CREATEGENERICOBJECT
+  PK11GenericObject *key;
+  PK11GenericObject *cacert[2];
+#endif
+#endif /* USE_NSS */
+#ifdef USE_QSOSSL
+  SSLHandle *handle;
+#endif /* USE_QSOSSL */
+};
+
+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;          /* certificate dir (doesn't work on windows) */
+  char *CAfile;          /* certificate to verify peer against */
+  const char *CRLfile;   /* CRL to check certificate revocation */
+  const char *issuercert;/* optional issuer certificate filename */
+  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 */
+  bool sessionid;        /* cache session IDs or not */
+  bool certinfo;         /* gather lots of certificate info */
+};
+
+/* 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 */
+  size_t idsize;    /* if known, otherwise 0 */
+  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;
+
+#ifdef USE_WINDOWS_SSPI
+#include "curl_sspi.h"
+#endif
+
+#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
+#include <iconv.h>
+#endif
+
+/* Struct used for NTLM challenge-response authentication */
+struct ntlmdata {
+  curlntlm state;
+#ifdef USE_WINDOWS_SSPI
+  CredHandle handle;
+  CtxtHandle c_handle;
+  SEC_WINNT_AUTH_IDENTITY identity;
+  SEC_WINNT_AUTH_IDENTITY *p_identity;
+  int has_handles;
+  void *type_2;
+  int n_type_2;
+#else
+  unsigned int flags;
+  unsigned char nonce[8];
+#endif
+};
+
+#ifdef HAVE_GSSAPI
+struct negotiatedata {
+  /* when doing Negotiate we first need to receive an auth token and then we
+     need to send our header */
+  enum { GSS_AUTHNONE, GSS_AUTHRECV, GSS_AUTHSENT } state;
+  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
+
+
+/*
+ * 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 proxy; /* if set, this transfer is done through a proxy - any type */
+  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 remote site specified with pure IPv6
+                   IP address */
+  bool ipv6;    /* we communicate with a site using an IPv6 address */
+
+  bool do_more; /* this is set TRUE if the ->curl_do_more() function is
+                   supposed to be called, after ->curl_do() */
+
+  bool tcpconnect;    /* the TCP layer (or similar) is connected, this is set
+                         the first time on the first connect function call */
+  bool protoconnstart;/* the protocol layer has STARTED its operation after
+                         the TCP layer connect */
+
+  bool retry;         /* this connection is about to get closed and then
+                         re-attempted at another connection. */
+  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 tunnel_connecting; /* TRUE while we're still waiting for a proxy CONNECT
+                           */
+  bool authneg;       /* TRUE when the auth phase has started, which means
+                         that we are creating a request with an auth header,
+                         but it is not the final request in the auth
+                         negotiation. */
+  bool rewindaftersend;/* TRUE when the sending couldn't be stopped even
+                          though it will be discarded. When the whole send
+                          operation is done, we must call the data rewind
+                          callback. */
+  bool ftp_use_epsv;  /* As set with CURLOPT_FTP_USE_EPSV, but if we find out
+                         EPSV doesn't work we disable it for the forthcoming
+                         requests */
+
+  bool ftp_use_eprt;  /* As set with CURLOPT_FTP_USE_EPRT, but if we find out
+                         EPRT doesn't work we disable it for the forthcoming
+                         requests */
+  bool netrc;         /* name+password provided by netrc */
+  bool userpwd_in_url; /* name+password found in url */
+
+  bool done;          /* set to FALSE when Curl_do() is called and set to TRUE
+                         when Curl_done() is called, to prevent Curl_done() to
+                         get invoked twice when the multi interface is
+                         used. */
+  bool stream_was_rewound; /* Indicates that the stream was rewound after a
+                              request read past the end of its response byte
+                              boundary */
+  bool proxy_connect_closed; /* set true if a proxy disconnected the
+                                connection in a CONNECT request with auth, so
+                                that libcurl should reconnect and continue. */
+  bool bound; /* set true if bind() has already been done on this socket/
+                 connection */
+};
+
+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 */
+  const char *dispname; /* name to display, as 'name' might be encoded */
+};
+
+/*
+ * Flags on the keepon member of the Curl_transfer_keeper
+ */
+
+#define KEEP_NONE  0
+#define KEEP_RECV  (1<<0)     /* there is or may be data to read */
+#define KEEP_SEND (1<<1)     /* there is or may be data to write */
+#define KEEP_RECV_HOLD (1<<2) /* when set, no reading should be done but there
+                                 might still be data to read */
+#define KEEP_SEND_HOLD (1<<3) /* when set, no writing should be done but there
+                                  might still be data to write */
+#define KEEP_RECV_PAUSE (1<<4) /* reading is paused */
+#define KEEP_SEND_PAUSE (1<<5) /* writing is paused */
+
+#define KEEP_RECVBITS (KEEP_RECV | KEEP_RECV_HOLD | KEEP_RECV_PAUSE)
+#define KEEP_SENDBITS (KEEP_SEND | KEEP_SEND_HOLD | KEEP_SEND_PAUSE)
+
+
+#ifdef HAVE_LIBZ
+typedef enum {
+  ZLIB_UNINIT,          /* uninitialized */
+  ZLIB_INIT,            /* initialized */
+  ZLIB_GZIP_HEADER,     /* reading gzip header */
+  ZLIB_GZIP_INFLATING,  /* inflating gzip stream */
+  ZLIB_INIT_GZIP        /* initialized in transparent gzip mode */
+} zlibInitState;
+#endif
+
+#ifdef CURLRES_ASYNCH
+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
+
+/* These function pointer types are here only to allow easier typecasting
+   within the source when we need to cast between data pointers (such as NULL)
+   and function pointers. */
+typedef CURLcode (*Curl_do_more_func)(struct connectdata *);
+typedef CURLcode (*Curl_done_func)(struct connectdata *, CURLcode, bool);
+
+
+enum expect100 {
+  EXP100_SEND_DATA,           /* enough waiting, just send the body now */
+  EXP100_AWAITING_CONTINUE,   /* waiting for the 100 Continue header */
+  EXP100_SENDING_REQUEST,     /* still sending the request but will wait for
+                                 the 100 header once done with the request */
+  EXP100_FAILED               /* used on 417 Expectation Failed */
+};
+
+/*
+ * Request specific data in the easy handle (SessionHandle).  Previously,
+ * these members were on the connectdata struct but since a conn struct may
+ * now be shared between different SessionHandles, we store connection-specific
+ * data here. This struct only keeps stuff that's interesting for *this*
+ * request, as it will be cleared between multiple ones
+ */
+struct SingleRequest {
+  curl_off_t size;        /* -1 if unknown at this point */
+  curl_off_t *bytecountp; /* return number of bytes read or NULL */
+
+  curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch,
+                             -1 means unlimited */
+  curl_off_t *writebytecountp; /* return number of bytes written or NULL */
+
+  curl_off_t bytecount;         /* total number of bytes read */
+  curl_off_t writebytecount;    /* number of bytes written */
+
+  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 */
+
+  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' or
+                                   'RTSP/1.? XXX' line */
+  struct timeval start100;      /* time stamp to wait for the 100 code from */
+  enum expect100 exp100;        /* expect 100 continue state */
+
+  int content_encoding;         /* What content encoding. sec 3.5, RFC2616. */
+
+#define IDENTITY 0              /* No encoding */
+#define DEFLATE 1               /* zlib deflate [RFC 1950 & 1951] */
+#define GZIP 2                  /* gzip algorithm [RFC 1952] */
+#define COMPRESS 3              /* Not handled, added for completeness */
+
+#ifdef HAVE_LIBZ
+  zlibInitState zlib_init;      /* possible zlib init state;
+                                   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;
+
+  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! */
+  bool ignorecl;    /* This HTTP response has no body so we ignore the Content-
+                       Length: header */
+
+  char *location;   /* This points to an allocated version of the Location:
+                       header data */
+  char *newurl;     /* Set to the new URL to use when a redirect or a retry is
+                       wanted */
+
+  /* '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;
+
+  bool chunk; /* if set, this is a chunked transfer-encoding */
+  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 trailerhdrpresent; /* Set when Trailer: header found in HTTP response.
+                             Required to determine whether to look for trailers
+                             in case of Transfer-Encoding: chunking */
+};
+
+/*
+ * Specific protocol handler.
+ */
+
+struct Curl_handler {
+  const char * scheme;        /* URL scheme name. */
+
+  /* Complement to setup_connection_internals(). */
+  CURLcode (*setup_connection)(struct connectdata *);
+
+  /* These two functions MUST be set to be protocol dependent */
+  CURLcode (*do_it)(struct connectdata *, bool *done);
+  Curl_done_func done;
+
+  /* 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.
+   */
+  Curl_do_more_func do_more;
+
+  /* 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.
+   * The 'done' pointer points to a bool that should be set to TRUE if the
+   * function completes before return. If it doesn't complete, the caller
+   * should call the curl_connecting() function until it is.
+   */
+  CURLcode (*connect_it)(struct connectdata *, bool *done);
+
+  /* See above. Currently only used for FTP. */
+  CURLcode (*connecting)(struct connectdata *, bool *done);
+  CURLcode (*doing)(struct connectdata *, bool *done);
+
+  /* Called from the multi interface during the PROTOCONNECT phase, and it
+     should then return a proper fd set */
+  int (*proto_getsock)(struct connectdata *conn,
+                       curl_socket_t *socks,
+                       int numsocks);
+
+  /* Called from the multi interface during the DOING phase, and it should
+     then return a proper fd set */
+  int (*doing_getsock)(struct connectdata *conn,
+                       curl_socket_t *socks,
+                       int numsocks);
+
+  /* Called from the multi interface during the DO_DONE, PERFORM and
+     WAITPERFORM phases, and it should then return a proper fd set. Not setting
+     this will make libcurl use the generic default one. */
+  int (*perform_getsock)(const struct connectdata *conn,
+                         curl_socket_t *socks,
+                         int numsocks);
+
+  /* This function *MAY* be set to a protocol-dependent function that is run
+   * by the curl_disconnect(), as a step in the disconnection.
+   */
+  CURLcode (*disconnect)(struct connectdata *);
+
+  long defport;       /* Default port. */
+  long protocol;      /* PROT_* flags concerning the protocol set */
+};
+
+/*
+ * The connectdata struct contains all fields and variables that should be
+ * unique for an entire connection.
+ */
+struct connectdata {
+  /* 'data' is the CURRENT SessionHandle using this connection -- take great
+     caution that this might very well vary between different times this
+     connection is used! */
+  struct SessionHandle *data;
+
+  /* chunk is for HTTP chunked encoding, but is in the general connectdata
+     struct only because we can do just about any protocol through a HTTP proxy
+     and a HTTP proxy may in fact respond using chunked encoding */
+  struct Curl_chunker chunk;
+
+  bool inuse; /* This is a marker for the connection cache logic. If this is
+                 TRUE this handle is being used by an easy handle and cannot
+                 be used by any other easy handle without careful
+                 consideration (== only for pipelining). */
+
+  /**** Fields set when inited and not modified again */
+  long connectindex; /* what index in the connection cache connects index this
+                        particular struct has */
+  long protocol; /* PROT_* flags concerning the protocol set */
+#define PROT_HTTP    CURLPROTO_HTTP
+#define PROT_HTTPS   CURLPROTO_HTTPS
+#define PROT_FTP     CURLPROTO_FTP
+#define PROT_TELNET  CURLPROTO_TELNET
+#define PROT_DICT    CURLPROTO_DICT
+#define PROT_LDAP    CURLPROTO_LDAP
+#define PROT_FILE    CURLPROTO_FILE
+#define PROT_FTPS    CURLPROTO_FTPS
+#define PROT_TFTP    CURLPROTO_TFTP
+#define PROT_SCP     CURLPROTO_SCP
+#define PROT_SFTP    CURLPROTO_SFTP
+#define PROT_IMAP    CURLPROTO_IMAP
+#define PROT_IMAPS   CURLPROTO_IMAPS
+#define PROT_POP3    CURLPROTO_POP3
+#define PROT_POP3S   CURLPROTO_POP3S
+#define PROT_SMTP    CURLPROTO_SMTP
+#define PROT_SMTPS   CURLPROTO_SMTPS
+#define PROT_RTSP    CURLPROTO_RTSP
+
+/* (1<<18) is currently the highest used bit in the public bitmask. We make
+   sure we use "private bits" above the public ones to make things easier. */
+
+#define PROT_EXTMASK 0xfffff
+
+#define PROT_SSL     (1<<25) /* protocol requires SSL */
+
+/* these ones need action before socket close */
+#define PROT_CLOSEACTION (PROT_FTP | PROT_IMAP | PROT_POP3)
+#define PROT_DUALCHANNEL PROT_FTP /* these protocols use two connections */
+
+  /* 'dns_entry' is the particular host we use. This points to an entry in the
+     DNS cache and it will not get pruned while locked. It gets unlocked in
+     Curl_done(). This entry will be NULL if the connection is re-used as then
+     there is no name resolve done. */
+  struct Curl_dns_entry *dns_entry;
+
+  /* 'ip_addr' is the particular IP we connected to. It points to a struct
+     within the DNS cache, so this pointer is only valid as long as the DNS
+     cache entry remains locked. It gets unlocked in Curl_done() */
+  Curl_addrinfo *ip_addr;
+
+  /* 'ip_addr_str' is the ip_addr data as a human readable string.
+     It remains available as long as the connection does, which is longer than
+     the ip_addr itself. */
+  char ip_addr_str[MAX_IPADR_LEN];
+
+  unsigned int scope;    /* address scope for IPv6 */
+
+  int socktype;  /* SOCK_STREAM or SOCK_DGRAM */
+
+  struct hostname host;
+  struct hostname proxy;
+
+  long port;       /* which port to use locally */
+  unsigned short remote_port; /* what remote port to connect to,
+                                 not the proxy port! */
+
+  char *user;    /* user name string, allocated */
+  char *passwd;  /* password string, allocated */
+
+  char *proxyuser;    /* proxy user name string, allocated */
+  char *proxypasswd;  /* proxy password string, allocated */
+  curl_proxytype proxytype; /* what kind of proxy that is in use */
+
+  int httpversion;        /* the HTTP version*10 reported by the server */
+  int rtspversion;        /* the RTSP version*10 reported by the server */
+
+  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 */
+
+  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 */
+
+  const struct Curl_handler * handler;  /* Connection's protocol handler. */
+
+  /**** curl_get() phase fields */
+
+  curl_socket_t sockfd;   /* socket to read from or CURL_SOCKET_BAD */
+  curl_socket_t writesockfd; /* socket to write to, it may very
+                                well be the same we read from.
+                                CURL_SOCKET_BAD disables */
+
+  /** 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 */
+    char *rtsp_transport; /* free later if not NULL */
+  } allocptr;
+
+  int sec_complete; /* if kerberos is enabled for this connection */
+#if defined(HAVE_KRB4) || defined(HAVE_GSSAPI)
+  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;
+  void *app_data;
+  const struct Curl_sec_client_mech *mech;
+  struct sockaddr_in local_addr;
+#endif
+
+  /* the two following *_inuse fields are only flags, not counters in any way.
+     If TRUE it means the channel is in use, and if FALSE it means the channel
+     is up for grabs by one. */
+
+  bool readchannel_inuse;  /* whether the read channel is in use by an easy
+                              handle */
+  bool writechannel_inuse; /* whether the write channel is in use by an easy
+                              handle */
+  bool server_supports_pipelining; /* TRUE if server supports pipelining,
+                                      set after first response */
+
+  struct curl_llist *send_pipe; /* List of handles waiting to
+                                   send on this pipeline */
+  struct curl_llist *recv_pipe; /* List of handles waiting to read
+                                   their responses on this pipeline */
+  struct curl_llist *pend_pipe; /* List of pending handles on
+                                   this pipeline */
+  struct curl_llist *done_pipe; /* Handles that are finished, but
+                                   still reference this connectdata */
+#define MAX_PIPELINE_LENGTH 5
+
+  char* master_buffer; /* The master buffer allocated on-demand;
+                          used for pipelining. */
+  size_t read_pos; /* Current read position in the master buffer */
+  size_t buf_len; /* Length of the buffer?? */
+
+
+  curl_seek_callback seek_func; /* function that seeks the input */
+  void *seek_client;            /* pointer to pass to the seek() above */
+
+  /*************** Request - specific items ************/
+
+  /* previously this was in the urldata struct */
+  curl_read_callback fread_func; /* 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() */
+
+#ifdef CURLRES_ASYNCH
+  /* data used for the asynch name resolve callback */
+  struct Curl_async async;
+#endif
+
+  /* These three are used for chunked-encoding trailer support */
+  char *trailer; /* allocated buffer to store trailer in */
+  int trlMax;    /* allocated buffer size */
+  int trlPos;    /* index of where to store data */
+
+  union {
+    struct ftp_conn ftpc;
+    struct ssh_conn sshc;
+    struct tftp_state_data *tftpc;
+    struct imap_conn imapc;
+    struct pop3_conn pop3c;
+    struct smtp_conn smtpc;
+    struct rtsp_conn rtspc;
+  } proto;
+
+  int cselect_bits; /* bitmask of socket events */
+  int waitfor;      /* current READ/WRITE bits to wait for */
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+  int socks5_gssapi_enctype;
+#endif
+
+  long verifypeer;
+  long verifyhost;
+};
+
+/* The end of connectdata. */
+
+/*
+ * Struct to keep statistical and informational data.
+ */
+struct PureInfo {
+  int httpcode;  /* Recent HTTP, FTP, or RTSP response code */
+  int httpproxycode; /* response code from proxy when received separate */
+  int httpversion; /* the http version number X.Y = X*10+Y */
+  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. */
+  bool timecond;  /* set to TRUE if the time condition didn't match, which
+                     thus made the document NOT get fetched */
+  long header_size;  /* size of read header(s) in bytes */
+  long request_size; /* the amount of bytes sent in the request(s) */
+  long proxyauthavail; /* what proxy auth types were announced */
+  long httpauthavail;  /* what host auth types were announced */
+  long numconnects; /* how many new connection did libcurl created */
+  char *contenttype; /* the content type of the object */
+  char *wouldredirect; /* URL this would've been redirected to if asked to */
+  char ip[MAX_IPADR_LEN]; /* this buffer gets the numerical ip version stored
+                             at the connect *attempt* so it will get the last
+                             tried connect IP even on failures */
+  struct curl_certinfo certs; /* info about the certs, only populated in
+                                 OpenSSL builds. Asked for with
+                                 CURLOPT_CERTINFO / CURLINFO_CERTINFO */
+};
+
+
+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_appconnect;
+  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;
+
+typedef enum {
+    RTSPREQ_NONE, /* first in list */
+    RTSPREQ_OPTIONS,
+    RTSPREQ_DESCRIBE,
+    RTSPREQ_ANNOUNCE,
+    RTSPREQ_SETUP,
+    RTSPREQ_PLAY,
+    RTSPREQ_PAUSE,
+    RTSPREQ_TEARDOWN,
+    RTSPREQ_GET_PARAMETER,
+    RTSPREQ_SET_PARAMETER,
+    RTSPREQ_RECORD,
+    RTSPREQ_RECEIVE,
+    RTSPREQ_LAST /* last in list */
+} Curl_RtspReq;
+
+/*
+ * 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 */
+  bool multi; /* TRUE if this is not yet authenticated but within the auth
+                 multipass negotiation */
+  bool iestyle; /* TRUE if digest should be done IE-style or FALSE if it should
+                   be RFC compliant */
+};
+
+struct conncache {
+  /* 'connects' will be an allocated array with pointers. If the pointer is
+     set, it holds an allocated connection. */
+  struct connectdata **connects;
+  long num;           /* number of entries of the 'connects' array */
+  enum {
+    CONNCACHE_PRIVATE, /* used for an easy handle alone */
+    CONNCACHE_MULTI    /* shared within a multi handle */
+  } type;
+};
+
+
+struct UrlState {
+  enum {
+    Curl_if_none,
+    Curl_if_easy,
+    Curl_if_multi
+  } used_interface;
+
+  struct conncache *connc; /* points to the connection cache this handle
+                              uses */
+
+  /* buffers to store authentication data in, as parsed from input options */
+  struct timeval keeps_speed; /* for the progress meter really */
+
+  long lastconnect;  /* index of most recent connect or -1 if undefined */
+
+  char *headerbuff; /* allocated buffer to store headers in */
+  size_t headersize;   /* size of the allocation */
+
+  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 *first_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 *tempwrite;      /* allocated buffer to keep data in when a write
+                           callback returns to make the connection paused */
+  size_t tempwritesize; /* size of the 'tempwrite' allocated buffer */
+  int tempwritetype;    /* type of the 'tempwrite' buffer as a bitmask that is
+                           used with Curl_client_write() */
+  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. */
+  int os_errno;  /* filled in with errno whenever an error occurs */
+#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;      /* state data for host Digest auth */
+  struct digestdata proxydigest; /* state data for proxy Digest auth */
+
+#ifdef HAVE_GSSAPI
+  struct negotiatedata negotiate; /* state data for host Negotiate auth */
+  struct negotiatedata proxyneg; /* state data for proxy Negotiate auth */
+#endif
+
+  struct auth authhost;  /* auth details for host */
+  struct auth authproxy; /* auth details for proxy */
+
+  bool authproblem; /* TRUE if there's some problem authenticating */
+
+#ifdef USE_ARES
+  ares_channel areschannel; /* for name resolves */
+#endif
+
+#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
+  ENGINE *engine;
+#endif /* USE_SSLEAY */
+  struct timeval expiretime; /* set this with Curl_expire() only */
+  struct Curl_tree timenode; /* for the splay stuff */
+
+  /* a place to store the most recently set FTP entrypath */
+  char *most_recent_ftp_entrypath;
+
+  /* set after initial USER failure, to prevent an authentication loop */
+  bool ftp_trying_alternative;
+
+  int httpversion;       /* the lowest HTTP version*10 reported by any server
+                            involved in this request */
+  bool expect100header;  /* TRUE if we added Expect: 100-continue */
+
+  bool pipe_broke; /* TRUE if the connection we were pipelined on broke
+                      and we need to restart from the beginning */
+
+#if !defined(WIN32) && !defined(MSDOS) && !defined(__EMX__) && \
+    !defined(__SYMBIAN32__)
+/* do FTP line-end conversions on most platforms */
+#define CURL_DO_LINEEND_CONV
+  /* for FTP downloads: track CRLF sequences that span blocks */
+  bool prev_block_had_trailing_cr;
+  /* for FTP downloads: how many CRLFs did we converted to LFs? */
+  curl_off_t crlf_conversions;
+#endif
+  /* If set to non-NULL, there's a connection in a shared connection cache
+     that uses this handle so we can't kill this SessionHandle just yet but
+     must keep it around and add it to the list of handles to kill once all
+     its connections are gone */
+  void *shared_conn;
+  bool closed; /* set to TRUE when curl_easy_cleanup() has been called on this
+                  handle, but it is kept around as mentioned for
+                  shared_conn */
+  char *pathbuffer;/* allocated buffer to store the URL's path part in */
+  char *path;      /* path to use, points to somewhere within the pathbuffer
+                      area */
+
+  bool use_range;
+  bool rangestringalloc; /* the range string is malloc()'ed */
+
+  char *range; /* range, if used. See README for detailed specification on
+                  this syntax. */
+  curl_off_t resume_from; /* continue [ftp] transfer from here */
+
+  /* This RTSP state information survives requests and connections */
+  long rtsp_next_client_CSeq; /* the session's next client CSeq */
+  long rtsp_next_server_CSeq; /* the session's next server CSeq */
+  long rtsp_CSeq_recv; /* most recent CSeq received */
+
+  /* Protocol specific data.
+   *
+   *************************************************************************
+   * Note that this data will be REMOVED after each request, so anything that
+   * should be kept/stored on a per-connection basis and thus live for the
+   * next request on the same connection MUST be put in the connectdata struct!
+   *************************************************************************/
+  union {
+    struct HTTP *http;
+    struct HTTP *https;  /* alias, just for the sake of being more readable */
+    struct RTSP *rtsp;
+    struct FTP *ftp;
+    /* void *tftp;    not used */
+    struct FILEPROTO *file;
+    void *telnet;        /* private for telnet.c-eyes only */
+    void *generic;
+    struct SSHPROTO *ssh;
+    struct FTP *imap;
+    struct FTP *pop3;
+    struct FTP *smtp;
+  } proto;
+  /* current user of this SessionHandle instance, or NULL */
+  struct connectdata *current_conn;
+
+  /* if true, force SSL connection retry (workaround for certain servers) */
+  bool ssl_connect_retry;
+};
+
+
+/*
+ * 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 */
+  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.
+ * Character pointer fields point to dynamic storage, unless otherwise stated.
+ */
+struct Curl_one_easy; /* declared and used only in multi.c */
+struct Curl_multi;    /* declared and used only in multi.c */
+
+enum dupstring {
+  STRING_CERT,            /* client certificate file name */
+  STRING_CERT_TYPE,       /* format for certificate (default: PEM)*/
+  STRING_COOKIE,          /* HTTP cookie string to send */
+  STRING_COOKIEJAR,       /* dump all cookies to this file */
+  STRING_CUSTOMREQUEST,   /* HTTP/FTP/RTSP request/method to use */
+  STRING_DEVICE,          /* local network interface/address to use */
+  STRING_ENCODING,        /* Accept-Encoding string */
+  STRING_FTP_ACCOUNT,     /* ftp account data */
+  STRING_FTP_ALTERNATIVE_TO_USER, /* command to send if USER/PASS fails */
+  STRING_FTPPORT,         /* port to send with the FTP PORT command */
+  STRING_KEY,             /* private key file name */
+  STRING_KEY_PASSWD,      /* plain text private key password */
+  STRING_KEY_TYPE,        /* format for private key (default: PEM) */
+  STRING_KRB_LEVEL,       /* krb security level */
+  STRING_NETRC_FILE,      /* if not NULL, use this instead of trying to find
+                             $HOME/.netrc */
+  STRING_COPYPOSTFIELDS,  /* if POST, set the fields' values here */
+  STRING_PROXY,           /* proxy to use */
+  STRING_SET_RANGE,       /* range, if used */
+  STRING_SET_REFERER,     /* custom string for the HTTP referer field */
+  STRING_SET_URL,         /* what original URL to work on */
+  STRING_SSL_CAPATH,      /* CA directory name (doesn't work on windows) */
+  STRING_SSL_CAFILE,      /* certificate file to verify peer against */
+  STRING_SSL_CIPHER_LIST, /* list of ciphers to use */
+  STRING_SSL_EGDSOCKET,   /* path to file containing the EGD daemon socket */
+  STRING_SSL_RANDOM_FILE, /* path to file containing "random" data */
+  STRING_USERAGENT,       /* User-Agent string */
+  STRING_SSL_CRLFILE,     /* crl file to check certificate */
+  STRING_SSL_ISSUERCERT,  /* issuer cert file to check certificate */
+  STRING_USERNAME,        /* <username>, if used */
+  STRING_PASSWORD,        /* <password>, if used */
+  STRING_PROXYUSERNAME,   /* Proxy <username>, if used */
+  STRING_PROXYPASSWORD,   /* Proxy <password>, if used */
+  STRING_NOPROXY,         /* List of hosts which should not use the proxy, if
+                             used */
+  STRING_RTSP_SESSION_ID, /* Session ID to use */
+  STRING_RTSP_STREAM_URI, /* Stream URI for this request */
+  STRING_RTSP_TRANSPORT,  /* Transport for this session */
+#ifdef USE_LIBSSH2
+  STRING_SSH_PRIVATE_KEY, /* path to the private key file for auth */
+  STRING_SSH_PUBLIC_KEY,  /* path to the public key file for auth */
+  STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */
+  STRING_SSH_KNOWNHOSTS,  /* file name of knownhosts file */
+#endif
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+  STRING_SOCKS5_GSSAPI_SERVICE,  /* GSSAPI service name */
+#endif
+  STRING_MAIL_FROM,
+
+  /* -- end of strings -- */
+  STRING_LAST /* not used, just an end-of-list marker */
+};
+
+struct UserDefined {
+  FILE *err;         /* the stderr user data goes here */
+  void *debugdata;   /* the data that will be passed to fdebug */
+  char *errorbuffer; /* (Static) store failure messages in here */
+  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 if non-NULL */
+  void *rtp_out;     /* write RTP to this if non-NULL */
+  long use_port;     /* which port to use (when not using default) */
+  long httpauth;     /* what kind of HTTP authentication to use (bitmask) */
+  long proxyauth;    /* what kind of proxy authentication to use (bitmask) */
+  long followlocation; /* as in HTTP Location: */
+  long maxredirs;    /* maximum no. of http(s) redirects to follow, set to -1
+                        for infinity */
+  bool post301;      /* Obey RFC 2616/10.3.2 and keep POSTs as POSTs after a
+                        301 */
+  bool post302;      /* keep POSTs as POSTs after a 302 */
+  bool free_referer; /* set TRUE if 'referer' points to a string we
+                        allocated */
+  void *postfields;  /* if POST, set the fields' values here */
+  curl_seek_callback seek_func;      /* function that seeks the input */
+  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) */
+  unsigned short localport; /* local port number to bind to */
+  int localportrange; /* number of additional port numbers to test in case the
+                         'localport' one can't be bind()ed */
+  curl_write_callback fwrite_func;   /* function that stores the output */
+  curl_write_callback fwrite_header; /* function that stores headers */
+  curl_write_callback fwrite_rtp;    /* function that stores interleaved RTP */
+  curl_read_callback fread_func;     /* function that reads the input */
+  curl_progress_callback fprogress;  /* function for progress information */
+  curl_debug_callback fdebug;      /* function that write informational data */
+  curl_ioctl_callback ioctl_func;  /* function for I/O control */
+  curl_sockopt_callback fsockopt;  /* function for setting socket options */
+  void *sockopt_client; /* pointer to pass to the socket options callback */
+  curl_opensocket_callback fopensocket; /* function for checking/translating
+                                           the address and opening the socket */
+  void* opensocket_client;
+
+  void *seek_client;    /* pointer to pass to the seek callback */
+  /* the 3 curl_conv_callback functions below are used on non-ASCII hosts */
+  /* function to convert from the network encoding: */
+  curl_conv_callback convfromnetwork;
+  /* function to convert to the network encoding: */
+  curl_conv_callback convtonetwork;
+  /* function to convert from UTF-8 encoding: */
+  curl_conv_callback convfromutf8;
+
+  void *progress_client; /* pointer to pass to the progress callback */
+  void *ioctl_client;   /* pointer to pass to the ioctl callback */
+  long timeout;         /* in milliseconds, 0 means no timeout */
+  long connecttimeout;  /* in milliseconds, 0 means no timeout */
+  long server_response_timeout; /* in milliseconds, 0 means no timeout */
+  long tftp_blksize ; /* in bytes, 0 means use default */
+  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 max_send_speed; /* high speed limit in bytes/second for upload */
+  curl_off_t max_recv_speed; /* high speed limit in bytes/second for download */
+  curl_off_t set_resume_from;  /* continue [ftp] transfer from here */
+  struct curl_slist *headers; /* linked list of extra headers */
+  struct curl_httppost *httppost;  /* linked list of POST data */
+  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_quote;  /* 3rd party quote */
+  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_HttpReq httpreq;   /* what kind of HTTP request (if any) is this */
+  long httpversion; /* when non-zero, a specific HTTP version requested to
+                       be used in the library's request(s) */
+  struct ssl_config_data ssl;  /* user defined SSL stuff */
+  curl_proxytype proxytype; /* what kind of proxy that is in use */
+  long dns_cache_timeout; /* DNS cache timeout */
+  long buffer_size;      /* size of receive buffer to use */
+  void *private_data; /* application-private data */
+
+  struct Curl_one_easy *one_easy; /* When adding an easy handle to a multi
+                                     handle, an internal 'Curl_one_easy'
+                                     struct is created and this is a pointer
+                                     to the particular struct associated with
+                                     this SessionHandle */
+
+  struct curl_slist *http200aliases; /* linked list of aliases for http200 */
+
+  long ip_version; /* the CURL_IPRESOLVE_* defines in the public header file
+                      0 - whatever, 1 - v2, 2 - v6 */
+
+  curl_off_t max_filesize; /* Maximum file size to download */
+
+  curl_ftpfile ftp_filemethod; /* how to get to a file when FTP is used  */
+
+  int ftp_create_missing_dirs; /* 1 - create directories that don't exist
+                                  2 - the same but also allow MKD to fail once
+                               */
+
+  curl_sshkeycallback ssh_keyfunc; /* key matching callback */
+  void *ssh_keyfunc_userp;         /* custom pointer to callback */
+
+/* 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;     /* get the time and get of the remote file */
+  bool tunnel_thru_httpproxy; /* use CONNECT through a HTTP proxy */
+  bool prefer_ascii;     /* ASCII rather than binary */
+  bool ftp_append;       /* append, not overwrite, on upload */
+  bool ftp_list_only;    /* switch FTP command for listing directories */
+  bool ftp_use_port;     /* use the FTP PORT command */
+  bool hide_progress;    /* don't use the progress meter */
+  bool http_fail_on_error;  /* fail on HTTP error codes >= 300 */
+  bool http_follow_location; /* follow HTTP redirects */
+  bool http_disable_hostname_check_before_authentication;
+  bool include_header;   /* include received protocol headers in data output */
+  bool http_set_referer; /* is a custom referer used */
+  bool http_auto_referer; /* set "correct" referer when following location: */
+  bool opt_no_body;      /* as set with CURLOPT_NO_BODY */
+  bool set_port;         /* custom port number used */
+  bool upload;           /* upload request */
+  enum CURL_NETRC_OPTION
+       use_netrc;        /* defined in include/curl.h */
+  bool verbose;          /* output verbosity */
+  bool krb;              /* kerberos connection requested */
+  bool reuse_forbid;     /* forbidden to be reused, close after use */
+  bool reuse_fresh;      /* do not re-use an existing connection  */
+  bool ftp_use_epsv;     /* if EPSV is to be attempted or not */
+  bool ftp_use_eprt;     /* if EPRT is to be attempted or not */
+  bool ftp_use_pret;     /* if PRET is to be used before PASV or not */
+
+  curl_usessl ftp_ssl;   /* if AUTH TLS is to be attempted etc, for FTP or
+                            IMAP or POP3 or others! */
+  curl_ftpauth ftpsslauth; /* what AUTH XXX to be attempted */
+  curl_ftpccc ftp_ccc;   /* FTP CCC options */
+  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 */
+  bool ignorecl;         /* ignore content length */
+  bool ftp_skip_ip;      /* skip the IP address the FTP server passes on to
+                            us */
+  bool connect_only;     /* make connection, let application use the socket */
+  long ssh_auth_types;   /* allowed SSH auth types */
+  bool http_te_skip;     /* pass the raw body data to the user, even when
+                            transfer-encoded (chunked, compressed) */
+  bool http_ce_skip;     /* pass the raw body data to the user, even when
+                            content-encoded (chunked, compressed) */
+  long new_file_perms;    /* Permissions to use when creating remote files */
+  long new_directory_perms; /* Permissions to use when creating remote dirs */
+  bool proxy_transfer_mode; /* set transfer mode (;type=<a|i>) when doing FTP
+                               via an HTTP proxy */
+  char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */
+  unsigned int scope;    /* address scope for IPv6 */
+  long allowed_protocols;
+  long redir_protocols;
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+  long socks5_gssapi_nec; /* flag to support nec socks5 server */
+#endif
+  struct curl_slist *mail_rcpt; /* linked list of mail recipients */
+  /* Common RTSP header options */
+  Curl_RtspReq rtspreq; /* RTSP request type */
+  long rtspversion; /* like httpversion, for RTSP */
+};
+
+struct Names {
+  struct curl_hash *hostcache;
+  enum {
+    HCACHE_NONE,    /* not pointing to anything */
+    HCACHE_PRIVATE, /* points to our own */
+    HCACHE_GLOBAL,  /* points to the (shrug) global one */
+    HCACHE_MULTI,   /* points to a shared one in the multi handle */
+    HCACHE_SHARED   /* points to a shared one in a shared object */
+  } hostcachetype;
+};
+
+/*
+ * The 'connectdata' struct MUST have all the connection oriented stuff as we
+ * may have several simultaneous connections and connection structs in memory.
+ *
+ * The 'struct UserDefined' 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 {
+  struct Names dns;
+  struct Curl_multi *multi;    /* if non-NULL, points to the multi handle
+                                  struct to which this "belongs" */
+  struct Curl_one_easy *multi_pos; /* if non-NULL, points to its position
+                                      in multi controlling structure to assist
+                                      in removal. */
+  struct Curl_share *share;    /* Share, handles global variable mutexing */
+  struct SingleRequest req;    /* Request-specific data */
+  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.
+                                  NOTE that the 'cookie' field in the
+                                  UserDefined struct defines if the "engine"
+                                  is to be used or not. */
+  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(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
+  iconv_t outbound_cd;         /* for translating to the network encoding */
+  iconv_t inbound_cd;          /* for translating from the network encoding */
+  iconv_t utf8_cd;             /* for translating to UTF8 */
+#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
+  unsigned int magic;          /* set to a CURLEASY_MAGIC_NUMBER */
+};
+
+#define LIBCURL_NAME "libcurl"
+
+#endif
diff --git a/lib/version.c b/lib/version.c
new file mode 100644
index 0000000..aa86e39
--- /dev/null
+++ b/lib/version.c
@@ -0,0 +1,292 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 <string.h>
+#include <stdio.h>
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sslgen.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
+
+#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS)
+#include <iconv.h>
+#endif
+
+#ifdef USE_LIBSSH2
+#include <libssh2.h>
+#endif
+
+#ifdef HAVE_LIBSSH2_VERSION
+/* get it run-time if possible */
+#define CURL_LIBSSH2_VERSION libssh2_version(0)
+#else
+/* use build-time if run-time not possible */
+#define CURL_LIBSSH2_VERSION LIBSSH2_VERSION
+#endif
+
+char *curl_version(void)
+{
+  static char version[200];
+  char *ptr=version;
+  size_t len;
+  size_t left = sizeof(version);
+  strcpy(ptr, LIBCURL_NAME "/" LIBCURL_VERSION );
+  len = strlen(ptr);
+  left -= len;
+  ptr += len;
+
+  if(left > 1) {
+    len = Curl_ssl_version(ptr + 1, left - 1);
+
+    if(len > 0) {
+      *ptr = ' ';
+      left -= ++len;
+      ptr += len;
+    }
+  }
+
+#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
+#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS)
+#ifdef _LIBICONV_VERSION
+  len = snprintf(ptr, left, " iconv/%d.%d",
+                 _LIBICONV_VERSION >> 8, _LIBICONV_VERSION & 255);
+#else
+  /* version unknown */
+  len = snprintf(ptr, left, " iconv");
+#endif /* _LIBICONV_VERSION */
+  left -= len;
+  ptr += len;
+#endif
+#ifdef USE_LIBSSH2
+  len = snprintf(ptr, left, " libssh2/%s", CURL_LIBSSH2_VERSION);
+  left -= len;
+  ptr += len;
+#endif
+
+  return version;
+}
+
+/* data for curl_version_info
+
+   Keep the list sorted alphabetically. It is also written so that each
+   protocol line has its own #if line to make things easier on the eye.
+ */
+
+static const char * const protocols[] = {
+#ifndef CURL_DISABLE_DICT
+  "dict",
+#endif
+#ifndef CURL_DISABLE_FILE
+  "file",
+#endif
+#ifndef CURL_DISABLE_FTP
+  "ftp",
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)
+  "ftps",
+#endif
+#ifndef CURL_DISABLE_HTTP
+  "http",
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
+  "https",
+#endif
+#ifndef CURL_DISABLE_IMAP
+  "imap",
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_IMAP)
+  "imaps",
+#endif
+#ifndef CURL_DISABLE_LDAP
+  "ldap",
+#endif
+#if defined(HAVE_LDAP_SSL) && !defined(CURL_DISABLE_LDAP)
+  "ldaps",
+#endif
+#ifndef CURL_DISABLE_POP3
+  "pop3",
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_POP3)
+  "pop3s",
+#endif
+#ifndef CURL_DISABLE_RTSP
+  "rtsp",
+#endif
+#ifdef USE_LIBSSH2
+  "scp",
+#endif
+#ifdef USE_LIBSSH2
+  "sftp",
+#endif
+#ifndef CURL_DISABLE_SMTP
+  "smtp",
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_SMTP)
+  "smtps",
+#endif
+#ifndef CURL_DISABLE_TELNET
+  "telnet",
+#endif
+#ifndef CURL_DISABLE_TFTP
+  "tftp",
+#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_SSL
+  | CURL_VERSION_SSL
+#endif
+#ifdef USE_NTLM
+  | CURL_VERSION_NTLM
+#endif
+#ifdef USE_WINDOWS_SSPI
+  | CURL_VERSION_SSPI
+#endif
+#ifdef HAVE_LIBZ
+  | CURL_VERSION_LIBZ
+#endif
+#ifdef HAVE_GSSAPI
+  | CURL_VERSION_GSSNEGOTIATE
+#endif
+#ifdef DEBUGBUILD
+  | CURL_VERSION_DEBUG
+#endif
+#ifdef CURLDEBUG
+  | CURL_VERSION_CURLDEBUG
+#endif
+#ifdef CURLRES_ASYNCH
+  | CURL_VERSION_ASYNCHDNS
+#endif
+#ifdef HAVE_SPNEGO
+  | CURL_VERSION_SPNEGO
+#endif
+#if (CURL_SIZEOF_CURL_OFF_T > 4) && \
+    ( (SIZEOF_OFF_T > 4) || defined(USE_WIN32_LARGE_FILES) )
+  | CURL_VERSION_LARGEFILE
+#endif
+#if defined(CURL_DOES_CONVERSIONS)
+  | CURL_VERSION_CONV
+#endif
+  ,
+  NULL, /* ssl_version */
+  0,    /* ssl_version_num, this is kept at zero */
+  NULL, /* zlib_version */
+  protocols,
+  NULL, /* c-ares version */
+  0,    /* c-ares version numerical */
+  NULL, /* libidn version */
+  0,    /* iconv version */
+  NULL, /* ssh lib version */
+};
+
+curl_version_info_data *curl_version_info(CURLversion stamp)
+{
+#ifdef USE_LIBSSH2
+  static char ssh_buffer[80];
+#endif
+
+#ifdef USE_SSL
+  static char ssl_buffer[80];
+  Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer));
+  version_info.ssl_version = ssl_buffer;
+#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
+
+#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS)
+#ifdef _LIBICONV_VERSION
+  version_info.iconv_ver_num = _LIBICONV_VERSION;
+#else
+  /* version unknown */
+  version_info.iconv_ver_num = -1;
+#endif /* _LIBICONV_VERSION */
+#endif
+
+#ifdef USE_LIBSSH2
+  snprintf(ssh_buffer, sizeof(ssh_buffer), "libssh2/%s", LIBSSH2_VERSION);
+  version_info.libssh_version = ssh_buffer;
+#endif
+
+  (void)stamp; /* avoid compiler warnings, we don't use this */
+
+  return &version_info;
+}
diff --git a/lib/warnless.c b/lib/warnless.c
new file mode 100644
index 0000000..4f42dd0
--- /dev/null
+++ b/lib/warnless.c
@@ -0,0 +1,127 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 "warnless.h"
+
+#define CURL_MASK_SCHAR  0x7F
+#define CURL_MASK_UCHAR  0xFF
+
+#if (SIZEOF_SHORT == 2)
+#  define CURL_MASK_SSHORT  0x7FFF
+#  define CURL_MASK_USHORT  0xFFFF
+#elif (SIZEOF_SHORT == 4)
+#  define CURL_MASK_SSHORT  0x7FFFFFFF
+#  define CURL_MASK_USHORT  0xFFFFFFFF
+#elif (SIZEOF_SHORT == 8)
+#  define CURL_MASK_SSHORT  0x7FFFFFFFFFFFFFFF
+#  define CURL_MASK_USHORT  0xFFFFFFFFFFFFFFFF
+#else
+# error "SIZEOF_SHORT not defined"
+#endif
+
+#if (SIZEOF_INT == 2)
+#  define CURL_MASK_SINT  0x7FFF
+#  define CURL_MASK_UINT  0xFFFF
+#elif (SIZEOF_INT == 4)
+#  define CURL_MASK_SINT  0x7FFFFFFF
+#  define CURL_MASK_UINT  0xFFFFFFFF
+#elif (SIZEOF_INT == 8)
+#  define CURL_MASK_SINT  0x7FFFFFFFFFFFFFFF
+#  define CURL_MASK_UINT  0xFFFFFFFFFFFFFFFF
+#elif (SIZEOF_INT == 16)
+#  define CURL_MASK_SINT  0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+#  define CURL_MASK_UINT  0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+#else
+# error "SIZEOF_INT not defined"
+#endif
+
+#if (CURL_SIZEOF_LONG == 2)
+#  define CURL_MASK_SLONG  0x7FFFL
+#  define CURL_MASK_ULONG  0xFFFFUL
+#elif (CURL_SIZEOF_LONG == 4)
+#  define CURL_MASK_SLONG  0x7FFFFFFFL
+#  define CURL_MASK_ULONG  0xFFFFFFFFUL
+#elif (CURL_SIZEOF_LONG == 8)
+#  define CURL_MASK_SLONG  0x7FFFFFFFFFFFFFFFL
+#  define CURL_MASK_ULONG  0xFFFFFFFFFFFFFFFFUL
+#elif (CURL_SIZEOF_LONG == 16)
+#  define CURL_MASK_SLONG  0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFL
+#  define CURL_MASK_ULONG  0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFUL
+#else
+# error "SIZEOF_LONG not defined"
+#endif
+
+/*
+** unsigned long to unsigned short
+*/
+
+unsigned short curlx_ultous(unsigned long ulnum)
+{
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+  return (unsigned short)(ulnum & (unsigned long) CURL_MASK_USHORT);
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned long to unsigned char
+*/
+
+unsigned char curlx_ultouc(unsigned long ulnum)
+{
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+  return (unsigned char)(ulnum & (unsigned long) CURL_MASK_UCHAR);
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+}
+
+/*
+** size_t to signed int
+*/
+
+int curlx_uztosi(size_t uznum)
+{
+#ifdef __INTEL_COMPILER
+#  pragma warning(push)
+#  pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+  return (int)(uznum & (size_t) CURL_MASK_SINT);
+
+#ifdef __INTEL_COMPILER
+#  pragma warning(pop)
+#endif
+}
diff --git a/lib/warnless.h b/lib/warnless.h
new file mode 100644
index 0000000..ac654fb
--- /dev/null
+++ b/lib/warnless.h
@@ -0,0 +1,31 @@
+#ifndef HEADER_CURL_WARNLESS_H
+#define HEADER_CURL_WARNLESS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+unsigned short curlx_ultous(unsigned long ulnum);
+
+unsigned char curlx_ultouc(unsigned long ulnum);
+
+int curlx_uztosi(size_t uznum);
+
+#endif /* HEADER_CURL_WARNLESS_H */
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..48dd835
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,724 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005  Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# ./src/Makefile.inc
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = @INSTALL@
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+bin_PROGRAMS = curl$(EXEEXT)
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+	$(srcdir)/Makefile.inc $(srcdir)/curl_config.h.in
+subdir = src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/curl-compilers.m4 \
+	$(top_srcdir)/m4/curl-confopts.m4 \
+	$(top_srcdir)/m4/curl-functions.m4 \
+	$(top_srcdir)/m4/curl-override.m4 \
+	$(top_srcdir)/m4/curl-reentrant.m4 \
+	$(top_srcdir)/m4/curl-system.m4 $(top_srcdir)/m4/libtool.m4 \
+	$(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+	$(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+	$(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+	$(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/lib/curl_config.h curl_config.h \
+	$(top_builddir)/include/curl/curlbuild.h
+CONFIG_CLEAN_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)"
+binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
+PROGRAMS = $(bin_PROGRAMS)
+am__objects_1 = main.$(OBJEXT) hugehelp.$(OBJEXT) urlglob.$(OBJEXT) \
+	writeout.$(OBJEXT) writeenv.$(OBJEXT) getpass.$(OBJEXT) \
+	homedir.$(OBJEXT) curlutil.$(OBJEXT) os-specific.$(OBJEXT)
+am__objects_2 = strtoofft.$(OBJEXT) strdup.$(OBJEXT) rawstr.$(OBJEXT) \
+	nonblock.$(OBJEXT)
+am__objects_3 =
+am_curl_OBJECTS = $(am__objects_1) $(am__objects_2) $(am__objects_3)
+curl_OBJECTS = $(am_curl_OBJECTS)
+DEFAULT_INCLUDES = 
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+	$(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+	$(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(curl_SOURCES)
+DIST_SOURCES = $(curl_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMDEP_FALSE = @AMDEP_FALSE@
+AMDEP_TRUE = @AMDEP_TRUE@
+AMTAR = @AMTAR@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CONFIGURE_OPTIONS = @CONFIGURE_OPTIONS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CROSSCOMPILING_FALSE = @CROSSCOMPILING_FALSE@
+CROSSCOMPILING_TRUE = @CROSSCOMPILING_TRUE@
+CURLDEBUG_FALSE = @CURLDEBUG_FALSE@
+CURLDEBUG_TRUE = @CURLDEBUG_TRUE@
+CURL_CA_BUNDLE = @CURL_CA_BUNDLE@
+CURL_DISABLE_DICT = @CURL_DISABLE_DICT@
+CURL_DISABLE_FILE = @CURL_DISABLE_FILE@
+CURL_DISABLE_FTP = @CURL_DISABLE_FTP@
+CURL_DISABLE_HTTP = @CURL_DISABLE_HTTP@
+CURL_DISABLE_IMAP = @CURL_DISABLE_IMAP@
+CURL_DISABLE_LDAP = @CURL_DISABLE_LDAP@
+CURL_DISABLE_LDAPS = @CURL_DISABLE_LDAPS@
+CURL_DISABLE_POP3 = @CURL_DISABLE_POP3@
+CURL_DISABLE_PROXY = @CURL_DISABLE_PROXY@
+CURL_DISABLE_RTSP = @CURL_DISABLE_RTSP@
+CURL_DISABLE_SMTP = @CURL_DISABLE_SMTP@
+CURL_DISABLE_TELNET = @CURL_DISABLE_TELNET@
+CURL_DISABLE_TFTP = @CURL_DISABLE_TFTP@
+CURL_LIBS = @CURL_LIBS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+HAVE_LIBZ = @HAVE_LIBZ@
+HAVE_LIBZ_FALSE = @HAVE_LIBZ_FALSE@
+HAVE_LIBZ_TRUE = @HAVE_LIBZ_TRUE@
+HAVE_PK11_CREATEGENERICOBJECT = @HAVE_PK11_CREATEGENERICOBJECT@
+IDN_ENABLED = @IDN_ENABLED@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPV6_ENABLED = @IPV6_ENABLED@
+KRB4_ENABLED = @KRB4_ENABLED@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCURL_LIBS = @LIBCURL_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@
+MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@
+MAKEINFO = @MAKEINFO@
+MANOPT = @MANOPT@
+MIMPURE_FALSE = @MIMPURE_FALSE@
+MIMPURE_TRUE = @MIMPURE_TRUE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NO_UNDEFINED_FALSE = @NO_UNDEFINED_FALSE@
+NO_UNDEFINED_TRUE = @NO_UNDEFINED_TRUE@
+# Use the C locale to ensure that only ASCII characters appear in the
+# embedded text.
+NROFF = env LC_ALL=C @NROFF@ @MANOPT@ # figured out by the configure script
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH = @PATH@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKGADD_NAME = @PKGADD_NAME@
+PKGADD_PKG = @PKGADD_PKG@
+PKGADD_VENDOR = @PKGADD_VENDOR@
+PKGCONFIG = @PKGCONFIG@
+RANDOM_FILE = @RANDOM_FILE@
+RANLIB = @RANLIB@
+REQUIRE_LIB_DEPS = @REQUIRE_LIB_DEPS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SONAME_BUMP_FALSE = @SONAME_BUMP_FALSE@
+SONAME_BUMP_TRUE = @SONAME_BUMP_TRUE@
+SSL_ENABLED = @SSL_ENABLED@
+STATICLIB_FALSE = @STATICLIB_FALSE@
+STATICLIB_TRUE = @STATICLIB_TRUE@
+STRIP = @STRIP@
+SUPPORT_FEATURES = @SUPPORT_FEATURES@
+SUPPORT_PROTOCOLS = @SUPPORT_PROTOCOLS@
+TEST_SERVER_LIBS = @TEST_SERVER_LIBS@
+USE_ARES = @USE_ARES@
+USE_EMBEDDED_ARES_FALSE = @USE_EMBEDDED_ARES_FALSE@
+USE_EMBEDDED_ARES_TRUE = @USE_EMBEDDED_ARES_TRUE@
+USE_GNUTLS = @USE_GNUTLS@
+USE_LIBSSH2 = @USE_LIBSSH2@
+USE_MANUAL_FALSE = @USE_MANUAL_FALSE@
+USE_MANUAL_TRUE = @USE_MANUAL_TRUE@
+USE_NSS = @USE_NSS@
+USE_SSLEAY = @USE_SSLEAY@
+USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@
+VERSION = @VERSION@
+VERSIONNUM = @VERSIONNUM@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
+am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libext = @libext@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+
+#***************************************************************************
+#                                  _   _ ____  _
+#  Project                     ___| | | |  _ \| |
+#                             / __| | | | |_) | |
+#                            | (__| |_| |  _ <| |___
+#                             \___|\___/|_| \_\_____|
+#
+# Copyright (C) 1998 - 2009, 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.
+#
+###########################################################################
+AUTOMAKE_OPTIONS = foreign nostdinc
+
+# Specify our include paths here, and do it relative to $(top_srcdir) and
+# $(top_builddir), to ensure that these paths which belong to the library
+# being currently built and tested are searched before the library which
+# might possibly already be installed in the system.
+#
+# $(top_builddir)/include/curl for generated curlbuild.h included from curl.h
+# $(top_builddir)/include for generated curlbuild.h included from lib/setup.h
+# $(top_srcdir)/include is for libcurl's external include files
+# $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file
+# $(top_builddir)/src is for curl's generated src/curl_config.h file
+# $(top_srcdir)/lib is for libcurl's lib/setup.h and other "borrowed" files
+# $(top_srcdir)/src is for curl's src/setup.h and "curl-private" files
+INCLUDES = -I$(top_builddir)/include/curl \
+           -I$(top_builddir)/include      \
+           -I$(top_srcdir)/include        \
+           -I$(top_builddir)/lib          \
+           -I$(top_builddir)/src          \
+           -I$(top_srcdir)/lib            \
+           -I$(top_srcdir)/src
+
+
+# libcurl has sources that provide functions named curlx_* that aren't part of
+# the official API, but we re-use the code here to avoid duplication.
+CURLX_ONES = $(top_srcdir)/lib/strtoofft.c \
+	$(top_srcdir)/lib/strdup.c \
+	$(top_srcdir)/lib/rawstr.c \
+	$(top_srcdir)/lib/nonblock.c
+
+CURL_SOURCES = main.c hugehelp.c urlglob.c writeout.c writeenv.c \
+	getpass.c homedir.c curlutil.c os-specific.c
+
+CURL_HFILES = hugehelp.h setup.h config-win32.h config-mac.h \
+	config-riscos.h urlglob.h version.h os-specific.h \
+	writeout.h writeenv.h getpass.h homedir.h curlutil.h
+
+curl_SOURCES = $(CURL_SOURCES) $(CURLX_ONES) $(CURL_HFILES)
+curl_LDADD = $(top_builddir)/lib/libcurl.la @CURL_LIBS@
+curl_DEPENDENCIES = $(top_builddir)/lib/libcurl.la
+BUILT_SOURCES = hugehelp.c
+CLEANFILES = hugehelp.c
+EXTRA_DIST = mkhelp.pl makefile.dj Makefile.vc6 Makefile.b32 Makefile.m32 \
+	Makefile.riscos curl_config.h.in macos/curl.mcp.xml.sit.hqx	  \
+	macos/MACINSTALL.TXT macos/src/curl_GUSIConfig.cpp vc6curlsrc.dsp \
+	macos/src/macos_main.cpp config-amigaos.h makefile.amiga curl.rc  \
+	Makefile.netware Makefile.inc Makefile.Watcom vc6curlsrc.dsw      \
+	CMakeLists.txt
+
+MANPAGE = $(top_srcdir)/docs/curl.1
+README = $(top_srcdir)/docs/MANUAL
+MKHELP = $(top_srcdir)/src/mkhelp.pl
+HUGE = hugehelp.c
+all: $(BUILT_SOURCES) curl_config.h
+	$(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/Makefile.inc $(am__configure_deps)
+	@for dep in $?; do \
+	  case '$(am__configure_deps)' in \
+	    *$$dep*) \
+	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+		&& exit 0; \
+	      exit 1;; \
+	  esac; \
+	done; \
+	echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign  src/Makefile'; \
+	cd $(top_srcdir) && \
+	  $(AUTOMAKE) --foreign  src/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+	@case '$?' in \
+	  *config.status*) \
+	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+	  *) \
+	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+	esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+curl_config.h: stamp-h2
+	@if test ! -f $@; then \
+	  rm -f stamp-h2; \
+	  $(MAKE) stamp-h2; \
+	else :; fi
+
+stamp-h2: $(srcdir)/curl_config.h.in $(top_builddir)/config.status
+	@rm -f stamp-h2
+	cd $(top_builddir) && $(SHELL) ./config.status src/curl_config.h
+$(srcdir)/curl_config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) 
+	cd $(top_srcdir) && $(AUTOHEADER)
+	rm -f stamp-h2
+	touch $@
+
+distclean-hdr:
+	-rm -f curl_config.h stamp-h2
+install-binPROGRAMS: $(bin_PROGRAMS)
+	@$(NORMAL_INSTALL)
+	test -z "$(bindir)" || $(mkdir_p) "$(DESTDIR)$(bindir)"
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  if test -f $$p \
+	     || test -f $$p1 \
+	  ; then \
+	    f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
+	   echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \
+	   $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \
+	  else :; fi; \
+	done
+
+uninstall-binPROGRAMS:
+	@$(NORMAL_UNINSTALL)
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+	  echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
+	  rm -f "$(DESTDIR)$(bindir)/$$f"; \
+	done
+
+clean-binPROGRAMS:
+	@list='$(bin_PROGRAMS)'; for p in $$list; do \
+	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+	  echo " rm -f $$p $$f"; \
+	  rm -f $$p $$f ; \
+	done
+curl$(EXEEXT): $(curl_OBJECTS) $(curl_DEPENDENCIES) 
+	@rm -f curl$(EXEEXT)
+	$(LINK) $(curl_LDFLAGS) $(curl_OBJECTS) $(curl_LDADD) $(LIBS)
+
+mostlyclean-compile:
+	-rm -f *.$(OBJEXT)
+
+distclean-compile:
+	-rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/curlutil.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getpass.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/homedir.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hugehelp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nonblock.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/os-specific.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rawstr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strdup.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strtoofft.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/urlglob.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/writeenv.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/writeout.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<
+
+strtoofft.o: $(top_srcdir)/lib/strtoofft.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT strtoofft.o -MD -MP -MF "$(DEPDIR)/strtoofft.Tpo" -c -o strtoofft.o `test -f '$(top_srcdir)/lib/strtoofft.c' || echo '$(srcdir)/'`$(top_srcdir)/lib/strtoofft.c; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/strtoofft.Tpo" "$(DEPDIR)/strtoofft.Po"; else rm -f "$(DEPDIR)/strtoofft.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$(top_srcdir)/lib/strtoofft.c' object='strtoofft.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o strtoofft.o `test -f '$(top_srcdir)/lib/strtoofft.c' || echo '$(srcdir)/'`$(top_srcdir)/lib/strtoofft.c
+
+strtoofft.obj: $(top_srcdir)/lib/strtoofft.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT strtoofft.obj -MD -MP -MF "$(DEPDIR)/strtoofft.Tpo" -c -o strtoofft.obj `if test -f '$(top_srcdir)/lib/strtoofft.c'; then $(CYGPATH_W) '$(top_srcdir)/lib/strtoofft.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/lib/strtoofft.c'; fi`; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/strtoofft.Tpo" "$(DEPDIR)/strtoofft.Po"; else rm -f "$(DEPDIR)/strtoofft.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$(top_srcdir)/lib/strtoofft.c' object='strtoofft.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o strtoofft.obj `if test -f '$(top_srcdir)/lib/strtoofft.c'; then $(CYGPATH_W) '$(top_srcdir)/lib/strtoofft.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/lib/strtoofft.c'; fi`
+
+strdup.o: $(top_srcdir)/lib/strdup.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT strdup.o -MD -MP -MF "$(DEPDIR)/strdup.Tpo" -c -o strdup.o `test -f '$(top_srcdir)/lib/strdup.c' || echo '$(srcdir)/'`$(top_srcdir)/lib/strdup.c; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/strdup.Tpo" "$(DEPDIR)/strdup.Po"; else rm -f "$(DEPDIR)/strdup.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$(top_srcdir)/lib/strdup.c' object='strdup.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o strdup.o `test -f '$(top_srcdir)/lib/strdup.c' || echo '$(srcdir)/'`$(top_srcdir)/lib/strdup.c
+
+strdup.obj: $(top_srcdir)/lib/strdup.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT strdup.obj -MD -MP -MF "$(DEPDIR)/strdup.Tpo" -c -o strdup.obj `if test -f '$(top_srcdir)/lib/strdup.c'; then $(CYGPATH_W) '$(top_srcdir)/lib/strdup.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/lib/strdup.c'; fi`; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/strdup.Tpo" "$(DEPDIR)/strdup.Po"; else rm -f "$(DEPDIR)/strdup.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$(top_srcdir)/lib/strdup.c' object='strdup.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o strdup.obj `if test -f '$(top_srcdir)/lib/strdup.c'; then $(CYGPATH_W) '$(top_srcdir)/lib/strdup.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/lib/strdup.c'; fi`
+
+rawstr.o: $(top_srcdir)/lib/rawstr.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rawstr.o -MD -MP -MF "$(DEPDIR)/rawstr.Tpo" -c -o rawstr.o `test -f '$(top_srcdir)/lib/rawstr.c' || echo '$(srcdir)/'`$(top_srcdir)/lib/rawstr.c; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/rawstr.Tpo" "$(DEPDIR)/rawstr.Po"; else rm -f "$(DEPDIR)/rawstr.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$(top_srcdir)/lib/rawstr.c' object='rawstr.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rawstr.o `test -f '$(top_srcdir)/lib/rawstr.c' || echo '$(srcdir)/'`$(top_srcdir)/lib/rawstr.c
+
+rawstr.obj: $(top_srcdir)/lib/rawstr.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT rawstr.obj -MD -MP -MF "$(DEPDIR)/rawstr.Tpo" -c -o rawstr.obj `if test -f '$(top_srcdir)/lib/rawstr.c'; then $(CYGPATH_W) '$(top_srcdir)/lib/rawstr.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/lib/rawstr.c'; fi`; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/rawstr.Tpo" "$(DEPDIR)/rawstr.Po"; else rm -f "$(DEPDIR)/rawstr.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$(top_srcdir)/lib/rawstr.c' object='rawstr.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o rawstr.obj `if test -f '$(top_srcdir)/lib/rawstr.c'; then $(CYGPATH_W) '$(top_srcdir)/lib/rawstr.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/lib/rawstr.c'; fi`
+
+nonblock.o: $(top_srcdir)/lib/nonblock.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nonblock.o -MD -MP -MF "$(DEPDIR)/nonblock.Tpo" -c -o nonblock.o `test -f '$(top_srcdir)/lib/nonblock.c' || echo '$(srcdir)/'`$(top_srcdir)/lib/nonblock.c; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/nonblock.Tpo" "$(DEPDIR)/nonblock.Po"; else rm -f "$(DEPDIR)/nonblock.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$(top_srcdir)/lib/nonblock.c' object='nonblock.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nonblock.o `test -f '$(top_srcdir)/lib/nonblock.c' || echo '$(srcdir)/'`$(top_srcdir)/lib/nonblock.c
+
+nonblock.obj: $(top_srcdir)/lib/nonblock.c
+@am__fastdepCC_TRUE@	if $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT nonblock.obj -MD -MP -MF "$(DEPDIR)/nonblock.Tpo" -c -o nonblock.obj `if test -f '$(top_srcdir)/lib/nonblock.c'; then $(CYGPATH_W) '$(top_srcdir)/lib/nonblock.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/lib/nonblock.c'; fi`; \
+@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/nonblock.Tpo" "$(DEPDIR)/nonblock.Po"; else rm -f "$(DEPDIR)/nonblock.Tpo"; exit 1; fi
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$(top_srcdir)/lib/nonblock.c' object='nonblock.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@	$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o nonblock.obj `if test -f '$(top_srcdir)/lib/nonblock.c'; then $(CYGPATH_W) '$(top_srcdir)/lib/nonblock.c'; else $(CYGPATH_W) '$(srcdir)/$(top_srcdir)/lib/nonblock.c'; fi`
+
+mostlyclean-libtool:
+	-rm -f *.lo
+
+clean-libtool:
+	-rm -rf .libs _libs
+
+distclean-libtool:
+	-rm -f libtool
+uninstall-info-am:
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	mkid -fID $$unique
+tags: TAGS
+
+TAGS:  $(HEADERS) $(SOURCES) curl_config.h.in $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS) curl_config.h.in $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+	  test -n "$$unique" || unique=$$empty_fix; \
+	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+	    $$tags $$unique; \
+	fi
+ctags: CTAGS
+CTAGS:  $(HEADERS) $(SOURCES) curl_config.h.in $(TAGS_DEPENDENCIES) \
+		$(TAGS_FILES) $(LISP)
+	tags=; \
+	here=`pwd`; \
+	list='$(SOURCES) $(HEADERS) curl_config.h.in $(LISP) $(TAGS_FILES)'; \
+	unique=`for i in $$list; do \
+	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+	  done | \
+	  $(AWK) '    { files[$$0] = 1; } \
+	       END { for (i in files) print i; }'`; \
+	test -z "$(CTAGS_ARGS)$$tags$$unique" \
+	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+	     $$tags $$unique
+
+GTAGS:
+	here=`$(am__cd) $(top_builddir) && pwd` \
+	  && cd $(top_srcdir) \
+	  && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+	$(mkdir_p) $(distdir)/macos $(distdir)/macos/src
+	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+	list='$(DISTFILES)'; for file in $$list; do \
+	  case $$file in \
+	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+	  esac; \
+	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+	    dir="/$$dir"; \
+	    $(mkdir_p) "$(distdir)$$dir"; \
+	  else \
+	    dir=''; \
+	  fi; \
+	  if test -d $$d/$$file; then \
+	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+	    fi; \
+	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+	  else \
+	    test -f $(distdir)/$$file \
+	    || cp -p $$d/$$file $(distdir)/$$file \
+	    || exit 1; \
+	  fi; \
+	done
+check-am: all-am
+check: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(PROGRAMS) curl_config.h
+installdirs:
+	for dir in "$(DESTDIR)$(bindir)"; do \
+	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
+	done
+install: $(BUILT_SOURCES)
+	$(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+	  `test -z '$(STRIP)' || \
+	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+	-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+	@echo "This command is intended for maintainers to use"
+	@echo "it deletes files that may require special tools to rebuild."
+	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+	distclean-hdr distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+	-rm -rf ./$(DEPDIR)
+	-rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+	mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-info-am
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \
+	clean-generic clean-libtool ctags distclean distclean-compile \
+	distclean-generic distclean-hdr distclean-libtool \
+	distclean-tags distdir dvi dvi-am html html-am info info-am \
+	install install-am install-binPROGRAMS install-data \
+	install-data-am install-exec install-exec-am install-info \
+	install-info-am install-man install-strip installcheck \
+	installcheck-am installdirs maintainer-clean \
+	maintainer-clean-generic mostlyclean mostlyclean-compile \
+	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+	tags uninstall uninstall-am uninstall-binPROGRAMS \
+	uninstall-info-am
+
+
+# Here are the stuff to create a built-in manual
+
+# This generates the hugehelp.c file in both uncompressed and compressed formats
+@HAVE_LIBZ_TRUE@@USE_MANUAL_TRUE@$(HUGE): $(README) $(MANPAGE)  mkhelp.pl
+@HAVE_LIBZ_TRUE@@USE_MANUAL_TRUE@	echo '#include "setup.h"' > $(HUGE)
+@HAVE_LIBZ_TRUE@@USE_MANUAL_TRUE@	echo '#ifndef HAVE_LIBZ' >> $(HUGE)
+@HAVE_LIBZ_TRUE@@USE_MANUAL_TRUE@	$(NROFF) $(MANPAGE) | $(PERL) $(MKHELP) $(README) >> $(HUGE)
+@HAVE_LIBZ_TRUE@@USE_MANUAL_TRUE@	echo '#else' >> $(HUGE)
+@HAVE_LIBZ_TRUE@@USE_MANUAL_TRUE@	$(NROFF) $(MANPAGE) | $(PERL) $(MKHELP) -c $(README) >> $(HUGE)
+@HAVE_LIBZ_TRUE@@USE_MANUAL_TRUE@	echo '#endif /* HAVE_LIBZ */' >> $(HUGE)
+# This generates the hugehelp.c file uncompressed only
+@HAVE_LIBZ_FALSE@@USE_MANUAL_TRUE@$(HUGE): $(README) $(MANPAGE)  mkhelp.pl
+@HAVE_LIBZ_FALSE@@USE_MANUAL_TRUE@	echo '#include "setup.h"' > $(HUGE)
+@HAVE_LIBZ_FALSE@@USE_MANUAL_TRUE@	$(NROFF) $(MANPAGE) | $(PERL) $(MKHELP) $(README) >> $(HUGE)
+
+# built-in manual has been disabled, make a blank file
+@USE_MANUAL_FALSE@$(HUGE):
+@USE_MANUAL_FALSE@	echo "/* built-in manual is disabled, blank function */" > $(HUGE)
+@USE_MANUAL_FALSE@	echo '#include "hugehelp.h"' >> $(HUGE)
+@USE_MANUAL_FALSE@	echo "void hugehelp(void) {}" >>$(HUGE)
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/Makefile.inc b/src/Makefile.inc
new file mode 100644
index 0000000..9faf89d
--- /dev/null
+++ b/src/Makefile.inc
@@ -0,0 +1,19 @@
+# ./src/Makefile.inc
+
+# libcurl has sources that provide functions named curlx_* that aren't part of
+# the official API, but we re-use the code here to avoid duplication.
+CURLX_ONES =  $(top_srcdir)/lib/strtoofft.c \
+	$(top_srcdir)/lib/strdup.c \
+	$(top_srcdir)/lib/rawstr.c \
+	$(top_srcdir)/lib/nonblock.c
+
+CURL_SOURCES = main.c hugehelp.c urlglob.c writeout.c writeenv.c \
+	getpass.c homedir.c curlutil.c os-specific.c
+
+CURL_HFILES = hugehelp.h setup.h config-win32.h config-mac.h \
+	config-riscos.h urlglob.h version.h os-specific.h \
+	writeout.h writeenv.h getpass.h homedir.h curlutil.h
+
+curl_SOURCES = $(CURL_SOURCES) $(CURLX_ONES) $(CURL_HFILES)
+
+
diff --git a/src/curl.rc b/src/curl.rc
new file mode 100644
index 0000000..58e439d
--- /dev/null
+++ b/src/curl.rc
@@ -0,0 +1,63 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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 <winver.h>
+#include "version.h"
+
+LANGUAGE  0x09,0x01
+
+#define RC_VERSION  CURL_VERSION_MAJOR, CURL_VERSION_MINOR, CURL_VERSION_PATCH, 0
+
+VS_VERSION_INFO VERSIONINFO
+  FILEVERSION     RC_VERSION
+  PRODUCTVERSION  RC_VERSION
+  FILEFLAGSMASK   0x3fL
+#if defined(DEBUGBUILD) || defined(_DEBUG)
+  FILEFLAGS 1
+#else
+  FILEFLAGS 0
+#endif
+  FILEOS      VOS__WINDOWS32
+  FILETYPE    VFT_APP
+  FILESUBTYPE 0x0L
+
+BEGIN
+  BLOCK "StringFileInfo"
+  BEGIN
+    BLOCK "040904b0"
+    BEGIN
+      VALUE "CompanyName",      "cURL, http://curl.haxx.se/\0"
+      VALUE "FileDescription",  "The cURL executable\0"
+      VALUE "FileVersion",      CURL_VERSION "\0"
+      VALUE "InternalName",     "curl\0"
+      VALUE "OriginalFilename", "curl.exe\0"
+      VALUE "ProductName",      "The cURL executable\0"
+      VALUE "ProductVersion",   CURL_VERSION "\0"
+      VALUE "LegalCopyright",   "© " CURL_COPYRIGHT "\0"
+      VALUE "License",          "http://curl.haxx.se/docs/copyright.html\0"
+    END
+  END
+
+  BLOCK "VarFileInfo"
+  BEGIN
+    VALUE "Translation", 0x409, 1200
+  END
+END
diff --git a/src/curl_config.h b/src/curl_config.h
new file mode 100644
index 0000000..1ac94f3
--- /dev/null
+++ b/src/curl_config.h
@@ -0,0 +1,974 @@
+/* src/curl_config.h.  Generated from curl_config.h.in by configure.  */
+/* lib/curl_config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* when building libcurl itself */
+/* #undef BUILDING_LIBCURL */
+
+/* Location of default ca bundle */
+#define CURL_CA_BUNDLE "/etc/ssl/certs/ca-certificates.crt"
+
+/* Location of default ca path */
+/* #undef CURL_CA_PATH */
+
+/* to disable cookies support */
+/* #undef CURL_DISABLE_COOKIES */
+
+/* to disable cryptographic authentication */
+/* #undef CURL_DISABLE_CRYPTO_AUTH */
+
+/* to disable DICT */
+/* #undef CURL_DISABLE_DICT */
+
+/* to disable FILE */
+/* #undef CURL_DISABLE_FILE */
+
+/* to disable FTP */
+/* #undef CURL_DISABLE_FTP */
+
+/* to disable HTTP */
+/* #undef CURL_DISABLE_HTTP */
+
+/* to disable IMAP */
+/* #undef CURL_DISABLE_IMAP */
+
+/* to disable LDAP */
+#define CURL_DISABLE_LDAP 1
+
+/* to disable LDAPS */
+#define CURL_DISABLE_LDAPS 1
+
+/* to disable POP3 */
+/* #undef CURL_DISABLE_POP3 */
+
+/* to disable proxies */
+/* #undef CURL_DISABLE_PROXY */
+
+/* to disable RTSP */
+/* #undef CURL_DISABLE_RTSP */
+
+/* to disable SMTP */
+/* #undef CURL_DISABLE_SMTP */
+
+/* to disable TELNET */
+/* #undef CURL_DISABLE_TELNET */
+
+/* to disable TFTP */
+/* #undef CURL_DISABLE_TFTP */
+
+/* to disable verbose strings */
+/* #undef CURL_DISABLE_VERBOSE_STRINGS */
+
+/* to make a symbol visible */
+/* #undef CURL_EXTERN_SYMBOL */
+
+/* to enable hidden symbols */
+/* #undef CURL_HIDDEN_SYMBOLS */
+
+/* W$ LDAP with non-W$ compiler */
+/* #undef CURL_LDAP_HYBRID */
+
+/* Use W$ LDAP implementation */
+/* #undef CURL_LDAP_WIN */
+
+/* when not building a shared library */
+/* #undef CURL_STATICLIB */
+
+/* your Entropy Gathering Daemon socket pathname */
+/* #undef EGD_SOCKET */
+
+/* Define if you want to enable IPv6 support */
+#define ENABLE_IPV6 1
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 socklen_t
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 unsigned int
+
+/* Specifies the number of arguments to getservbyport_r */
+#define GETSERVBYPORT_R_ARGS 6
+
+/* Specifies the size of the buffer to pass to getservbyport_r */
+#define GETSERVBYPORT_R_BUFSIZE 4096
+
+/* Define to 1 if you have the alarm function. */
+#define HAVE_ALARM 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 <arpa/tftp.h> header file. */
+#define HAVE_ARPA_TFTP_H 1
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the basename function. */
+#define HAVE_BASENAME 1
+
+/* Define to 1 if bool is an available type. */
+#define HAVE_BOOL_T 1
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+#define HAVE_CLOCK_GETTIME_MONOTONIC 1
+
+/* Define to 1 if you have the closesocket function. */
+/* #undef HAVE_CLOSESOCKET */
+
+/* Define to 1 if you have the CloseSocket camel case function. */
+/* #undef HAVE_CLOSESOCKET_CAMEL */
+
+/* Define to 1 if you have the connect function. */
+#define HAVE_CONNECT 1
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+#define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1
+
+/* 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 */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `ENGINE_cleanup' function. */
+#define HAVE_ENGINE_CLEANUP 1
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+#define HAVE_ENGINE_LOAD_BUILTIN_ENGINES 1
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <err.h> header file. */
+/* #undef HAVE_ERR_H */
+
+/* Define to 1 if you have the fcntl function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#define HAVE_FCNTL_O_NONBLOCK 1
+
+/* Define to 1 if you have the fdopen function. */
+#define HAVE_FDOPEN 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#define HAVE_FREEADDRINFO 1
+
+/* Define to 1 if you have the freeifaddrs function. */
+#define HAVE_FREEIFADDRS 1
+
+/* Define to 1 if you have the ftruncate function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if the getaddrinfo function is threadsafe. */
+#define HAVE_GETADDRINFO_THREADSAFE 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
+
+/* gethostbyaddr_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYADDR_R_5 */
+
+/* gethostbyaddr_r() takes 7 args */
+/* #undef HAVE_GETHOSTBYADDR_R_7 */
+
+/* gethostbyaddr_r() takes 8 args */
+#define HAVE_GETHOSTBYADDR_R_8 1
+
+/* Define to 1 if you have the gethostbyname function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the gethostbyname_r function. */
+#define HAVE_GETHOSTBYNAME_R 1
+
+/* gethostbyname_r() takes 3 args */
+/* #undef HAVE_GETHOSTBYNAME_R_3 */
+
+/* gethostbyname_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYNAME_R_5 */
+
+/* gethostbyname_r() takes 6 args */
+#define HAVE_GETHOSTBYNAME_R_6 1
+
+/* Define to 1 if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have a working getifaddrs function. */
+#define HAVE_GETIFADDRS 1
+
+/* Define to 1 if you have the getnameinfo function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getpass_r' function. */
+/* #undef HAVE_GETPASS_R */
+
+/* Define to 1 if you have the `getppid' function. */
+#define HAVE_GETPPID 1
+
+/* Define to 1 if you have the `getprotobyname' function. */
+#define HAVE_GETPROTOBYNAME 1
+
+/* Define to 1 if you have the `getpwuid' function. */
+#define HAVE_GETPWUID 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+#define HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the getservbyport_r function. */
+#define HAVE_GETSERVBYPORT_R 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+/* #undef HAVE_GLIBC_STRERROR_R */
+
+/* Define to 1 if you have a working gmtime_r function. */
+#define HAVE_GMTIME_R 1
+
+/* if you have the gssapi libraries */
+/* #undef HAVE_GSSAPI */
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */
+
+/* if you have the GNU gssapi libraries */
+/* #undef HAVE_GSSGNU */
+
+/* if you have the Heimdal gssapi libraries */
+/* #undef HAVE_GSSHEIMDAL */
+
+/* if you have the MIT gssapi libraries */
+/* #undef HAVE_GSSMIT */
+
+/* Define to 1 if you have the `idna_strerror' function. */
+/* #undef HAVE_IDNA_STRERROR */
+
+/* Define to 1 if you have the `idn_free' function. */
+/* #undef HAVE_IDN_FREE */
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+/* #undef HAVE_IDN_FREE_H */
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#define HAVE_IFADDRS_H 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_r function. */
+/* #undef HAVE_INET_NTOA_R */
+
+/* inet_ntoa_r() takes 2 args */
+/* #undef HAVE_INET_NTOA_R_2 */
+
+/* inet_ntoa_r() takes 3 args */
+/* #undef HAVE_INET_NTOA_R_3 */
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#define HAVE_INET_NTOP 1
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#define HAVE_INET_PTON 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the ioctl function. */
+#define HAVE_IOCTL 1
+
+/* Define to 1 if you have the ioctlsocket function. */
+/* #undef HAVE_IOCTLSOCKET */
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+/* #undef HAVE_IOCTLSOCKET_CAMEL */
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+   */
+/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+/* #undef HAVE_IOCTLSOCKET_FIONBIO */
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+#define HAVE_IOCTL_FIONBIO 1
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+#define HAVE_IOCTL_SIOCGIFADDR 1
+
+/* Define to 1 if you have the <io.h> header file. */
+/* #undef HAVE_IO_H */
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+/* #undef HAVE_KRB4 */
+
+/* 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 lber.h header file. */
+/* #undef HAVE_LBER_H */
+
+/* Define to 1 if you have the ldapssl.h header file. */
+/* #undef HAVE_LDAPSSL_H */
+
+/* Define to 1 if you have the ldap.h header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Use LDAPS implementation */
+/* #undef HAVE_LDAP_SSL */
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+/* #undef HAVE_LDAP_SSL_H */
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+/* #undef HAVE_LDAP_URL_PARSE */
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#define HAVE_LIBGEN_H 1
+
+/* Define to 1 if you have the `idn' library (-lidn). */
+/* #undef HAVE_LIBIDN */
+
+/* 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 `ssh2' library (-lssh2). */
+/* #undef HAVE_LIBSSH2 */
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+/* #undef HAVE_LIBSSH2_H */
+
+/* Define to 1 if you have the `libssh2_version' function. */
+/* #undef HAVE_LIBSSH2_VERSION */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+#define HAVE_LIBSSL 1
+
+/* if zlib is available */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* if your compiler supports LL */
+#define HAVE_LL 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have a working localtime_r function. */
+#define HAVE_LOCALTIME_R 1
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#define HAVE_LONGLONG 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 memrchr function or macro. */
+/* #undef HAVE_MEMRCHR */
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+#define HAVE_MSG_NOSIGNAL 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/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#define HAVE_NETINET_TCP_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if NI_WITHSCOPEID exists and works. */
+/* #undef HAVE_NI_WITHSCOPEID */
+
+/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE
+   */
+/* #undef HAVE_OLD_GSSMIT */
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+#define HAVE_OPENSSL_CRYPTO_H 1
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+#define HAVE_OPENSSL_ENGINE_H 1
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+#define HAVE_OPENSSL_ERR_H 1
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+#define HAVE_OPENSSL_PEM_H 1
+
+/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
+#define HAVE_OPENSSL_PKCS12_H 1
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+#define HAVE_OPENSSL_RSA_H 1
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+#define HAVE_OPENSSL_SSL_H 1
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+#define HAVE_OPENSSL_X509_H 1
+
+/* 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 `pipe' function. */
+#define HAVE_PIPE 1
+
+/* if you have the function PK11_CreateGenericObject */
+/* #undef HAVE_PK11_CREATEGENERICOBJECT */
+
+/* Define to 1 if you have a working poll function. */
+#define HAVE_POLL 1
+
+/* If you have a fine poll */
+#define HAVE_POLL_FINE 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define HAVE_POLL_H 1
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+#define HAVE_POSIX_STRERROR_R 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. */
+#define HAVE_RAND_EGD 1
+
+/* Define to 1 if you have the `RAND_screen' function. */
+/* #undef HAVE_RAND_SCREEN */
+
+/* Define to 1 if you have the `RAND_status' function. */
+#define HAVE_RAND_STATUS 1
+
+/* Define to 1 if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to 1 if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* 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 send function. */
+#define HAVE_SEND 1
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#define HAVE_SETJMP_H 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `setmode' function. */
+/* #undef HAVE_SETMODE */
+
+/* Define to 1 if you have the `setrlimit' function. */
+#define HAVE_SETRLIMIT 1
+
+/* Define to 1 if you have the setsockopt function. */
+#define HAVE_SETSOCKOPT 1
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */
+
+/* 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 siginterrupt function. */
+#define HAVE_SIGINTERRUPT 1
+
+/* Define to 1 if you have the signal function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+#define HAVE_SIGSETJMP 1
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define to 1 if you have the socket function. */
+#define HAVE_SOCKET 1
+
+/* Define to 1 if you have the <socket.h> header file. */
+/* #undef HAVE_SOCKET_H */
+
+/* Define this if you have the SPNEGO library fbopenssl */
+/* #undef HAVE_SPNEGO */
+
+/* Define to 1 if you have the `SSL_get_shutdown' function. */
+#define HAVE_SSL_GET_SHUTDOWN 1
+
+/* Define to 1 if you have the <ssl.h> header file. */
+/* #undef HAVE_SSL_H */
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#define HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* 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 strcasestr function. */
+/* #undef HAVE_STRCASESTR */
+
+/* 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 strerror_r function. */
+#define HAVE_STRERROR_R 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 strncasecmp function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define to 1 if you have the strncmpi function. */
+/* #undef HAVE_STRNCMPI */
+
+/* Define to 1 if you have the strnicmp function. */
+/* #undef HAVE_STRNICMP */
+
+/* Define to 1 if you have the <stropts.h> header file. */
+#define HAVE_STROPTS_H 1
+
+/* 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 strtoll function. */
+#define HAVE_STRTOLL 1
+
+/* if struct sockaddr_storage is defined */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if you have the timeval struct. */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+/* #undef HAVE_SYS_FILIO_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 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/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_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/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_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 <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 <tld.h> header file. */
+/* #undef HAVE_TLD_H */
+
+/* Define to 1 if you have the `tld_strerror' function. */
+/* #undef HAVE_TLD_STRERROR */
+
+/* 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 compiler supports C99 variadic macro style. */
+#define HAVE_VARIADIC_MACROS_C99 1
+
+/* Define to 1 if compiler supports old gcc variadic macro style. */
+#define HAVE_VARIADIC_MACROS_GCC 1
+
+/* Define to 1 if you have the winber.h header file. */
+/* #undef HAVE_WINBER_H */
+
+/* Define to 1 if you have the windows.h header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the winldap.h header file. */
+/* #undef HAVE_WINLDAP_H */
+
+/* Define to 1 if you have the winsock2.h header file. */
+/* #undef HAVE_WINSOCK2_H */
+
+/* Define to 1 if you have the winsock.h header file. */
+/* #undef HAVE_WINSOCK_H */
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#define HAVE_WRITABLE_ARGV 1
+
+/* Define to 1 if you have the writev function. */
+#define HAVE_WRITEV 1
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
+/* Define to 1 if you have the <x509.h> header file. */
+/* #undef HAVE_X509_H */
+
+/* if you have the zlib.h header file */
+#define HAVE_ZLIB_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if you are building a native Windows target. */
+/* #undef NATIVE_WINDOWS */
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+/* #undef NEED_LBER_H */
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+/* #undef NEED_MALLOC_H */
+
+/* Define to 1 if you need the memory.h header file even with stdlib.h */
+/* #undef NEED_MEMORY_H */
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+/* #undef NEED_REENTRANT */
+
+/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */
+/* #undef NEED_THREAD_SAFE */
+
+/* cpu-machine-OS */
+#define OS "arm-unknown-eabi"
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "curl"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "curl -"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "curl"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "-"
+
+/* a suitable file to read random data from */
+#define RANDOM_FILE "/dev/urandom"
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 int
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 void
+
+/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */
+#define RECVFROM_TYPE_ARG2_IS_VOID 1
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG5_IS_VOID */
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 socklen_t
+
+/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG6_IS_VOID */
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV ssize_t
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV ssize_t
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to the type qualifier of arg 5 for select. */
+#define SELECT_QUAL_ARG5 
+
+/* Define to the type of arg 1 for select. */
+#define SELECT_TYPE_ARG1 int
+
+/* Define to the type of args 2, 3 and 4 for select. */
+#define SELECT_TYPE_ARG234 fd_set *
+
+/* Define to the type of arg 5 for select. */
+#define SELECT_TYPE_ARG5 struct timeval *
+
+/* Define to the function return type for select. */
+#define SELECT_TYPE_RETV int
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV ssize_t
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* The size of `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 8
+
+/* The size of `time_t', as computed by sizeof. */
+#define SIZEOF_TIME_T 8
+
+/* The size of `void*', as computed by sizeof. */
+#define SIZEOF_VOIDP 8
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to the type of arg 3 for strerror_r. */
+#define STRERROR_R_TYPE_ARG3 size_t
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define to enable c-ares support */
+/* #undef USE_ARES */
+
+/* Define to disable non-blocking sockets. */
+/* #undef USE_BLOCKING_SOCKETS */
+
+/* if GnuTLS is enabled */
+/* #undef USE_GNUTLS */
+
+/* if libSSH2 is in use */
+/* #undef USE_LIBSSH2 */
+
+/* If you want to build curl with the built-in manual */
+#define USE_MANUAL 1
+
+/* if NSS is enabled */
+/* #undef USE_NSS */
+
+/* if OpenSSL is in use */
+#define USE_OPENSSL 1
+
+/* if SSL is enabled */
+#define USE_SSLEAY 1
+
+/* Define to 1 if you are building a Windows target without large file
+   support. */
+/* #undef USE_WIN32_LARGE_FILES */
+
+/* to enable SSPI support */
+/* #undef USE_WINDOWS_SSPI */
+
+/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
+/* #undef USE_YASSLEMUL */
+
+/* Version number of package */
+#define VERSION "7.20.1"
+
+/* Define to avoid automatic inclusion of winsock.h */
+/* #undef WIN32_LEAN_AND_MEAN */
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+/* #  undef _ALL_SOURCE */
+#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. */
+/* #undef _LARGE_FILES */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+/* #undef in_addr_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* the signed version of size_t */
+/* #undef ssize_t */
diff --git a/src/curl_config.h.in b/src/curl_config.h.in
new file mode 100644
index 0000000..846fb27
--- /dev/null
+++ b/src/curl_config.h.in
@@ -0,0 +1,973 @@
+/* lib/curl_config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* when building libcurl itself */
+#undef BUILDING_LIBCURL
+
+/* Location of default ca bundle */
+#undef CURL_CA_BUNDLE
+
+/* Location of default ca path */
+#undef CURL_CA_PATH
+
+/* to disable cookies support */
+#undef CURL_DISABLE_COOKIES
+
+/* to disable cryptographic authentication */
+#undef CURL_DISABLE_CRYPTO_AUTH
+
+/* to disable DICT */
+#undef CURL_DISABLE_DICT
+
+/* to disable FILE */
+#undef CURL_DISABLE_FILE
+
+/* to disable FTP */
+#undef CURL_DISABLE_FTP
+
+/* to disable HTTP */
+#undef CURL_DISABLE_HTTP
+
+/* to disable IMAP */
+#undef CURL_DISABLE_IMAP
+
+/* to disable LDAP */
+#undef CURL_DISABLE_LDAP
+
+/* to disable LDAPS */
+#undef CURL_DISABLE_LDAPS
+
+/* to disable POP3 */
+#undef CURL_DISABLE_POP3
+
+/* to disable proxies */
+#undef CURL_DISABLE_PROXY
+
+/* to disable RTSP */
+#undef CURL_DISABLE_RTSP
+
+/* to disable SMTP */
+#undef CURL_DISABLE_SMTP
+
+/* to disable TELNET */
+#undef CURL_DISABLE_TELNET
+
+/* to disable TFTP */
+#undef CURL_DISABLE_TFTP
+
+/* to disable verbose strings */
+#undef CURL_DISABLE_VERBOSE_STRINGS
+
+/* to make a symbol visible */
+#undef CURL_EXTERN_SYMBOL
+
+/* to enable hidden symbols */
+#undef CURL_HIDDEN_SYMBOLS
+
+/* W$ LDAP with non-W$ compiler */
+#undef CURL_LDAP_HYBRID
+
+/* Use W$ LDAP implementation */
+#undef CURL_LDAP_WIN
+
+/* when not building a shared library */
+#undef CURL_STATICLIB
+
+/* your Entropy Gathering Daemon socket pathname */
+#undef EGD_SOCKET
+
+/* Define if you want to enable IPv6 support */
+#undef ENABLE_IPV6
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#undef GETNAMEINFO_QUAL_ARG1
+
+/* Define to the type of arg 1 for getnameinfo. */
+#undef GETNAMEINFO_TYPE_ARG1
+
+/* Define to the type of arg 2 for getnameinfo. */
+#undef GETNAMEINFO_TYPE_ARG2
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#undef GETNAMEINFO_TYPE_ARG46
+
+/* Define to the type of arg 7 for getnameinfo. */
+#undef GETNAMEINFO_TYPE_ARG7
+
+/* Specifies the number of arguments to getservbyport_r */
+#undef GETSERVBYPORT_R_ARGS
+
+/* Specifies the size of the buffer to pass to getservbyport_r */
+#undef GETSERVBYPORT_R_BUFSIZE
+
+/* Define to 1 if you have the alarm function. */
+#undef HAVE_ALARM
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#undef HAVE_ALLOCA_H
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#undef HAVE_ARPA_INET_H
+
+/* Define to 1 if you have the <arpa/tftp.h> header file. */
+#undef HAVE_ARPA_TFTP_H
+
+/* Define to 1 if you have the <assert.h> header file. */
+#undef HAVE_ASSERT_H
+
+/* Define to 1 if you have the basename function. */
+#undef HAVE_BASENAME
+
+/* Define to 1 if bool is an available type. */
+#undef HAVE_BOOL_T
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+#undef HAVE_CLOCK_GETTIME_MONOTONIC
+
+/* Define to 1 if you have the closesocket function. */
+#undef HAVE_CLOSESOCKET
+
+/* Define to 1 if you have the CloseSocket camel case function. */
+#undef HAVE_CLOSESOCKET_CAMEL
+
+/* Define to 1 if you have the connect function. */
+#undef HAVE_CONNECT
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+#undef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA
+
+/* 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
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the `ENGINE_cleanup' function. */
+#undef HAVE_ENGINE_CLEANUP
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+#undef HAVE_ENGINE_LOAD_BUILTIN_ENGINES
+
+/* Define to 1 if you have the <errno.h> header file. */
+#undef HAVE_ERRNO_H
+
+/* Define to 1 if you have the <err.h> header file. */
+#undef HAVE_ERR_H
+
+/* Define to 1 if you have the fcntl function. */
+#undef HAVE_FCNTL
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#undef HAVE_FCNTL_O_NONBLOCK
+
+/* Define to 1 if you have the fdopen function. */
+#undef HAVE_FDOPEN
+
+/* Define to 1 if you have the `fork' function. */
+#undef HAVE_FORK
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#undef HAVE_FREEADDRINFO
+
+/* Define to 1 if you have the freeifaddrs function. */
+#undef HAVE_FREEIFADDRS
+
+/* Define to 1 if you have the ftruncate function. */
+#undef HAVE_FTRUNCATE
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#undef HAVE_GETADDRINFO
+
+/* Define to 1 if the getaddrinfo function is threadsafe. */
+#undef HAVE_GETADDRINFO_THREADSAFE
+
+/* Define to 1 if you have the `geteuid' function. */
+#undef HAVE_GETEUID
+
+/* Define to 1 if you have the gethostbyaddr function. */
+#undef HAVE_GETHOSTBYADDR
+
+/* Define to 1 if you have the gethostbyaddr_r function. */
+#undef HAVE_GETHOSTBYADDR_R
+
+/* gethostbyaddr_r() takes 5 args */
+#undef HAVE_GETHOSTBYADDR_R_5
+
+/* gethostbyaddr_r() takes 7 args */
+#undef HAVE_GETHOSTBYADDR_R_7
+
+/* gethostbyaddr_r() takes 8 args */
+#undef HAVE_GETHOSTBYADDR_R_8
+
+/* Define to 1 if you have the gethostbyname function. */
+#undef HAVE_GETHOSTBYNAME
+
+/* Define to 1 if you have the gethostbyname_r function. */
+#undef HAVE_GETHOSTBYNAME_R
+
+/* gethostbyname_r() takes 3 args */
+#undef HAVE_GETHOSTBYNAME_R_3
+
+/* gethostbyname_r() takes 5 args */
+#undef HAVE_GETHOSTBYNAME_R_5
+
+/* gethostbyname_r() takes 6 args */
+#undef HAVE_GETHOSTBYNAME_R_6
+
+/* Define to 1 if you have the gethostname function. */
+#undef HAVE_GETHOSTNAME
+
+/* Define to 1 if you have a working getifaddrs function. */
+#undef HAVE_GETIFADDRS
+
+/* Define to 1 if you have the getnameinfo function. */
+#undef HAVE_GETNAMEINFO
+
+/* Define to 1 if you have the `getpass_r' function. */
+#undef HAVE_GETPASS_R
+
+/* Define to 1 if you have the `getppid' function. */
+#undef HAVE_GETPPID
+
+/* Define to 1 if you have the `getprotobyname' function. */
+#undef HAVE_GETPROTOBYNAME
+
+/* Define to 1 if you have the `getpwuid' function. */
+#undef HAVE_GETPWUID
+
+/* Define to 1 if you have the `getrlimit' function. */
+#undef HAVE_GETRLIMIT
+
+/* Define to 1 if you have the getservbyport_r function. */
+#undef HAVE_GETSERVBYPORT_R
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#undef HAVE_GETTIMEOFDAY
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+#undef HAVE_GLIBC_STRERROR_R
+
+/* Define to 1 if you have a working gmtime_r function. */
+#undef HAVE_GMTIME_R
+
+/* if you have the gssapi libraries */
+#undef HAVE_GSSAPI
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_GENERIC_H
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_H
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+#undef HAVE_GSSAPI_GSSAPI_KRB5_H
+
+/* if you have the GNU gssapi libraries */
+#undef HAVE_GSSGNU
+
+/* if you have the Heimdal gssapi libraries */
+#undef HAVE_GSSHEIMDAL
+
+/* if you have the MIT gssapi libraries */
+#undef HAVE_GSSMIT
+
+/* Define to 1 if you have the `idna_strerror' function. */
+#undef HAVE_IDNA_STRERROR
+
+/* Define to 1 if you have the `idn_free' function. */
+#undef HAVE_IDN_FREE
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+#undef HAVE_IDN_FREE_H
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#undef HAVE_IFADDRS_H
+
+/* Define to 1 if you have the `inet_addr' function. */
+#undef HAVE_INET_ADDR
+
+/* Define to 1 if you have the inet_ntoa_r function. */
+#undef HAVE_INET_NTOA_R
+
+/* inet_ntoa_r() takes 2 args */
+#undef HAVE_INET_NTOA_R_2
+
+/* inet_ntoa_r() takes 3 args */
+#undef HAVE_INET_NTOA_R_3
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#undef HAVE_INET_NTOP
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#undef HAVE_INET_PTON
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the ioctl function. */
+#undef HAVE_IOCTL
+
+/* Define to 1 if you have the ioctlsocket function. */
+#undef HAVE_IOCTLSOCKET
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+#undef HAVE_IOCTLSOCKET_CAMEL
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+   */
+#undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+#undef HAVE_IOCTLSOCKET_FIONBIO
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+#undef HAVE_IOCTL_FIONBIO
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+#undef HAVE_IOCTL_SIOCGIFADDR
+
+/* Define to 1 if you have the <io.h> header file. */
+#undef HAVE_IO_H
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+#undef HAVE_KRB4
+
+/* 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 lber.h header file. */
+#undef HAVE_LBER_H
+
+/* Define to 1 if you have the ldapssl.h header file. */
+#undef HAVE_LDAPSSL_H
+
+/* Define to 1 if you have the ldap.h header file. */
+#undef HAVE_LDAP_H
+
+/* Use LDAPS implementation */
+#undef HAVE_LDAP_SSL
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+#undef HAVE_LDAP_SSL_H
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+#undef HAVE_LDAP_URL_PARSE
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#undef HAVE_LIBGEN_H
+
+/* Define to 1 if you have the `idn' library (-lidn). */
+#undef HAVE_LIBIDN
+
+/* 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 `ssh2' library (-lssh2). */
+#undef HAVE_LIBSSH2
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+#undef HAVE_LIBSSH2_H
+
+/* Define to 1 if you have the `libssh2_version' function. */
+#undef HAVE_LIBSSH2_VERSION
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+#undef HAVE_LIBSSL
+
+/* if zlib is available */
+#undef HAVE_LIBZ
+
+/* Define to 1 if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* if your compiler supports LL */
+#undef HAVE_LL
+
+/* Define to 1 if you have the <locale.h> header file. */
+#undef HAVE_LOCALE_H
+
+/* Define to 1 if you have a working localtime_r function. */
+#undef HAVE_LOCALTIME_R
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#undef HAVE_LONGLONG
+
+/* Define to 1 if you have the malloc.h header file. */
+#undef HAVE_MALLOC_H
+
+/* Define to 1 if you have the memory.h header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have the memrchr function or macro. */
+#undef HAVE_MEMRCHR
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+#undef HAVE_MSG_NOSIGNAL
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#undef HAVE_NETDB_H
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#undef HAVE_NETINET_IN_H
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#undef HAVE_NETINET_TCP_H
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#undef HAVE_NET_IF_H
+
+/* Define to 1 if NI_WITHSCOPEID exists and works. */
+#undef HAVE_NI_WITHSCOPEID
+
+/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE
+   */
+#undef HAVE_OLD_GSSMIT
+
+/* 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/pkcs12.h> header file. */
+#undef HAVE_OPENSSL_PKCS12_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. */
+#undef HAVE_PERROR
+
+/* Define to 1 if you have the `pipe' function. */
+#undef HAVE_PIPE
+
+/* if you have the function PK11_CreateGenericObject */
+#undef HAVE_PK11_CREATEGENERICOBJECT
+
+/* Define to 1 if you have a working poll function. */
+#undef HAVE_POLL
+
+/* If you have a fine poll */
+#undef HAVE_POLL_FINE
+
+/* Define to 1 if you have the <poll.h> header file. */
+#undef HAVE_POLL_H
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+#undef HAVE_POSIX_STRERROR_R
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#undef HAVE_PWD_H
+
+/* 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 recv function. */
+#undef HAVE_RECV
+
+/* Define to 1 if you have the recvfrom function. */
+#undef HAVE_RECVFROM
+
+/* Define to 1 if you have the <rsa.h> header file. */
+#undef HAVE_RSA_H
+
+/* Define to 1 if you have the select function. */
+#undef HAVE_SELECT
+
+/* Define to 1 if you have the send function. */
+#undef HAVE_SEND
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#undef HAVE_SETJMP_H
+
+/* Define to 1 if you have the `setlocale' function. */
+#undef HAVE_SETLOCALE
+
+/* Define to 1 if you have the `setmode' function. */
+#undef HAVE_SETMODE
+
+/* Define to 1 if you have the `setrlimit' function. */
+#undef HAVE_SETRLIMIT
+
+/* Define to 1 if you have the setsockopt function. */
+#undef HAVE_SETSOCKOPT
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+#undef HAVE_SETSOCKOPT_SO_NONBLOCK
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+#undef HAVE_SGTTY_H
+
+/* Define to 1 if you have the sigaction function. */
+#undef HAVE_SIGACTION
+
+/* Define to 1 if you have the siginterrupt function. */
+#undef HAVE_SIGINTERRUPT
+
+/* Define to 1 if you have the signal function. */
+#undef HAVE_SIGNAL
+
+/* Define to 1 if you have the <signal.h> header file. */
+#undef HAVE_SIGNAL_H
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+#undef HAVE_SIGSETJMP
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#undef HAVE_SIG_ATOMIC_T
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+#undef HAVE_SIG_ATOMIC_T_VOLATILE
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+#undef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
+
+/* Define to 1 if you have the socket function. */
+#undef HAVE_SOCKET
+
+/* Define to 1 if you have the <socket.h> header file. */
+#undef HAVE_SOCKET_H
+
+/* Define this if you have the SPNEGO library fbopenssl */
+#undef HAVE_SPNEGO
+
+/* Define to 1 if you have the `SSL_get_shutdown' function. */
+#undef HAVE_SSL_GET_SHUTDOWN
+
+/* Define to 1 if you have the <ssl.h> header file. */
+#undef HAVE_SSL_H
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#undef HAVE_STDBOOL_H
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#undef HAVE_STDIO_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the strcasecmp function. */
+#undef HAVE_STRCASECMP
+
+/* Define to 1 if you have the strcasestr function. */
+#undef HAVE_STRCASESTR
+
+/* Define to 1 if you have the strcmpi function. */
+#undef HAVE_STRCMPI
+
+/* Define to 1 if you have the strdup function. */
+#undef HAVE_STRDUP
+
+/* Define to 1 if you have the strerror_r function. */
+#undef HAVE_STRERROR_R
+
+/* Define to 1 if you have the stricmp function. */
+#undef HAVE_STRICMP
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* 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 strncasecmp function. */
+#undef HAVE_STRNCASECMP
+
+/* Define to 1 if you have the strncmpi function. */
+#undef HAVE_STRNCMPI
+
+/* Define to 1 if you have the strnicmp function. */
+#undef HAVE_STRNICMP
+
+/* Define to 1 if you have the <stropts.h> header file. */
+#undef HAVE_STROPTS_H
+
+/* Define to 1 if you have the strstr function. */
+#undef HAVE_STRSTR
+
+/* Define to 1 if you have the strtok_r function. */
+#undef HAVE_STRTOK_R
+
+/* Define to 1 if you have the strtoll function. */
+#undef HAVE_STRTOLL
+
+/* if struct sockaddr_storage is defined */
+#undef HAVE_STRUCT_SOCKADDR_STORAGE
+
+/* Define to 1 if you have the timeval struct. */
+#undef HAVE_STRUCT_TIMEVAL
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#undef HAVE_SYS_FILIO_H
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#undef HAVE_SYS_IOCTL_H
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#undef HAVE_SYS_POLL_H
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#undef HAVE_SYS_RESOURCE_H
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#undef HAVE_SYS_SOCKET_H
+
+/* 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. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#undef HAVE_SYS_TIME_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#undef HAVE_SYS_UIO_H
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#undef HAVE_SYS_UN_H
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+#undef HAVE_SYS_UTIME_H
+
+/* Define to 1 if you have the <termios.h> header file. */
+#undef HAVE_TERMIOS_H
+
+/* Define to 1 if you have the <termio.h> header file. */
+#undef HAVE_TERMIO_H
+
+/* Define to 1 if you have the <time.h> header file. */
+#undef HAVE_TIME_H
+
+/* Define to 1 if you have the <tld.h> header file. */
+#undef HAVE_TLD_H
+
+/* Define to 1 if you have the `tld_strerror' function. */
+#undef HAVE_TLD_STRERROR
+
+/* Define to 1 if you have the `uname' function. */
+#undef HAVE_UNAME
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if you have the `utime' function. */
+#undef HAVE_UTIME
+
+/* Define to 1 if you have the <utime.h> header file. */
+#undef HAVE_UTIME_H
+
+/* Define to 1 if compiler supports C99 variadic macro style. */
+#undef HAVE_VARIADIC_MACROS_C99
+
+/* Define to 1 if compiler supports old gcc variadic macro style. */
+#undef HAVE_VARIADIC_MACROS_GCC
+
+/* Define to 1 if you have the winber.h header file. */
+#undef HAVE_WINBER_H
+
+/* Define to 1 if you have the windows.h header file. */
+#undef HAVE_WINDOWS_H
+
+/* Define to 1 if you have the winldap.h header file. */
+#undef HAVE_WINLDAP_H
+
+/* Define to 1 if you have the winsock2.h header file. */
+#undef HAVE_WINSOCK2_H
+
+/* Define to 1 if you have the winsock.h header file. */
+#undef HAVE_WINSOCK_H
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#undef HAVE_WRITABLE_ARGV
+
+/* Define to 1 if you have the writev function. */
+#undef HAVE_WRITEV
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+#undef HAVE_WS2TCPIP_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
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#undef LT_OBJDIR
+
+/* Define to 1 if you are building a native Windows target. */
+#undef NATIVE_WINDOWS
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+#undef NEED_LBER_H
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+#undef NEED_MALLOC_H
+
+/* Define to 1 if you need the memory.h header file even with stdlib.h */
+#undef NEED_MEMORY_H
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+#undef NEED_REENTRANT
+
+/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */
+#undef NEED_THREAD_SAFE
+
+/* cpu-machine-OS */
+#undef OS
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* a suitable file to read random data from */
+#undef RANDOM_FILE
+
+/* Define to the type of arg 1 for recvfrom. */
+#undef RECVFROM_TYPE_ARG1
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#undef RECVFROM_TYPE_ARG2
+
+/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */
+#undef RECVFROM_TYPE_ARG2_IS_VOID
+
+/* Define to the type of arg 3 for recvfrom. */
+#undef RECVFROM_TYPE_ARG3
+
+/* Define to the type of arg 4 for recvfrom. */
+#undef RECVFROM_TYPE_ARG4
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#undef RECVFROM_TYPE_ARG5
+
+/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */
+#undef RECVFROM_TYPE_ARG5_IS_VOID
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#undef RECVFROM_TYPE_ARG6
+
+/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */
+#undef RECVFROM_TYPE_ARG6_IS_VOID
+
+/* Define to the function return type for recvfrom. */
+#undef RECVFROM_TYPE_RETV
+
+/* Define to the type of arg 1 for recv. */
+#undef RECV_TYPE_ARG1
+
+/* Define to the type of arg 2 for recv. */
+#undef RECV_TYPE_ARG2
+
+/* Define to the type of arg 3 for recv. */
+#undef RECV_TYPE_ARG3
+
+/* Define to the type of arg 4 for recv. */
+#undef RECV_TYPE_ARG4
+
+/* Define to the function return type for recv. */
+#undef RECV_TYPE_RETV
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#undef RETSIGTYPE
+
+/* Define to the type qualifier of arg 5 for select. */
+#undef SELECT_QUAL_ARG5
+
+/* Define to the type of arg 1 for select. */
+#undef SELECT_TYPE_ARG1
+
+/* Define to the type of args 2, 3 and 4 for select. */
+#undef SELECT_TYPE_ARG234
+
+/* Define to the type of arg 5 for select. */
+#undef SELECT_TYPE_ARG5
+
+/* Define to the function return type for select. */
+#undef SELECT_TYPE_RETV
+
+/* Define to the type qualifier of arg 2 for send. */
+#undef SEND_QUAL_ARG2
+
+/* Define to the type of arg 1 for send. */
+#undef SEND_TYPE_ARG1
+
+/* Define to the type of arg 2 for send. */
+#undef SEND_TYPE_ARG2
+
+/* Define to the type of arg 3 for send. */
+#undef SEND_TYPE_ARG3
+
+/* Define to the type of arg 4 for send. */
+#undef SEND_TYPE_ARG4
+
+/* Define to the function return type for send. */
+#undef SEND_TYPE_RETV
+
+/* The size of `int', as computed by sizeof. */
+#undef SIZEOF_INT
+
+/* The size of `long', as computed by sizeof. */
+#undef SIZEOF_LONG
+
+/* The size of `off_t', as computed by sizeof. */
+#undef SIZEOF_OFF_T
+
+/* The size of `short', as computed by sizeof. */
+#undef SIZEOF_SHORT
+
+/* The size of `size_t', as computed by sizeof. */
+#undef SIZEOF_SIZE_T
+
+/* The size of `time_t', as computed by sizeof. */
+#undef SIZEOF_TIME_T
+
+/* The size of `void*', as computed by sizeof. */
+#undef SIZEOF_VOIDP
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to the type of arg 3 for strerror_r. */
+#undef STRERROR_R_TYPE_ARG3
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Define to enable c-ares support */
+#undef USE_ARES
+
+/* Define to disable non-blocking sockets. */
+#undef USE_BLOCKING_SOCKETS
+
+/* if GnuTLS is enabled */
+#undef USE_GNUTLS
+
+/* if libSSH2 is in use */
+#undef USE_LIBSSH2
+
+/* If you want to build curl with the built-in manual */
+#undef USE_MANUAL
+
+/* if NSS is enabled */
+#undef USE_NSS
+
+/* if OpenSSL is in use */
+#undef USE_OPENSSL
+
+/* if SSL is enabled */
+#undef USE_SSLEAY
+
+/* Define to 1 if you are building a Windows target without large file
+   support. */
+#undef USE_WIN32_LARGE_FILES
+
+/* to enable SSPI support */
+#undef USE_WINDOWS_SSPI
+
+/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
+#undef USE_YASSLEMUL
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to avoid automatic inclusion of winsock.h */
+#undef WIN32_LEAN_AND_MEAN
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+#  undef _ALL_SOURCE
+#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. */
+#undef _LARGE_FILES
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+#undef in_addr_t
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#undef size_t
+
+/* the signed version of size_t */
+#undef ssize_t
diff --git a/src/curlutil.c b/src/curlutil.c
new file mode 100644
index 0000000..bca2db7
--- /dev/null
+++ b/src/curlutil.c
@@ -0,0 +1,134 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2008, 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 "curlutil.h"
+
+#if defined(WIN32) && !defined(MSDOS)
+
+struct timeval cutil_tvnow(void)
+{
+  /*
+  ** GetTickCount() is available on _all_ Windows versions from W95 up
+  ** to nowadays. Returns milliseconds elapsed since last system boot,
+  ** increases monotonically and wraps once 49.7 days have elapsed.
+  */
+  struct timeval now;
+  DWORD milliseconds = GetTickCount();
+  now.tv_sec = milliseconds / 1000;
+  now.tv_usec = (milliseconds % 1000) * 1000;
+  return now;
+}
+
+#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC)
+
+struct timeval cutil_tvnow(void)
+{
+  /*
+  ** clock_gettime() is granted to be increased monotonically when the
+  ** monotonic clock is queried. Time starting point is unspecified, it
+  ** could be the system start-up time, the Epoch, or something else,
+  ** in any case the time starting point does not change once that the
+  ** system has started up.
+  */
+  struct timeval now;
+  struct timespec tsnow;
+  if(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow)) {
+    now.tv_sec = tsnow.tv_sec;
+    now.tv_usec = tsnow.tv_nsec / 1000;
+  }
+  /*
+  ** Even when the configure process has truly detected monotonic clock
+  ** availability, it might happen that it is not actually available at
+  ** run-time. When this occurs simply fallback to other time source.
+  */
+#ifdef HAVE_GETTIMEOFDAY
+  else
+    (void)gettimeofday(&now, NULL);
+#else
+  else {
+    now.tv_sec = (long)time(NULL);
+    now.tv_usec = 0;
+  }
+#endif
+  return now;
+}
+
+#elif defined(HAVE_GETTIMEOFDAY)
+
+struct timeval cutil_tvnow(void)
+{
+  /*
+  ** gettimeofday() is not granted to be increased monotonically, due to
+  ** clock drifting and external source time synchronization it can jump
+  ** forward or backward in time.
+  */
+  struct timeval now;
+  (void)gettimeofday(&now, NULL);
+  return now;
+}
+
+#else
+
+struct timeval cutil_tvnow(void)
+{
+  /*
+  ** time() returns the value of time in seconds since the Epoch.
+  */
+  struct timeval now;
+  now.tv_sec = (long)time(NULL);
+  now.tv_usec = 0;
+  return now;
+}
+
+#endif
+
+/*
+ * 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 cutil_tvdiff(struct timeval newer, struct timeval older)
+{
+  return (newer.tv_sec-older.tv_sec)*1000+
+    (newer.tv_usec-older.tv_usec)/1000;
+}
+
+/*
+ * Same as cutil_tvdiff but with full usec resolution.
+ *
+ * Returns: the time difference in seconds with subsecond resolution.
+ */
+double cutil_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 cutil_tvlong(struct timeval t1)
+{
+  return t1.tv_sec;
+}
+
diff --git a/src/curlutil.h b/src/curlutil.h
new file mode 100644
index 0000000..a993a77
--- /dev/null
+++ b/src/curlutil.h
@@ -0,0 +1,49 @@
+#ifndef __CURL_SRC_UTIL_H
+#define __CURL_SRC_UTIL_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, 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"
+
+
+struct timeval cutil_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 cutil_tvdiff(struct timeval t1, struct timeval t2);
+
+/*
+ * Same as cutil_tvdiff but with full usec resolution.
+ *
+ * Returns: the time difference in seconds with subsecond resolution.
+ */
+double cutil_tvdiff_secs(struct timeval t1, struct timeval t2);
+
+long cutil_tvlong(struct timeval t1);
+
+
+#endif  /* __CURL_SRC_UTIL_H */
+
diff --git a/src/getpass.c b/src/getpass.c
new file mode 100644
index 0000000..b441a5a
--- /dev/null
+++ b/src/getpass.c
@@ -0,0 +1,267 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+/* This file is a reimplementation of the previous one, due to license
+   problems. */
+
+#include "setup.h"
+
+#ifndef HAVE_GETPASS_R
+/* this file is only for systems without getpass_r() */
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "getpass.h"
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_TERMIOS_H
+#include <termios.h>
+#else
+#ifdef HAVE_TERMIO_H
+#include <termio.h>
+#endif
+#endif
+
+/* The last #include file should be: */
+#if defined(CURLDEBUG) && defined(CURLTOOLDEBUG)
+#include "memdebug.h"
+#endif
+
+#ifdef __VMS
+/* VMS implementation */
+#include descrip
+#include starlet
+#include iodef
+/* #include iosbdef */
+char *getpass_r(const char *prompt, char *buffer, size_t buflen)
+{
+  long sts;
+  short chan;
+
+  /* MSK, 23-JAN-2004, iosbdef.h wasn't in VAX V7.2 or CC 6.4  */
+  /* distribution so I created this.  May revert back later to */
+  /* struct _iosb iosb;                                        */
+  struct _iosb
+     {
+     short int iosb$w_status; /* status     */
+     short int iosb$w_bcnt;   /* byte count */
+     int       unused;        /* unused     */
+     } iosb;
+
+  $DESCRIPTOR(ttdesc, "TT");
+
+  buffer[0]='\0';
+  sts = sys$assign(&ttdesc, &chan,0,0);
+  if (sts & 1) {
+    sts = sys$qiow(0, chan,
+                   IO$_READPROMPT | IO$M_NOECHO,
+                   &iosb, 0, 0, buffer, buflen, 0, 0,
+                   prompt, strlen(prompt));
+
+    if((sts & 1) && (iosb.iosb$w_status&1))
+      buffer[iosb.iosb$w_bcnt] = '\0';
+
+    sts = sys$dassgn(chan);
+  }
+  return buffer; /* we always return success */
+}
+#define DONE
+#endif /* __VMS */
+
+
+#ifdef WIN32
+/* Windows implementation */
+#include <conio.h>
+#endif
+
+#ifdef __SYMBIAN32__
+#define getch() getchar()
+#endif
+
+#if defined(WIN32) || defined(__SYMBIAN32__)
+
+char *getpass_r(const char *prompt, char *buffer, size_t buflen)
+{
+  size_t i;
+  fputs(prompt, stderr);
+
+  for(i=0; i<buflen; i++) {
+    buffer[i] = (char)getch();
+    if ( buffer[i] == '\r' || buffer[i] == '\n' ) {
+      buffer[i] = 0;
+      break;
+    }
+    else
+      if ( buffer[i] == '\b')
+        /* remove this letter and if this is not the first key, remove the
+           previous one as well */
+        i = i - (i>=1?2:1);
+  }
+#ifndef __SYMBIAN32__
+  /* since echo is disabled, print a newline */
+  fputs("\n", stderr);
+#endif
+  /* if user didn't hit ENTER, terminate buffer */
+  if (i==buflen)
+    buffer[buflen-1]=0;
+
+  return buffer; /* we always return success */
+}
+#define DONE
+#endif /* WIN32 || __SYMBIAN32__ */
+
+#ifdef NETWARE
+/* NetWare implementation */
+#ifdef __NOVELL_LIBC__
+#include <screen.h>
+char *getpass_r(const char *prompt, char *buffer, size_t buflen)
+{
+  return getpassword(prompt, buffer, buflen);
+}
+#else
+#include <nwconio.h>
+char *getpass_r(const char *prompt, char *buffer, size_t buflen)
+{
+  size_t i = 0;
+
+  printf("%s", prompt);
+  do {
+    buffer[i++] = getch();
+    if (buffer[i-1] == '\b') {
+      /* remove this letter and if this is not the first key,
+         remove the previous one as well */
+      if (i > 1) {
+        printf("\b \b");
+        i = i - 2;
+      } else {
+        RingTheBell();
+        i = i - 1;
+      }
+    } else if (buffer[i-1] != 13) {
+      putchar('*');
+    }
+  } while ((buffer[i-1] != 13) && (i < buflen));
+  buffer[i-1] = 0;
+  printf("\r\n");
+  return buffer;
+}
+#endif /* __NOVELL_LIBC__ */
+#define DONE
+#endif /* NETWARE */
+
+#ifndef DONE /* not previously provided */
+
+#ifdef HAVE_TERMIOS_H
+#define struct_term struct termios
+#else
+#ifdef HAVE_TERMIO_H
+#define struct_term  struct termio
+#else
+#undef struct_term
+#endif
+#endif
+
+static bool ttyecho(bool enable, int fd)
+{
+#ifdef struct_term
+  static struct_term withecho;
+  static struct_term noecho;
+#endif
+  if(!enable) {
+  /* disable echo by extracting the current 'withecho' mode and remove the
+     ECHO bit and set back the struct */
+#ifdef HAVE_TERMIOS_H
+    tcgetattr(fd, &withecho);
+    noecho = withecho;
+    noecho.c_lflag &= ~ECHO;
+    tcsetattr(fd, TCSANOW, &noecho);
+#else /* HAVE_TERMIOS_H */
+#ifdef HAVE_TERMIO_H
+    ioctl(fd, TCGETA, &withecho);
+    noecho = withecho;
+    noecho.c_lflag &= ~ECHO;
+    ioctl(fd, TCSETA, &noecho);
+#else /* HAVE_TERMIO_H */
+/* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we can't disable echo! */
+    (void)fd; /* prevent compiler warning on unused variable */
+    return FALSE; /* not disabled */
+#endif
+#endif
+    return TRUE; /* disabled */
+  }
+  else {
+    /* re-enable echo, assumes we disabled it before (and set the structs we
+       now use to reset the terminal status) */
+#ifdef HAVE_TERMIOS_H
+    tcsetattr(fd, TCSAFLUSH, &withecho);
+#else /* HAVE_TERMIOS_H */
+#ifdef HAVE_TERMIO_H
+    ioctl(fd, TCSETA, &withecho);
+#else
+/* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H */
+    return FALSE; /* not enabled */
+#endif
+#endif
+    return TRUE; /* enabled */
+  }
+}
+
+char *getpass_r(const char *prompt, /* prompt to display */
+                char *password,     /* buffer to store password in */
+                size_t buflen)      /* size of buffer to store password in */
+{
+  ssize_t nread;
+  bool disabled;
+  int fd=open("/dev/tty", O_RDONLY);
+  if(-1 == fd)
+    fd = 1; /* use stdin if the tty couldn't be used */
+
+  disabled = ttyecho(FALSE, fd); /* disable terminal echo */
+
+  fputs(prompt, stderr);
+  nread=read(fd, password, buflen);
+  if(nread > 0)
+    password[--nread]=0; /* zero terminate where enter is stored */
+  else
+    password[0]=0; /* got nothing */
+
+  if(disabled) {
+    /* if echo actually was disabled, add a newline */
+    fputs("\n", stderr);
+    (void)ttyecho(TRUE, fd); /* enable echo */
+  }
+
+  if(1 != fd)
+    close(fd);
+
+  return password; /* return pointer to buffer */
+}
+
+#endif /* DONE */
+#endif /* HAVE_GETPASS_R */
diff --git a/src/getpass.h b/src/getpass.h
new file mode 100644
index 0000000..3b29d47
--- /dev/null
+++ b/src/getpass.h
@@ -0,0 +1,34 @@
+#ifndef __GETPASS_H
+#define __GETPASS_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+#ifndef HAVE_GETPASS_R
+/* If there's a system-provided function named like this, we trust it is
+   also found in one of the standard headers. */
+
+/*
+ * Returning NULL will abort the continued operation!
+ */
+char* getpass_r(const char *prompt, char* buffer, size_t buflen );
+#endif
+
+#endif
diff --git a/src/homedir.c b/src/homedir.c
new file mode 100644
index 0000000..ab1d369
--- /dev/null
+++ b/src/homedir.c
@@ -0,0 +1,120 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef __VMS
+#include <unixlib.h>
+#endif
+
+#include "homedir.h"
+
+#if defined(CURLDEBUG) && defined(CURLTOOLDEBUG)
+#include "memdebug.h"
+#endif
+
+static
+char *GetEnv(const char *variable, char do_expand)
+{
+  char *env = NULL;
+#ifdef WIN32
+  char  buf1[1024], buf2[1024];
+  DWORD rc;
+
+  /* Don't use getenv(); it doesn't find variable added after program was
+   * started. Don't accept truncated results (i.e. rc >= sizeof(buf1)).  */
+
+  rc = GetEnvironmentVariable(variable, buf1, sizeof(buf1));
+  if (rc > 0 && rc < sizeof(buf1)) {
+    env = buf1;
+    variable = buf1;
+  }
+  if (do_expand && strchr(variable,'%')) {
+    /* buf2 == variable if not expanded */
+    rc = ExpandEnvironmentStrings (variable, buf2, sizeof(buf2));
+    if (rc > 0 && rc < sizeof(buf2) &&
+        !strchr(buf2,'%'))    /* no vars still unexpanded */
+      env = buf2;
+  }
+#else
+  (void)do_expand;
+#ifdef __VMS
+  env = getenv(variable);
+  if (env && strcmp("HOME",variable) == 0) {
+        env = decc_translate_vms(env);
+  }
+#else
+  /* no length control */
+  env = getenv(variable);
+#endif
+#endif
+  return (env && env[0])?strdup(env):NULL;
+}
+
+/* return the home directory of the current user as an allocated string */
+char *homedir(void)
+{
+  char *home;
+
+  home = GetEnv("CURL_HOME", FALSE);
+  if(home)
+    return home;
+
+  home = GetEnv("HOME", FALSE);
+  if(home)
+    return home;
+
+#if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
+ {
+   struct passwd *pw = getpwuid(geteuid());
+
+   if (pw) {
+#ifdef __VMS
+     home = decc_translate_vms(pw->pw_dir);
+#else
+     home = pw->pw_dir;
+#endif
+     if (home && home[0])
+       home = strdup(home);
+     else
+       home = NULL;
+   }
+ }
+#endif /* PWD-stuff */
+#ifdef WIN32
+  home = GetEnv("APPDATA", TRUE);
+  if(!home)
+    home = GetEnv("%USERPROFILE%\\Application Data", TRUE); /* Normally only
+                                                               on Win-2K/XP */
+#endif /* WIN32 */
+  return home;
+}
diff --git a/src/homedir.h b/src/homedir.h
new file mode 100644
index 0000000..c88d517
--- /dev/null
+++ b/src/homedir.h
@@ -0,0 +1,27 @@
+#ifndef HEADER_CURL_HOMEDIR_H
+#define HEADER_CURL_HOMEDIR_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+char *homedir(void);
+
+#endif /* HEADER_CURL_HOMEDIR_H */
diff --git a/src/hugehelp.c b/src/hugehelp.c
new file mode 100644
index 0000000..d3e5761
--- /dev/null
+++ b/src/hugehelp.c
@@ -0,0 +1,6958 @@
+#include "setup.h"
+#ifndef HAVE_LIBZ
+/*
+ * NEVER EVER edit this manually, fix the mkhelp.pl script instead!
+ * Generation time: Sun Mar 28 23:35:15 2010
+ */
+#include "setup.h"
+#ifdef USE_MANUAL
+#include "hugehelp.h"
+#include <stdio.h>
+void hugehelp(void)
+{
+   fputs(
+"                                  _   _ ____  _\n"
+"  Project                     ___| | | |  _ \\| |\n"
+"                             / __| | | | |_) | |\n"
+"                            | (__| |_| |  _ <| |___\n"
+"                             \\___|\\___/|_| \\_\\_____|\n"
+"\n"
+"NAME\n"
+"       curl - transfer a URL\n"
+"\n"
+"SYNOPSIS\n"
+"       curl [options] [URL...]\n"
+"\n"
+"DESCRIPTION\n"
+"       curl  is  a tool to transfer data from or to a server, using one of the\n"
+"       supported protocols (HTTP, HTTPS, FTP, FTPS,  SCP,  SFTP,  TFTP,  DICT,\n"
+, stdout);
+ fputs(
+"       TELNET,  LDAP  or  FILE).  The command is designed to work without user\n"
+"       interaction.\n"
+"\n"
+"       curl offers a busload of useful tricks like proxy support, user authen-\n"
+"       tication,  FTP upload, HTTP post, SSL connections, cookies, file trans-\n"
+"       fer resume and more. As you will see below, the number of features will\n"
+"       make your head spin!\n"
+"\n"
+"       curl  is  powered  by  libcurl  for  all transfer-related features. See\n"
+"       libcurl(3) for details.\n"
+"\n"
+"URL\n"
+, stdout);
+ fputs(
+"       The URL syntax is protocol-dependent. You'll find a  detailed  descrip-\n"
+"       tion in RFC 3986.\n"
+"\n"
+"       You  can  specify  multiple  URLs or parts of URLs by writing part sets\n"
+"       within braces as in:\n"
+"\n"
+"        http://site.{one,two,three}.com\n"
+"\n"
+"       or you can get sequences of alphanumeric series by using [] as in:\n"
+"\n"
+"        ftp://ftp.numericals.com/file[1-100].txt\n"
+"        ftp://ftp.numericals.com/file[001-100].txt    (with leading zeros)\n"
+"        ftp://ftp.letters.com/file[a-z].txt\n"
+"\n"
+, stdout);
+ fputs(
+"       No nesting of the sequences is supported at the moment, but you can use\n"
+"       several ones next to each other:\n"
+"\n"
+"        http://any.org/archive[1996-1999]/vol[1-4]/part{a,b,c}.html\n"
+"\n"
+"       You  can  specify  any amount of URLs on the command line. They will be\n"
+"       fetched in a sequential manner in the specified order.\n"
+"\n"
+"       Since curl 7.15.1 you can also specify a step counter for  the  ranges,\n"
+"       so that you can get every Nth number or letter:\n"
+"\n"
+, stdout);
+ fputs(
+"        http://www.numericals.com/file[1-100:10].txt\n"
+"        http://www.letters.com/file[a-z:2].txt\n"
+"\n"
+"       If  you  specify  URL  without protocol:// prefix, curl will attempt to\n"
+"       guess what protocol you might want. It will then default  to  HTTP  but\n"
+"       try  other  protocols based on often-used host name prefixes. For exam-\n"
+"       ple, for host names starting with \"ftp.\" curl will assume you  want  to\n"
+"       speak FTP.\n"
+"\n"
+, stdout);
+ fputs(
+"       curl  will  do  its best to use what you pass to it as a URL. It is not\n"
+"       trying to validate it as a syntactically correct URL by any  means  but\n"
+"       is instead very liberal with what it accepts.\n"
+"\n"
+"       Curl will attempt to re-use connections for multiple file transfers, so\n"
+"       that getting many files from the same server will not do multiple  con-\n"
+"       nects / handshakes. This improves speed. Of course this is only done on\n"
+, stdout);
+ fputs(
+"       files specified on a single command line and  cannot  be  used  between\n"
+"       separate curl invokes.\n"
+"\n"
+"PROGRESS METER\n"
+"       curl  normally  displays a progress meter during operations, indicating\n"
+"       the amount of transferred data,  transfer  speeds  and  estimated  time\n"
+"       left, etc.\n"
+"\n"
+"       However,  since  curl displays this data to the terminal by default, if\n"
+"       you invoke curl to do an operation and it is about to write data to the\n"
+, stdout);
+ fputs(
+"       terminal,  it disables the progress meter as otherwise it would mess up\n"
+"       the output mixing progress meter and response data.\n"
+"\n"
+"       If you want a progress meter for HTTP POST or PUT requests, you need to\n"
+"       redirect  the  response  output to a file, using shell redirect (>), -o\n"
+"       [file] or similar.\n"
+"\n"
+"       It is not the same case for FTP upload as that operation does not  spit\n"
+"       out any response data to the terminal.\n"
+"\n"
+, stdout);
+ fputs(
+"       If you prefer a progress \"bar\" instead of the regular meter, -# is your\n"
+"       friend.\n"
+"OPTIONS\n"
+"       In general, all boolean options are enabled with --option and yet again\n"
+"       disabled  with --no-option. That is, you use the exact same option name\n"
+"       but prefix it with \"no-\". However, in this list we mostly only list and\n"
+"       show  the --option version of them. (This concept with --no options was\n"
+"       added in  7.19.0.  Previously  most  options  were  toggled  on/off  on\n"
+, stdout);
+ fputs(
+"       repeated use of the same command line option.)\n"
+"\n"
+"       -a/--append\n"
+"              (FTP/SFTP) When used in an upload, this will tell curl to append\n"
+"              to the target file  instead  of  overwriting  it.  If  the  file\n"
+"              doesn't  exist,  it  will  be  created.   Note that this flag is\n"
+"              ignored by some SSH servers (including OpenSSH).\n"
+"\n"
+"       -A/--user-agent <agent string>\n"
+"              (HTTP) Specify the User-Agent string to send to the HTTP server.\n"
+, stdout);
+ fputs(
+"              Some   badly   done  CGIs  fail  if  this  field  isn't  set  to\n"
+"              \"Mozilla/4.0\". To encode blanks  in  the  string,  surround  the\n"
+"              string  with  single  quote marks. This can also be set with the\n"
+"              -H/--header option of course.\n"
+"\n"
+"              If this option is set more than once, the last one will  be  the\n"
+"              one that's used.\n"
+"\n"
+"       --anyauth\n"
+"              (HTTP) Tells curl to figure out authentication method by itself,\n"
+, stdout);
+ fputs(
+"              and use the most secure one the remote site claims  to  support.\n"
+"              This is done by first doing a request and checking the response-\n"
+"              headers, thus possibly inducing  an  extra  network  round-trip.\n"
+"              This  is  used  instead  of  setting  a  specific authentication\n"
+"              method, which you can do with  --basic,  --digest,  --ntlm,  and\n"
+"              --negotiate.\n"
+"\n"
+, stdout);
+ fputs(
+"              Note  that  using --anyauth is not recommended if you do uploads\n"
+"              from stdin, since it may require data to be sent twice and  then\n"
+"              the client must be able to rewind. If the need should arise when\n"
+"              uploading from stdin, the upload operation will fail.\n"
+"\n"
+"       -b/--cookie <name=data>\n"
+"              (HTTP) Pass the data to the HTTP server as a cookie. It is  sup-\n"
+"              posedly  the data previously received from the server in a \"Set-\n"
+, stdout);
+ fputs(
+"              Cookie:\" line.  The data should be in the format  \"NAME1=VALUE1;\n"
+"              NAME2=VALUE2\".\n"
+"\n"
+"              If  no  '=' symbol is used in the line, it is treated as a file-\n"
+"              name to use to read previously stored cookie lines  from,  which\n"
+"              should  be used in this session if they match. Using this method\n"
+"              also activates the \"cookie parser\" which will make  curl  record\n"
+, stdout);
+ fputs(
+"              incoming cookies too, which may be handy if you're using this in\n"
+"              combination with the -L/--location option. The  file  format  of\n"
+"              the  file  to  read cookies from should be plain HTTP headers or\n"
+"              the Netscape/Mozilla cookie file format.\n"
+"\n"
+"              NOTE that the file specified with -b/--cookie is  only  used  as\n"
+"              input.  No cookies will be stored in the file. To store cookies,\n"
+, stdout);
+ fputs(
+"              use the -c/--cookie-jar option or you could even save  the  HTTP\n"
+"              headers to a file using -D/--dump-header!\n"
+"\n"
+"              If  this  option is set more than once, the last one will be the\n"
+"              one that's used.\n"
+"\n"
+"       -B/--use-ascii\n"
+"              Enable ASCII transfer when using FTP or LDAP. For FTP, this  can\n"
+"              also  be enforced by using an URL that ends with \";type=A\". This\n"
+, stdout);
+ fputs(
+"              option causes data sent to stdout to be in text mode  for  win32\n"
+"              systems.\n"
+"\n"
+"       --basic\n"
+"              (HTTP)  Tells curl to use HTTP Basic authentication. This is the\n"
+"              default and this option is usually pointless, unless you use  it\n"
+"              to  override  a  previously  set  option  that  sets a different\n"
+"              authentication method (such as --ntlm,  --digest,  or  --negoti-\n"
+"              ate).\n"
+"\n"
+"       --ciphers <list of ciphers>\n"
+, stdout);
+ fputs(
+"              (SSL) Specifies which ciphers to use in the connection. The list\n"
+"              of ciphers must specify valid ciphers. Read  up  on  SSL  cipher\n"
+"              list           details           on           this          URL:\n"
+"              http://www.openssl.org/docs/apps/ciphers.html\n"
+"\n"
+"              NSS ciphers are done differently than OpenSSL  and  GnuTLS.  The\n"
+"              full  list of NSS ciphers is in the NSSCipherSuite entry at this\n"
+, stdout);
+ fputs(
+"              URL: http://directory.fedora.redhat.com/docs/mod_nss.html#Direc-\n"
+"              tives\n"
+"\n"
+"              If this option is used several times, the last one will override\n"
+"              the others.\n"
+"\n"
+"       --compressed\n"
+"              (HTTP) Request a compressed response using one of the algorithms\n"
+"              libcurl supports, and return the uncompressed document.  If this\n"
+"              option is used and the server  sends  an  unsupported  encoding,\n"
+, stdout);
+ fputs(
+"              curl will report an error.\n"
+"\n"
+"       --connect-timeout <seconds>\n"
+"              Maximum  time  in  seconds  that you allow the connection to the\n"
+"              server to take.  This only limits  the  connection  phase,  once\n"
+"              curl  has  connected this option is of no more use. See also the\n"
+"              -m/--max-time option.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       -c/--cookie-jar <file name>\n"
+, stdout);
+ fputs(
+"              Specify to which file you want curl to write all cookies after a\n"
+"              completed  operation.  Curl  writes  all cookies previously read\n"
+"              from a specified file as  well  as  all  cookies  received  from\n"
+"              remote server(s). If no cookies are known, no file will be writ-\n"
+"              ten. The file will be written using  the  Netscape  cookie  file\n"
+"              format.  If  you  set  the  file name to a single dash, \"-\", the\n"
+, stdout);
+ fputs(
+"              cookies will be written to stdout.\n"
+"\n"
+"              NOTE If the cookie jar can't be created or written to, the whole\n"
+"              curl operation won't fail or even report an error clearly. Using\n"
+"              -v will get a warning displayed, but that is  the  only  visible\n"
+"              feedback you get about this possibly lethal situation.\n"
+"\n"
+"              If  this  option  is used several times, the last specified file\n"
+"              name will be used.\n"
+"\n"
+, stdout);
+ fputs(
+"       -C/--continue-at <offset>\n"
+"              Continue/Resume a previous file transfer at  the  given  offset.\n"
+"              The  given  offset  is  the  exact  number of bytes that will be\n"
+"              skipped, counting from the beginning of the source  file  before\n"
+"              it is transferred to the destination.  If used with uploads, the\n"
+"              FTP server command SIZE will not be used by curl.\n"
+"\n"
+"              Use \"-C -\" to tell curl to automatically find out  where/how  to\n"
+, stdout);
+ fputs(
+"              resume  the  transfer. It then uses the given output/input files\n"
+"              to figure that out.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       --create-dirs\n"
+"              When used in conjunction with the -o option,  curl  will  create\n"
+"              the  necessary  local directory hierarchy as needed. This option\n"
+"              creates the dirs mentioned with the -o option, nothing else.  If\n"
+, stdout);
+ fputs(
+"              the  -o file name uses no dir or if the dirs it mentions already\n"
+"              exist, no dir will be created.\n"
+"\n"
+"              To create remote directories when using FTP or SFTP, try  --ftp-\n"
+"              create-dirs.\n"
+"\n"
+"       --crlf (FTP) Convert LF to CRLF in upload. Useful for MVS (OS/390).\n"
+"\n"
+"       --crlfile <file>\n"
+"              (HTTPS/FTPS)  Provide a file using PEM format with a Certificate\n"
+"              Revocation List that may specify peer certificates that  are  to\n"
+, stdout);
+ fputs(
+"              be considered revoked.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"              (Added in 7.19.7)\n"
+"\n"
+"       -d/--data <data>\n"
+"              (HTTP)  Sends  the  specified data in a POST request to the HTTP\n"
+"              server, in the same way that a browser  does  when  a  user  has\n"
+"              filled  in an HTML form and presses the submit button. This will\n"
+"              cause curl to pass the data to the server using the content-type\n"
+, stdout);
+ fputs(
+"              application/x-www-form-urlencoded.  Compare to -F/--form.\n"
+"\n"
+"              -d/--data  is  the  same  as  --data-ascii.  To post data purely\n"
+"              binary, you should instead use the --data-binary option. To URL-\n"
+"              encode the value of a form field you may use --data-urlencode.\n"
+"\n"
+"              If  any of these options is used more than once on the same com-\n"
+"              mand line, the data pieces specified  will  be  merged  together\n"
+, stdout);
+ fputs(
+"              with  a  separating  &-symbol.  Thus,  using  '-d name=daniel -d\n"
+"              skill=lousy'  would  generate  a  post  chunk  that  looks  like\n"
+"              'name=daniel&skill=lousy'.\n"
+"\n"
+"              If  you  start  the data with the letter @, the rest should be a\n"
+"              file name to read the data from, or - if you want curl  to  read\n"
+"              the  data  from stdin.  The contents of the file must already be\n"
+, stdout);
+ fputs(
+"              URL-encoded. Multiple files can also be specified. Posting  data\n"
+"              from  a file named 'foobar' would thus be done with --data @foo-\n"
+"              bar.\n"
+"\n"
+"       --data-binary <data>\n"
+"              (HTTP) This posts data exactly as specified with no  extra  pro-\n"
+"              cessing whatsoever.\n"
+"\n"
+"              If  you  start  the data with the letter @, the rest should be a\n"
+"              filename.  Data is posted in a similar  manner  as  --data-ascii\n"
+, stdout);
+ fputs(
+"              does,  except  that  newlines  are preserved and conversions are\n"
+"              never done.\n"
+"\n"
+"              If this option is used several times,  the  ones  following  the\n"
+"              first will append data as described in -d/--data.\n"
+"\n"
+"       --data-urlencode <data>\n"
+"              (HTTP) This posts data, similar to the other --data options with\n"
+"              the exception that this performs URL-encoding. (Added in 7.18.0)\n"
+, stdout);
+ fputs(
+"              To be CGI-compliant, the <data> part should begin  with  a  name\n"
+"              followed  by a separator and a content specification. The <data>\n"
+"              part can be passed to curl using one of the following syntaxes:\n"
+"\n"
+"              content\n"
+"                     This will make curl URL-encode the content and pass  that\n"
+"                     on.  Just  be careful so that the content doesn't contain\n"
+"                     any = or @ symbols, as that will  then  make  the  syntax\n"
+, stdout);
+ fputs(
+"                     match one of the other cases below!\n"
+"\n"
+"              =content\n"
+"                     This  will make curl URL-encode the content and pass that\n"
+"                     on. The preceding = symbol is not included in the data.\n"
+"\n"
+"              name=content\n"
+"                     This will make curl URL-encode the content part and  pass\n"
+"                     that  on.  Note that the name part is expected to be URL-\n"
+"                     encoded already.\n"
+"\n"
+"              @filename\n"
+, stdout);
+ fputs(
+"                     This will  make  curl  load  data  from  the  given  file\n"
+"                     (including  any  newlines), URL-encode that data and pass\n"
+"                     it on in the POST.\n"
+"\n"
+"              name@filename\n"
+"                     This will  make  curl  load  data  from  the  given  file\n"
+"                     (including  any  newlines), URL-encode that data and pass\n"
+"                     it on in the POST. The  name  part  gets  an  equal  sign\n"
+, stdout);
+ fputs(
+"                     appended, resulting in name=urlencoded-file-content. Note\n"
+"                     that the name is expected to be URL-encoded already.\n"
+"\n"
+"       --digest\n"
+"              (HTTP) Enables HTTP Digest authentication. This is a authentica-\n"
+"              tion that prevents the password from being sent over the wire in\n"
+"              clear text. Use this in combination with  the  normal  -u/--user\n"
+"              option to set user name and password. See also --ntlm, --negoti-\n"
+, stdout);
+ fputs(
+"              ate and --anyauth for related options.\n"
+"\n"
+"              If this option is used several times, the following  occurrences\n"
+"              make no difference.\n"
+"\n"
+"       --disable-eprt\n"
+"              (FTP) Tell curl to disable the use of the EPRT and LPRT commands\n"
+"              when doing active FTP transfers. Curl will normally always first\n"
+"              attempt  to use EPRT, then LPRT before using PORT, but with this\n"
+, stdout);
+ fputs(
+"              option, it will use PORT right away. EPRT and  LPRT  are  exten-\n"
+"              sions  to  the  original  FTP  protocol, and may not work on all\n"
+"              servers, but they enable more functionality in a better way than\n"
+"              the traditional PORT command.\n"
+"\n"
+"              Since  curl 7.19.0, --eprt can be used to explicitly enable EPRT\n"
+"              again and --no-eprt is an alias for --disable-eprt.\n"
+"\n"
+, stdout);
+ fputs(
+"              Disabling EPRT only changes the active behavior. If you want  to\n"
+"              switch  to  passive  mode  you  need to not use -P/--ftp-port or\n"
+"              force it with --ftp-pasv.\n"
+"\n"
+"       --disable-epsv\n"
+"              (FTP) Tell curl to disable the use  of  the  EPSV  command  when\n"
+"              doing  passive  FTP  transfers.  Curl will normally always first\n"
+"              attempt to use EPSV before PASV, but with this option,  it  will\n"
+"              not try using EPSV.\n"
+"\n"
+, stdout);
+ fputs(
+"              Since  curl 7.19.0, --epsv can be used to explicitly enable EPRT\n"
+"              again and --no-epsv is an alias for --disable-epsv.\n"
+"\n"
+"              Disabling EPSV only changes the passive behavior. If you want to\n"
+"              switch to active mode you need to use -P/--ftp-port.\n"
+"\n"
+"       -D/--dump-header <file>\n"
+"              Write the protocol headers to the specified file.\n"
+"\n"
+"              This  option  is handy to use when you want to store the headers\n"
+, stdout);
+ fputs(
+"              that a HTTP site sends to you. Cookies from  the  headers  could\n"
+"              then   be  read  in  a  second  curl  invocation  by  using  the\n"
+"              -b/--cookie option! The -c/--cookie-jar option is however a bet-\n"
+"              ter way to store cookies.\n"
+"\n"
+"              When  used  in FTP, the FTP server response lines are considered\n"
+"              being \"headers\" and thus are saved there.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+, stdout);
+ fputs(
+"       -e/--referer <URL>\n"
+"              (HTTP) Sends the \"Referer Page\" information to the HTTP  server.\n"
+"              This  can also be set with the -H/--header flag of course.  When\n"
+"              used with -L/--location you can append \";auto\" to the  --referer\n"
+"              URL to make curl automatically set the previous URL when it fol-\n"
+"              lows a Location: header. The \";auto\" string can be  used  alone,\n"
+"              even if you don't set an initial --referer.\n"
+"\n"
+, stdout);
+ fputs(
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       --engine <name>\n"
+"              Select  the  OpenSSL crypto engine to use for cipher operations.\n"
+"              Use --engine list  to  print  a  list  of  build-time  supported\n"
+"              engines.  Note  that  not  all  (or  none) of the engines may be\n"
+"              available at run-time.\n"
+"\n"
+"       --environment\n"
+"              (RISC OS ONLY) Sets a range of environment variables, using  the\n"
+, stdout);
+ fputs(
+"              names the -w option supports, to allow easier extraction of use-\n"
+"              ful information after having run curl.\n"
+"\n"
+"       --egd-file <file>\n"
+"              (SSL) Specify the path name  to  the  Entropy  Gathering  Daemon\n"
+"              socket.  The  socket  is  used to seed the random engine for SSL\n"
+"              connections. See also the --random-file option.\n"
+"\n"
+"       -E/--cert <certificate[:password]>\n"
+"              (SSL) Tells curl to use the specified certificate file when get-\n"
+, stdout);
+ fputs(
+"              ting  a  file with HTTPS or FTPS. The certificate must be in PEM\n"
+"              format.  If the optional password isn't specified,  it  will  be\n"
+"              queried  for  on  the  terminal. Note that this option assumes a\n"
+"              \"certificate\" file that is the private key and the private  cer-\n"
+"              tificate  concatenated!  See  --cert  and  --key to specify them\n"
+"              independently.\n"
+"\n"
+, stdout);
+ fputs(
+"              If curl is built against the NSS SSL library  then  this  option\n"
+"              tells curl the nickname of the certificate to use within the NSS\n"
+"              database defined by the  environment  variable  SSL_DIR  (or  by\n"
+"              default  /etc/pki/nssdb).  If  the  NSS PEM PKCS#11 module (lib-\n"
+"              nsspem.so) is available then PEM files may be loaded.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       --cert-type <type>\n"
+, stdout);
+ fputs(
+"              (SSL) Tells curl what certificate type the provided  certificate\n"
+"              is in. PEM, DER and ENG are recognized types.  If not specified,\n"
+"              PEM is assumed.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       --cacert <CA certificate>\n"
+"              (SSL) Tells curl to use the specified certificate file to verify\n"
+"              the  peer.  The  file  may contain multiple CA certificates. The\n"
+, stdout);
+ fputs(
+"              certificate(s) must be in PEM format. Normally curl is built  to\n"
+"              use a default file for this, so this option is typically used to\n"
+"              alter that default file.\n"
+"\n"
+"              curl recognizes the environment variable named  'CURL_CA_BUNDLE'\n"
+"              if  it  is  set,  and uses the given path as a path to a CA cert\n"
+"              bundle. This option overrides that variable.\n"
+"\n"
+"              The windows version of curl will automatically  look  for  a  CA\n"
+, stdout);
+ fputs(
+"              certs file named 'curl-ca-bundle.crt', either in the same direc-\n"
+"              tory as curl.exe, or in the Current Working Directory, or in any\n"
+"              folder along your PATH.\n"
+"\n"
+"              If  curl  is  built against the NSS SSL library then this option\n"
+"              tells curl the nickname of the CA certificate to use within  the\n"
+"              NSS  database defined by the environment variable SSL_DIR (or by\n"
+, stdout);
+ fputs(
+"              default /etc/pki/nssdb).  If the NSS PEM  PKCS#11  module  (lib-\n"
+"              nsspem.so) is available then PEM files may be loaded.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       --capath <CA certificate directory>\n"
+"              (SSL)  Tells  curl to use the specified certificate directory to\n"
+"              verify the peer. The certificates must be in PEM format, and the\n"
+, stdout);
+ fputs(
+"              directory  must  have  been processed using the c_rehash utility\n"
+"              supplied with openssl. Using --capath can  allow  curl  to  make\n"
+"              SSL-connections much more efficiently than using --cacert if the\n"
+"              --cacert file contains many CA certificates.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       -f/--fail\n"
+"              (HTTP) Fail silently (no output at all) on server  errors.  This\n"
+, stdout);
+ fputs(
+"              is  mostly done to better enable scripts etc to better deal with\n"
+"              failed attempts. In normal cases when a  HTTP  server  fails  to\n"
+"              deliver  a  document,  it  returns  an  HTML document stating so\n"
+"              (which often also describes why and more). This flag  will  pre-\n"
+"              vent curl from outputting that and return error 22.\n"
+"\n"
+"              This  method is not fail-safe and there are occasions where non-\n"
+, stdout);
+ fputs(
+"              successful response codes will  slip  through,  especially  when\n"
+"              authentication is involved (response codes 401 and 407).\n"
+"\n"
+"       --ftp-account [data]\n"
+"              (FTP) When an FTP server asks for \"account data\" after user name\n"
+"              and password has been provided, this data is sent off using  the\n"
+"              ACCT command. (Added in 7.13.0)\n"
+"\n"
+"              If  this option is used twice, the second will override the pre-\n"
+"              vious use.\n"
+"\n"
+, stdout);
+ fputs(
+"       --ftp-create-dirs\n"
+"              (FTP/SFTP) When an FTP or SFTP URL/operation uses  a  path  that\n"
+"              doesn't  currently exist on the server, the standard behavior of\n"
+"              curl is to fail. Using this option, curl will instead attempt to\n"
+"              create missing directories.\n"
+"\n"
+"       --ftp-method [method]\n"
+"              (FTP)  Control  what method curl should use to reach a file on a\n"
+"              FTP(S) server. The method argument should be one of the  follow-\n"
+, stdout);
+ fputs(
+"              ing alternatives:\n"
+"\n"
+"              multicwd\n"
+"                     curl  does  a  single CWD operation for each path part in\n"
+"                     the given URL. For deep hierarchies this means very  many\n"
+"                     commands.  This  is  how  RFC1738 says it should be done.\n"
+"                     This is the default but the slowest behavior.\n"
+"\n"
+"              nocwd  curl does no CWD at all. curl will do  SIZE,  RETR,  STOR\n"
+, stdout);
+ fputs(
+"                     etc and give a full path to the server for all these com-\n"
+"                     mands. This is the fastest behavior.\n"
+"\n"
+"              singlecwd\n"
+"                     curl does one CWD with the full target directory and then\n"
+"                     operates  on  the  file  \"normally\" (like in the multicwd\n"
+"                     case). This is somewhat  more  standards  compliant  than\n"
+"                     'nocwd' but without the full penalty of 'multicwd'.\n"
+"       (Added in 7.15.1)\n"
+"\n"
+, stdout);
+ fputs(
+"       --ftp-pasv\n"
+"              (FTP)  Use  passive  mode for the data conection. Passive is the\n"
+"              internal default behavior, but using this option can be used  to\n"
+"              override a previous -P/-ftp-port option. (Added in 7.11.0)\n"
+"\n"
+"              If  this option is used several times, the following occurrences\n"
+"              make no difference. Undoing an  enforced  passive  really  isn't\n"
+"              doable  but  you must then instead enforce the correct -P/--ftp-\n"
+, stdout);
+ fputs(
+"              port again.\n"
+"\n"
+"              Passive mode means that curl will try the EPSV command first and\n"
+"              then PASV, unless --disable-epsv is used.\n"
+"\n"
+"       --ftp-alternative-to-user <command>\n"
+"              (FTP)  If  authenticating with the USER and PASS commands fails,\n"
+"              send this  command.   When  connecting  to  Tumbleweed's  Secure\n"
+"              Transport  server  over  FTPS  using a client certificate, using\n"
+, stdout);
+ fputs(
+"              \"SITE AUTH\" will tell the server to retrieve the  username  from\n"
+"              the certificate. (Added in 7.15.5)\n"
+"\n"
+"       --ftp-skip-pasv-ip\n"
+"              (FTP) Tell curl to not use the IP address the server suggests in\n"
+"              its response to curl's PASV command when curl connects the  data\n"
+"              connection.  Instead  curl  will  re-use  the same IP address it\n"
+"              already uses for the control connection. (Added in 7.14.2)\n"
+"\n"
+, stdout);
+ fputs(
+"              This option has no effect if PORT, EPRT or EPSV is used  instead\n"
+"              of PASV.\n"
+"\n"
+"       --ftp-pret\n"
+"              (FTP)  Tell  curl to send a PRET command before PASV (and EPSV).\n"
+"              Certain FTP servers, mainly drftpd,  require  this  non-standard\n"
+"              command  for  directory  listings as well as up and downloads in\n"
+"              PASV mode.  (Added in 7.20.x)\n"
+"\n"
+"       --ssl  (FTP, POP3, IMAP, SMTP) Try to use SSL/TLS for  the  connection.\n"
+, stdout);
+ fputs(
+"              Reverts to a non-secure connection if the server doesn't support\n"
+"              SSL/TLS.  See also --ftp-ssl-control and --ssl-reqd for  differ-\n"
+"              ent levels of encryption required. (Added in 7.20.0)\n"
+"\n"
+"              This  option  was  formerly known as --ftp-ssl (Added in 7.11.0)\n"
+"              and that can still be used but will be removed in a future  ver-\n"
+"              sion.\n"
+"\n"
+"       --ftp-ssl-control\n"
+, stdout);
+ fputs(
+"              (FTP)  Require  SSL/TLS  for  the FTP login, clear for transfer.\n"
+"              Allows secure authentication, but non-encrypted  data  transfers\n"
+"              for  efficiency.   Fails the transfer if the server doesn't sup-\n"
+"              port SSL/TLS.  (Added in 7.16.0)\n"
+"\n"
+"       --ssl-reqd\n"
+"              (FTP, POP3, IMAP, SMTP)  Require  SSL/TLS  for  the  connection.\n"
+"              Terminates the connection if the server doesn't support SSL/TLS.\n"
+"              (Added in 7.20.0)\n"
+"\n"
+, stdout);
+ fputs(
+"              This option was  formerly  known  as  --ftp-ssl-reqd  (added  in\n"
+"              7.15.5)  and  that  can  still  be used but will be removed in a\n"
+"              future version.\n"
+"\n"
+"       --ftp-ssl-ccc\n"
+"              (FTP) Use CCC (Clear Command Channel)  Shuts  down  the  SSL/TLS\n"
+"              layer after authenticating. The rest of the control channel com-\n"
+"              munication will be unencrypted. This allows NAT routers to  fol-\n"
+, stdout);
+ fputs(
+"              low the FTP transaction. The default mode is passive. See --ftp-\n"
+"              ssl-ccc-mode for other modes.  (Added in 7.16.1)\n"
+"\n"
+"       --ftp-ssl-ccc-mode [active/passive]\n"
+"              (FTP) Use CCC (Clear Command Channel) Sets  the  CCC  mode.  The\n"
+"              passive  mode  will  not initiate the shutdown, but instead wait\n"
+"              for the server to do it, and will not reply to the shutdown from\n"
+, stdout);
+ fputs(
+"              the server. The active mode initiates the shutdown and waits for\n"
+"              a reply from the server.  (Added in 7.16.2)\n"
+"\n"
+"       -F/--form <name=content>\n"
+"              (HTTP) This lets curl emulate a filled-in form in which  a  user\n"
+"              has  pressed  the  submit  button. This causes curl to POST data\n"
+"              using the Content-Type multipart/form-data according to RFC2388.\n"
+"              This  enables  uploading of binary files etc. To force the 'con-\n"
+, stdout);
+ fputs(
+"              tent' part to be a file, prefix the file name with an @ sign. To\n"
+"              just get the content part from a file, prefix the file name with\n"
+"              the symbol <. The difference between @ and  <  is  then  that  @\n"
+"              makes  a  file  get attached in the post as a file upload, while\n"
+"              the < makes a text field and just get the contents for that text\n"
+"              field from a file.\n"
+"\n"
+, stdout);
+ fputs(
+"              Example,  to send your password file to the server, where 'pass-\n"
+"              word' is the name of the form-field to which /etc/passwd will be\n"
+"              the input:\n"
+"\n"
+"              curl -F password=@/etc/passwd www.mypasswords.com\n"
+"\n"
+"              To  read  the file's content from stdin instead of a file, use -\n"
+"              where the file name should've been. This goes for both @  and  <\n"
+"              constructs.\n"
+"\n"
+, stdout);
+ fputs(
+"              You  can  also  tell  curl  what  Content-Type  to  use by using\n"
+"              'type=', in a manner similar to:\n"
+"\n"
+"              curl -F \"web=@index.html;type=text/html\" url.com\n"
+"\n"
+"              or\n"
+"\n"
+"              curl -F \"name=daniel;type=text/foo\" url.com\n"
+"\n"
+"              You can also explicitly change the name field of an file  upload\n"
+"              part by setting filename=, like this:\n"
+"\n"
+"              curl -F \"file=@localfile;filename=nameinpost\" url.com\n"
+"\n"
+, stdout);
+ fputs(
+"              See further examples and details in the MANUAL.\n"
+"\n"
+"              This option can be used multiple times.\n"
+"\n"
+"       --form-string <name=string>\n"
+"              (HTTP)  Similar  to  --form except that the value string for the\n"
+"              named parameter is used literally. Leading '@' and  '<'  charac-\n"
+"              ters, and the ';type=' string in the value have no special mean-\n"
+"              ing. Use this in preference to --form if there's any possibility\n"
+, stdout);
+ fputs(
+"              that  the  string  value may accidentally trigger the '@' or '<'\n"
+"              features of --form.\n"
+"\n"
+"       -g/--globoff\n"
+"              This option switches off the \"URL globbing parser\". When you set\n"
+"              this  option, you can specify URLs that contain the letters {}[]\n"
+"              without having them being interpreted by curl itself. Note  that\n"
+"              these  letters are not normal legal URL contents but they should\n"
+, stdout);
+ fputs(
+"              be encoded according to the URI standard.\n"
+"\n"
+"       -G/--get\n"
+"              When used,  this  option  will  make  all  data  specified  with\n"
+"              -d/--data  or  --data-binary  to  be  used in a HTTP GET request\n"
+"              instead of the POST request that otherwise would  be  used.  The\n"
+"              data will be appended to the URL with a '?' separator.\n"
+"\n"
+"              If  used  in  combination with -I, the POST data will instead be\n"
+, stdout);
+ fputs(
+"              appended to the URL with a HEAD request.\n"
+"\n"
+"              If this option is used several times, the following  occurrences\n"
+"              make  no  difference. This is because undoing a GET doesn't make\n"
+"              sense, but you  should  then  instead  enforce  the  alternative\n"
+"              method you prefer.\n"
+"\n"
+"       -h/--help\n"
+"              Usage help.\n"
+"\n"
+"       -H/--header <header>\n"
+"              (HTTP)  Extra  header  to  use  when getting a web page. You may\n"
+, stdout);
+ fputs(
+"              specify any number of extra headers. Note that if you should add\n"
+"              a  custom  header  that has the same name as one of the internal\n"
+"              ones curl would use, your externally set  header  will  be  used\n"
+"              instead of the internal one. This allows you to make even trick-\n"
+"              ier stuff than curl would normally do. You  should  not  replace\n"
+"              internally  set  headers  without  knowing  perfectly  well what\n"
+, stdout);
+ fputs(
+"              you're doing. Remove an internal header by giving a  replacement\n"
+"              without  content  on  the  right  side  of  the colon, as in: -H\n"
+"              \"Host:\".\n"
+"\n"
+"              curl will make sure that each header  you  add/replace  is  sent\n"
+"              with the proper end-of-line marker, you should thus not add that\n"
+"              as a part of the header content: do not add newlines or carriage\n"
+"              returns, they will only mess things up for you.\n"
+"\n"
+, stdout);
+ fputs(
+"              See also the -A/--user-agent and -e/--referer options.\n"
+"\n"
+"              This  option  can  be  used multiple times to add/replace/remove\n"
+"              multiple headers.\n"
+"\n"
+"       --hostpubmd5 <md5>\n"
+"              Pass a string  containing  32  hexadecimal  digits.  The  string\n"
+"              should  be  the 128 bit MD5 checksum of the remote host's public\n"
+"              key, curl will refuse the connection with the  host  unless  the\n"
+, stdout);
+ fputs(
+"              md5sums  match.  This option is only for SCP and SFTP transfers.\n"
+"              (Added in 7.17.1)\n"
+"\n"
+"       --ignore-content-length\n"
+"              (HTTP) Ignore the Content-Length header.  This  is  particularly\n"
+"              useful  for servers running Apache 1.x, which will report incor-\n"
+"              rect Content-Length for files larger than 2 gigabytes.\n"
+"\n"
+"       -i/--include\n"
+"              (HTTP) Include the HTTP-header in the  output.  The  HTTP-header\n"
+, stdout);
+ fputs(
+"              includes  things  like  server-name, date of the document, HTTP-\n"
+"              version and more...\n"
+"\n"
+"       --interface <name>\n"
+"              Perform an operation using a specified interface. You can  enter\n"
+"              interface  name,  IP address or host name. An example could look\n"
+"              like:\n"
+"\n"
+"               curl --interface eth0:1 http://www.netscape.com/\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       -I/--head\n"
+, stdout);
+ fputs(
+"              (HTTP/FTP/FILE) Fetch the HTTP-header only! HTTP-servers feature\n"
+"              the  command  HEAD which this uses to get nothing but the header\n"
+"              of a document. When used on a FTP or FILE  file,  curl  displays\n"
+"              the file size and last modification time only.\n"
+"\n"
+"       -j/--junk-session-cookies\n"
+"              (HTTP) When curl is told to read cookies from a given file, this\n"
+"              option will make it discard all  \"session  cookies\".  This  will\n"
+, stdout);
+ fputs(
+"              basically  have  the same effect as if a new session is started.\n"
+"              Typical browsers always discard  session  cookies  when  they're\n"
+"              closed down.\n"
+"\n"
+"       -J/--remote-header-name\n"
+"              (HTTP)  This option tells the -O/--remote-name option to use the\n"
+"              server-specified   Content-Disposition   filename   instead   of\n"
+"              extracting a filename from the URL.\n"
+"\n"
+"       -k/--insecure\n"
+, stdout);
+ fputs(
+"              (SSL)  This  option explicitly allows curl to perform \"insecure\"\n"
+"              SSL connections and transfers. All SSL connections are attempted\n"
+"              to  be  made secure by using the CA certificate bundle installed\n"
+"              by default. This makes  all  connections  considered  \"insecure\"\n"
+"              fail unless -k/--insecure is used.\n"
+"\n"
+"              See     this    online    resource    for    further    details:\n"
+"              http://curl.haxx.se/docs/sslcerts.html\n"
+, stdout);
+ fputs(
+"\n"
+"       --keepalive-time <seconds>\n"
+"              This option sets the time a  connection  needs  to  remain  idle\n"
+"              before  sending keepalive probes and the time between individual\n"
+"              keepalive probes. It is currently effective on operating systems\n"
+"              offering  the  TCP_KEEPIDLE  and  TCP_KEEPINTVL  socket  options\n"
+"              (meaning Linux, recent AIX, HP-UX and more). This option has  no\n"
+"              effect if --no-keepalive is used. (Added in 7.18.0)\n"
+"\n"
+, stdout);
+ fputs(
+"              If  this option is used multiple times, the last occurrence sets\n"
+"              the amount.\n"
+"       --key <key>\n"
+"              (SSL/SSH) Private key file name. Allows you to provide your pri-\n"
+"              vate key in this separate file.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       --key-type <type>\n"
+"              (SSL)  Private key file type. Specify which type your --key pro-\n"
+, stdout);
+ fputs(
+"              vided private key is. DER, PEM, and ENG are  supported.  If  not\n"
+"              specified, PEM is assumed.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       --krb <level>\n"
+"              (FTP)  Enable Kerberos authentication and use. The level must be\n"
+"              entered and should be one of 'clear', 'safe', 'confidential', or\n"
+"              'private'.  Should  you  use  a  level that is not one of these,\n"
+, stdout);
+ fputs(
+"              'private' will instead be used.\n"
+"\n"
+"              This option requires a library built with  kerberos4  or  GSSAPI\n"
+"              (GSS-Negotiate)  support. This is not very common. Use -V/--ver-\n"
+"              sion to see if your curl supports it.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       -K/--config <config file>\n"
+"              Specify which config file to read curl arguments from. The  con-\n"
+, stdout);
+ fputs(
+"              fig  file  is a text file in which command line arguments can be\n"
+"              written which then will be used as if they were written  on  the\n"
+"              actual command line. Options and their parameters must be speci-\n"
+"              fied on the same config  file  line,  separated  by  whitespace,\n"
+"              colon,  the equals sign or any combination thereof (however, the\n"
+"              preferred separator is the equals sign). If the parameter is  to\n"
+, stdout);
+ fputs(
+"              contain  whitespace,  the  parameter  must  be  enclosed  within\n"
+"              quotes. Within double quotes, the following escape sequences are\n"
+"              available:  \\\\, \\\", \\t, \\n, \\r and \\v. A backslash preceding any\n"
+"              other letter is ignored. If the first column of a config line is\n"
+"              a  '#' character, the rest of the line will be treated as a com-\n"
+"              ment. Only write one option per  physical  line  in  the  config\n"
+"              file.\n"
+"\n"
+, stdout);
+ fputs(
+"              Specify the filename to -K/--config as '-' to make curl read the\n"
+"              file from stdin.\n"
+"\n"
+"              Note that to be able to specify a URL in the  config  file,  you\n"
+"              need  to  specify  it  using the --url option, and not by simply\n"
+"              writing the URL on its own line. So, it could  look  similar  to\n"
+"              this:\n"
+"\n"
+"              url = \"http://curl.haxx.se/docs/\"\n"
+"\n"
+"              Long  option  names  can  optionally be given in the config file\n"
+, stdout);
+ fputs(
+"              without the initial double dashes.\n"
+"\n"
+"              When curl is invoked, it always (unless -q is used) checks for a\n"
+"              default  config  file  and  uses it if found. The default config\n"
+"              file is checked for in the following places in this order:\n"
+"\n"
+"              1) curl tries to find the \"home dir\": It first  checks  for  the\n"
+"              CURL_HOME and then the HOME environment variables. Failing that,\n"
+, stdout);
+ fputs(
+"              it uses getpwuid() on UNIX-like systems (which returns the  home\n"
+"              dir  given the current user in your system). On Windows, it then\n"
+"              checks for the APPDATA variable, or as a last resort the '%USER-\n"
+"              PROFILE%\\Application Data'.\n"
+"\n"
+"              2)  On  windows, if there is no _curlrc file in the home dir, it\n"
+"              checks for one in the same dir the curl executable is placed. On\n"
+, stdout);
+ fputs(
+"              UNIX-like  systems,  it will simply try to load .curlrc from the\n"
+"              determined home dir.\n"
+"\n"
+"              # --- Example file ---\n"
+"              # this is a comment\n"
+"              url = \"curl.haxx.se\"\n"
+"              output = \"curlhere.html\"\n"
+"              user-agent = \"superagent/1.0\"\n"
+"\n"
+"              # and fetch another URL too\n"
+"              url = \"curl.haxx.se/docs/manpage.html\"\n"
+"              -O\n"
+"              referer = \"http://nowhereatall.com/\"\n"
+, stdout);
+ fputs(
+"              # --- End of example file ---\n"
+"\n"
+"              This option can be used multiple times to load  multiple  config\n"
+"              files.\n"
+"\n"
+"       --libcurl <file>\n"
+"              Append  this  option  to any ordinary curl command line, and you\n"
+"              will get a libcurl-using source code written to  the  file  that\n"
+"              does the equivalent of what your command-line operation does!\n"
+"\n"
+"              NOTE:  this does not properly support -F and the sending of mul-\n"
+, stdout);
+ fputs(
+"              tipart formposts, so in those cases the output program  will  be\n"
+"              missing necessary calls to curl_formadd(3), and possibly more.\n"
+"\n"
+"              If  this  option is used several times, the last given file name\n"
+"              will be used. (Added in 7.16.1)\n"
+"\n"
+"       --limit-rate <speed>\n"
+"              Specify the maximum transfer rate you want  curl  to  use.  This\n"
+"              feature is useful if you have a limited pipe and you'd like your\n"
+, stdout);
+ fputs(
+"              transfer not to use your entire bandwidth.\n"
+"\n"
+"              The given speed is measured in bytes/second, unless a suffix  is\n"
+"              appended.   Appending  'k' or 'K' will count the number as kilo-\n"
+"              bytes, 'm' or M' makes it megabytes, while 'g' or 'G'  makes  it\n"
+"              gigabytes. Examples: 200K, 3m and 1G.\n"
+"\n"
+"              The  given  rate  is the average speed counted during the entire\n"
+, stdout);
+ fputs(
+"              transfer. It means that curl might use higher transfer speeds in\n"
+"              short bursts, but over time it uses no more than the given rate.\n"
+"              If  you  also  use the -Y/--speed-limit option, that option will\n"
+"              take precedence and might cripple the rate-limiting slightly, to\n"
+"              help keeping the speed-limit logic working.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       -l/--list-only\n"
+, stdout);
+ fputs(
+"              (FTP)  When listing an FTP directory, this switch forces a name-\n"
+"              only view.  Especially useful if you want to  machine-parse  the\n"
+"              contents  of  an  FTP  directory since the normal directory view\n"
+"              doesn't use a standard look or format.\n"
+"\n"
+"              This option causes an FTP NLST command to  be  sent.   Some  FTP\n"
+"              servers  list  only files in their response to NLST; they do not\n"
+, stdout);
+ fputs(
+"              include subdirectories and symbolic links.\n"
+"\n"
+"       --local-port <num>[-num]\n"
+"              Set a preferred number or range of local port numbers to use for\n"
+"              the  connection(s).   Note  that  port  numbers  by nature are a\n"
+"              scarce resource that will be busy at times so setting this range\n"
+"              to something too narrow might cause unnecessary connection setup\n"
+"              failures. (Added in 7.15.2)\n"
+"\n"
+"       -L/--location\n"
+, stdout);
+ fputs(
+"              (HTTP/HTTPS) If the server reports that the requested  page  has\n"
+"              moved to a different location (indicated with a Location: header\n"
+"              and a 3XX response code), this option will make  curl  redo  the\n"
+"              request  on the new place. If used together with -i/--include or\n"
+"              -I/--head, headers from all requested pages will be shown.  When\n"
+"              authentication  is  used, curl only sends its credentials to the\n"
+, stdout);
+ fputs(
+"              initial host. If a redirect takes curl to a different  host,  it\n"
+"              won't  be  able to intercept the user+password. See also --loca-\n"
+"              tion-trusted on how to change this. You can limit the amount  of\n"
+"              redirects to follow by using the --max-redirs option.\n"
+"\n"
+"              When  curl follows a redirect and the request is not a plain GET\n"
+"              (for example POST or PUT), it will do the following request with\n"
+, stdout);
+ fputs(
+"              a GET if the HTTP response was 301, 302, or 303. If the response\n"
+"              code was any other 3xx code, curl  will  re-send  the  following\n"
+"              request using the same unmodified method.\n"
+"\n"
+"       --location-trusted\n"
+"              (HTTP/HTTPS) Like -L/--location, but will allow sending the name\n"
+"              + password to all hosts that the site may redirect to. This  may\n"
+"              or may not introduce a security breach if the site redirects you\n"
+, stdout);
+ fputs(
+"              to a site to which you'll send your authentication  info  (which\n"
+"              is plaintext in the case of HTTP Basic authentication).\n"
+"\n"
+"       --mail-rcpt <address>\n"
+"              (SMTP)  Specify  a single address that the given mail should get\n"
+"              sent to. This option can be used multiple times to specify  many\n"
+"              recipients.\n"
+"\n"
+"              (Added in 7.20.0)\n"
+"\n"
+"       --mail-from <address>\n"
+, stdout);
+ fputs(
+"              (SMTP)  Specify  a single address that the given mail should get\n"
+"              sent from.\n"
+"\n"
+"              (Added in 7.20.0)\n"
+"\n"
+"       --max-filesize <bytes>\n"
+"              Specify the maximum size (in bytes) of a file  to  download.  If\n"
+"              the  file requested is larger than this value, the transfer will\n"
+"              not start and curl will return with exit code 63.\n"
+"\n"
+"              NOTE: The file size is not always known prior to  download,  and\n"
+, stdout);
+ fputs(
+"              for such files this option has no effect even if the file trans-\n"
+"              fer ends up being larger than this given  limit.  This  concerns\n"
+"              both FTP and HTTP transfers.\n"
+"\n"
+"       -m/--max-time <seconds>\n"
+"              Maximum  time  in  seconds that you allow the whole operation to\n"
+"              take.  This is useful for preventing your batch jobs from  hang-\n"
+"              ing  for  hours  due  to slow networks or links going down.  See\n"
+, stdout);
+ fputs(
+"              also the --connect-timeout option.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       -M/--manual\n"
+"              Manual. Display the huge help text.\n"
+"\n"
+"       -n/--netrc\n"
+"              Makes curl scan the .netrc  (_netrc  on  Windows)  file  in  the\n"
+"              user's home directory for login name and password. This is typi-\n"
+"              cally used for FTP on UNIX. If used with HTTP, curl will  enable\n"
+, stdout);
+ fputs(
+"              user  authentication.  See netrc(4) or ftp(1) for details on the\n"
+"              file format. Curl will not complain if that  file  doesn't  have\n"
+"              the  right permissions (it should not be either world- or group-\n"
+"              readable). The environment variable \"HOME\" is used to  find  the\n"
+"              home directory.\n"
+"\n"
+"              A  quick  and  very  simple  example of how to setup a .netrc to\n"
+, stdout);
+ fputs(
+"              allow curl to FTP to the machine host.domain.com with user  name\n"
+"              'myself' and password 'secret' should look similar to:\n"
+"\n"
+"              machine host.domain.com login myself password secret\n"
+"\n"
+"       --netrc-optional\n"
+"              Very  similar to --netrc, but this option makes the .netrc usage\n"
+"              optional and not mandatory as the --netrc option does.\n"
+"\n"
+"       --negotiate\n"
+"              (HTTP) Enables GSS-Negotiate authentication.  The  GSS-Negotiate\n"
+, stdout);
+ fputs(
+"              method was designed by Microsoft and is used in their web appli-\n"
+"              cations. It is  primarily  meant  as  a  support  for  Kerberos5\n"
+"              authentication but may be also used along with another authenti-\n"
+"              cation method. For more information see IETF draft draft-brezak-\n"
+"              spnego-http-04.txt.\n"
+"\n"
+"              If  you  want to enable Negotiate for your proxy authentication,\n"
+"              then use --proxy-negotiate.\n"
+"\n"
+, stdout);
+ fputs(
+"              This option requires a library built with GSSAPI  support.  This\n"
+"              is not very common. Use -V/--version to see if your version sup-\n"
+"              ports GSS-Negotiate.\n"
+"\n"
+"              When using this option, you must also provide a  fake  -u/--user\n"
+"              option  to  activate the authentication code properly. Sending a\n"
+"              '-u :' is enough as the user  name  and  password  from  the  -u\n"
+"              option aren't actually used.\n"
+"\n"
+, stdout);
+ fputs(
+"              If  this option is used several times, the following occurrences\n"
+"              make no difference.\n"
+"\n"
+"       -N/--no-buffer\n"
+"              Disables the buffering of the output stream. In normal work sit-\n"
+"              uations,  curl  will  use a standard buffered output stream that\n"
+"              will have the effect that it will output the data in chunks, not\n"
+"              necessarily  exactly  when  the data arrives.  Using this option\n"
+"              will disable that buffering.\n"
+"\n"
+, stdout);
+ fputs(
+"              Note that this is the negated option name  documented.  You  can\n"
+"              thus use --buffer to enforce the buffering.\n"
+"\n"
+"       --no-keepalive\n"
+"              Disables the use of keepalive messages on the TCP connection, as\n"
+"              by default curl enables them.\n"
+"\n"
+"              Note that this is the negated option name  documented.  You  can\n"
+"              thus use --keepalive to enforce keepalive.\n"
+"\n"
+"       --no-sessionid\n"
+, stdout);
+ fputs(
+"              (SSL)  Disable curl's use of SSL session-ID caching.  By default\n"
+"              all transfers are done using the cache. Note that while  nothing\n"
+"              should  ever  get  hurt  by attempting to reuse SSL session-IDs,\n"
+"              there seem to be broken SSL implementations in the wild that may\n"
+"              require  you to disable this in order for you to succeed. (Added\n"
+"              in 7.16.0)\n"
+"\n"
+"              Note that this is the negated option name  documented.  You  can\n"
+, stdout);
+ fputs(
+"              thus use --sessionid to enforce session-ID caching.\n"
+"\n"
+"       --noproxy <no-proxy-list>\n"
+"              Comma-separated  list  of hosts which do not use a proxy, if one\n"
+"              is specified.  The only wildcard is a single * character,  which\n"
+"              matches all hosts, and effectively disables the proxy. Each name\n"
+"              in this list is matched as either a domain  which  contains  the\n"
+"              hostname,  or  the hostname itself. For example, local.com would\n"
+, stdout);
+ fputs(
+"              match  local.com,  local.com:80,  and  www.local.com,  but   not\n"
+"              www.notlocal.com.  (Added in 7.19.4).\n"
+"\n"
+"       --ntlm (HTTP)  Enables  NTLM  authentication.  The  NTLM authentication\n"
+"              method was designed by Microsoft and is used by IIS web servers.\n"
+"              It  is a proprietary protocol, reverse-engineered by clever peo-\n"
+"              ple and implemented in curl based on their efforts. This kind of\n"
+, stdout);
+ fputs(
+"              behavior  should  not be endorsed, you should encourage everyone\n"
+"              who uses NTLM to switch to a public and  documented  authentica-\n"
+"              tion method instead, such as Digest.\n"
+"\n"
+"              If  you  want to enable NTLM for your proxy authentication, then\n"
+"              use --proxy-ntlm.\n"
+"\n"
+"              This option requires a  library  built  with  SSL  support.  Use\n"
+"              -V/--version to see if your curl supports NTLM.\n"
+"\n"
+, stdout);
+ fputs(
+"              If  this option is used several times, the following occurrences\n"
+"              make no difference.\n"
+"\n"
+"       -o/--output <file>\n"
+"              Write output to <file> instead of stdout. If you are using {} or\n"
+"              []  to  fetch  multiple documents, you can use '#' followed by a\n"
+"              number in the <file> specifier. That variable will  be  replaced\n"
+"              with the current string for the URL being fetched. Like in:\n"
+"\n"
+, stdout);
+ fputs(
+"                curl http://{one,two}.site.com -o \"file_#1.txt\"\n"
+"\n"
+"              or use several variables like:\n"
+"\n"
+"                curl http://{site,host}.host[1-5].com -o \"#1_#2\"\n"
+"\n"
+"              You  may use this option as many times as the number of URLs you\n"
+"              have.\n"
+"\n"
+"              See also the --create-dirs option to create the  local  directo-\n"
+"              ries  dynamically.  Specifying the output as '-' (a single dash)\n"
+"              will force the output to be done to stdout.\n"
+"\n"
+, stdout);
+ fputs(
+"       -O/--remote-name\n"
+"              Write output to a local file named like the remote file we  get.\n"
+"              (Only  the file part of the remote file is used, the path is cut\n"
+"              off.)\n"
+"\n"
+"              The remote file name to use for saving  is  extracted  from  the\n"
+"              given URL, nothing else.\n"
+"\n"
+"              You  may use this option as many times as the number of URLs you\n"
+"              have.\n"
+"\n"
+"       --remote-name-all\n"
+, stdout);
+ fputs(
+"              This option changes the default action for all given URLs to  be\n"
+"              dealt  with as if -O/--remote-name were used for each one. So if\n"
+"              you want to disable that for a specific URL after --remote-name-\n"
+"              all  has  been  used,  you  must use \"-o -\" or --no-remote-name.\n"
+"              (Added in 7.19.0)\n"
+"\n"
+"       --pass <phrase>\n"
+"              (SSL/SSH) Passphrase for the private key\n"
+"\n"
+, stdout);
+ fputs(
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       --post301\n"
+"              Tells curl to respect  RFC  2616/10.3.2  and  not  convert  POST\n"
+"              requests into GET requests when following a 301 redirection. The\n"
+"              non-RFC behaviour is ubiquitous in web browsers,  so  curl  does\n"
+"              the  conversion  by  default to maintain consistency. However, a\n"
+"              server may require a POST to remain a POST after  such  a  redi-\n"
+, stdout);
+ fputs(
+"              rection. This option is meaningful only when using -L/--location\n"
+"              (Added in 7.17.1)\n"
+"\n"
+"       --post302\n"
+"              Tells curl to respect  RFC  2616/10.3.2  and  not  convert  POST\n"
+"              requests into GET requests when following a 302 redirection. The\n"
+"              non-RFC behaviour is ubiquitous in web browsers,  so  curl  does\n"
+"              the  conversion  by  default to maintain consistency. However, a\n"
+, stdout);
+ fputs(
+"              server may require a POST to remain a POST after  such  a  redi-\n"
+"              rection. This option is meaningful only when using -L/--location\n"
+"              (Added in 7.19.1)\n"
+"\n"
+"       --proxy-anyauth\n"
+"              Tells curl to pick a suitable authentication method when  commu-\n"
+"              nicating  with  the  given  proxy.  This  might  cause  an extra\n"
+"              request/response round-trip. (Added in 7.13.2)\n"
+"\n"
+"       --proxy-basic\n"
+, stdout);
+ fputs(
+"              Tells curl to use HTTP Basic authentication  when  communicating\n"
+"              with the given proxy. Use --basic for enabling HTTP Basic with a\n"
+"              remote host. Basic is the  default  authentication  method  curl\n"
+"              uses with proxies.\n"
+"\n"
+"       --proxy-digest\n"
+"              Tells  curl to use HTTP Digest authentication when communicating\n"
+"              with the given proxy. Use --digest for enabling HTTP Digest with\n"
+"              a remote host.\n"
+"\n"
+, stdout);
+ fputs(
+"       --proxy-negotiate\n"
+"              Tells curl to use HTTP Negotiate authentication when communicat-\n"
+"              ing with the given proxy.  Use  --negotiate  for  enabling  HTTP\n"
+"              Negotiate with a remote host. (Added in 7.17.1)\n"
+"\n"
+"       --proxy-ntlm\n"
+"              Tells  curl  to  use HTTP NTLM authentication when communicating\n"
+"              with the given proxy. Use --ntlm for enabling NTLM with a remote\n"
+"              host.\n"
+"\n"
+"       --proxy1.0 <proxyhost[:port]>\n"
+, stdout);
+ fputs(
+"              Use  the  specified  HTTP  1.0  proxy. If the port number is not\n"
+"              specified, it is assumed at port 1080.\n"
+"\n"
+"              The only difference between  this  and  the  HTTP  proxy  option\n"
+"              (-x/--proxy),  is that attempts to use CONNECT through the proxy\n"
+"              will specify an HTTP 1.0 protocol instead of  the  default  HTTP\n"
+"              1.1.\n"
+"\n"
+"       -p/--proxytunnel\n"
+"              When  an HTTP proxy is used (-x/--proxy), this option will cause\n"
+, stdout);
+ fputs(
+"              non-HTTP protocols  to  attempt  to  tunnel  through  the  proxy\n"
+"              instead  of merely using it to do HTTP-like operations. The tun-\n"
+"              nel approach is made with the HTTP  proxy  CONNECT  request  and\n"
+"              requires that the proxy allows direct connect to the remote port\n"
+"              number curl wants to tunnel through to.\n"
+"\n"
+"       --pubkey <key>\n"
+"              (SSH) Public key file name. Allows you to  provide  your  public\n"
+, stdout);
+ fputs(
+"              key in this separate file.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       -P/--ftp-port <address>\n"
+"              (FTP)  Reverses  the  default initiator/listener roles when con-\n"
+"              necting with FTP. This switch makes curl  use  active  mode.  In\n"
+"              practice,  curl  then  tells  the  server to connect back to the\n"
+"              client's specified address and port, while passive mode asks the\n"
+, stdout);
+ fputs(
+"              server  to  setup  an  IP address and port for it to connect to.\n"
+"              <address> should be one of:\n"
+"\n"
+"              interface\n"
+"                     i.e \"eth0\" to specify which interface's  IP  address  you\n"
+"                     want to use (Unix only)\n"
+"\n"
+"              IP address\n"
+"                     i.e \"192.168.10.1\" to specify the exact IP address\n"
+"\n"
+"              host name\n"
+"                     i.e \"my.host.domain\" to specify the machine\n"
+"\n"
+, stdout);
+ fputs(
+"              -      make  curl  pick the same IP address that is already used\n"
+"                     for the control connection\n"
+"\n"
+"       If this option is used several times, the last one will be  used.  Dis-\n"
+"       able  the  use  of PORT with --ftp-pasv. Disable the attempt to use the\n"
+"       EPRT command instead of PORT by using --disable-eprt.  EPRT  is  really\n"
+"       PORT++.\n"
+"\n"
+"       Starting in 7.19.5, you can append \":[start]-[end]\" to the right of the\n"
+, stdout);
+ fputs(
+"       address, to tell curl what TCP port range to use. That means you  spec-\n"
+"       ify  a  port  range,  from  a lower to a higher number. A single number\n"
+"       works as well, but do note that it increases the risk of failure  since\n"
+"       the port may not be available.\n"
+"\n"
+"       -q     If  used  as the first parameter on the command line, the curlrc\n"
+"              config file will not be read and used. See the  -K/--config  for\n"
+"              details on the default config file search path.\n"
+"\n"
+, stdout);
+ fputs(
+"       -Q/--quote <command>\n"
+"              (FTP/SFTP)  Send  an arbitrary command to the remote FTP or SFTP\n"
+"              server. Quote commands are sent BEFORE the transfer takes  place\n"
+"              (just  after  the  initial PWD command in an FTP transfer, to be\n"
+"              exact). To make commands take place after a successful transfer,\n"
+"              prefix  them  with  a  dash '-'.  To make commands be sent after\n"
+, stdout);
+ fputs(
+"              libcurl has changed  the  working  directory,  just  before  the\n"
+"              transfer command(s), prefix the command with a '+' (this is only\n"
+"              supported for FTP). You may specify any number of  commands.  If\n"
+"              the  server  returns failure for one of the commands, the entire\n"
+"              operation will be aborted. You must send  syntactically  correct\n"
+"              FTP  commands  as  RFC959  defines to FTP servers, or one of the\n"
+, stdout);
+ fputs(
+"              commands listed below to SFTP servers.  This option can be  used\n"
+"              multiple times.\n"
+"\n"
+"              SFTP  is  a  binary protocol. Unlike for FTP, libcurl interprets\n"
+"              SFTP quote commands before sending them to the server.   Follow-\n"
+"              ing is the list of all supported SFTP quote commands:\n"
+"\n"
+"              chgrp group file\n"
+"                     The  chgrp command sets the group ID of the file named by\n"
+, stdout);
+ fputs(
+"                     the file operand to the group ID specified by  the  group\n"
+"                     operand. The group operand is a decimal integer group ID.\n"
+"\n"
+"              chmod mode file\n"
+"                     The  chmod  command  modifies  the  file mode bits of the\n"
+"                     specified file. The mode operand is an octal integer mode\n"
+"                     number.\n"
+"\n"
+"              chown user file\n"
+"                     The chown command sets the owner of the file named by the\n"
+, stdout);
+ fputs(
+"                     file operand to the user ID specified by the  user  oper-\n"
+"                     and. The user operand is a decimal integer user ID.\n"
+"\n"
+"              ln source_file target_file\n"
+"                     The ln and symlink commands create a symbolic link at the\n"
+"                     target_file location pointing to  the  source_file  loca-\n"
+"                     tion.\n"
+"\n"
+"              mkdir directory_name\n"
+"                     The  mkdir  command  creates  the  directory named by the\n"
+, stdout);
+ fputs(
+"                     directory_name operand.\n"
+"\n"
+"              pwd    The pwd command returns the absolute pathname of the cur-\n"
+"                     rent working directory.\n"
+"\n"
+"              rename source target\n"
+"                     The rename command renames the file or directory named by\n"
+"                     the source operand to the destination path named  by  the\n"
+"                     target operand.\n"
+"\n"
+"              rm file\n"
+, stdout);
+ fputs(
+"                     The rm command removes the file specified by the file op-\n"
+"                     erand.\n"
+"\n"
+"              rmdir directory\n"
+"                     The rmdir command removes the directory  entry  specified\n"
+"                     by the directory operand, provided it is empty.\n"
+"\n"
+"              symlink source_file target_file\n"
+"                     See ln.\n"
+"\n"
+"       --random-file <file>\n"
+"              (SSL) Specify the path name to file containing what will be con-\n"
+, stdout);
+ fputs(
+"              sidered as random data. The data is  used  to  seed  the  random\n"
+"              engine for SSL connections.  See also the --egd-file option.\n"
+"\n"
+"       -r/--range <range>\n"
+"              (HTTP/FTP/SFTP/FILE)  Retrieve a byte range (i.e a partial docu-\n"
+"              ment) from a HTTP/1.1, FTP or  SFTP  server  or  a  local  FILE.\n"
+"              Ranges can be specified in a number of ways.\n"
+"\n"
+"              0-499     specifies the first 500 bytes\n"
+"\n"
+, stdout);
+ fputs(
+"              500-999   specifies the second 500 bytes\n"
+"\n"
+"              -500      specifies the last 500 bytes\n"
+"\n"
+"              9500-     specifies the bytes from offset 9500 and forward\n"
+"\n"
+"              0-0,-1    specifies the first and last byte only(*)(H)\n"
+"\n"
+"              500-700,600-799\n"
+"                        specifies 300 bytes from offset 500(H)\n"
+"\n"
+"              100-199,500-599\n"
+"                        specifies two separate 100-byte ranges(*)(H)\n"
+"\n"
+, stdout);
+ fputs(
+"       (*)  =  NOTE  that this will cause the server to reply with a multipart\n"
+"       response!\n"
+"\n"
+"       Only digit characters (0-9) are valid in the 'start' and 'stop'  fields\n"
+"       of  the 'start-stop' range syntax. If a non-digit character is given in\n"
+"       the range, the server's response will be unspecified, depending on  the\n"
+"       server's configuration.\n"
+"\n"
+"       You  should  also  be aware that many HTTP/1.1 servers do not have this\n"
+, stdout);
+ fputs(
+"       feature enabled, so that when  you  attempt  to  get  a  range,  you'll\n"
+"       instead get the whole document.\n"
+"\n"
+"       FTP  and SFTP range downloads only support the simple 'start-stop' syn-\n"
+"       tax (optionally with one of the numbers omitted). FTP  use  depends  on\n"
+"       the extended FTP command SIZE.\n"
+"\n"
+"       If this option is used several times, the last one will be used.\n"
+"\n"
+"       --raw  When  used, it disables all internal HTTP decoding of content or\n"
+, stdout);
+ fputs(
+"              transfer encodings and instead makes them passed  on  unaltered,\n"
+"              raw. (Added in 7.16.2)\n"
+"\n"
+"       -R/--remote-time\n"
+"              When  used,  this  will  make  libcurl attempt to figure out the\n"
+"              timestamp of the remote file, and if that is available make  the\n"
+"              local file get that same timestamp.\n"
+"\n"
+"       --retry <num>\n"
+"              If  a  transient  error is returned when curl tries to perform a\n"
+, stdout);
+ fputs(
+"              transfer, it will retry this number of times before  giving  up.\n"
+"              Setting  the  number to 0 makes curl do no retries (which is the\n"
+"              default). Transient error means either: a timeout,  an  FTP  4xx\n"
+"              response code or an HTTP 5xx response code.\n"
+"\n"
+"              When  curl  is about to retry a transfer, it will first wait one\n"
+"              second and then for all forthcoming retries it will  double  the\n"
+, stdout);
+ fputs(
+"              waiting  time until it reaches 10 minutes which then will be the\n"
+"              delay between the rest of the retries.  By  using  --retry-delay\n"
+"              you   disable  this  exponential  backoff  algorithm.  See  also\n"
+"              --retry-max-time to limit the total time  allowed  for  retries.\n"
+"              (Added in 7.12.3)\n"
+"\n"
+"              If  this  option  is  used  multiple  times, the last occurrence\n"
+"              decide the amount.\n"
+"\n"
+"       --retry-delay <seconds>\n"
+, stdout);
+ fputs(
+"              Make curl sleep this amount of time before  each  retry  when  a\n"
+"              transfer  has  failed  with  a  transient  error (it changes the\n"
+"              default backoff time algorithm between retries). This option  is\n"
+"              only  interesting if --retry is also used. Setting this delay to\n"
+"              zero will make curl use the default  backoff  time.   (Added  in\n"
+"              7.12.3)\n"
+"\n"
+"              If  this  option  is  used  multiple  times, the last occurrence\n"
+, stdout);
+ fputs(
+"              determines the amount.\n"
+"\n"
+"       --retry-max-time <seconds>\n"
+"              The retry timer is reset  before  the  first  transfer  attempt.\n"
+"              Retries will be done as usual (see --retry) as long as the timer\n"
+"              hasn't reached this given limit. Notice that if the timer hasn't\n"
+"              reached  the  limit, the request will be made and while perform-\n"
+"              ing, it may take longer than this given time period. To limit  a\n"
+, stdout);
+ fputs(
+"              single  request's  maximum  time,  use  -m/--max-time.  Set this\n"
+"              option to zero to not timeout retries. (Added in 7.12.3)\n"
+"\n"
+"              If this option is  used  multiple  times,  the  last  occurrence\n"
+"              determines the amount.\n"
+"\n"
+"       -s/--silent\n"
+"              Silent  or  quiet  mode. Don't show progress meter or error mes-\n"
+"              sages.  Makes Curl mute.\n"
+"\n"
+"       -S/--show-error\n"
+, stdout);
+ fputs(
+"              When used with -s it makes curl show  an  error  message  if  it\n"
+"              fails.\n"
+"\n"
+"       --socks4 <host[:port]>\n"
+"              Use the specified SOCKS4 proxy. If the port number is not speci-\n"
+"              fied, it is assumed at port 1080. (Added in 7.15.2)\n"
+"\n"
+"              This option overrides any previous use of  -x/--proxy,  as  they\n"
+"              are mutually exclusive.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+, stdout);
+ fputs(
+"       --socks4a <host[:port]>\n"
+"              Use the specified SOCKS4a proxy. If the port number is not spec-\n"
+"              ified, it is assumed at port 1080. (Added in 7.18.0)\n"
+"\n"
+"              This option overrides any previous use of  -x/--proxy,  as  they\n"
+"              are mutually exclusive.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       --socks5-hostname <host[:port]>\n"
+"              Use  the  specified  SOCKS5 proxy (and let the proxy resolve the\n"
+, stdout);
+ fputs(
+"              host name). If the port number is not specified, it  is  assumed\n"
+"              at port 1080. (Added in 7.18.0)\n"
+"\n"
+"              This  option  overrides  any previous use of -x/--proxy, as they\n"
+"              are mutually exclusive.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"              (This  option  was  previously  wrongly  documented  and used as\n"
+"              --socks without the number appended.)\n"
+"\n"
+"       --socks5 <host[:port]>\n"
+, stdout);
+ fputs(
+"              Use the specified SOCKS5 proxy  -  but  resolve  the  host  name\n"
+"              locally.  If  the port number is not specified, it is assumed at\n"
+"              port 1080.\n"
+"\n"
+"              This option overrides any previous use of  -x/--proxy,  as  they\n"
+"              are mutually exclusive.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"              (This option was  previously  wrongly  documented  and  used  as\n"
+, stdout);
+ fputs(
+"              --socks without the number appended.)\n"
+"\n"
+"              This  option (as well as --socks4) does not work with IPV6, FTPS\n"
+"              or LDAP.\n"
+"\n"
+"       --socks5-gssapi-service <servicename>\n"
+"              The default service name for a socks server is rcmd/server-fqdn.\n"
+"              This option allows you to change it.\n"
+"\n"
+"              Examples:\n"
+"               --socks5  proxy-name  --socks5-gssapi-service sockd   would use\n"
+"              sockd/proxy-name\n"
+, stdout);
+ fputs(
+"               --socks5  proxy-name  --socks5-gssapi-service   sockd/real-name\n"
+"              would  use  sockd/real-name  for cases where the proxy-name does\n"
+"              not match the princpal name.\n"
+"               (Added in 7.19.4).\n"
+"\n"
+"       --socks5-gssapi-nec\n"
+"              As part of the gssapi negotiation a protection mode  is  negoti-\n"
+"              ated.  The  rfc1961  says  in  section 4.3/4.4 it should be pro-\n"
+"              tected, but the NEC  reference  implementation  does  not.   The\n"
+, stdout);
+ fputs(
+"              option  --socks5-gssapi-nec  allows  the unprotected exchange of\n"
+"              the protection mode negotiation. (Added in 7.19.4).\n"
+"\n"
+"       --stderr <file>\n"
+"              Redirect all writes to stderr to the specified file instead.  If\n"
+"              the  file  name is a plain '-', it is instead written to stdout.\n"
+"              This option has no point when you're using a shell  with  decent\n"
+"              redirecting capabilities.\n"
+"\n"
+, stdout);
+ fputs(
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       --tcp-nodelay\n"
+"              Turn  on the TCP_NODELAY option. See the curl_easy_setopt(3) man\n"
+"              page for details about this option. (Added in 7.11.2)\n"
+"\n"
+"       -t/--telnet-option <OPT=val>\n"
+"              Pass options to the telnet protocol. Supported options are:\n"
+"\n"
+"              TTYPE=<term> Sets the terminal type.\n"
+"\n"
+"              XDISPLOC=<X display> Sets the X display location.\n"
+"\n"
+, stdout);
+ fputs(
+"              NEW_ENV=<var,val> Sets an environment variable.\n"
+"\n"
+"       --tftp-blksize <value>\n"
+"              (TFTP) Set TFTP BLKSIZE option (must be >512). This is the block\n"
+"              size  that curl will try to use when tranferring data to or from\n"
+"              a TFTP server. By default 512 bytes will be used.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"              (Added in 7.20.0)\n"
+"\n"
+"       -T/--upload-file <file>\n"
+, stdout);
+ fputs(
+"              This transfers the specified local file to the  remote  URL.  If\n"
+"              there is no file part in the specified URL, Curl will append the\n"
+"              local file name. NOTE that you must use a trailing / on the last\n"
+"              directory  to really prove to Curl that there is no file name or\n"
+"              curl will think that your last directory name is the remote file\n"
+"              name to use. That will most likely cause the upload operation to\n"
+, stdout);
+ fputs(
+"              fail. If this is used on a HTTP(S) server, the PUT command  will\n"
+"              be used.\n"
+"\n"
+"              Use  the file name \"-\" (a single dash) to use stdin instead of a\n"
+"              given file.  Alternately, the file name \".\"  (a  single  period)\n"
+"              may  be  specified  instead  of \"-\" to use stdin in non-blocking\n"
+"              mode to  allow  reading  server  output  while  stdin  is  being\n"
+"              uploaded.\n"
+"\n"
+, stdout);
+ fputs(
+"              You can specify one -T for each URL on the command line. Each -T\n"
+"              + URL pair specifies what to upload and to where. curl also sup-\n"
+"              ports \"globbing\" of the -T argument, meaning that you can upload\n"
+"              multiple files to a single URL by using the  same  URL  globbing\n"
+"              style supported in the URL, like this:\n"
+"\n"
+"              curl -T \"{file1,file2}\" http://www.uploadtothissite.com\n"
+"\n"
+"              or even\n"
+"\n"
+, stdout);
+ fputs(
+"              curl -T \"img[1-1000].png\" ftp://ftp.picturemania.com/upload/\n"
+"\n"
+"       --trace <file>\n"
+"              Enables  a  full  trace  dump of all incoming and outgoing data,\n"
+"              including descriptive information, to the given output file. Use\n"
+"              \"-\" as filename to have the output sent to stdout.\n"
+"\n"
+"              This  option overrides previous uses of -v/--verbose or --trace-\n"
+"              ascii.\n"
+"\n"
+, stdout);
+ fputs(
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       --trace-ascii <file>\n"
+"              Enables a full trace dump of all  incoming  and  outgoing  data,\n"
+"              including descriptive information, to the given output file. Use\n"
+"              \"-\" as filename to have the output sent to stdout.\n"
+"\n"
+"              This is very similar to --trace, but leaves out the hex part and\n"
+"              only  shows  the ASCII part of the dump. It makes smaller output\n"
+, stdout);
+ fputs(
+"              that might be easier to read for untrained humans.\n"
+"\n"
+"              This option overrides previous uses of -v/--verbose or --trace.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       --trace-time\n"
+"              Prepends a time stamp to each trace or verbose  line  that  curl\n"
+"              displays.  (Added in 7.14.0)\n"
+"\n"
+"       -u/--user <user:password>\n"
+"              Specify the user name and password to use for server authentica-\n"
+, stdout);
+ fputs(
+"              tion. Overrides -n/--netrc and --netrc-optional.\n"
+"\n"
+"              If you just give the user name (without entering a  colon)  curl\n"
+"              will prompt for a password.\n"
+"\n"
+"              If  you  use an SSPI-enabled curl binary and do NTLM authentica-\n"
+"              tion, you can force curl to pick up the user name  and  password\n"
+"              from  your  environment by simply specifying a single colon with\n"
+"              this option: \"-u :\".\n"
+"\n"
+, stdout);
+ fputs(
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       -U/--proxy-user <user:password>\n"
+"              Specify the user name and password to use for proxy  authentica-\n"
+"              tion.\n"
+"\n"
+"              If  you  use an SSPI-enabled curl binary and do NTLM authentica-\n"
+"              tion, you can force curl to pick up the user name  and  password\n"
+"              from  your  environment by simply specifying a single colon with\n"
+"              this option: \"-U :\".\n"
+"\n"
+, stdout);
+ fputs(
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       --url <URL>\n"
+"              Specify a URL to fetch. This option is  mostly  handy  when  you\n"
+"              want to specify URL(s) in a config file.\n"
+"\n"
+"              This  option  may  be used any number of times. To control where\n"
+"              this URL is written, use the -o/--output or the -O/--remote-name\n"
+"              options.\n"
+"\n"
+"       -v/--verbose\n"
+, stdout);
+ fputs(
+"              Makes  the  fetching  more  verbose/talkative. Mostly useful for\n"
+"              debugging. A line starting with '>' means \"header data\" sent  by\n"
+"              curl, '<' means \"header data\" received by curl that is hidden in\n"
+"              normal cases, and a line starting with '*' means additional info\n"
+"              provided by curl.\n"
+"\n"
+"              Note  that  if  you  only  want  HTTP  headers  in  the  output,\n"
+"              -i/--include might be the option you're looking for.\n"
+"\n"
+, stdout);
+ fputs(
+"              If you think this option still doesn't give you enough  details,\n"
+"              consider using --trace or --trace-ascii instead.\n"
+"\n"
+"              This option overrides previous uses of --trace-ascii or --trace.\n"
+"\n"
+"              Use -S/--silent to make curl quiet.\n"
+"\n"
+"       -V/--version\n"
+"              Displays information about curl and the libcurl version it uses.\n"
+"              The  first  line  includes the full version of curl, libcurl and\n"
+, stdout);
+ fputs(
+"              other 3rd party libraries linked with the executable.\n"
+"\n"
+"              The second line (starts with \"Protocols:\") shows  all  protocols\n"
+"              that libcurl reports to support.\n"
+"\n"
+"              The third line (starts with \"Features:\") shows specific features\n"
+"              libcurl reports to offer. Available features include:\n"
+"\n"
+"              IPv6   You can use IPv6 with this.\n"
+"\n"
+"              krb4   Krb4 for FTP is supported.\n"
+"\n"
+"              SSL    HTTPS and FTPS are supported.\n"
+"\n"
+, stdout);
+ fputs(
+"              libz   Automatic decompression of compressed files over HTTP  is\n"
+"                     supported.\n"
+"\n"
+"              NTLM   NTLM authentication is supported.\n"
+"\n"
+"              GSS-Negotiate\n"
+"                     Negotiate authentication and krb5 for FTP is supported.\n"
+"\n"
+"              Debug  This  curl  uses a libcurl built with Debug. This enables\n"
+"                     more error-tracking and memory debugging etc.  For  curl-\n"
+"                     developers only!\n"
+"\n"
+"              AsynchDNS\n"
+, stdout);
+ fputs(
+"                     This curl uses asynchronous name resolves.\n"
+"\n"
+"              SPNEGO SPNEGO Negotiate authentication is supported.\n"
+"\n"
+"              Largefile\n"
+"                     This curl supports transfers of large files, files larger\n"
+"                     than 2GB.\n"
+"\n"
+"              IDN    This curl supports IDN - international domain names.\n"
+"\n"
+"              SSPI   SSPI is supported. If you use NTLM and set a  blank  user\n"
+, stdout);
+ fputs(
+"                     name,  curl  will authenticate with your current user and\n"
+"                     password.\n"
+"\n"
+"       -w/--write-out <format>\n"
+"              Defines what to display on stdout after a completed and success-\n"
+"              ful  operation.  The  format  is a string that may contain plain\n"
+"              text mixed with any number of variables. The string can be spec-\n"
+"              ified  as \"string\", to get read from a particular file you spec-\n"
+, stdout);
+ fputs(
+"              ify it \"@filename\" and to tell curl  to  read  the  format  from\n"
+"              stdin you write \"@-\".\n"
+"\n"
+"              The  variables  present in the output format will be substituted\n"
+"              by the value or text that curl thinks fit, as  described  below.\n"
+"              All  variables are specified as %{variable_name} and to output a\n"
+"              normal % you just write them as %%. You can output a newline  by\n"
+, stdout);
+ fputs(
+"              using \\n, a carriage return with \\r and a tab space with \\t.\n"
+"\n"
+"              NOTE: The %-symbol is a special symbol in the win32-environment,\n"
+"              where all occurrences of %  must  be  doubled  when  using  this\n"
+"              option.\n"
+"\n"
+"              The variables available at this point are:\n"
+"\n"
+"              url_effective  The URL that was fetched last. This is most mean-\n"
+"                             ingful if you've told curl  to  follow  location:\n"
+, stdout);
+ fputs(
+"                             headers.\n"
+"\n"
+"              http_code      The numerical response code that was found in the\n"
+"                             last retrieved HTTP(S)  or  FTP(s)  transfer.  In\n"
+"                             7.18.2  the alias response_code was added to show\n"
+"                             the same info.\n"
+"\n"
+"              http_connect   The numerical code that was  found  in  the  last\n"
+"                             response   (from  a  proxy)  to  a  curl  CONNECT\n"
+, stdout);
+ fputs(
+"                             request. (Added in 7.12.4)\n"
+"\n"
+"              time_total     The total time, in seconds, that the full  opera-\n"
+"                             tion lasted. The time will be displayed with mil-\n"
+"                             lisecond resolution.\n"
+"\n"
+"              time_namelookup\n"
+"                             The time, in seconds,  it  took  from  the  start\n"
+"                             until the name resolving was completed.\n"
+"\n"
+, stdout);
+ fputs(
+"              time_connect   The  time,  in  seconds,  it  took from the start\n"
+"                             until the TCP connect  to  the  remote  host  (or\n"
+"                             proxy) was completed.\n"
+"\n"
+"              time_appconnect\n"
+"                             The  time,  in  seconds,  it  took from the start\n"
+"                             until the SSL/SSH/etc  connect/handshake  to  the\n"
+"                             remote host was completed. (Added in 7.19.0)\n"
+"\n"
+, stdout);
+ fputs(
+"              time_pretransfer\n"
+"                             The  time,  in  seconds,  it  took from the start\n"
+"                             until the file transfer was just about to  begin.\n"
+"                             This includes all pre-transfer commands and nego-\n"
+"                             tiations that are specific to the particular pro-\n"
+"                             tocol(s) involved.\n"
+"\n"
+"              time_redirect  The time, in seconds, it took for all redirection\n"
+, stdout);
+ fputs(
+"                             steps include name lookup,  connect,  pretransfer\n"
+"                             and  transfer  before  the  final transaction was\n"
+"                             started. time_redirect shows the complete  execu-\n"
+"                             tion  time  for  multiple redirections. (Added in\n"
+"                             7.12.3)\n"
+"\n"
+"              time_starttransfer\n"
+"                             The time, in seconds,  it  took  from  the  start\n"
+, stdout);
+ fputs(
+"                             until  the first byte was just about to be trans-\n"
+"                             ferred. This includes time_pretransfer  and  also\n"
+"                             the  time  the  server  needed  to  calculate the\n"
+"                             result.\n"
+"\n"
+"              size_download  The total amount of bytes that were downloaded.\n"
+"\n"
+"              size_upload    The total amount of bytes that were uploaded.\n"
+"\n"
+, stdout);
+ fputs(
+"              size_header    The total amount of bytes of the downloaded head-\n"
+"                             ers.\n"
+"\n"
+"              size_request   The  total  amount of bytes that were sent in the\n"
+"                             HTTP request.\n"
+"\n"
+"              speed_download The average download speed that curl measured for\n"
+"                             the complete download. Bytes per second.\n"
+"\n"
+"              speed_upload   The  average  upload speed that curl measured for\n"
+, stdout);
+ fputs(
+"                             the complete upload. Bytes per second.\n"
+"\n"
+"              content_type   The Content-Type of the  requested  document,  if\n"
+"                             there was any.\n"
+"\n"
+"              num_connects   Number  of new connects made in the recent trans-\n"
+"                             fer. (Added in 7.12.3)\n"
+"\n"
+"              num_redirects  Number of redirects that  were  followed  in  the\n"
+"                             request. (Added in 7.12.3)\n"
+"\n"
+, stdout);
+ fputs(
+"              redirect_url   When a HTTP request was made without -L to follow\n"
+"                             redirects, this variable will show the actual URL\n"
+"                             a redirect would take you to. (Added in 7.18.2)\n"
+"\n"
+"              ftp_entry_path The initial path libcurl ended up in when logging\n"
+"                             on to the remote FTP server. (Added in 7.15.4)\n"
+"\n"
+"              ssl_verify_result\n"
+, stdout);
+ fputs(
+"                             The result of the SSL peer certificate  verifica-\n"
+"                             tion that was requested. 0 means the verification\n"
+"                             was successful. (Added in 7.19.0)\n"
+"\n"
+"       If this option is used several times, the last one will be used.\n"
+"\n"
+"       -x/--proxy <proxyhost[:port]>\n"
+"              Use the specified HTTP proxy. If the port number is  not  speci-\n"
+"              fied, it is assumed at port 1080.\n"
+"\n"
+, stdout);
+ fputs(
+"              This  option  overrides  existing environment variables that set\n"
+"              the proxy to use. If there's an environment variable  setting  a\n"
+"              proxy, you can set proxy to \"\" to override it.\n"
+"\n"
+"              Note  that  all  operations that are performed over a HTTP proxy\n"
+"              will transparently be converted to HTTP. It means  that  certain\n"
+"              protocol specific operations might not be available. This is not\n"
+, stdout);
+ fputs(
+"              the case if you can tunnel through the proxy, as done  with  the\n"
+"              -p/--proxytunnel option.\n"
+"\n"
+"              Starting  with 7.14.1, the proxy host can be specified the exact\n"
+"              same way as the proxy environment variables, including the  pro-\n"
+"              tocol prefix (http://) and the embedded user + password.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       -X/--request <command>\n"
+, stdout);
+ fputs(
+"              (HTTP) Specifies a custom request method to use when communicat-\n"
+"              ing with the HTTP server.  The specified request  will  be  used\n"
+"              instead  of  the  method otherwise used (which defaults to GET).\n"
+"              Read the HTTP 1.1 specification for  details  and  explanations.\n"
+"              Common  additional  HTTP  requests  include  PUT and DELETE, but\n"
+"              related technologies like WebDAV offers PROPFIND, COPY, MOVE and\n"
+"              more.\n"
+"\n"
+, stdout);
+ fputs(
+"              (FTP) Specifies a custom FTP command to use instead of LIST when\n"
+"              doing file lists with FTP.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       -y/--speed-time <time>\n"
+"              If a download is slower than speed-limit bytes per second during\n"
+"              a speed-time period, the download gets aborted. If speed-time is\n"
+"              used, the default speed-limit will be 1 unless set with -Y.\n"
+"\n"
+, stdout);
+ fputs(
+"              This option controls transfers and thus  will  not  affect  slow\n"
+"              connects  etc.  If this is a concern for you, try the --connect-\n"
+"              timeout option.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       -Y/--speed-limit <speed>\n"
+"              If a download is slower than this given speed (in bytes per sec-\n"
+"              ond)  for  speed-time seconds it gets aborted. speed-time is set\n"
+, stdout);
+ fputs(
+"              with -y and is 30 if not set.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       -z/--time-cond <date expression>\n"
+"              (HTTP/FTP) Request a file that has been modified later than  the\n"
+"              given  time  and date, or one that has been modified before that\n"
+"              time. The date expression can be all sorts of date strings or if\n"
+"              it  doesn't  match  any  internal ones, it tries to get the time\n"
+, stdout);
+ fputs(
+"              from a given file name  instead!  See  the  curl_getdate(3)  man\n"
+"              pages for date expression details.\n"
+"\n"
+"              Start the date expression with a dash (-) to make it request for\n"
+"              a document that is older than the given date/time, default is  a\n"
+"              document that is newer than the specified date/time.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       --max-redirs <num>\n"
+, stdout);
+ fputs(
+"              Set   maximum   number  of  redirection-followings  allowed.  If\n"
+"              -L/--location is used, this option can be used to  prevent  curl\n"
+"              from following redirections \"in absurdum\". By default, the limit\n"
+"              is set to 50 redirections. Set this option to -1 to make it lim-\n"
+"              itless.\n"
+"\n"
+"              If this option is used several times, the last one will be used.\n"
+"\n"
+"       -0/--http1.0\n"
+, stdout);
+ fputs(
+"              (HTTP)  Forces curl to issue its requests using HTTP 1.0 instead\n"
+"              of using its internally preferred: HTTP 1.1.\n"
+"\n"
+"       -1/--tlsv1\n"
+"              (SSL) Forces curl to use TLS version 1 when negotiating  with  a\n"
+"              remote TLS server.\n"
+"\n"
+"       -2/--sslv2\n"
+"              (SSL)  Forces  curl to use SSL version 2 when negotiating with a\n"
+"              remote SSL server.\n"
+"\n"
+"       -3/--sslv3\n"
+"              (SSL) Forces curl to use SSL version 3 when negotiating  with  a\n"
+, stdout);
+ fputs(
+"              remote SSL server.\n"
+"\n"
+"       -4/--ipv4\n"
+"              If  libcurl  is  capable  of resolving an address to multiple IP\n"
+"              versions (which it is if it is IPv6-capable), this option  tells\n"
+"              libcurl to resolve names to IPv4 addresses only.\n"
+"\n"
+"       -6/--ipv6\n"
+"              If  libcurl  is  capable  of resolving an address to multiple IP\n"
+"              versions (which it is if it is IPv6-capable), this option  tells\n"
+, stdout);
+ fputs(
+"              libcurl to resolve names to IPv6 addresses only.\n"
+"\n"
+"       -#/--progress-bar\n"
+"              Make curl display progress information as a progress bar instead\n"
+"              of the default statistics.\n"
+"\n"
+"FILES\n"
+"       ~/.curlrc\n"
+"              Default config file, see -K/--config for details.\n"
+"\n"
+"ENVIRONMENT\n"
+"       The environment variables can be specified in lower case or upper case.\n"
+"       The lower case version has precedence. http_proxy is an exception as it\n"
+, stdout);
+ fputs(
+"       is only available in lower case.\n"
+"\n"
+"       http_proxy [protocol://]<host>[:port]\n"
+"              Sets the proxy server to use for HTTP.\n"
+"       HTTPS_PROXY [protocol://]<host>[:port]\n"
+"              Sets the proxy server to use for HTTPS.\n"
+"\n"
+"       FTP_PROXY [protocol://]<host>[:port]\n"
+"              Sets the proxy server to use for FTP.\n"
+"\n"
+"       ALL_PROXY [protocol://]<host>[:port]\n"
+"              Sets the proxy server to use if no  protocol-specific  proxy  is\n"
+"              set.\n"
+"\n"
+, stdout);
+ fputs(
+"       NO_PROXY <comma-separated list of hosts>\n"
+"              list  of  host names that shouldn't go through any proxy. If set\n"
+"              to a asterisk '*' only, it matches all hosts.\n"
+"\n"
+"EXIT CODES\n"
+"       There are a bunch of different  error  codes  and  their  corresponding\n"
+"       error  messages  that  may appear during bad conditions. At the time of\n"
+"       this writing, the exit codes are:\n"
+"\n"
+"       1      Unsupported protocol. This build of curl has no support for this\n"
+, stdout);
+ fputs(
+"              protocol.\n"
+"\n"
+"       2      Failed to initialize.\n"
+"\n"
+"       3      URL malformed. The syntax was not correct.\n"
+"\n"
+"       5      Couldn't  resolve  proxy.  The  given  proxy  host  could not be\n"
+"              resolved.\n"
+"\n"
+"       6      Couldn't resolve host. The given remote host was not resolved.\n"
+"\n"
+"       7      Failed to connect to host.\n"
+"\n"
+"       8      FTP weird server reply.  The  server  sent  data  curl  couldn't\n"
+"              parse.\n"
+"\n"
+, stdout);
+ fputs(
+"       9      FTP  access  denied. The server denied login or denied access to\n"
+"              the particular resource or directory you wanted to  reach.  Most\n"
+"              often  you  tried to change to a directory that doesn't exist on\n"
+"              the server.\n"
+"\n"
+"       11     FTP weird PASS reply. Curl couldn't parse the reply sent to  the\n"
+"              PASS request.\n"
+"\n"
+"       13     FTP  weird PASV reply, Curl couldn't parse the reply sent to the\n"
+"              PASV request.\n"
+"\n"
+, stdout);
+ fputs(
+"       14     FTP weird 227 format.  Curl  couldn't  parse  the  227-line  the\n"
+"              server sent.\n"
+"\n"
+"       15     FTP  can't  get host. Couldn't resolve the host IP we got in the\n"
+"              227-line.\n"
+"\n"
+"       17     FTP couldn't set binary.  Couldn't  change  transfer  method  to\n"
+"              binary.\n"
+"\n"
+"       18     Partial file. Only a part of the file was transferred.\n"
+"\n"
+"       19     FTP  couldn't download/access the given file, the RETR (or simi-\n"
+"              lar) command failed.\n"
+"\n"
+, stdout);
+ fputs(
+"       21     FTP quote error. A quote command returned error from the server.\n"
+"       22     HTTP page not retrieved. The requested  url  was  not  found  or\n"
+"              returned  another  error  with  the HTTP error code being 400 or\n"
+"              above. This return code only appears if -f/--fail is used.\n"
+"\n"
+"       23     Write error. Curl couldn't write data to a local  filesystem  or\n"
+"              similar.\n"
+"\n"
+"       25     FTP  couldn't  STOR  file. The server denied the STOR operation,\n"
+, stdout);
+ fputs(
+"              used for FTP uploading.\n"
+"\n"
+"       26     Read error. Various reading problems.\n"
+"\n"
+"       27     Out of memory. A memory allocation request failed.\n"
+"\n"
+"       28     Operation timeout. The specified  time-out  period  was  reached\n"
+"              according to the conditions.\n"
+"\n"
+"       30     FTP  PORT  failed.  The PORT command failed. Not all FTP servers\n"
+"              support the PORT  command,  try  doing  a  transfer  using  PASV\n"
+"              instead!\n"
+"\n"
+, stdout);
+ fputs(
+"       31     FTP  couldn't use REST. The REST command failed. This command is\n"
+"              used for resumed FTP transfers.\n"
+"\n"
+"       33     HTTP range error. The range \"command\" didn't work.\n"
+"\n"
+"       34     HTTP post error. Internal post-request generation error.\n"
+"\n"
+"       35     SSL connect error. The SSL handshaking failed.\n"
+"\n"
+"       36     FTP bad download resume. Couldn't continue  an  earlier  aborted\n"
+"              download.\n"
+"\n"
+, stdout);
+ fputs(
+"       37     FILE couldn't read file. Failed to open the file. Permissions?\n"
+"\n"
+"       38     LDAP cannot bind. LDAP bind operation failed.\n"
+"\n"
+"       39     LDAP search failed.\n"
+"\n"
+"       41     Function not found. A required LDAP function was not found.\n"
+"\n"
+"       42     Aborted by callback. An application told curl to abort the oper-\n"
+"              ation.\n"
+"\n"
+"       43     Internal error. A function was called with a bad parameter.\n"
+"\n"
+, stdout);
+ fputs(
+"       45     Interface error. A specified outgoing  interface  could  not  be\n"
+"              used.\n"
+"\n"
+"       47     Too many redirects. When following redirects, curl hit the maxi-\n"
+"              mum amount.\n"
+"\n"
+"       48     Unknown TELNET option specified.\n"
+"\n"
+"       49     Malformed telnet option.\n"
+"\n"
+"       51     The peer's SSL certificate or SSH MD5 fingerprint was not ok.\n"
+"\n"
+"       52     The server didn't reply anything, which here  is  considered  an\n"
+"              error.\n"
+"\n"
+, stdout);
+ fputs(
+"       53     SSL crypto engine not found.\n"
+"\n"
+"       54     Cannot set SSL crypto engine as default.\n"
+"\n"
+"       55     Failed sending network data.\n"
+"\n"
+"       56     Failure in receiving network data.\n"
+"\n"
+"       58     Problem with the local certificate.\n"
+"\n"
+"       59     Couldn't use specified SSL cipher.\n"
+"\n"
+"       60     Peer  certificate cannot be authenticated with known CA certifi-\n"
+"              cates.\n"
+"\n"
+"       61     Unrecognized transfer encoding.\n"
+"\n"
+"       62     Invalid LDAP URL.\n"
+"\n"
+, stdout);
+ fputs(
+"       63     Maximum file size exceeded.\n"
+"\n"
+"       64     Requested FTP SSL level failed.\n"
+"\n"
+"       65     Sending the data requires a rewind that failed.\n"
+"\n"
+"       66     Failed to initialise SSL Engine.\n"
+"\n"
+"       67     The user name, password, or similar was not  accepted  and  curl\n"
+"              failed to log in.\n"
+"\n"
+"       68     File not found on TFTP server.\n"
+"\n"
+"       69     Permission problem on TFTP server.\n"
+"\n"
+"       70     Out of disk space on TFTP server.\n"
+"\n"
+"       71     Illegal TFTP operation.\n"
+"\n"
+, stdout);
+ fputs(
+"       72     Unknown TFTP transfer ID.\n"
+"\n"
+"       73     File already exists (TFTP).\n"
+"\n"
+"       74     No such user (TFTP).\n"
+"\n"
+"       75     Character conversion failed.\n"
+"\n"
+"       76     Character conversion functions required.\n"
+"\n"
+"       77     Problem with reading the SSL CA cert (path? access rights?).\n"
+"\n"
+"       78     The resource referenced in the URL does not exist.\n"
+"\n"
+"       79     An unspecified error occurred during the SSH session.\n"
+"\n"
+"       80     Failed to shut down the SSL connection.\n"
+"\n"
+, stdout);
+ fputs(
+"       82     Could  not  load  CRL  file,  missing  or wrong format (added in\n"
+"              7.19.0).\n"
+"\n"
+"       83     Issuer check failed (added in 7.19.0).\n"
+"\n"
+"       XX     More error codes will appear here in future releases. The exist-\n"
+"              ing ones are meant to never change.\n"
+"\n"
+"AUTHORS / CONTRIBUTORS\n"
+"       Daniel  Stenberg is the main author, but the whole list of contributors\n"
+"       is found in the separate THANKS file.\n"
+"\n"
+"WWW\n"
+"       http://curl.haxx.se\n"
+"\n"
+"FTP\n"
+, stdout);
+ fputs(
+"       ftp://ftp.sunet.se/pub/www/utilities/curl/\n"
+"\n"
+"SEE ALSO\n"
+"       ftp(1), wget(1)\n"
+"\n"
+"LATEST VERSION\n"
+"\n"
+"  You always find news about what's going on as well as the latest versions\n"
+"  from the curl web pages, located at:\n"
+"\n"
+"        http://curl.haxx.se\n"
+"\n"
+"SIMPLE USAGE\n"
+"\n"
+"  Get the main page from Netscape's web-server:\n"
+"\n"
+"        curl http://www.netscape.com/\n"
+"\n"
+"  Get the README file the user's home directory at funet's ftp-server:\n"
+"\n"
+"        curl ftp://ftp.funet.fi/README\n"
+"\n"
+, stdout);
+ fputs(
+"  Get a web page from a server using port 8000:\n"
+"\n"
+"        curl http://www.weirdserver.com:8000/\n"
+"\n"
+"  Get a list of a directory of an FTP site:\n"
+"\n"
+"        curl ftp://cool.haxx.se/\n"
+"\n"
+"  Get the definition of curl from a dictionary:\n"
+"\n"
+"        curl dict://dict.org/m:curl\n"
+"\n"
+"  Fetch two documents at once:\n"
+"\n"
+"        curl ftp://cool.haxx.se/ http://www.weirdserver.com:8000/\n"
+"\n"
+"  Get a file off an FTPS server:\n"
+"\n"
+"        curl ftps://files.are.secure.com/secrets.txt\n"
+"\n"
+, stdout);
+ fputs(
+"  or use the more appropriate FTPS way to get the same file:\n"
+"\n"
+"        curl --ftp-ssl ftp://files.are.secure.com/secrets.txt\n"
+"\n"
+"  Get a file from an SSH server using SFTP:\n"
+"\n"
+"        curl -u username sftp://shell.example.com/etc/issue\n"
+"\n"
+"  Get a file from an SSH server using SCP using a private key to authenticate:\n"
+"\n"
+"        curl -u username: --key ~/.ssh/id_dsa --pubkey ~/.ssh/id_dsa.pub \\\n"
+"            scp://shell.example.com/~/personal.txt\n"
+"\n"
+"  Get the main page from an IPv6 web server:\n"
+"\n"
+, stdout);
+ fputs(
+"        curl -g \"http://[2001:1890:1112:1::20]/\"\n"
+"\n"
+"DOWNLOAD TO A FILE\n"
+"\n"
+"  Get a web page and store in a local file:\n"
+"\n"
+"        curl -o thatpage.html http://www.netscape.com/\n"
+"\n"
+"  Get a web page and store in a local file, make the local file get the name\n"
+"  of the remote document (if no file name part is specified in the URL, this\n"
+"  will fail):\n"
+"\n"
+"        curl -O http://www.netscape.com/index.html\n"
+"\n"
+"  Fetch two files and store them with their remote names:\n"
+"\n"
+, stdout);
+ fputs(
+"        curl -O www.haxx.se/index.html -O curl.haxx.se/download.html\n"
+"\n"
+"USING PASSWORDS\n"
+"\n"
+" FTP\n"
+"\n"
+"   To ftp files using name+passwd, include them in the URL like:\n"
+"\n"
+"        curl ftp://name:passwd@machine.domain:port/full/path/to/file\n"
+"\n"
+"   or specify them with the -u flag like\n"
+"\n"
+"        curl -u name:passwd ftp://machine.domain:port/full/path/to/file\n"
+"\n"
+" FTPS\n"
+"\n"
+"   It is just like for FTP, but you may also want to specify and use\n"
+"   SSL-specific options for certificates etc.\n"
+"\n"
+, stdout);
+ fputs(
+"   Note that using FTPS:// as prefix is the \"implicit\" way as described in the\n"
+"   standards while the recommended \"explicit\" way is done by using FTP:// and\n"
+"   the --ftp-ssl option.\n"
+"\n"
+" SFTP / SCP\n"
+"\n"
+"   This is similar to FTP, but you can specify a private key to use instead of\n"
+"   a password. Note that the private key may itself be protected by a password\n"
+"   that is unrelated to the login password of the remote system.  If you\n"
+"   provide a private key file you must also provide a public key file.\n"
+, stdout);
+ fputs(
+"\n"
+" HTTP\n"
+"\n"
+"   Curl also supports user and password in HTTP URLs, thus you can pick a file\n"
+"   like:\n"
+"\n"
+"        curl http://name:passwd@machine.domain/full/path/to/file\n"
+"\n"
+"   or specify user and password separately like in\n"
+"\n"
+"        curl -u name:passwd http://machine.domain/full/path/to/file\n"
+"\n"
+"   HTTP offers many different methods of authentication and curl supports\n"
+"   several: Basic, Digest, NTLM and Negotiate. Without telling which method to\n"
+, stdout);
+ fputs(
+"   use, curl defaults to Basic. You can also ask curl to pick the most secure\n"
+"   ones out of the ones that the server accepts for the given URL, by using\n"
+"   --anyauth.\n"
+"\n"
+"   NOTE! Since HTTP URLs don't support user and password, you can't use that\n"
+"   style when using Curl via a proxy. You _must_ use the -u style fetch\n"
+"   during such circumstances.\n"
+"\n"
+" HTTPS\n"
+"\n"
+"   Probably most commonly used with private certificates, as explained below.\n"
+"\n"
+"PROXY\n"
+"\n"
+, stdout);
+ fputs(
+" Get an ftp file using a proxy named my-proxy that uses port 888:\n"
+"\n"
+"        curl -x my-proxy:888 ftp://ftp.leachsite.com/README\n"
+"\n"
+" Get a file from a HTTP server that requires user and password, using the\n"
+" same proxy as above:\n"
+"\n"
+"        curl -u user:passwd -x my-proxy:888 http://www.get.this/\n"
+"\n"
+" Some proxies require special authentication. Specify by using -U as above:\n"
+"\n"
+"        curl -U user:passwd -x my-proxy:888 http://www.get.this/\n"
+"\n"
+, stdout);
+ fputs(
+" A comma-separated list of hosts and domains which do not use the proxy can\n"
+" be specified as:\n"
+"\n"
+"        curl --noproxy localhost,get.this -x my-proxy:888 http://www.get.this/\n"
+"\n"
+" If the proxy is specified with --proxy1.0 instead of --proxy or -x, then\n"
+" curl will use HTTP/1.0 instead of HTTP/1.1 for any CONNECT attempts.\n"
+"\n"
+" curl also supports SOCKS4 and SOCKS5 proxies with --socks4 and --socks5.\n"
+"\n"
+" See also the environment variables Curl support that offer further proxy\n"
+" control.\n"
+"\n"
+"RANGES\n"
+"\n"
+, stdout);
+ fputs(
+"  With HTTP 1.1 byte-ranges were introduced. Using this, a client can request\n"
+"  to get only one or more subparts of a specified document. Curl supports\n"
+"  this with the -r flag.\n"
+"\n"
+"  Get the first 100 bytes of a document:\n"
+"\n"
+"        curl -r 0-99 http://www.get.this/\n"
+"\n"
+"  Get the last 500 bytes of a document:\n"
+"\n"
+"        curl -r -500 http://www.get.this/\n"
+"\n"
+"  Curl also supports simple ranges for FTP files as well. Then you can only\n"
+"  specify start and stop position.\n"
+"\n"
+, stdout);
+ fputs(
+"  Get the first 100 bytes of a document using FTP:\n"
+"\n"
+"        curl -r 0-99 ftp://www.get.this/README\n"
+"\n"
+"UPLOADING\n"
+"\n"
+" FTP / FTPS / SFTP / SCP\n"
+"\n"
+"  Upload all data on stdin to a specified server:\n"
+"\n"
+"        curl -T - ftp://ftp.upload.com/myfile\n"
+"\n"
+"  Upload data from a specified file, login with user and password:\n"
+"\n"
+"        curl -T uploadfile -u user:passwd ftp://ftp.upload.com/myfile\n"
+"\n"
+"  Upload a local file to the remote site, and use the local file name remote\n"
+"  too:\n"
+"\n"
+, stdout);
+ fputs(
+"        curl -T uploadfile -u user:passwd ftp://ftp.upload.com/\n"
+"\n"
+"  Upload a local file to get appended to the remote file:\n"
+"\n"
+"        curl -T localfile -a ftp://ftp.upload.com/remotefile\n"
+"\n"
+"  Curl also supports ftp upload through a proxy, but only if the proxy is\n"
+"  configured to allow that kind of tunneling. If it does, you can run curl in\n"
+"  a fashion similar to:\n"
+"\n"
+"        curl --proxytunnel -x proxy:port -T localfile ftp.upload.com\n"
+"\n"
+" HTTP\n"
+"\n"
+"  Upload all data on stdin to a specified http site:\n"
+"\n"
+, stdout);
+ fputs(
+"        curl -T - http://www.upload.com/myfile\n"
+"\n"
+"  Note that the http server must have been configured to accept PUT before\n"
+"  this can be done successfully.\n"
+"\n"
+"  For other ways to do http data upload, see the POST section below.\n"
+"\n"
+"VERBOSE / DEBUG\n"
+"\n"
+"  If curl fails where it isn't supposed to, if the servers don't let you in,\n"
+"  if you can't understand the responses: use the -v flag to get verbose\n"
+"  fetching. Curl will output lots of info and what it sends and receives in\n"
+, stdout);
+ fputs(
+"  order to let the user see all client-server interaction (but it won't show\n"
+"  you the actual data).\n"
+"\n"
+"        curl -v ftp://ftp.upload.com/\n"
+"\n"
+"  To get even more details and information on what curl does, try using the\n"
+"  --trace or --trace-ascii options with a given file name to log to, like\n"
+"  this:\n"
+"\n"
+"        curl --trace trace.txt www.haxx.se\n"
+"\n"
+"\n"
+"DETAILED INFORMATION\n"
+"\n"
+"  Different protocols provide different ways of getting detailed information\n"
+, stdout);
+ fputs(
+"  about specific files/documents. To get curl to show detailed information\n"
+"  about a single file, you should use -I/--head option. It displays all\n"
+"  available info on a single file for HTTP and FTP. The HTTP information is a\n"
+"  lot more extensive.\n"
+"\n"
+"  For HTTP, you can get the header information (the same as -I would show)\n"
+"  shown before the data by using -i/--include. Curl understands the\n"
+"  -D/--dump-header option when getting files from both FTP and HTTP, and it\n"
+, stdout);
+ fputs(
+"  will then store the headers in the specified file.\n"
+"\n"
+"  Store the HTTP headers in a separate file (headers.txt in the example):\n"
+"\n"
+"        curl --dump-header headers.txt curl.haxx.se\n"
+"\n"
+"  Note that headers stored in a separate file can be very useful at a later\n"
+"  time if you want curl to use cookies sent by the server. More about that in\n"
+"  the cookies section.\n"
+"\n"
+"POST (HTTP)\n"
+"\n"
+"  It's easy to post data using curl. This is done using the -d <data>\n"
+"  option.  The post data must be urlencoded.\n"
+"\n"
+, stdout);
+ fputs(
+"  Post a simple \"name\" and \"phone\" guestbook.\n"
+"\n"
+"        curl -d \"name=Rafael%20Sagula&phone=3320780\" \\\n"
+"                http://www.where.com/guest.cgi\n"
+"\n"
+"  How to post a form with curl, lesson #1:\n"
+"\n"
+"  Dig out all the <input> tags in the form that you want to fill in. (There's\n"
+"  a perl program called formfind.pl on the curl site that helps with this).\n"
+"\n"
+"  If there's a \"normal\" post, you use -d to post. -d takes a full \"post\n"
+"  string\", which is in the format\n"
+"\n"
+, stdout);
+ fputs(
+"        <variable1>=<data1>&<variable2>=<data2>&...\n"
+"\n"
+"  The 'variable' names are the names set with \"name=\" in the <input> tags, and\n"
+"  the data is the contents you want to fill in for the inputs. The data *must*\n"
+"  be properly URL encoded. That means you replace space with + and that you\n"
+"  write weird letters with %XX where XX is the hexadecimal representation of\n"
+"  the letter's ASCII code.\n"
+"\n"
+"  Example:\n"
+"\n"
+"  (page located at http://www.formpost.com/getthis/\n"
+"\n"
+, stdout);
+ fputs(
+"        <form action=\"post.cgi\" method=\"post\">\n"
+"        <input name=user size=10>\n"
+"        <input name=pass type=password size=10>\n"
+"        <input name=id type=hidden value=\"blablabla\">\n"
+"        <input name=ding value=\"submit\">\n"
+"        </form>\n"
+"\n"
+"  We want to enter user 'foobar' with password '12345'.\n"
+"\n"
+"  To post to this, you enter a curl command line like:\n"
+"\n"
+"        curl -d \"user=foobar&pass=12345&id=blablabla&ding=submit\"  (continues)\n"
+"          http://www.formpost.com/getthis/post.cgi\n"
+"\n"
+"\n"
+, stdout);
+ fputs(
+"  While -d uses the application/x-www-form-urlencoded mime-type, generally\n"
+"  understood by CGI's and similar, curl also supports the more capable\n"
+"  multipart/form-data type. This latter type supports things like file upload.\n"
+"\n"
+"  -F accepts parameters like -F \"name=contents\". If you want the contents to\n"
+"  be read from a file, use <@filename> as contents. When specifying a file,\n"
+"  you can also specify the file content type by appending ';type=<mime type>'\n"
+, stdout);
+ fputs(
+"  to the file name. You can also post the contents of several files in one\n"
+"  field.  For example, the field name 'coolfiles' is used to send three files,\n"
+"  with different content types using the following syntax:\n"
+"\n"
+"        curl -F \"coolfiles=@fil1.gif;type=image/gif,fil2.txt,fil3.html\" \\\n"
+"        http://www.post.com/postit.cgi\n"
+"\n"
+"  If the content-type is not specified, curl will try to guess from the file\n"
+"  extension (it only knows a few), or use the previously specified type (from\n"
+, stdout);
+ fputs(
+"  an earlier file if several files are specified in a list) or else it will\n"
+"  using the default type 'text/plain'.\n"
+"\n"
+"  Emulate a fill-in form with -F. Let's say you fill in three fields in a\n"
+"  form. One field is a file name which to post, one field is your name and one\n"
+"  field is a file description. We want to post the file we have written named\n"
+"  \"cooltext.txt\". To let curl do the posting of this data instead of your\n"
+"  favourite browser, you have to read the HTML source of the form page and\n"
+, stdout);
+ fputs(
+"  find the names of the input fields. In our example, the input field names\n"
+"  are 'file', 'yourname' and 'filedescription'.\n"
+"\n"
+"        curl -F \"file=@cooltext.txt\" -F \"yourname=Daniel\" \\\n"
+"             -F \"filedescription=Cool text file with cool text inside\" \\\n"
+"             http://www.post.com/postit.cgi\n"
+"\n"
+"  To send two files in one post you can do it in two ways:\n"
+"\n"
+"  1. Send multiple files in a single \"field\" with a single field name:\n"
+"\n"
+"        curl -F \"pictures=@dog.gif,cat.gif\"\n"
+"\n"
+, stdout);
+ fputs(
+"  2. Send two fields with two field names:\n"
+"\n"
+"        curl -F \"docpicture=@dog.gif\" -F \"catpicture=@cat.gif\"\n"
+"\n"
+"  To send a field value literally without interpreting a leading '@'\n"
+"  or '<', or an embedded ';type=', use --form-string instead of\n"
+"  -F. This is recommended when the value is obtained from a user or\n"
+"  some other unpredictable source. Under these circumstances, using\n"
+"  -F instead of --form-string would allow a user to trick curl into\n"
+"  uploading a file.\n"
+"\n"
+"REFERRER\n"
+"\n"
+, stdout);
+ fputs(
+"  A HTTP request has the option to include information about which address\n"
+"  that referred to actual page.  Curl allows you to specify the\n"
+"  referrer to be used on the command line. It is especially useful to\n"
+"  fool or trick stupid servers or CGI scripts that rely on that information\n"
+"  being available or contain certain data.\n"
+"\n"
+"        curl -e www.coolsite.com http://www.showme.com/\n"
+"\n"
+"  NOTE: The Referer: [sic] field is defined in the HTTP spec to be a full URL.\n"
+"\n"
+"USER AGENT\n"
+"\n"
+, stdout);
+ fputs(
+"  A HTTP request has the option to include information about the browser\n"
+"  that generated the request. Curl allows it to be specified on the command\n"
+"  line. It is especially useful to fool or trick stupid servers or CGI\n"
+"  scripts that only accept certain browsers.\n"
+"\n"
+"  Example:\n"
+"\n"
+"  curl -A 'Mozilla/3.0 (Win95; I)' http://www.nationsbank.com/\n"
+"\n"
+"  Other common strings:\n"
+"    'Mozilla/3.0 (Win95; I)'     Netscape Version 3 for Windows 95\n"
+"    'Mozilla/3.04 (Win95; U)'    Netscape Version 3 for Windows 95\n"
+, stdout);
+ fputs(
+"    'Mozilla/2.02 (OS/2; U)'     Netscape Version 2 for OS/2\n"
+"    'Mozilla/4.04 [en] (X11; U; AIX 4.2; Nav)'           NS for AIX\n"
+"    'Mozilla/4.05 [en] (X11; U; Linux 2.0.32 i586)'      NS for Linux\n"
+"\n"
+"  Note that Internet Explorer tries hard to be compatible in every way:\n"
+"    'Mozilla/4.0 (compatible; MSIE 4.01; Windows 95)'    MSIE for W95\n"
+"\n"
+"  Mozilla is not the only possible User-Agent name:\n"
+"    'Konqueror/1.0'             KDE File Manager desktop client\n"
+, stdout);
+ fputs(
+"    'Lynx/2.7.1 libwww-FM/2.14' Lynx command line browser\n"
+"\n"
+"COOKIES\n"
+"\n"
+"  Cookies are generally used by web servers to keep state information at the\n"
+"  client's side. The server sets cookies by sending a response line in the\n"
+"  headers that looks like 'Set-Cookie: <data>' where the data part then\n"
+"  typically contains a set of NAME=VALUE pairs (separated by semicolons ';'\n"
+"  like \"NAME1=VALUE1; NAME2=VALUE2;\"). The server can also specify for what\n"
+, stdout);
+ fputs(
+"  path the \"cookie\" should be used for (by specifying \"path=value\"), when the\n"
+"  cookie should expire (\"expire=DATE\"), for what domain to use it\n"
+"  (\"domain=NAME\") and if it should be used on secure connections only\n"
+"  (\"secure\").\n"
+"\n"
+"  If you've received a page from a server that contains a header like:\n"
+"        Set-Cookie: sessionid=boo123; path=\"/foo\";\n"
+"\n"
+"  it means the server wants that first pair passed on when we get anything in\n"
+"  a path beginning with \"/foo\".\n"
+"\n"
+, stdout);
+ fputs(
+"  Example, get a page that wants my name passed in a cookie:\n"
+"\n"
+"        curl -b \"name=Daniel\" www.sillypage.com\n"
+"\n"
+"  Curl also has the ability to use previously received cookies in following\n"
+"  sessions. If you get cookies from a server and store them in a file in a\n"
+"  manner similar to:\n"
+"\n"
+"        curl --dump-header headers www.example.com\n"
+"\n"
+"  ... you can then in a second connect to that (or another) site, use the\n"
+"  cookies from the 'headers' file like:\n"
+"\n"
+"        curl -b headers www.example.com\n"
+"\n"
+, stdout);
+ fputs(
+"  While saving headers to a file is a working way to store cookies, it is\n"
+"  however error-prone and not the preferred way to do this. Instead, make curl\n"
+"  save the incoming cookies using the well-known netscape cookie format like\n"
+"  this:\n"
+"\n"
+"        curl -c cookies.txt www.example.com\n"
+"\n"
+"  Note that by specifying -b you enable the \"cookie awareness\" and with -L\n"
+"  you can make curl follow a location: (which often is used in combination\n"
+, stdout);
+ fputs(
+"  with cookies). So that if a site sends cookies and a location, you can\n"
+"  use a non-existing file to trigger the cookie awareness like:\n"
+"\n"
+"        curl -L -b empty.txt www.example.com\n"
+"\n"
+"  The file to read cookies from must be formatted using plain HTTP headers OR\n"
+"  as netscape's cookie file. Curl will determine what kind it is based on the\n"
+"  file contents.  In the above command, curl will parse the header and store\n"
+"  the cookies received from www.example.com.  curl will send to the server the\n"
+, stdout);
+ fputs(
+"  stored cookies which match the request as it follows the location.  The\n"
+"  file \"empty.txt\" may be a nonexistent file.\n"
+"\n"
+"  Alas, to both read and write cookies from a netscape cookie file, you can\n"
+"  set both -b and -c to use the same file:\n"
+"\n"
+"        curl -b cookies.txt -c cookies.txt www.example.com\n"
+"\n"
+"PROGRESS METER\n"
+"\n"
+"  The progress meter exists to show a user that something actually is\n"
+"  happening. The different fields in the output have the following meaning:\n"
+"\n"
+, stdout);
+ fputs(
+"  % Total    % Received % Xferd  Average Speed          Time             Curr.\n"
+"                                 Dload  Upload Total    Current  Left    Speed\n"
+"  0  151M    0 38608    0     0   9406      0  4:41:43  0:00:04  4:41:39  9287\n"
+"\n"
+"  From left-to-right:\n"
+"   %             - percentage completed of the whole transfer\n"
+"   Total         - total size of the whole expected transfer\n"
+"   %             - percentage completed of the download\n"
+"   Received      - currently downloaded amount of bytes\n"
+, stdout);
+ fputs(
+"   %             - percentage completed of the upload\n"
+"   Xferd         - currently uploaded amount of bytes\n"
+"   Average Speed\n"
+"   Dload         - the average transfer speed of the download\n"
+"   Average Speed\n"
+"   Upload        - the average transfer speed of the upload\n"
+"   Time Total    - expected time to complete the operation\n"
+"   Time Current  - time passed since the invoke\n"
+"   Time Left     - expected time left to completion\n"
+"   Curr.Speed    - the average transfer speed the last 5 seconds (the first\n"
+, stdout);
+ fputs(
+"                   5 seconds of a transfer is based on less time of course.)\n"
+"\n"
+"  The -# option will display a totally different progress bar that doesn't\n"
+"  need much explanation!\n"
+"\n"
+"SPEED LIMIT\n"
+"\n"
+"  Curl allows the user to set the transfer speed conditions that must be met\n"
+"  to let the transfer keep going. By using the switch -y and -Y you\n"
+"  can make curl abort transfers if the transfer speed is below the specified\n"
+"  lowest limit for a specified time.\n"
+"\n"
+, stdout);
+ fputs(
+"  To have curl abort the download if the speed is slower than 3000 bytes per\n"
+"  second for 1 minute, run:\n"
+"\n"
+"        curl -Y 3000 -y 60 www.far-away-site.com\n"
+"\n"
+"  This can very well be used in combination with the overall time limit, so\n"
+"  that the above operation must be completed in whole within 30 minutes:\n"
+"\n"
+"        curl -m 1800 -Y 3000 -y 60 www.far-away-site.com\n"
+"\n"
+"  Forcing curl not to transfer data faster than a given rate is also possible,\n"
+, stdout);
+ fputs(
+"  which might be useful if you're using a limited bandwidth connection and you\n"
+"  don't want your transfer to use all of it (sometimes referred to as\n"
+"  \"bandwidth throttle\").\n"
+"\n"
+"  Make curl transfer data no faster than 10 kilobytes per second:\n"
+"\n"
+"        curl --limit-rate 10K www.far-away-site.com\n"
+"\n"
+"    or\n"
+"\n"
+"        curl --limit-rate 10240 www.far-away-site.com\n"
+"\n"
+"  Or prevent curl from uploading data faster than 1 megabyte per second:\n"
+"\n"
+"        curl -T upload --limit-rate 1M ftp://uploadshereplease.com\n"
+"\n"
+, stdout);
+ fputs(
+"  When using the --limit-rate option, the transfer rate is regulated on a\n"
+"  per-second basis, which will cause the total transfer speed to become lower\n"
+"  than the given number. Sometimes of course substantially lower, if your\n"
+"  transfer stalls during periods.\n"
+"\n"
+"CONFIG FILE\n"
+"\n"
+"  Curl automatically tries to read the .curlrc file (or _curlrc file on win32\n"
+"  systems) from the user's home dir on startup.\n"
+"\n"
+"  The config file could be made up with normal command line switches, but you\n"
+, stdout);
+ fputs(
+"  can also specify the long options without the dashes to make it more\n"
+"  readable. You can separate the options and the parameter with spaces, or\n"
+"  with = or :. Comments can be used within the file. If the first letter on a\n"
+"  line is a '#'-symbol the rest of the line is treated as a comment.\n"
+"\n"
+"  If you want the parameter to contain spaces, you must enclose the entire\n"
+"  parameter within double quotes (\"). Within those quotes, you specify a\n"
+"  quote as \\\".\n"
+"\n"
+, stdout);
+ fputs(
+"  NOTE: You must specify options and their arguments on the same line.\n"
+"\n"
+"  Example, set default time out and proxy in a config file:\n"
+"\n"
+"        # We want a 30 minute timeout:\n"
+"        -m 1800\n"
+"        # ... and we use a proxy for all accesses:\n"
+"        proxy = proxy.our.domain.com:8080\n"
+"\n"
+"  White spaces ARE significant at the end of lines, but all white spaces\n"
+"  leading up to the first characters of each line are ignored.\n"
+"\n"
+"  Prevent curl from reading the default file by using -q as the first command\n"
+, stdout);
+ fputs(
+"  line parameter, like:\n"
+"\n"
+"        curl -q www.thatsite.com\n"
+"\n"
+"  Force curl to get and display a local help page in case it is invoked\n"
+"  without URL by making a config file similar to:\n"
+"\n"
+"        # default url to get\n"
+"        url = \"http://help.with.curl.com/curlhelp.html\"\n"
+"\n"
+"  You can specify another config file to be read by using the -K/--config\n"
+"  flag. If you set config file name to \"-\" it'll read the config from stdin,\n"
+"  which can be handy if you want to hide options from being visible in process\n"
+, stdout);
+ fputs(
+"  tables etc:\n"
+"\n"
+"        echo \"user = user:passwd\" | curl -K - http://that.secret.site.com\n"
+"\n"
+"EXTRA HEADERS\n"
+"\n"
+"  When using curl in your own very special programs, you may end up needing\n"
+"  to pass on your own custom headers when getting a web page. You can do\n"
+"  this by using the -H flag.\n"
+"\n"
+"  Example, send the header \"X-you-and-me: yes\" to the server when getting a\n"
+"  page:\n"
+"\n"
+"        curl -H \"X-you-and-me: yes\" www.love.com\n"
+"\n"
+"  This can also be useful in case you want curl to send a different text in a\n"
+, stdout);
+ fputs(
+"  header than it normally does. The -H header you specify then replaces the\n"
+"  header curl would normally send. If you replace an internal header with an\n"
+"  empty one, you prevent that header from being sent. To prevent the Host:\n"
+"  header from being used:\n"
+"\n"
+"        curl -H \"Host:\" www.server.com\n"
+"\n"
+"FTP and PATH NAMES\n"
+"\n"
+"  Do note that when getting files with the ftp:// URL, the given path is\n"
+"  relative the directory you enter. To get the file 'README' from your home\n"
+"  directory at your ftp site, do:\n"
+"\n"
+, stdout);
+ fputs(
+"        curl ftp://user:passwd@my.site.com/README\n"
+"\n"
+"  But if you want the README file from the root directory of that very same\n"
+"  site, you need to specify the absolute file name:\n"
+"\n"
+"        curl ftp://user:passwd@my.site.com//README\n"
+"\n"
+"  (I.e with an extra slash in front of the file name.)\n"
+"\n"
+"SFTP and SCP and PATH NAMES\n"
+"\n"
+"  With sftp: and scp: URLs, the path name given is the absolute name on the\n"
+"  server. To access a file relative to the remote user's home directory,\n"
+, stdout);
+ fputs(
+"  prefix the file with /~/ , such as:\n"
+"\n"
+"        curl -u $USER sftp://home.example.com/~/.bashrc\n"
+"\n"
+"FTP and firewalls\n"
+"\n"
+"  The FTP protocol requires one of the involved parties to open a second\n"
+"  connection as soon as data is about to get transfered. There are two ways to\n"
+"  do this.\n"
+"\n"
+"  The default way for curl is to issue the PASV command which causes the\n"
+"  server to open another port and await another connection performed by the\n"
+, stdout);
+ fputs(
+"  client. This is good if the client is behind a firewall that don't allow\n"
+"  incoming connections.\n"
+"\n"
+"        curl ftp.download.com\n"
+"\n"
+"  If the server for example, is behind a firewall that don't allow connections\n"
+"  on other ports than 21 (or if it just doesn't support the PASV command), the\n"
+"  other way to do it is to use the PORT command and instruct the server to\n"
+"  connect to the client on the given (as parameters to the PORT command) IP\n"
+"  number and port.\n"
+"\n"
+, stdout);
+ fputs(
+"  The -P flag to curl supports a few different options. Your machine may have\n"
+"  several IP-addresses and/or network interfaces and curl allows you to select\n"
+"  which of them to use. Default address can also be used:\n"
+"\n"
+"        curl -P - ftp.download.com\n"
+"\n"
+"  Download with PORT but use the IP address of our 'le0' interface (this does\n"
+"  not work on windows):\n"
+"\n"
+"        curl -P le0 ftp.download.com\n"
+"\n"
+"  Download with PORT but use 192.168.0.10 as our IP address to use:\n"
+"\n"
+, stdout);
+ fputs(
+"        curl -P 192.168.0.10 ftp.download.com\n"
+"\n"
+"NETWORK INTERFACE\n"
+"\n"
+"  Get a web page from a server using a specified port for the interface:\n"
+"\n"
+"        curl --interface eth0:1 http://www.netscape.com/\n"
+"\n"
+"  or\n"
+"\n"
+"        curl --interface 192.168.1.10 http://www.netscape.com/\n"
+"\n"
+"HTTPS\n"
+"\n"
+"  Secure HTTP requires SSL libraries to be installed and used when curl is\n"
+"  built. If that is done, curl is capable of retrieving and posting documents\n"
+"  using the HTTPS protocol.\n"
+"\n"
+"  Example:\n"
+"\n"
+, stdout);
+ fputs(
+"        curl https://www.secure-site.com\n"
+"\n"
+"  Curl is also capable of using your personal certificates to get/post files\n"
+"  from sites that require valid certificates. The only drawback is that the\n"
+"  certificate needs to be in PEM-format. PEM is a standard and open format to\n"
+"  store certificates with, but it is not used by the most commonly used\n"
+"  browsers (Netscape and MSIE both use the so called PKCS#12 format). If you\n"
+, stdout);
+ fputs(
+"  want curl to use the certificates you use with your (favourite) browser, you\n"
+"  may need to download/compile a converter that can convert your browser's\n"
+"  formatted certificates to PEM formatted ones. This kind of converter is\n"
+"  included in recent versions of OpenSSL, and for older versions Dr Stephen\n"
+"  N. Henson has written a patch for SSLeay that adds this functionality. You\n"
+"  can get his patch (that requires an SSLeay installation) from his site at:\n"
+"  http://www.drh-consultancy.demon.co.uk/\n"
+, stdout);
+ fputs(
+"\n"
+"  Example on how to automatically retrieve a document using a certificate with\n"
+"  a personal password:\n"
+"\n"
+"        curl -E /path/to/cert.pem:password https://secure.site.com/\n"
+"\n"
+"  If you neglect to specify the password on the command line, you will be\n"
+"  prompted for the correct password before any data can be received.\n"
+"\n"
+"  Many older SSL-servers have problems with SSLv3 or TLS, that newer versions\n"
+"  of OpenSSL etc is using, therefore it is sometimes useful to specify what\n"
+, stdout);
+ fputs(
+"  SSL-version curl should use. Use -3, -2 or -1 to specify that exact SSL\n"
+"  version to use (for SSLv3, SSLv2 or TLSv1 respectively):\n"
+"\n"
+"        curl -2 https://secure.site.com/\n"
+"\n"
+"  Otherwise, curl will first attempt to use v3 and then v2.\n"
+"\n"
+"  To use OpenSSL to convert your favourite browser's certificate into a PEM\n"
+"  formatted one that curl can use, do something like this (assuming netscape,\n"
+"  but IE is likely to work similarly):\n"
+"\n"
+"    You start with hitting the 'security' menu button in netscape.\n"
+"\n"
+, stdout);
+ fputs(
+"    Select 'certificates->yours' and then pick a certificate in the list\n"
+"\n"
+"    Press the 'export' button\n"
+"\n"
+"    enter your PIN code for the certs\n"
+"\n"
+"    select a proper place to save it\n"
+"\n"
+"    Run the 'openssl' application to convert the certificate. If you cd to the\n"
+"    openssl installation, you can do it like:\n"
+"\n"
+"     # ./apps/openssl pkcs12 -in [file you saved] -clcerts -out [PEMfile]\n"
+"\n"
+"\n"
+"RESUMING FILE TRANSFERS\n"
+"\n"
+" To continue a file transfer where it was previously aborted, curl supports\n"
+, stdout);
+ fputs(
+" resume on http(s) downloads as well as ftp uploads and downloads.\n"
+"\n"
+" Continue downloading a document:\n"
+"\n"
+"        curl -C - -o file ftp://ftp.server.com/path/file\n"
+"\n"
+" Continue uploading a document(*1):\n"
+"\n"
+"        curl -C - -T file ftp://ftp.server.com/path/file\n"
+"\n"
+" Continue downloading a document from a web server(*2):\n"
+"\n"
+"        curl -C - -o file http://www.server.com/\n"
+"\n"
+" (*1) = This requires that the ftp server supports the non-standard command\n"
+"        SIZE. If it doesn't, curl will say so.\n"
+"\n"
+, stdout);
+ fputs(
+" (*2) = This requires that the web server supports at least HTTP/1.1. If it\n"
+"        doesn't, curl will say so.\n"
+"\n"
+"TIME CONDITIONS\n"
+"\n"
+" HTTP allows a client to specify a time condition for the document it\n"
+" requests. It is If-Modified-Since or If-Unmodified-Since. Curl allow you to\n"
+" specify them with the -z/--time-cond flag.\n"
+"\n"
+" For example, you can easily make a download that only gets performed if the\n"
+" remote file is newer than a local copy. It would be made like:\n"
+"\n"
+, stdout);
+ fputs(
+"        curl -z local.html http://remote.server.com/remote.html\n"
+"\n"
+" Or you can download a file only if the local file is newer than the remote\n"
+" one. Do this by prepending the date string with a '-', as in:\n"
+"\n"
+"        curl -z -local.html http://remote.server.com/remote.html\n"
+"\n"
+" You can specify a \"free text\" date as condition. Tell curl to only download\n"
+" the file if it was updated since January 12, 2012:\n"
+"\n"
+"        curl -z \"Jan 12 2012\" http://remote.server.com/remote.html\n"
+"\n"
+, stdout);
+ fputs(
+" Curl will then accept a wide range of date formats. You always make the date\n"
+" check the other way around by prepending it with a dash '-'.\n"
+"\n"
+"DICT\n"
+"\n"
+"  For fun try\n"
+"\n"
+"        curl dict://dict.org/m:curl\n"
+"        curl dict://dict.org/d:heisenbug:jargon\n"
+"        curl dict://dict.org/d:daniel:web1913\n"
+"\n"
+"  Aliases for 'm' are 'match' and 'find', and aliases for 'd' are 'define'\n"
+"  and 'lookup'. For example,\n"
+"\n"
+"        curl dict://dict.org/find:curl\n"
+"\n"
+, stdout);
+ fputs(
+"  Commands that break the URL description of the RFC (but not the DICT\n"
+"  protocol) are\n"
+"\n"
+"        curl dict://dict.org/show:db\n"
+"        curl dict://dict.org/show:strat\n"
+"\n"
+"  Authentication is still missing (but this is not required by the RFC)\n"
+"\n"
+"LDAP\n"
+"\n"
+"  If you have installed the OpenLDAP library, curl can take advantage of it\n"
+"  and offer ldap:// support.\n"
+"\n"
+"  LDAP is a complex thing and writing an LDAP query is not an easy task. I do\n"
+, stdout);
+ fputs(
+"  advice you to dig up the syntax description for that elsewhere. Two places\n"
+"  that might suit you are:\n"
+"\n"
+"  Netscape's \"Netscape Directory SDK 3.0 for C Programmer's Guide Chapter 10:\n"
+"  Working with LDAP URLs\":\n"
+"  http://developer.netscape.com/docs/manuals/dirsdk/csdk30/url.htm\n"
+"\n"
+"  RFC 2255, \"The LDAP URL Format\" http://curl.haxx.se/rfc/rfc2255.txt\n"
+"\n"
+"  To show you an example, this is now I can get all people from my local LDAP\n"
+"  server that has a certain sub-domain in their email address:\n"
+"\n"
+, stdout);
+ fputs(
+"        curl -B \"ldap://ldap.frontec.se/o=frontec??sub?mail=*sth.frontec.se\"\n"
+"\n"
+"  If I want the same info in HTML format, I can get it by not using the -B\n"
+"  (enforce ASCII) flag.\n"
+"\n"
+"ENVIRONMENT VARIABLES\n"
+"\n"
+"  Curl reads and understands the following environment variables:\n"
+"\n"
+"        http_proxy, HTTPS_PROXY, FTP_PROXY\n"
+"\n"
+"  They should be set for protocol-specific proxies. General proxy should be\n"
+"  set with\n"
+"\n"
+"        ALL_PROXY\n"
+"\n"
+"  A comma-separated list of host names that shouldn't go through any proxy is\n"
+, stdout);
+ fputs(
+"  set in (only an asterisk, '*' matches all hosts)\n"
+"\n"
+"        NO_PROXY\n"
+"\n"
+"  If the host name matches one of these strings, or the host is within the\n"
+"  domain of one of these strings, transactions with that node will not be\n"
+"  proxied.\n"
+"\n"
+"\n"
+"  The usage of the -x/--proxy flag overrides the environment variables.\n"
+"\n"
+"NETRC\n"
+"\n"
+"  Unix introduced the .netrc concept a long time ago. It is a way for a user\n"
+"  to specify name and password for commonly visited ftp sites in a file so\n"
+, stdout);
+ fputs(
+"  that you don't have to type them in each time you visit those sites. You\n"
+"  realize this is a big security risk if someone else gets hold of your\n"
+"  passwords, so therefore most unix programs won't read this file unless it is\n"
+"  only readable by yourself (curl doesn't care though).\n"
+"\n"
+"  Curl supports .netrc files if told so (using the -n/--netrc and\n"
+"  --netrc-optional options). This is not restricted to only ftp,\n"
+"  but curl can use it for all protocols where authentication is used.\n"
+"\n"
+, stdout);
+ fputs(
+"  A very simple .netrc file could look something like:\n"
+"\n"
+"        machine curl.haxx.se login iamdaniel password mysecret\n"
+"\n"
+"CUSTOM OUTPUT\n"
+"\n"
+"  To better allow script programmers to get to know about the progress of\n"
+"  curl, the -w/--write-out option was introduced. Using this, you can specify\n"
+"  what information from the previous transfer you want to extract.\n"
+"\n"
+"  To display the amount of bytes downloaded together with some text and an\n"
+"  ending newline:\n"
+"\n"
+, stdout);
+ fputs(
+"        curl -w 'We downloaded %{size_download} bytes\\n' www.download.com\n"
+"\n"
+"KERBEROS FTP TRANSFER\n"
+"\n"
+"  Curl supports kerberos4 and kerberos5/GSSAPI for FTP transfers. You need\n"
+"  the kerberos package installed and used at curl build time for it to be\n"
+"  used.\n"
+"\n"
+"  First, get the krb-ticket the normal way, like with the kinit/kauth tool.\n"
+"  Then use curl in way similar to:\n"
+"\n"
+"        curl --krb private ftp://krb4site.com -u username:fakepwd\n"
+"\n"
+, stdout);
+ fputs(
+"  There's no use for a password on the -u switch, but a blank one will make\n"
+"  curl ask for one and you already entered the real password to kinit/kauth.\n"
+"\n"
+"TELNET\n"
+"\n"
+"  The curl telnet support is basic and very easy to use. Curl passes all data\n"
+"  passed to it on stdin to the remote server. Connect to a remote telnet\n"
+"  server using a command line similar to:\n"
+"\n"
+"        curl telnet://remote.server.com\n"
+"\n"
+"  And enter the data to pass to the server on stdin. The result will be sent\n"
+, stdout);
+ fputs(
+"  to stdout or to the file you specify with -o.\n"
+"\n"
+"  You might want the -N/--no-buffer option to switch off the buffered output\n"
+"  for slow connections or similar.\n"
+"\n"
+"  Pass options to the telnet protocol negotiation, by using the -t option. To\n"
+"  tell the server we use a vt100 terminal, try something like:\n"
+"\n"
+"        curl -tTTYPE=vt100 telnet://remote.server.com\n"
+"\n"
+"  Other interesting options for it -t include:\n"
+"\n"
+"   - XDISPLOC=<X display> Sets the X display location.\n"
+"\n"
+, stdout);
+ fputs(
+"   - NEW_ENV=<var,val> Sets an environment variable.\n"
+"\n"
+"  NOTE: the telnet protocol does not specify any way to login with a specified\n"
+"  user and password so curl can't do that automatically. To do that, you need\n"
+"  to track when the login prompt is received and send the username and\n"
+"  password accordingly.\n"
+"\n"
+"PERSISTENT CONNECTIONS\n"
+"\n"
+"  Specifying multiple files on a single command line will make curl transfer\n"
+"  all of them, one after the other in the specified order.\n"
+"\n"
+, stdout);
+ fputs(
+"  libcurl will attempt to use persistent connections for the transfers so that\n"
+"  the second transfer to the same host can use the same connection that was\n"
+"  already initiated and was left open in the previous transfer. This greatly\n"
+"  decreases connection time for all but the first transfer and it makes a far\n"
+"  better use of the network.\n"
+"\n"
+"  Note that curl cannot use persistent connections for transfers that are used\n"
+"  in subsequence curl invokes. Try to stuff as many URLs as possible on the\n"
+, stdout);
+ fputs(
+"  same command line if they are using the same host, as that'll make the\n"
+"  transfers faster. If you use a http proxy for file transfers, practically\n"
+"  all transfers will be persistent.\n"
+"\n"
+"MULTIPLE TRANSFERS WITH A SINGLE COMMAND LINE\n"
+"\n"
+"  As is mentioned above, you can download multiple files with one command line\n"
+"  by simply adding more URLs. If you want those to get saved to a local file\n"
+"  instead of just printed to stdout, you need to add one save option for each\n"
+, stdout);
+ fputs(
+"  URL you specify. Note that this also goes for the -O option (but not\n"
+"  --remote-name-all).\n"
+"\n"
+"  For example: get two files and use -O for the first and a custom file\n"
+"  name for the second:\n"
+"\n"
+"    curl -O http://url.com/file.txt ftp://ftp.com/moo.exe -o moo.jpg\n"
+"\n"
+"  You can also upload multiple files in a similar fashion:\n"
+"\n"
+"    curl -T local1 ftp://ftp.com/moo.exe -T local2 ftp://ftp.com/moo2.txt\n"
+"\n"
+"IPv6\n"
+"\n"
+"  curl will connect to a server with IPv6 when a host lookup returns an IPv6\n"
+, stdout);
+ fputs(
+"  address and fall back to IPv4 if the connection fails. The --ipv4 and --ipv6\n"
+"  options can specify which address to use when both are available. IPv6\n"
+"  addresses can also be specified directly in URLs using the syntax:\n"
+"\n"
+"    http://[2001:1890:1112:1::20]/overview.html\n"
+"\n"
+"  When this style is used, the -g option must be given to stop curl from\n"
+"  interpreting the square brackets as special globbing characters.  Link local\n"
+, stdout);
+ fputs(
+"  and site local addresses including a scope identifier, such as fe80::1234%1,\n"
+"  may also be used, but the scope portion must be numeric and the percent\n"
+"  character must be URL escaped. The previous example in an SFTP URL might\n"
+"  look like:\n"
+"\n"
+"    sftp://[fe80::1234%251]/\n"
+"\n"
+"  IPv6 addresses provided other than in URLs (e.g. to the --proxy, --interface\n"
+"  or --ftp-port options) should not be URL encoded.\n"
+"\n"
+"\n"
+"MAILING LISTS\n"
+"\n"
+"  For your convenience, we have several open mailing lists to discuss curl,\n"
+, stdout);
+ fputs(
+"  its development and things relevant to this. Get all info at\n"
+"  http://curl.haxx.se/mail/. Some of the lists available are:\n"
+"\n"
+"  curl-users\n"
+"\n"
+"    Users of the command line tool. How to use it, what doesn't work, new\n"
+"    features, related tools, questions, news, installations, compilations,\n"
+"    running, porting etc.\n"
+"\n"
+"  curl-library\n"
+"\n"
+"    Developers using or developing libcurl. Bugs, extensions, improvements.\n"
+"\n"
+"  curl-announce\n"
+"\n"
+, stdout);
+ fputs(
+"    Low-traffic. Only receives announcements of new public versions. At worst,\n"
+"    that makes something like one or two mails per month, but usually only one\n"
+"    mail every second month.\n"
+"\n"
+"  curl-and-php\n"
+"\n"
+"    Using the curl functions in PHP. Everything curl with a PHP angle. Or PHP\n"
+"    with a curl angle.\n"
+"\n"
+"  curl-and-python\n"
+"\n"
+"    Python hackers using curl with or without the python binding pycurl.\n"
+"\n"
+"  Please direct curl questions, feature requests and trouble reports to one of\n"
+, stdout);
+ fputs(
+"  these mailing lists instead of mailing any individual.\n"
+, stdout) ;
+}
+#endif /* USE_MANUAL */
+#else
+/*
+ * NEVER EVER edit this manually, fix the mkhelp.pl script instead!
+ * Generation time: Sun Mar 28 23:35:15 2010
+ */
+#include "setup.h"
+#ifdef USE_MANUAL
+#include "hugehelp.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <zlib.h>
+static const unsigned char hugehelpgz[] = {
+  /* This mumbo-jumbo is the huge help text compressed with gzip.
+     Thanks to this operation, the size of this data shrunk from 130818
+     to 40275 bytes. You can disable the use of compressed help
+     texts by NOT passing -c to the mkhelp.pl tool. */
+  0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03, 0xed, 0xbd,
+  0x7b, 0x5b, 0x23, 0xd7, 0xb1, 0x2e, 0xfe, 0x3f, 0x9f, 0xa2, 0x23, 0xff,
+  0x12, 0x41, 0x22, 0x89, 0xcb, 0x5c, 0xec, 0x21, 0x33, 0xde, 0xc6, 0xc0,
+  0xd8, 0x6c, 0x33, 0x03, 0x07, 0x31, 0xbe, 0x1c, 0xc7, 0xcf, 0x3c, 0x2d,
+  0xa9, 0x81, 0x0e, 0x92, 0x5a, 0xe9, 0x6e, 0x01, 0x72, 0x76, 0xf6, 0x67,
+  0x3f, 0x55, 0x6f, 0x55, 0xad, 0xb5, 0xfa, 0x22, 0x66, 0x9c, 0xd8, 0x39,
+  0xbf, 0x73, 0x9e, 0x93, 0xbd, 0x3d, 0x80, 0xd4, 0xbd, 0xae, 0xb5, 0x6a,
+  0xd5, 0xf5, 0xad, 0x28, 0xfa, 0xd0, 0xff, 0xde, 0xe3, 0xbf, 0xf7, 0xf4,
+  0x3f, 0xfa, 0xb9, 0x11, 0x45, 0xe7, 0x79, 0xf6, 0xd7, 0x64, 0x5c, 0xb6,
+  0x3f, 0xfb, 0xfe, 0xfd, 0x7f, 0x45, 0xf2, 0x7f, 0xf4, 0xce, 0x5f, 0xe8,
+  0xe7, 0xc6, 0xa3, 0x6d, 0x6f, 0x47, 0xfe, 0x85, 0xff, 0x7a, 0xbf, 0x15,
+  0x7d, 0xe8, 0x85, 0xff, 0x8a, 0x36, 0xf1, 0xc2, 0x7b, 0xed, 0xe1, 0x25,
+  0xff, 0xfe, 0xfe, 0xfd, 0xe3, 0x9d, 0xfc, 0x85, 0x47, 0xc5, 0xff, 0x6c,
+  0xf3, 0x7b, 0x7f, 0x79, 0xcf, 0xbf, 0xd2, 0x27, 0x1b, 0x1b, 0x6f, 0x0f,
+  0xde, 0x1c, 0xdb, 0xab, 0xe3, 0x65, 0x3e, 0x8d, 0xfa, 0x51, 0x99, 0xc7,
+  0xf3, 0xe2, 0x2a, 0xc9, 0xa3, 0x38, 0x7a, 0x77, 0x71, 0xba, 0xb1, 0x31,
+  0xfc, 0xe1, 0xed, 0xd9, 0xf9, 0xf0, 0x64, 0x58, 0x79, 0xec, 0xc7, 0x6c,
+  0x51, 0xa6, 0xd9, 0xbc, 0xf8, 0x29, 0xfa, 0x91, 0x1e, 0x1a, 0x0c, 0x06,
+  0x3f, 0x6d, 0x6c, 0x1c, 0x1d, 0x0f, 0x0f, 0x2f, 0x4e, 0xce, 0x2f, 0x4f,
+  0xce, 0xde, 0x56, 0x9e, 0x8d, 0xd2, 0x22, 0xa2, 0xc6, 0xca, 0x2c, 0x9b,
+  0xd2, 0x3f, 0xbe, 0xfd, 0x49, 0x5c, 0xc6, 0xd1, 0x55, 0x9e, 0xcd, 0xa2,
+  0x2c, 0xe7, 0x2f, 0xe2, 0xa8, 0x48, 0xf2, 0xbb, 0x24, 0xef, 0x45, 0xcb,
+  0x22, 0x9d, 0x5f, 0x47, 0xd9, 0x3c, 0x89, 0xb2, 0xab, 0xa8, 0xbc, 0x49,
+  0xac, 0xb9, 0x62, 0xb9, 0x58, 0x64, 0x79, 0x99, 0x4c, 0xa2, 0x45, 0x9e,
+  0x95, 0xd9, 0x38, 0x9b, 0x16, 0xd1, 0xe6, 0xd7, 0x97, 0x97, 0xe7, 0xbd,
+  0x88, 0xff, 0x1d, 0xf6, 0xa2, 0xd7, 0xfc, 0xfb, 0x6b, 0xfc, 0x1a, 0x0d,
+  0x0f, 0xcf, 0xf9, 0x5f, 0x7c, 0x14, 0x5d, 0xca, 0x8f, 0xa3, 0x93, 0xc3,
+  0xcb, 0x9e, 0x35, 0x77, 0x79, 0x7c, 0xfa, 0xf6, 0xf8, 0x92, 0x3e, 0x3d,
+  0x3d, 0x3a, 0x38, 0x8f, 0x78, 0x14, 0xd1, 0xeb, 0x93, 0xd3, 0xe3, 0xad,
+  0x01, 0x7d, 0x75, 0x93, 0x44, 0xe3, 0x6c, 0x36, 0x8b, 0xe7, 0x13, 0x1e,
+  0xfe, 0x24, 0x29, 0xd2, 0xeb, 0x39, 0xf5, 0x4b, 0xc3, 0xbc, 0xcf, 0xf2,
+  0xdb, 0xe8, 0x3e, 0x2d, 0x6f, 0xb2, 0x65, 0x49, 0x23, 0x4d, 0x72, 0x6b,
+  0x2e, 0x9d, 0x97, 0x49, 0x1e, 0x8f, 0x79, 0x5d, 0x06, 0x1b, 0x95, 0x15,
+  0xc8, 0xae, 0x68, 0xbe, 0x05, 0x4d, 0x70, 0xb4, 0x2c, 0xa6, 0x59, 0x3c,
+  0xe1, 0x69, 0xd1, 0x9b, 0x57, 0x4b, 0x5a, 0x90, 0x3c, 0x1d, 0xdf, 0x16,
+  0xd1, 0x34, 0xbd, 0x4d, 0x78, 0x52, 0x0f, 0x2b, 0x9b, 0x64, 0x0f, 0x6d,
+  0x47, 0xf1, 0x92, 0xe6, 0x3f, 0xef, 0x5b, 0x73, 0x65, 0x3a, 0x8e, 0xb9,
+  0x03, 0x1a, 0x34, 0x4d, 0x28, 0x5a, 0x2e, 0xb8, 0x39, 0x99, 0x7d, 0xb4,
+  0xc8, 0x0a, 0x7a, 0x6b, 0x38, 0x3c, 0xa5, 0x91, 0xcf, 0xe7, 0x09, 0x06,
+  0x52, 0xf4, 0xe8, 0x8f, 0xec, 0x36, 0x4d, 0xe8, 0x97, 0xab, 0x74, 0x9a,
+  0xc8, 0xea, 0xbb, 0xe6, 0x78, 0x1b, 0xf2, 0xa4, 0x58, 0xce, 0x92, 0x88,
+  0x67, 0x3a, 0xcb, 0xf2, 0x64, 0x10, 0x1d, 0x14, 0xd1, 0x2a, 0x5b, 0xd2,
+  0x14, 0xa7, 0x53, 0xda, 0x91, 0x24, 0x1a, 0x25, 0xd3, 0xec, 0xbe, 0xc7,
+  0xfb, 0x10, 0xcd, 0x97, 0xb3, 0x11, 0xbd, 0x42, 0xc3, 0xbf, 0x4a, 0xe2,
+  0x72, 0x49, 0xaf, 0xe2, 0x31, 0x6b, 0x6e, 0x16, 0xd3, 0x2c, 0xe8, 0xdd,
+  0x3c, 0xba, 0x49, 0x68, 0x96, 0xc5, 0x22, 0x9d, 0xff, 0x6e, 0xa3, 0x49,
+  0x0b, 0x8b, 0xec, 0x3e, 0xc9, 0x69, 0x31, 0xa3, 0xd1, 0x2a, 0xa2, 0x99,
+  0x8f, 0xe4, 0x9b, 0x2b, 0x5e, 0xff, 0x78, 0x3a, 0x75, 0x04, 0xd2, 0xcf,
+  0x93, 0x69, 0xcc, 0x9b, 0x6d, 0x7d, 0x0d, 0xa2, 0x61, 0xe2, 0x68, 0x41,
+  0xdf, 0xdb, 0x7c, 0xb2, 0x85, 0x37, 0x27, 0x49, 0x19, 0xa7, 0xd3, 0x82,
+  0x16, 0x9e, 0x89, 0xd6, 0x36, 0x98, 0x86, 0x4c, 0x7f, 0x46, 0xc5, 0x6a,
+  0x5e, 0xc6, 0x0f, 0xdc, 0xb7, 0xd1, 0x4d, 0x7f, 0x92, 0x2c, 0x92, 0xf9,
+  0x24, 0x99, 0x97, 0x83, 0xe8, 0x87, 0x6c, 0xd9, 0xa5, 0x6e, 0xaf, 0x52,
+  0x5a, 0x81, 0x38, 0xd2, 0x96, 0x78, 0x78, 0xb4, 0xeb, 0xe3, 0x3c, 0x5d,
+  0x04, 0x8b, 0x9f, 0xcd, 0x69, 0x97, 0xa3, 0x8b, 0xd7, 0x87, 0xd1, 0x93,
+  0x17, 0x9f, 0x3d, 0xf7, 0xbb, 0x4c, 0x4d, 0xd0, 0x04, 0xe3, 0x39, 0x91,
+  0xe8, 0x22, 0x19, 0xa7, 0x57, 0x34, 0xaf, 0xd9, 0x72, 0x5a, 0xa6, 0x0b,
+  0x5a, 0x71, 0x1e, 0x41, 0xc1, 0xc4, 0xb5, 0x88, 0xf3, 0xb2, 0xe0, 0xb5,
+  0xc3, 0x07, 0x34, 0xf7, 0xfb, 0x3c, 0x2d, 0x99, 0xd0, 0xf9, 0x0b, 0x5a,
+  0xe9, 0xb2, 0xb0, 0xe6, 0x98, 0xba, 0xa8, 0x9f, 0x11, 0x51, 0x13, 0xad,
+  0x70, 0x5c, 0x50, 0xa7, 0xfb, 0xae, 0xaf, 0xe8, 0xa6, 0x2c, 0x17, 0xfb,
+  0xdb, 0xdb, 0x45, 0x5a, 0x26, 0x83, 0xbf, 0xd3, 0x21, 0xe9, 0x95, 0xf7,
+  0x59, 0xaf, 0xbc, 0xc9, 0x93, 0xe4, 0x1f, 0x03, 0xa2, 0x59, 0xf7, 0x20,
+  0x75, 0xc9, 0xfb, 0xc8, 0xc3, 0xba, 0x4e, 0xb8, 0x83, 0xbf, 0x2d, 0x93,
+  0x39, 0x37, 0x48, 0x43, 0x88, 0xa7, 0x8b, 0x9b, 0x98, 0x76, 0x33, 0x21,
+  0xf2, 0xe3, 0x63, 0x47, 0x04, 0xc2, 0x23, 0x92, 0x83, 0xf7, 0xe3, 0x4f,
+  0x8d, 0x3e, 0xaf, 0xd0, 0x25, 0xfd, 0x3b, 0xd0, 0x97, 0x62, 0x5a, 0x6b,
+  0xea, 0x6c, 0x9b, 0x89, 0xea, 0xc7, 0xdd, 0xfe, 0xee, 0xce, 0xce, 0x4f,
+  0x83, 0xf2, 0xa1, 0xfc, 0xc8, 0x17, 0x76, 0x76, 0xfc, 0x2b, 0xfc, 0xf4,
+  0x26, 0xcf, 0x38, 0x9a, 0x12, 0xd1, 0x70, 0xff, 0x3f, 0x27, 0x79, 0x56,
+  0x6c, 0xb5, 0x34, 0x35, 0x4d, 0x4a, 0x3a, 0x62, 0x41, 0x3b, 0x71, 0xff,
+  0x67, 0xe9, 0xd6, 0x1e, 0x7e, 0x9b, 0x45, 0xf3, 0xa4, 0xc0, 0xaa, 0x0a,
+  0xeb, 0x08, 0xa6, 0x4d, 0xdb, 0xef, 0x19, 0x48, 0x5c, 0xe2, 0xdb, 0x59,
+  0x36, 0x23, 0x1a, 0xe8, 0xd1, 0xc1, 0x2c, 0xdd, 0x62, 0xd1, 0xb9, 0x73,
+  0x0c, 0x27, 0x21, 0x7e, 0x14, 0x4f, 0x99, 0x15, 0x15, 0xd4, 0x30, 0x0d,
+  0x96, 0x18, 0x40, 0x12, 0x8f, 0x6f, 0xa2, 0x8c, 0xde, 0xce, 0x9b, 0x9b,
+  0x12, 0xcf, 0x57, 0x83, 0x2c, 0xbf, 0xde, 0x8e, 0xf3, 0xf1, 0x4d, 0x7a,
+  0x47, 0x2b, 0xf3, 0xe2, 0xc5, 0xf3, 0x3e, 0xfd, 0xf3, 0xe2, 0xa7, 0xed,
+  0xbb, 0x6c, 0x4a, 0x0b, 0xf5, 0xf4, 0xa7, 0x6d, 0xde, 0xee, 0xbf, 0xc7,
+  0xbd, 0x51, 0x6f, 0xfc, 0x8f, 0xc1, 0x4d, 0x39, 0x9b, 0x3e, 0x46, 0x45,
+  0xd4, 0x5e, 0x14, 0xcf, 0xb2, 0xe5, 0xbc, 0x74, 0x84, 0x43, 0x34, 0x58,
+  0x06, 0xdc, 0x69, 0x9a, 0xce, 0xe9, 0xcc, 0x12, 0xa5, 0xaf, 0xe4, 0xc4,
+  0x8e, 0x12, 0x7f, 0xb8, 0xcb, 0xf1, 0x0d, 0x4d, 0x95, 0x28, 0x29, 0xd6,
+  0x65, 0x28, 0x53, 0x9a, 0x0c, 0xbd, 0x36, 0xa7, 0x43, 0x9c, 0x4a, 0x3b,
+  0xd2, 0x55, 0x4a, 0xcf, 0x65, 0xf9, 0x24, 0xc9, 0x3d, 0x4d, 0x0f, 0x53,
+  0x5a, 0x35, 0x39, 0xb5, 0x9f, 0x0e, 0x76, 0x9f, 0x0d, 0x76, 0xdd, 0x02,
+  0xd1, 0x56, 0x66, 0x6e, 0x88, 0xd4, 0x74, 0x99, 0x2c, 0x68, 0x38, 0x4b,
+  0x66, 0x7f, 0x72, 0x8a, 0xb9, 0xdd, 0x88, 0x4e, 0xf1, 0x35, 0xb1, 0x1d,
+  0xb7, 0x94, 0xc4, 0xf9, 0x6f, 0xe2, 0xb2, 0x42, 0x92, 0xbc, 0xba, 0xab,
+  0xe8, 0x2d, 0x6d, 0xbd, 0x31, 0x96, 0x3c, 0x92, 0x3d, 0x6e, 0xae, 0xec,
+  0xfd, 0xfd, 0xfd, 0x7a, 0xda, 0xdb, 0xdf, 0xad, 0x91, 0x5f, 0xf0, 0x52,
+  0x1b, 0xd1, 0xec, 0xef, 0x55, 0xc9, 0xe6, 0xe4, 0x2a, 0xc2, 0xc0, 0xfc,
+  0xc2, 0x33, 0xdb, 0x70, 0x5c, 0xde, 0xb8, 0x06, 0xb5, 0x48, 0xbf, 0x27,
+  0x57, 0xe9, 0x43, 0x4f, 0x16, 0x06, 0x2b, 0x1e, 0x53, 0xfb, 0xb3, 0x05,
+  0x93, 0x86, 0x35, 0x77, 0xbd, 0x4c, 0x0a, 0xe2, 0x8c, 0x3c, 0x5d, 0x7b,
+  0x15, 0xcd, 0xcf, 0xd2, 0xeb, 0x9b, 0x32, 0xba, 0x8f, 0x99, 0xeb, 0x9c,
+  0x94, 0xf2, 0x36, 0xb3, 0x77, 0xe2, 0x34, 0x57, 0x31, 0xf1, 0x8b, 0x88,
+  0xc9, 0x4b, 0x98, 0x39, 0x53, 0xa4, 0xe3, 0x3b, 0xb4, 0x48, 0x42, 0x70,
+  0x51, 0x70, 0xf1, 0x8d, 0xe2, 0x82, 0x37, 0x6d, 0x4e, 0x84, 0x51, 0xd2,
+  0x0d, 0xb1, 0xe4, 0xbf, 0x6e, 0xe8, 0x0a, 0x88, 0xe6, 0xf1, 0x2c, 0xd1,
+  0x61, 0x32, 0xcf, 0x7c, 0x4d, 0x8b, 0x9a, 0x3c, 0xc4, 0x33, 0xc7, 0xc6,
+  0x88, 0x29, 0xf5, 0xb0, 0x4f, 0xee, 0x69, 0x3a, 0x18, 0x25, 0x11, 0x25,
+  0x9f, 0x1a, 0x1c, 0xc4, 0x0e, 0x1f, 0xb6, 0x4e, 0x38, 0xc5, 0x02, 0x77,
+  0x04, 0x96, 0x88, 0x87, 0x1f, 0x05, 0x93, 0xa5, 0x25, 0x8b, 0x6f, 0xf9,
+  0x36, 0xaa, 0x5d, 0x7a, 0xf2, 0x66, 0x34, 0xa1, 0x19, 0xa5, 0xc4, 0xf7,
+  0x46, 0x74, 0x2c, 0x79, 0x7a, 0x34, 0x4e, 0x59, 0x19, 0x6e, 0x6c, 0x41,
+  0x0d, 0xf3, 0x87, 0x69, 0xc9, 0x1c, 0x07, 0x02, 0x07, 0x56, 0x86, 0x8e,
+  0xea, 0x3c, 0x0b, 0xe7, 0xcf, 0x43, 0xa3, 0xe7, 0xee, 0xe2, 0x69, 0x4a,
+  0x62, 0x43, 0xe2, 0x5e, 0x00, 0x67, 0x1f, 0xf3, 0xad, 0x38, 0x9d, 0xae,
+  0x88, 0x08, 0xf3, 0x9c, 0xe5, 0x32, 0xde, 0x3c, 0xe2, 0x66, 0x7c, 0x78,
+  0xa2, 0x59, 0x42, 0xb7, 0x49, 0x65, 0x39, 0x53, 0xe6, 0x6d, 0x44, 0xb4,
+  0x74, 0x43, 0x81, 0xfe, 0xe8, 0x26, 0xc1, 0x21, 0xc7, 0xd4, 0x31, 0x34,
+  0x6e, 0x7d, 0x3c, 0x4e, 0x16, 0x65, 0xe1, 0xe7, 0x74, 0xd8, 0xb2, 0xdf,
+  0x74, 0x77, 0xf2, 0xba, 0x87, 0xf7, 0x2d, 0x16, 0xd6, 0xf1, 0x7e, 0x7f,
+  0xe5, 0xb2, 0x00, 0xd0, 0xa3, 0x43, 0xe0, 0xe6, 0xc4, 0xfd, 0xd0, 0x19,
+  0xc0, 0xa2, 0xcf, 0x78, 0xa4, 0xfc, 0x6c, 0x21, 0xf2, 0x10, 0xce, 0x25,
+  0xef, 0xa2, 0x08, 0x44, 0xd2, 0x2d, 0x2d, 0x08, 0x2f, 0xa6, 0xbf, 0x57,
+  0xa8, 0x57, 0xb7, 0xa7, 0xdc, 0x7d, 0x41, 0xb2, 0x24, 0x31, 0xf5, 0x49,
+  0x71, 0x43, 0xd7, 0x70, 0xc1, 0x3c, 0x81, 0x67, 0x3a, 0x23, 0x8a, 0xb9,
+  0xe3, 0x1d, 0x5e, 0x24, 0xc9, 0x64, 0x10, 0x9d, 0x5d, 0xf1, 0x51, 0xcd,
+  0x69, 0xd0, 0x25, 0xbe, 0x66, 0x7e, 0x42, 0x2b, 0x37, 0x81, 0xb0, 0x35,
+  0x77, 0xac, 0x03, 0x63, 0x09, 0x58, 0x03, 0x58, 0x08, 0x0d, 0x75, 0x5a,
+  0x65, 0x3c, 0x90, 0x1a, 0xf8, 0x38, 0xf3, 0xe0, 0x68, 0x8b, 0xa3, 0x08,
+  0x64, 0x48, 0xbf, 0x95, 0xf7, 0x49, 0x32, 0xf7, 0x6c, 0x94, 0x78, 0x1e,
+  0x6f, 0x1b, 0x08, 0x23, 0x9d, 0xdf, 0x65, 0x3c, 0xc0, 0x8d, 0x8d, 0xf3,
+  0x8b, 0xb3, 0xaf, 0x2e, 0x8e, 0x87, 0xc3, 0xe8, 0xcd, 0xf1, 0xe5, 0xf1,
+  0x45, 0x95, 0x7a, 0xe6, 0x59, 0x3e, 0xc3, 0xa6, 0x46, 0x93, 0xb4, 0x58,
+  0x4c, 0xe3, 0x15, 0x6f, 0x37, 0xcd, 0xe5, 0x3a, 0xe7, 0xb3, 0x35, 0x4b,
+  0x98, 0xd9, 0x4c, 0x96, 0x39, 0x38, 0xfd, 0x82, 0xf6, 0x4f, 0xa5, 0x1d,
+  0xba, 0xc4, 0x21, 0x22, 0xcd, 0xaf, 0xfd, 0x4a, 0x27, 0x01, 0x0b, 0xb5,
+  0xcd, 0x60, 0xf9, 0x83, 0x05, 0xd0, 0x5e, 0xe4, 0x05, 0x52, 0x59, 0x23,
+  0x16, 0x56, 0x79, 0x56, 0x7c, 0x8d, 0xcc, 0x20, 0x7f, 0xd0, 0xc5, 0x3f,
+  0xf3, 0x72, 0x47, 0x72, 0x45, 0xf7, 0x05, 0xb1, 0x56, 0x4f, 0x1a, 0x5f,
+  0x93, 0x3c, 0x03, 0xb9, 0x95, 0x97, 0x68, 0x9c, 0xe8, 0x0c, 0xdc, 0xb0,
+  0xb1, 0xd0, 0x10, 0x76, 0x59, 0xfa, 0xa5, 0xd1, 0xd0, 0xd0, 0x67, 0xe9,
+  0x9c, 0x28, 0x8e, 0x68, 0x54, 0x4f, 0x3e, 0x0d, 0xfc, 0xca, 0x9a, 0xe3,
+  0x83, 0x21, 0x6b, 0x24, 0x0d, 0xd1, 0x5b, 0xb4, 0xef, 0xc4, 0x32, 0xdd,
+  0x3c, 0x31, 0xc0, 0x14, 0xc7, 0x24, 0x1e, 0x31, 0x83, 0x62, 0xb1, 0x94,
+  0x84, 0x89, 0x24, 0xec, 0xc6, 0xcd, 0x5f, 0x7b, 0xeb, 0xf1, 0x39, 0xe4,
+  0x51, 0xc5, 0x23, 0xde, 0x5c, 0x1e, 0x48, 0x6d, 0x39, 0xe9, 0x44, 0x81,
+  0xcb, 0xdc, 0xa7, 0x05, 0x4e, 0xd8, 0x7d, 0xb6, 0x9c, 0x92, 0x50, 0xc8,
+  0x0f, 0x2c, 0x17, 0xe1, 0x72, 0x52, 0x97, 0x0b, 0xea, 0x75, 0x96, 0x3e,
+  0x40, 0x7c, 0xa9, 0xb5, 0x42, 0x63, 0xa3, 0x3f, 0x17, 0xb4, 0x1d, 0x32,
+  0x9e, 0x41, 0xc8, 0x66, 0x21, 0x59, 0x32, 0x07, 0x69, 0x6c, 0x26, 0x1f,
+  0x1c, 0xb0, 0xbe, 0xf3, 0xb3, 0xe1, 0x25, 0xdf, 0x04, 0xe7, 0xef, 0x2e,
+  0xa9, 0x21, 0xba, 0xb6, 0x8a, 0x92, 0x36, 0x96, 0x5f, 0x9c, 0x27, 0x10,
+  0xc1, 0xad, 0x39, 0xda, 0xc3, 0x14, 0xe7, 0x5d, 0x2f, 0x1c, 0xeb, 0xd4,
+  0xc6, 0x07, 0x9d, 0x82, 0x49, 0xd9, 0x34, 0x8a, 0xe2, 0x26, 0xa1, 0x83,
+  0xe4, 0x5e, 0xdb, 0xfc, 0x7c, 0xab, 0x17, 0xf5, 0x5d, 0x73, 0x3f, 0xf2,
+  0xa3, 0x3f, 0x71, 0xcf, 0x45, 0x3a, 0x4b, 0xa7, 0x71, 0x70, 0x17, 0x3a,
+  0x96, 0xe4, 0x8f, 0xe6, 0x98, 0xd8, 0x2f, 0xc6, 0xec, 0xe5, 0x70, 0x5e,
+  0x40, 0x9c, 0x6b, 0xbf, 0x51, 0x93, 0x2c, 0x91, 0xf7, 0x58, 0x18, 0x76,
+  0x1c, 0x88, 0xb7, 0x8c, 0x8f, 0x7c, 0x65, 0x99, 0xea, 0xd4, 0xd1, 0x58,
+  0x36, 0x66, 0xe9, 0x50, 0xcb, 0xdc, 0xc2, 0x75, 0x46, 0x71, 0xde, 0x71,
+  0xcc, 0x4c, 0x05, 0x9e, 0x3c, 0xb9, 0x5e, 0xd2, 0xe0, 0x65, 0x55, 0x69,
+  0x7e, 0x9f, 0xf0, 0xd0, 0x59, 0x28, 0x77, 0x87, 0x9b, 0xa4, 0xbd, 0xf9,
+  0x64, 0xb0, 0x71, 0x06, 0x55, 0xcd, 0xe9, 0x75, 0x27, 0x7c, 0x27, 0xcf,
+  0x99, 0x13, 0xf6, 0x20, 0x86, 0x8f, 0x48, 0x5f, 0x4b, 0x40, 0x75, 0xc2,
+  0xd8, 0xe2, 0x3c, 0x89, 0x92, 0x39, 0x13, 0xcf, 0x44, 0x58, 0x65, 0xbf,
+  0x2f, 0x5f, 0x61, 0xc7, 0x57, 0x74, 0x9d, 0xc7, 0xd7, 0x71, 0xea, 0xce,
+  0xbc, 0x12, 0xda, 0x24, 0xb2, 0x87, 0xe7, 0x99, 0x3e, 0xcf, 0x9c, 0x89,
+  0x99, 0xac, 0x6e, 0xea, 0x12, 0xbc, 0x28, 0xe1, 0x3b, 0x8a, 0xf6, 0x04,
+  0x6b, 0xab, 0xed, 0xf2, 0xd5, 0x64, 0xcd, 0x8d, 0x70, 0x0d, 0xf3, 0x9d,
+  0x06, 0xca, 0xc4, 0x2d, 0x45, 0x2d, 0x76, 0x06, 0xfe, 0xf4, 0x41, 0xa0,
+  0x49, 0x59, 0x97, 0xa2, 0x9b, 0xe6, 0x9e, 0x65, 0xbb, 0xa2, 0x24, 0xfe,
+  0x01, 0xfe, 0x86, 0xcf, 0x68, 0x9c, 0x8e, 0x23, 0xdd, 0x64, 0xf7, 0x42,
+  0x36, 0x6e, 0x16, 0xd4, 0x46, 0x91, 0xe2, 0x3a, 0xe5, 0xcf, 0x67, 0x83,
+  0x68, 0x13, 0x0c, 0x94, 0xb8, 0x2c, 0xdf, 0x04, 0x7e, 0x16, 0x6e, 0x41,
+  0xee, 0x63, 0x27, 0xb0, 0xc7, 0x93, 0x89, 0x08, 0x5a, 0x2c, 0x2a, 0xbd,
+  0x18, 0xec, 0x0c, 0xd8, 0x46, 0x90, 0xdc, 0xa5, 0x19, 0xe9, 0x7b, 0x7c,
+  0x07, 0xf1, 0x45, 0xeb, 0xde, 0x8b, 0x58, 0xfb, 0xe1, 0x1b, 0xf4, 0xfa,
+  0x1a, 0xeb, 0x93, 0xcd, 0xb7, 0x49, 0x41, 0x8c, 0x02, 0xf6, 0x9b, 0x93,
+  0x72, 0x02, 0xce, 0xc3, 0x6b, 0x63, 0x72, 0x2c, 0x88, 0x2e, 0xe4, 0xbd,
+  0xba, 0x9a, 0x5b, 0x8e, 0x4e, 0xfa, 0xf1, 0x76, 0xbf, 0x1f, 0x2f, 0x58,
+  0xb1, 0xa9, 0x99, 0x03, 0x36, 0x89, 0x48, 0xb7, 0x59, 0x13, 0xde, 0x8a,
+  0xbe, 0x63, 0x79, 0x03, 0x5c, 0x9a, 0xe5, 0xc2, 0xb9, 0x53, 0x21, 0xb1,
+  0x74, 0x22, 0x91, 0xf0, 0x21, 0x31, 0xce, 0xd3, 0xda, 0x9c, 0x51, 0x6a,
+  0x9c, 0xb3, 0x14, 0x87, 0x4b, 0xce, 0x51, 0x21, 0x8f, 0x37, 0xa2, 0x1b,
+  0x27, 0x37, 0xed, 0x86, 0xf6, 0x6b, 0x20, 0x12, 0x16, 0x4e, 0x29, 0x3f,
+  0x5d, 0x6b, 0x8e, 0x0f, 0xc9, 0xbc, 0x4b, 0x2b, 0x94, 0x3c, 0xa4, 0xac,
+  0xc2, 0xf2, 0x0e, 0xab, 0xf4, 0xc0, 0x57, 0xca, 0x38, 0xc7, 0x62, 0x0c,
+  0x20, 0xde, 0x97, 0x89, 0x1c, 0x31, 0x0c, 0xf7, 0x6a, 0x1a, 0x5f, 0x13,
+  0x1d, 0xd5, 0x9a, 0x23, 0x4d, 0x3d, 0x63, 0xf6, 0x4e, 0xdc, 0xb5, 0x20,
+  0xf1, 0x9e, 0x34, 0xe2, 0xaf, 0xf5, 0x22, 0x2d, 0xa2, 0x4d, 0x62, 0xd0,
+  0xd3, 0x25, 0xb4, 0x8c, 0x33, 0x9a, 0x18, 0x7d, 0xb5, 0xe5, 0xcf, 0x59,
+  0xff, 0x80, 0xd6, 0x8f, 0xb5, 0xee, 0x7e, 0x4c, 0x27, 0xa1, 0x8c, 0x5e,
+  0xca, 0x8f, 0xa2, 0xe4, 0x5b, 0xe6, 0xf3, 0xfa, 0x92, 0x32, 0xaf, 0xda,
+  0x8a, 0x86, 0x2a, 0x30, 0xf2, 0xdc, 0xde, 0xf1, 0xab, 0x07, 0xc1, 0x3b,
+  0xbc, 0x50, 0x05, 0x2d, 0x9f, 0x2d, 0x18, 0xd8, 0x9b, 0x0c, 0x65, 0x50,
+  0x6b, 0x6e, 0xc8, 0x23, 0xa5, 0xf9, 0xc6, 0x13, 0x26, 0x18, 0xb9, 0x8f,
+  0xa3, 0xc3, 0xaf, 0x4e, 0x88, 0x5c, 0xae, 0x48, 0x1d, 0xa5, 0x59, 0x61,
+  0x01, 0x59, 0x7d, 0xa6, 0x1b, 0x99, 0xd8, 0x32, 0xcd, 0x1b, 0x6b, 0x46,
+  0x7a, 0x63, 0x28, 0x8d, 0xe9, 0xff, 0x3a, 0x6f, 0xb2, 0x9f, 0x69, 0x01,
+  0xe3, 0xed, 0xa7, 0x83, 0x1d, 0x3a, 0x23, 0x97, 0xa4, 0xb5, 0xcc, 0xc7,
+  0xd9, 0x84, 0x94, 0xf9, 0x69, 0x3c, 0xbf, 0x2d, 0x22, 0xd0, 0x2a, 0xf6,
+  0x43, 0x46, 0xca, 0x77, 0xd7, 0x32, 0xcf, 0xe9, 0x96, 0x9c, 0x44, 0xe1,
+  0xe5, 0x61, 0xc7, 0x45, 0xa6, 0x23, 0x87, 0xc0, 0x04, 0x81, 0xe8, 0x6f,
+  0x4b, 0xde, 0x8e, 0x59, 0x9c, 0xdf, 0x9a, 0xb4, 0xe1, 0xb4, 0x83, 0x51,
+  0x82, 0x81, 0xe1, 0xf9, 0x66, 0x73, 0xfd, 0xaf, 0x69, 0xa1, 0xd9, 0x44,
+  0xc0, 0x22, 0xbf, 0x9c, 0xbe, 0xcc, 0xe4, 0x12, 0xbf, 0x1d, 0x9e, 0xfb,
+  0x61, 0xde, 0xfa, 0x20, 0x6b, 0x71, 0xd4, 0x32, 0x9b, 0x2a, 0x98, 0x12,
+  0xe8, 0x4d, 0x3a, 0x9f, 0x62, 0x9d, 0x98, 0xc6, 0x74, 0xcc, 0x78, 0xe1,
+  0x3c, 0xed, 0x34, 0xfb, 0xe6, 0xef, 0x99, 0x82, 0xba, 0x05, 0x4e, 0x41,
+  0xb0, 0xfb, 0x7d, 0x62, 0xc9, 0x6c, 0x6e, 0x69, 0xdf, 0xe8, 0x4b, 0x3a,
+  0x15, 0x85, 0x3b, 0x16, 0x57, 0xe9, 0xf5, 0x32, 0x4f, 0x84, 0x91, 0xc3,
+  0x42, 0x63, 0x86, 0x19, 0x66, 0xbb, 0x37, 0x19, 0x88, 0x8f, 0xa4, 0xde,
+  0x64, 0x7a, 0xd5, 0xab, 0x35, 0xc7, 0xc7, 0xd7, 0x58, 0x1e, 0xf8, 0x42,
+  0x91, 0x8c, 0xd1, 0xd4, 0x3c, 0x51, 0xf6, 0x3d, 0xe3, 0x55, 0x65, 0xed,
+  0x3e, 0x1a, 0x4f, 0xe3, 0x74, 0x56, 0x88, 0x56, 0xa0, 0xaa, 0x6b, 0x9d,
+  0x6e, 0x2e, 0x55, 0x8a, 0x03, 0xc1, 0x8c, 0x58, 0x8a, 0xcc, 0x0b, 0x96,
+  0x13, 0x79, 0xbb, 0x62, 0xbb, 0x3e, 0xd1, 0x29, 0xe9, 0x82, 0xe3, 0x5b,
+  0x10, 0x25, 0x7a, 0x91, 0x9b, 0xa7, 0x5f, 0x6b, 0x4e, 0x36, 0xa5, 0xe0,
+  0xf5, 0x5c, 0x16, 0x6c, 0x51, 0x2a, 0xd2, 0x11, 0x11, 0x24, 0x49, 0x55,
+  0xcb, 0x31, 0x28, 0x80, 0xb5, 0x53, 0xd2, 0x83, 0xf3, 0x98, 0x65, 0xce,
+  0x12, 0xb6, 0xb0, 0x08, 0x64, 0xd3, 0x27, 0x12, 0x59, 0xb4, 0x8e, 0x0e,
+  0x36, 0x1f, 0x91, 0x0b, 0x2b, 0x4c, 0xa2, 0x50, 0xe9, 0x97, 0x8d, 0x2e,
+  0x2a, 0x6a, 0x8e, 0x6b, 0xab, 0x59, 0x6b, 0x4e, 0xd6, 0xb6, 0x47, 0x42,
+  0x7a, 0x4a, 0x2a, 0xb8, 0x69, 0x92, 0x24, 0x1c, 0x09, 0x5d, 0xf6, 0xfb,
+  0xa4, 0x13, 0xa5, 0xe3, 0x1e, 0xff, 0x36, 0x49, 0x49, 0xf9, 0x2c, 0xf1,
+  0xeb, 0xbc, 0x9c, 0xce, 0x7a, 0x51, 0xc8, 0xfd, 0xdd, 0x8e, 0xcf, 0x93,
+  0xeb, 0x8c, 0x74, 0xe2, 0xb2, 0x49, 0x75, 0xe0, 0x34, 0xc2, 0x6a, 0x54,
+  0x78, 0x70, 0xf4, 0x61, 0xa2, 0x00, 0xc9, 0x10, 0xc4, 0x8e, 0xd9, 0x8a,
+  0x34, 0xe1, 0xd3, 0xc9, 0xc3, 0xa1, 0xa1, 0x08, 0x3f, 0xad, 0xf3, 0x24,
+  0x88, 0xf5, 0x45, 0x49, 0x8c, 0xa7, 0xa7, 0x42, 0x22, 0xf1, 0xb8, 0x59,
+  0xbc, 0xc2, 0x0e, 0x91, 0x34, 0xe2, 0x24, 0x00, 0x1c, 0x1c, 0x62, 0x20,
+  0xe5, 0x7d, 0x3a, 0x56, 0xf1, 0x9a, 0x17, 0xa4, 0xce, 0x80, 0xd9, 0x00,
+  0x30, 0x4d, 0xf9, 0xc1, 0xd9, 0x92, 0xf6, 0x97, 0xde, 0xe2, 0xcb, 0x56,
+  0x54, 0x92, 0x7b, 0xda, 0xad, 0x81, 0x1c, 0x9b, 0x44, 0x44, 0x26, 0xba,
+  0xed, 0x58, 0x92, 0x8b, 0xf3, 0x14, 0xca, 0x57, 0xa3, 0x39, 0x19, 0x33,
+  0x4f, 0x32, 0x1c, 0x27, 0xbf, 0xae, 0x82, 0x8d, 0x17, 0x68, 0x70, 0xb4,
+  0x98, 0x23, 0x05, 0x07, 0x67, 0x44, 0xa7, 0x59, 0xac, 0x8c, 0xd1, 0x4b,
+  0xbe, 0xb3, 0x5f, 0xf1, 0x64, 0xd6, 0xf0, 0xcb, 0x73, 0x68, 0x7c, 0x37,
+  0x55, 0x91, 0x27, 0xe0, 0x8b, 0xa2, 0xd6, 0x49, 0x6b, 0xa6, 0x0a, 0x32,
+  0xed, 0xd7, 0x09, 0x95, 0x48, 0x33, 0x01, 0xab, 0x74, 0x6d, 0x2d, 0xfc,
+  0x85, 0x4b, 0x3b, 0x93, 0xa4, 0x77, 0x6c, 0x39, 0x74, 0xda, 0x94, 0x34,
+  0x0e, 0x53, 0x48, 0x67, 0x98, 0x94, 0xf5, 0xe6, 0x0e, 0xd1, 0xe1, 0x7e,
+  0x47, 0xcd, 0x29, 0xb0, 0x1c, 0xa2, 0x55, 0x5d, 0x3a, 0x5a, 0x60, 0xb5,
+  0x97, 0x5c, 0xb1, 0x5e, 0x42, 0x44, 0xd1, 0x61, 0xd3, 0xf9, 0xee, 0xab,
+  0x6f, 0x0f, 0x4e, 0xdf, 0x1d, 0xef, 0xfe, 0xb9, 0x4e, 0x3d, 0xf4, 0xdd,
+  0x9e, 0x7c, 0xb7, 0xd7, 0x69, 0xe3, 0x68, 0x44, 0x40, 0x51, 0xd4, 0x7d,
+  0xd5, 0x25, 0x05, 0x76, 0x36, 0xca, 0xa6, 0x3c, 0x4b, 0xbb, 0x93, 0xc1,
+  0xc9, 0x68, 0x14, 0x3d, 0x95, 0xf0, 0x4b, 0xb9, 0xfe, 0x64, 0x61, 0xf8,
+  0xf6, 0xac, 0x8f, 0x1d, 0xfa, 0xbe, 0x6a, 0xd6, 0x20, 0x80, 0x78, 0x12,
+  0x2e, 0x46, 0x51, 0xe2, 0x36, 0xd4, 0x0d, 0xe2, 0x96, 0x0b, 0xa1, 0x47,
+  0x3a, 0x13, 0x38, 0x48, 0x75, 0x5e, 0x2f, 0x33, 0xe6, 0x29, 0xfb, 0x21,
+  0x81, 0xeb, 0x16, 0x90, 0x8f, 0x52, 0x10, 0xd6, 0x8a, 0xa8, 0xb7, 0x1c,
+  0xdf, 0x0c, 0xe8, 0xd2, 0x13, 0x9e, 0x92, 0x16, 0x7a, 0x3c, 0xeb, 0xfc,
+  0x8e, 0xaf, 0x03, 0x56, 0xd1, 0xef, 0x68, 0x16, 0xb2, 0xf5, 0x1d, 0x1d,
+  0x0b, 0x29, 0x85, 0xb4, 0x2f, 0x1d, 0x3d, 0xce, 0xa0, 0x2c, 0x58, 0x90,
+  0x55, 0x03, 0xe4, 0xf3, 0x95, 0xd7, 0x9b, 0xa3, 0xb3, 0x93, 0xcd, 0xb8,
+  0x47, 0x35, 0x6b, 0xb3, 0x5b, 0xc1, 0x18, 0x02, 0x9f, 0x27, 0x1a, 0x35,
+  0xeb, 0xc0, 0x2b, 0x3d, 0x91, 0xdd, 0x3c, 0xd1, 0xe3, 0x2b, 0xea, 0x6e,
+  0x9d, 0xf2, 0xa9, 0xb1, 0x11, 0x09, 0xdb, 0x4a, 0xda, 0x72, 0x59, 0x45,
+  0xfd, 0x53, 0x22, 0xe8, 0x69, 0xa6, 0x0c, 0xdd, 0x0b, 0xad, 0x2a, 0xbd,
+  0x44, 0x8e, 0x06, 0xb2, 0xab, 0x96, 0x73, 0xa9, 0xcf, 0x30, 0xcf, 0xc6,
+  0x56, 0xd8, 0x40, 0xe5, 0x68, 0x39, 0x72, 0x22, 0xdd, 0x90, 0x56, 0x16,
+  0x94, 0xaf, 0x4c, 0x97, 0x34, 0x8f, 0x96, 0xe6, 0xde, 0x26, 0x65, 0x31,
+  0x8e, 0x17, 0xc9, 0xb6, 0xde, 0xe8, 0xb6, 0x91, 0xe8, 0x45, 0x06, 0xd2,
+  0x64, 0x5e, 0x67, 0x97, 0xc7, 0x26, 0x26, 0xe9, 0x93, 0x5e, 0x97, 0x17,
+  0x41, 0x36, 0x38, 0xb3, 0x7c, 0xc2, 0x20, 0x24, 0x2b, 0x93, 0x8e, 0x1b,
+  0x02, 0xd5, 0x9c, 0xb4, 0xa9, 0x01, 0x8c, 0xab, 0x36, 0x19, 0x35, 0x35,
+  0x1a, 0x71, 0xd9, 0xd9, 0xa0, 0x9e, 0x20, 0x6c, 0xe0, 0x63, 0xe7, 0x79,
+  0xa8, 0x73, 0x1b, 0xbd, 0xfd, 0xfa, 0x63, 0x37, 0x86, 0xfe, 0x5f, 0x63,
+  0x2f, 0x09, 0xa8, 0xd9, 0x1a, 0x0b, 0x45, 0x92, 0xfd, 0x9c, 0x44, 0xdf,
+  0xbb, 0x44, 0xd7, 0x96, 0xd7, 0xab, 0xfd, 0xca, 0xf2, 0xda, 0x9e, 0xf1,
+  0xeb, 0x23, 0x6a, 0x7e, 0xb2, 0x9c, 0x2d, 0x54, 0xd2, 0xf8, 0x5d, 0xdb,
+  0x31, 0x14, 0x89, 0xea, 0x97, 0x8a, 0x16, 0xa3, 0xe4, 0x17, 0x09, 0x16,
+  0x5f, 0x8a, 0x58, 0xd9, 0x8f, 0x8b, 0x71, 0x9a, 0xd6, 0xde, 0x3a, 0x86,
+  0x46, 0x15, 0x1d, 0x0c, 0x0f, 0x4f, 0x4e, 0xbc, 0x25, 0xe2, 0x5e, 0x84,
+  0x74, 0x9e, 0x06, 0xab, 0x97, 0xb4, 0x24, 0xec, 0xa2, 0x12, 0x5b, 0x1e,
+  0x1c, 0x59, 0x32, 0x6e, 0xba, 0xfd, 0xda, 0x4e, 0x1b, 0x8f, 0x2f, 0x99,
+  0x13, 0x6d, 0x8c, 0x45, 0x0a, 0x96, 0x86, 0x68, 0x3e, 0x6c, 0x17, 0x03,
+  0x59, 0xd0, 0xa5, 0x55, 0xa8, 0x12, 0xf5, 0xe7, 0x72, 0xb5, 0x48, 0x5e,
+  0x1d, 0x74, 0x44, 0x82, 0xab, 0xcf, 0x49, 0x16, 0x66, 0x1c, 0xd3, 0xf0,
+  0xd5, 0x86, 0x21, 0xb7, 0x13, 0x6f, 0xf1, 0x44, 0x2d, 0x0f, 0xca, 0x1b,
+  0xd9, 0x3a, 0x3e, 0x63, 0x11, 0x53, 0x6c, 0xc0, 0x74, 0x0b, 0x3d, 0xd9,
+  0xab, 0xb3, 0x96, 0x15, 0x5d, 0xff, 0xb3, 0x22, 0x94, 0xb9, 0x70, 0x63,
+  0xb7, 0x5f, 0x15, 0x35, 0x91, 0x8b, 0xc9, 0x06, 0xc7, 0xe5, 0x4b, 0x7e,
+  0xa5, 0x26, 0x28, 0x0c, 0x9c, 0x20, 0xd4, 0xdc, 0x18, 0x33, 0xae, 0xf2,
+  0x65, 0x5a, 0x93, 0x24, 0x97, 0xc5, 0x12, 0x36, 0xa6, 0x05, 0xc9, 0x4b,
+  0xe5, 0x94, 0x18, 0x5c, 0x2f, 0x5a, 0xce, 0xf9, 0xa7, 0xd3, 0x4c, 0x23,
+  0xaf, 0xb5, 0x7b, 0xe5, 0x07, 0xfa, 0x4d, 0x9e, 0xf2, 0x5c, 0xe3, 0x28,
+  0xe4, 0xb5, 0x22, 0x8d, 0x6b, 0xfb, 0x2a, 0x3d, 0xb0, 0x63, 0x87, 0x1e,
+  0x9b, 0xa4, 0xec, 0x04, 0xa4, 0x11, 0xd7, 0x77, 0xac, 0x55, 0x7c, 0xdc,
+  0x2c, 0x96, 0xc4, 0xd0, 0x88, 0xe5, 0x3b, 0xf1, 0x25, 0x10, 0x69, 0x78,
+  0x79, 0x4d, 0x76, 0xa9, 0x5f, 0x06, 0xc4, 0x64, 0x43, 0x8d, 0xa6, 0x3f,
+  0x4e, 0x17, 0x37, 0x7c, 0x3a, 0x5e, 0x42, 0x03, 0x66, 0x29, 0x5b, 0x3e,
+  0x68, 0x5c, 0xcf, 0xc3, 0xe1, 0xa9, 0x69, 0x33, 0x38, 0xe0, 0xe0, 0xa8,
+  0xf6, 0xb6, 0x2e, 0x7f, 0x6a, 0xae, 0x07, 0x33, 0x77, 0x0a, 0x57, 0xe4,
+  0xa6, 0xeb, 0x84, 0xe3, 0x3a, 0x12, 0x01, 0xc5, 0xec, 0xea, 0x30, 0xe0,
+  0xda, 0x57, 0x83, 0xe8, 0x02, 0xc2, 0xe0, 0x72, 0xc1, 0xa7, 0x27, 0x82,
+  0xeb, 0x52, 0xbf, 0xab, 0x35, 0x87, 0xc1, 0x87, 0x3b, 0x0a, 0x67, 0x5f,
+  0xe5, 0xf0, 0x55, 0xd8, 0x66, 0x1a, 0x7c, 0x47, 0x44, 0xbf, 0x5f, 0x67,
+  0x19, 0xde, 0x3b, 0x40, 0x92, 0xcd, 0xbc, 0x28, 0xa6, 0x70, 0xda, 0x4c,
+  0xb2, 0x71, 0xb1, 0x4d, 0x0a, 0x6f, 0xb1, 0x6d, 0x03, 0xac, 0xb8, 0x67,
+  0x8c, 0xb9, 0x0e, 0x87, 0x6e, 0x6e, 0x6c, 0x13, 0x81, 0xe4, 0xed, 0x76,
+  0x77, 0xba, 0x12, 0xd6, 0x21, 0xda, 0xe5, 0xa9, 0xda, 0x12, 0xbf, 0x9a,
+  0x2f, 0x2f, 0x4f, 0x87, 0x22, 0x57, 0xd4, 0x25, 0xc3, 0x25, 0xeb, 0x2a,
+  0xb6, 0x3b, 0x61, 0xe3, 0xb8, 0xaf, 0xe4, 0x0e, 0x18, 0x0e, 0x0f, 0xf1,
+  0xe1, 0x70, 0xc9, 0x6a, 0x01, 0x75, 0x93, 0xaf, 0x22, 0x55, 0x82, 0x6b,
+  0xcd, 0xf1, 0x6c, 0x6d, 0x7e, 0x62, 0xe6, 0xca, 0xf2, 0xd5, 0xe0, 0x2a,
+  0x99, 0x64, 0x79, 0x3c, 0x20, 0x56, 0x4d, 0x24, 0x09, 0x4f, 0x08, 0xe6,
+  0x4a, 0xc7, 0xf5, 0x3d, 0xcd, 0x1e, 0xd3, 0xfc, 0xe4, 0x88, 0x9f, 0xae,
+  0x93, 0x13, 0x5d, 0xdb, 0x49, 0xf1, 0x61, 0x8d, 0x0c, 0x17, 0x87, 0x39,
+  0xcb, 0xd8, 0x5a, 0x5a, 0xb4, 0xb1, 0x4d, 0x3b, 0x35, 0x2d, 0xb7, 0x1c,
+  0xec, 0x8e, 0x15, 0xc6, 0x40, 0x83, 0x5c, 0xb0, 0x91, 0x2b, 0x99, 0xb4,
+  0x73, 0x87, 0x0b, 0x53, 0x6d, 0x22, 0xff, 0xa4, 0x37, 0xa8, 0xd5, 0x23,
+  0x08, 0x88, 0x31, 0x5e, 0x67, 0x39, 0x31, 0xbc, 0x59, 0xd1, 0x20, 0x2d,
+  0xf1, 0x3f, 0xab, 0x7e, 0x45, 0x03, 0x17, 0x03, 0x66, 0xb9, 0xcc, 0x65,
+  0xf1, 0x97, 0xf3, 0xa0, 0x03, 0x5a, 0xb6, 0xe5, 0x0c, 0x5e, 0x63, 0x5b,
+  0x85, 0x76, 0x8e, 0x69, 0x6b, 0x22, 0x3c, 0xc7, 0xc9, 0x9f, 0xb0, 0x06,
+  0x14, 0xa2, 0x45, 0x2d, 0xe7, 0xde, 0x1b, 0x29, 0xda, 0x39, 0xeb, 0xe1,
+  0x75, 0xf9, 0xc4, 0x79, 0x1d, 0xf2, 0x84, 0x9f, 0xe5, 0x37, 0x69, 0x11,
+  0xb3, 0xbc, 0xba, 0x54, 0x38, 0x8f, 0x7d, 0x5e, 0x78, 0xe6, 0xc9, 0x2f,
+  0x49, 0xa5, 0xcc, 0xa8, 0x9f, 0xfa, 0x19, 0x7f, 0x13, 0x3f, 0xa4, 0xb3,
+  0xe5, 0x4c, 0xec, 0xd9, 0x62, 0x02, 0xd0, 0x27, 0x23, 0xef, 0x9b, 0x23,
+  0x7e, 0x98, 0xdd, 0xd7, 0x8e, 0x79, 0xcd, 0xa2, 0xec, 0xac, 0xfa, 0x98,
+  0x13, 0x7f, 0x47, 0x52, 0xdb, 0x40, 0xb5, 0x3d, 0x35, 0xb7, 0xcd, 0xd8,
+  0xe7, 0x23, 0x77, 0x76, 0xd0, 0x4e, 0xb4, 0xb8, 0x89, 0x8b, 0x84, 0x59,
+  0x18, 0xdd, 0xac, 0x6d, 0x53, 0x25, 0xe1, 0xad, 0x70, 0x6f, 0x24, 0x0d,
+  0x7e, 0x4d, 0x9b, 0x49, 0x82, 0x33, 0x2e, 0x68, 0x5a, 0x5e, 0xc4, 0x03,
+  0xc8, 0x95, 0xd7, 0x62, 0x63, 0x98, 0xd1, 0xad, 0x3b, 0x8b, 0x1f, 0xb0,
+  0x2a, 0x26, 0xc4, 0xfd, 0x5a, 0x94, 0xac, 0xb2, 0x71, 0xb0, 0x09, 0x35,
+  0x59, 0xe6, 0x25, 0x04, 0x11, 0x96, 0xcc, 0xeb, 0x9b, 0xe0, 0x0c, 0x46,
+  0x99, 0xf2, 0x58, 0x3c, 0xe9, 0xcc, 0xe2, 0x76, 0xdb, 0x89, 0x39, 0x9f,
+  0xed, 0xb0, 0x26, 0x72, 0xc5, 0x57, 0xb0, 0xae, 0x37, 0x05, 0xd8, 0xc5,
+  0x34, 0x01, 0x0d, 0x39, 0x25, 0x6d, 0xa0, 0xde, 0x2a, 0x69, 0xa4, 0x88,
+  0x2a, 0xcd, 0x54, 0xd4, 0xa4, 0x78, 0xd2, 0xa6, 0xa7, 0xc6, 0x81, 0xb4,
+  0x88, 0xd1, 0xc5, 0x30, 0x5a, 0x32, 0x9f, 0x8a, 0xb5, 0x35, 0xd7, 0x9c,
+  0xd7, 0xb5, 0xf0, 0x6e, 0xad, 0x39, 0x33, 0x66, 0x80, 0x52, 0x36, 0x8b,
+  0x2d, 0xa8, 0xa5, 0x73, 0x2f, 0x46, 0x32, 0xff, 0xbc, 0x9d, 0x67, 0xf7,
+  0xa4, 0x6d, 0xce, 0x33, 0xe9, 0xcb, 0xd6, 0x97, 0xc7, 0xde, 0xe0, 0x46,
+  0x89, 0xde, 0x38, 0x8d, 0x27, 0x4b, 0x27, 0x2f, 0x09, 0xcd, 0x99, 0xd4,
+  0x6c, 0x03, 0x6d, 0xb5, 0x3b, 0xaa, 0xf4, 0x1c, 0xba, 0x7f, 0x93, 0x32,
+  0x14, 0xe2, 0x4d, 0xb3, 0x72, 0xbe, 0xaf, 0x49, 0x5c, 0xdc, 0xf4, 0xa2,
+  0x4e, 0xbf, 0xd3, 0x6b, 0xa1, 0xb8, 0xba, 0x6c, 0x6c, 0xe3, 0x72, 0xc2,
+  0x52, 0xbb, 0x9c, 0xae, 0x8a, 0xba, 0x8e, 0x93, 0x89, 0x87, 0xc4, 0xba,
+  0x2e, 0x74, 0x7a, 0xb5, 0x7c, 0xf2, 0x85, 0xef, 0x1b, 0x13, 0x7a, 0xbc,
+  0xbf, 0xc9, 0xa6, 0xad, 0x27, 0x28, 0x50, 0xd5, 0x33, 0x6e, 0x06, 0xd6,
+  0x43, 0x76, 0x01, 0xb3, 0x24, 0x5d, 0x63, 0x22, 0xd1, 0x78, 0x9a, 0xc4,
+  0xf9, 0x74, 0xa5, 0x5a, 0x5c, 0xfd, 0x04, 0xdd, 0xc9, 0x54, 0xd8, 0xc6,
+  0x1b, 0x13, 0x75, 0xe6, 0x73, 0x5e, 0x5f, 0x75, 0x6b, 0x25, 0x13, 0x09,
+  0x9a, 0x28, 0xc5, 0x94, 0xaf, 0xab, 0x26, 0x6a, 0xc4, 0x5d, 0xca, 0x56,
+  0xa3, 0xc6, 0x6a, 0x27, 0xc9, 0x64, 0x14, 0x8f, 0x6f, 0xb1, 0xd2, 0x68,
+  0x53, 0x5c, 0x57, 0x7c, 0xfe, 0x9c, 0xa1, 0x89, 0x48, 0xf9, 0x86, 0x0e,
+  0x5e, 0x91, 0x96, 0xcb, 0x78, 0xdd, 0x89, 0xad, 0x0a, 0xed, 0x1f, 0x3c,
+  0xb4, 0x55, 0x5a, 0x6e, 0xd3, 0x9d, 0xd7, 0x1c, 0xe9, 0x43, 0x1c, 0x69,
+  0x12, 0xcd, 0xe6, 0x4b, 0x92, 0xdd, 0x89, 0xad, 0x66, 0x57, 0x57, 0x44,
+  0x20, 0x9f, 0x37, 0x4c, 0x07, 0xf2, 0xc8, 0xf6, 0x85, 0x06, 0x52, 0xb9,
+  0x23, 0x56, 0x75, 0xff, 0xf2, 0x85, 0x2d, 0xab, 0x74, 0x9d, 0xf2, 0x5e,
+  0x44, 0xd2, 0x5c, 0xd3, 0x64, 0x56, 0x7f, 0x22, 0xf2, 0xeb, 0x2b, 0x3e,
+  0x92, 0x20, 0x0c, 0x6b, 0xb4, 0x12, 0xa5, 0x3a, 0x2e, 0xeb, 0xd1, 0x1f,
+  0xc6, 0xa4, 0x6f, 0xd3, 0xc5, 0x82, 0x37, 0x0b, 0x01, 0x1a, 0xce, 0xc4,
+  0xc3, 0xad, 0x8d, 0x92, 0xeb, 0x74, 0x3e, 0x0f, 0x43, 0x65, 0xb2, 0x65,
+  0x3e, 0x76, 0x0a, 0xec, 0x28, 0xa1, 0xf3, 0x51, 0x6f, 0xce, 0x4c, 0x12,
+  0xde, 0x89, 0xaa, 0x26, 0x9c, 0x09, 0xa2, 0x6e, 0x8c, 0xfd, 0x9c, 0x5c,
+  0xc9, 0x9e, 0x40, 0xc5, 0x50, 0x8b, 0x58, 0xdb, 0x91, 0x79, 0xed, 0xed,
+  0x3e, 0xe6, 0xda, 0x18, 0x9e, 0xfc, 0xcf, 0x63, 0xef, 0xf0, 0x36, 0x23,
+  0x04, 0x69, 0x31, 0x4c, 0xdd, 0x0d, 0x72, 0x78, 0x47, 0x77, 0x7d, 0xa7,
+  0x7f, 0x18, 0xf5, 0x3b, 0x18, 0x48, 0xc5, 0x73, 0xb1, 0x2c, 0x33, 0x3a,
+  0xde, 0x1a, 0x1a, 0x80, 0xe8, 0x2e, 0xa6, 0x37, 0xd6, 0xad, 0xf2, 0x64,
+  0x5b, 0xfc, 0x3f, 0x59, 0x83, 0x5f, 0x61, 0x0b, 0x65, 0xb1, 0x6d, 0x96,
+  0x30, 0x43, 0x95, 0xea, 0x36, 0x11, 0x0b, 0x86, 0xec, 0x8f, 0xb8, 0x19,
+  0xb7, 0xa1, 0x1e, 0x8b, 0xcb, 0xbc, 0xa9, 0x2a, 0xa8, 0xa1, 0x58, 0xdc,
+  0x82, 0x2d, 0x2c, 0xe0, 0xd7, 0xbb, 0x81, 0xfa, 0xc2, 0x2d, 0x48, 0x4d,
+  0xc8, 0xeb, 0xe3, 0xa8, 0xf8, 0x7c, 0x88, 0xa4, 0xff, 0x4a, 0x32, 0x4d,
+  0xcd, 0xe4, 0x61, 0x6e, 0xad, 0x5e, 0x35, 0x7a, 0x43, 0xda, 0x6c, 0xb3,
+  0x72, 0xd0, 0x05, 0x4d, 0x22, 0x51, 0xcc, 0xa1, 0x29, 0x6c, 0x2a, 0x61,
+  0x7f, 0xb7, 0x4a, 0x9b, 0xd1, 0x4d, 0x4a, 0x63, 0xcf, 0xc7, 0x37, 0x2b,
+  0xbe, 0x2e, 0xd8, 0x00, 0xc9, 0xce, 0x9b, 0x4b, 0x3f, 0xcb, 0x3a, 0xdb,
+  0x42, 0x1f, 0x6a, 0x15, 0x4c, 0x59, 0x63, 0x60, 0x7d, 0x28, 0x9b, 0x1b,
+  0xfd, 0xd4, 0xc6, 0x47, 0x64, 0x71, 0xc3, 0x44, 0x9b, 0x4c, 0x59, 0x02,
+  0xa0, 0x05, 0x6c, 0x1b, 0x5d, 0x3f, 0x0b, 0x38, 0x38, 0xb6, 0x8d, 0xee,
+  0x17, 0x6a, 0x9c, 0x39, 0xa1, 0x18, 0xb0, 0xa4, 0x2b, 0xb6, 0xc2, 0x4a,
+  0x6f, 0x74, 0x19, 0x4d, 0xf9, 0x42, 0x5c, 0xd5, 0x9a, 0x53, 0x9f, 0x94,
+  0xbe, 0x6e, 0x6b, 0x6f, 0x3e, 0xa9, 0xfa, 0x76, 0x5e, 0x66, 0xfa, 0x95,
+  0x5d, 0x7d, 0xb6, 0x2a, 0xa2, 0x53, 0xd5, 0xb5, 0x7a, 0x09, 0x4e, 0x45,
+  0x7c, 0x4f, 0xbf, 0x7f, 0x55, 0x36, 0xac, 0x9c, 0xc1, 0x96, 0x56, 0x77,
+  0x7a, 0x7a, 0x05, 0x9f, 0xde, 0x16, 0x73, 0x1f, 0xa2, 0x94, 0x32, 0x3a,
+  0x7d, 0xcd, 0xd4, 0x76, 0x78, 0x41, 0x3f, 0x53, 0x73, 0xea, 0x31, 0x5b,
+  0x47, 0x90, 0x29, 0x2b, 0xe4, 0x6f, 0xbe, 0x1d, 0x46, 0x9b, 0x67, 0xc3,
+  0xed, 0x27, 0x2f, 0x76, 0xb6, 0xea, 0x6d, 0xf1, 0x4a, 0x41, 0x62, 0x69,
+  0x35, 0xda, 0x0e, 0xb7, 0x39, 0xa0, 0x76, 0x0b, 0x61, 0xcf, 0x77, 0xac,
+  0xf4, 0x56, 0xcc, 0x2c, 0xe7, 0xc7, 0x6f, 0xcc, 0x1e, 0x86, 0xdd, 0x8a,
+  0xa3, 0x43, 0x1a, 0x0f, 0xdb, 0xf2, 0x9b, 0x84, 0x73, 0x91, 0xdc, 0x99,
+  0x55, 0xed, 0x94, 0x15, 0x1e, 0x9c, 0x0a, 0xb6, 0xda, 0x99, 0x7a, 0xb8,
+  0x48, 0x98, 0x13, 0xf8, 0xf7, 0x95, 0xb5, 0x41, 0x4e, 0x68, 0x9e, 0xd6,
+  0x11, 0x64, 0xd4, 0x82, 0x86, 0x94, 0x43, 0xf6, 0xe7, 0x90, 0x89, 0xc9,
+  0x6f, 0x77, 0xc2, 0x6c, 0x4d, 0x0e, 0xcc, 0xd9, 0x0b, 0x5f, 0xef, 0xa7,
+  0x81, 0xff, 0x75, 0xc2, 0x16, 0x27, 0x36, 0x92, 0xbc, 0x7c, 0xc4, 0x02,
+  0x4e, 0x42, 0xab, 0x4a, 0xdc, 0x49, 0x14, 0x5c, 0x4e, 0x78, 0x0f, 0xf6,
+  0x69, 0xc4, 0x3f, 0x98, 0xe7, 0x26, 0xb0, 0x90, 0xb7, 0x8a, 0xdf, 0x3d,
+  0x17, 0xc7, 0x87, 0x9b, 0x2c, 0x5e, 0xc9, 0x8a, 0xc5, 0xd1, 0x28, 0xcf,
+  0xee, 0x39, 0x80, 0x58, 0x42, 0x10, 0x84, 0xf6, 0xd8, 0x5a, 0x81, 0xa8,
+  0x62, 0x16, 0xb3, 0xeb, 0xd7, 0x33, 0xcd, 0x59, 0x5c, 0x34, 0x2c, 0x1e,
+  0x7c, 0x7d, 0xf9, 0xe6, 0x14, 0xdb, 0x0a, 0x0d, 0x46, 0xb4, 0x1f, 0x39,
+  0xa1, 0xc5, 0x72, 0x44, 0xb2, 0x3d, 0xdf, 0xfd, 0xa5, 0x33, 0xbb, 0x84,
+  0x31, 0xc0, 0x46, 0xb9, 0x31, 0x02, 0xa3, 0x94, 0x17, 0x2f, 0xda, 0xac,
+  0xfe, 0xca, 0xf8, 0xcd, 0x3c, 0x8b, 0xcd, 0x24, 0x11, 0x87, 0xf4, 0x98,
+  0xd5, 0xa2, 0x4e, 0x39, 0xa4, 0x95, 0x4f, 0xd5, 0x44, 0xb2, 0xfd, 0xd0,
+  0x27, 0xc5, 0xbd, 0xcf, 0x83, 0xeb, 0x53, 0xf3, 0xe2, 0xd7, 0x64, 0xef,
+  0xf0, 0x21, 0x89, 0xc2, 0x4c, 0x28, 0xd4, 0x7c, 0xff, 0x35, 0xed, 0x04,
+  0x3f, 0xd1, 0xd8, 0x3d, 0xbf, 0x47, 0xfe, 0x56, 0xc5, 0xd2, 0x41, 0xb4,
+  0x95, 0xaf, 0xc4, 0x50, 0x37, 0xc0, 0x69, 0xe6, 0xa0, 0x6a, 0xf5, 0x2f,
+  0x10, 0x1f, 0x9f, 0xd6, 0xb9, 0x03, 0x1b, 0x8f, 0xf3, 0x95, 0x04, 0x32,
+  0xa8, 0x6d, 0xd7, 0x7c, 0x5c, 0xce, 0xcc, 0x29, 0x6d, 0xca, 0x93, 0xde,
+  0x9a, 0x9c, 0xb1, 0xaa, 0x5e, 0x3f, 0xef, 0xea, 0xa4, 0xe5, 0xd7, 0xee,
+  0xe2, 0xe9, 0x12, 0xda, 0x6b, 0x2c, 0xfb, 0x20, 0x5e, 0x5f, 0x44, 0x11,
+  0xc6, 0x2b, 0x34, 0xae, 0x0d, 0xbb, 0x35, 0x68, 0x95, 0x95, 0x38, 0xcc,
+  0x44, 0xae, 0xf7, 0x22, 0x71, 0x11, 0x08, 0x76, 0x06, 0xaa, 0x96, 0x4e,
+  0x8b, 0x2c, 0xb5, 0x48, 0x83, 0xfa, 0xe0, 0x5c, 0xe4, 0x41, 0x2f, 0x70,
+  0xba, 0xa4, 0x7c, 0x0d, 0x04, 0x64, 0x1c, 0xf8, 0x5e, 0x67, 0x49, 0x7e,
+  0x8d, 0xe8, 0xa9, 0x8c, 0xa4, 0xbd, 0xa6, 0x4d, 0x47, 0x7c, 0x76, 0xb1,
+  0x8b, 0x0e, 0x83, 0xf0, 0xfe, 0x87, 0xbe, 0x38, 0x44, 0xa0, 0x4d, 0x2e,
+  0xe9, 0x5c, 0x9a, 0x54, 0xdf, 0xed, 0x4f, 0x22, 0xf5, 0x2d, 0xcd, 0x69,
+  0x25, 0x68, 0x1f, 0x9b, 0x82, 0xce, 0x74, 0xfa, 0x6a, 0x4a, 0x62, 0xd7,
+  0xaa, 0x1b, 0x69, 0xe8, 0x92, 0x06, 0xb4, 0x94, 0x6a, 0xa7, 0x43, 0x14,
+  0xc6, 0xf8, 0x66, 0x39, 0xbf, 0x35, 0xdb, 0xdc, 0x94, 0x84, 0xee, 0x22,
+  0x42, 0xf4, 0x7d, 0xad, 0xb9, 0x6e, 0xd0, 0xd9, 0x1f, 0xc2, 0xb6, 0x5b,
+  0x57, 0x59, 0x94, 0x07, 0x8e, 0xa1, 0x0c, 0x1c, 0x52, 0xee, 0xf2, 0x92,
+  0x08, 0xd4, 0xe8, 0x8b, 0x9e, 0xb9, 0x5e, 0xcb, 0xc0, 0x0f, 0x10, 0x37,
+  0xcf, 0xa1, 0x57, 0x3c, 0xe0, 0x40, 0x70, 0x0d, 0x8a, 0xd3, 0x86, 0x78,
+  0x79, 0xdf, 0xfc, 0x8d, 0x5e, 0x65, 0x74, 0xfe, 0x86, 0xb6, 0xdb, 0x50,
+  0xe8, 0xdd, 0xfb, 0xf6, 0x5c, 0x82, 0x03, 0xce, 0x5b, 0x61, 0xf2, 0x1f,
+  0xba, 0x86, 0xb9, 0x4e, 0xaf, 0xc2, 0xa6, 0x38, 0xc9, 0x34, 0xeb, 0x4e,
+  0xdc, 0x9b, 0x30, 0xcc, 0xb1, 0xe6, 0xfc, 0x37, 0x82, 0x18, 0x44, 0xe7,
+  0x99, 0xc4, 0x63, 0x63, 0x14, 0x6d, 0xea, 0xa6, 0xdd, 0x27, 0x3c, 0xe9,
+  0x49, 0xd4, 0xbd, 0xca, 0xb2, 0x51, 0x9c, 0x77, 0x75, 0x0b, 0xe1, 0x87,
+  0x1e, 0xa9, 0x95, 0x4d, 0x63, 0x70, 0x30, 0x9d, 0x2f, 0xe8, 0xb9, 0x3a,
+  0x85, 0x8e, 0xe2, 0x8a, 0x5d, 0x24, 0x3c, 0x77, 0x8f, 0x71, 0xe4, 0x4b,
+  0x55, 0x41, 0x4a, 0x35, 0x71, 0x43, 0xca, 0x9e, 0x42, 0x7a, 0xa9, 0xb9,
+  0x4d, 0xd8, 0x6b, 0xa7, 0xde, 0xef, 0x45, 0xde, 0xe8, 0x9e, 0x05, 0x22,
+  0xc4, 0xd0, 0x12, 0x6d, 0x15, 0x59, 0x72, 0x17, 0x46, 0x53, 0xff, 0x76,
+  0xc4, 0xc2, 0xcb, 0x46, 0x1b, 0x7a, 0x84, 0xfb, 0x43, 0xe6, 0xe1, 0x82,
+  0xbe, 0x25, 0x8e, 0x2d, 0xb2, 0x90, 0xef, 0x06, 0x8f, 0x6b, 0x09, 0xc4,
+  0xe9, 0xf1, 0x0c, 0x11, 0xf1, 0xa4, 0x67, 0x64, 0x9e, 0xdc, 0xab, 0xd3,
+  0x90, 0x99, 0x2b, 0x5f, 0x05, 0xcc, 0xb7, 0xc5, 0xb4, 0x35, 0x86, 0xf4,
+  0x51, 0x58, 0x7c, 0x58, 0x5d, 0xb9, 0xe2, 0x25, 0xc0, 0xce, 0xfd, 0x93,
+  0x97, 0xb2, 0x29, 0x95, 0xf0, 0x58, 0x66, 0x6c, 0x98, 0x32, 0x0d, 0xbf,
+  0xb1, 0x0e, 0x1c, 0xf5, 0x20, 0xd1, 0xb9, 0x08, 0x58, 0x92, 0x45, 0x8d,
+  0x0b, 0xcd, 0xe1, 0x18, 0xc9, 0x8a, 0x38, 0xe6, 0xdf, 0xa0, 0x12, 0xc7,
+  0x44, 0x7f, 0x09, 0xa1, 0xf4, 0xdc, 0x02, 0xeb, 0x8d, 0x26, 0x31, 0xda,
+  0x4a, 0xa0, 0x2e, 0x4c, 0x2c, 0x6d, 0x84, 0x94, 0x48, 0xb8, 0x1b, 0x2f,
+  0x32, 0x8c, 0x6b, 0x2e, 0x9e, 0x89, 0x54, 0x77, 0xe6, 0xf5, 0x85, 0x3f,
+  0x66, 0x34, 0xdf, 0x41, 0x55, 0xe2, 0xf8, 0x6c, 0xb0, 0xb3, 0xd5, 0x14,
+  0x3a, 0x89, 0x36, 0x0e, 0xbf, 0x3a, 0x81, 0xd1, 0x74, 0x9a, 0xc6, 0x9c,
+  0xd1, 0xc0, 0x7d, 0xc8, 0x5c, 0x34, 0xbf, 0xc4, 0x88, 0xe8, 0x9a, 0xed,
+  0x7e, 0x8e, 0xf9, 0x86, 0x31, 0x76, 0xce, 0x2c, 0xc2, 0x2b, 0xad, 0xf9,
+  0x39, 0xb1, 0xb1, 0xe7, 0x4c, 0x22, 0x3b, 0x63, 0xe3, 0x1a, 0x2e, 0x64,
+  0x23, 0xf6, 0x8e, 0x80, 0xd6, 0xb5, 0x43, 0xef, 0xcc, 0x1b, 0xd8, 0xe9,
+  0x19, 0xc3, 0x8a, 0x4a, 0xcb, 0x05, 0xa6, 0xd5, 0xb0, 0xd2, 0xfa, 0x4d,
+  0x96, 0x94, 0x9d, 0xa4, 0xd8, 0xdf, 0x68, 0x58, 0x59, 0xd0, 0x7d, 0x7b,
+  0xbe, 0x9b, 0x93, 0x46, 0xc4, 0x91, 0x8c, 0x4e, 0x3c, 0xcb, 0x0a, 0x85,
+  0x0c, 0x91, 0x6b, 0x58, 0x2c, 0xc1, 0xfa, 0xb7, 0x37, 0x07, 0x5d, 0xf6,
+  0x3f, 0x99, 0x21, 0x42, 0xd6, 0x24, 0x0a, 0x67, 0x69, 0xda, 0x32, 0x19,
+  0xc2, 0xd6, 0x2c, 0x84, 0x8d, 0xff, 0x8e, 0x1b, 0x5e, 0x66, 0x17, 0xfa,
+  0xb3, 0x8a, 0x5e, 0x31, 0xff, 0xfe, 0x42, 0xdd, 0xfe, 0x6c, 0x6c, 0x0e,
+  0xb5, 0x77, 0xd1, 0x32, 0xd5, 0x09, 0x2e, 0xa2, 0x09, 0x96, 0xa1, 0xbd,
+  0x39, 0x38, 0xe0, 0xc3, 0xd5, 0x13, 0xf2, 0xe3, 0xc0, 0xd4, 0x42, 0x92,
+  0xb6, 0x1a, 0x2e, 0xcf, 0x57, 0x1f, 0x5e, 0xbd, 0x5f, 0xba, 0x7c, 0x8f,
+  0xaf, 0xde, 0x25, 0xa2, 0x8c, 0x49, 0x46, 0x40, 0x74, 0xc9, 0xab, 0x20,
+  0xdc, 0x81, 0xb5, 0x7b, 0x09, 0xc6, 0xf3, 0xfe, 0xe3, 0xea, 0xd1, 0x0c,
+  0x4c, 0x34, 0xaf, 0x7e, 0xad, 0x5d, 0x07, 0x31, 0xc2, 0x25, 0xc3, 0x83,
+  0x6f, 0x6f, 0x4e, 0xd8, 0x1e, 0xf6, 0x3e, 0x8c, 0x37, 0xd4, 0x5b, 0x19,
+  0x2d, 0x50, 0x7f, 0xc9, 0xc3, 0x42, 0x4d, 0xd4, 0x38, 0x7d, 0x2d, 0xc2,
+  0x5c, 0x45, 0xa6, 0x9b, 0xd8, 0x9d, 0xda, 0x98, 0xdf, 0x17, 0xc6, 0xc4,
+  0x3f, 0x34, 0xb9, 0x4a, 0x70, 0x04, 0xc2, 0x72, 0xc2, 0x8b, 0xbd, 0x62,
+  0x5a, 0x6a, 0xb1, 0x74, 0x19, 0x27, 0xf3, 0x01, 0x90, 0x92, 0x1f, 0x61,
+  0xec, 0x7d, 0xab, 0x57, 0x5d, 0xb3, 0x58, 0xc5, 0x5e, 0xdb, 0xe8, 0xf6,
+  0xe6, 0x52, 0x56, 0x98, 0x6c, 0xfb, 0x58, 0x71, 0x69, 0xdd, 0xbe, 0xff,
+  0xcb, 0xa6, 0x28, 0x36, 0x3a, 0x50, 0x83, 0x90, 0x03, 0x9b, 0x33, 0xd5,
+  0xab, 0x43, 0x6a, 0x1b, 0xdd, 0x5f, 0x11, 0xa7, 0x8b, 0xae, 0x61, 0x02,
+  0xb8, 0x9f, 0xd8, 0x22, 0xc7, 0xc6, 0xa6, 0x29, 0x44, 0xa3, 0x54, 0x62,
+  0x9d, 0x5f, 0x79, 0x75, 0xa6, 0x8f, 0x40, 0x1f, 0xa5, 0xda, 0x01, 0xe8,
+  0xf0, 0x11, 0x62, 0x75, 0xc4, 0xd9, 0x4e, 0x97, 0x6b, 0x29, 0xd0, 0x7c,
+  0xca, 0xed, 0xb7, 0x9d, 0x84, 0x26, 0x14, 0xe2, 0x74, 0x3f, 0xc2, 0x83,
+  0x6b, 0xbd, 0xee, 0x71, 0xf0, 0x4d, 0xd3, 0x87, 0x68, 0x97, 0x1c, 0x1b,
+  0x46, 0x21, 0x70, 0x22, 0xf9, 0x80, 0x56, 0xfc, 0x3e, 0xcb, 0x35, 0x48,
+  0x6b, 0x94, 0x80, 0xeb, 0xf3, 0x19, 0xcd, 0xe0, 0x55, 0x62, 0x1b, 0x37,
+  0x07, 0xc6, 0x35, 0x43, 0x76, 0xd8, 0x66, 0x8d, 0x70, 0x03, 0xd8, 0x37,
+  0x2c, 0xb0, 0xa7, 0x19, 0xca, 0xa3, 0x76, 0x2a, 0xe4, 0x91, 0xd0, 0x5c,
+  0x97, 0x1a, 0xdc, 0xdb, 0xee, 0xb0, 0x43, 0xa4, 0xae, 0xe4, 0xf3, 0xca,
+  0x52, 0x1a, 0x51, 0xf0, 0x10, 0x03, 0x47, 0x93, 0xf9, 0xe3, 0x1f, 0xf1,
+  0xbf, 0xe3, 0x55, 0x1f, 0x2d, 0xc8, 0xc6, 0x17, 0xcb, 0x64, 0x55, 0x99,
+  0xe0, 0x5f, 0xb0, 0x51, 0x04, 0x62, 0x50, 0x36, 0xa6, 0x73, 0x92, 0x23,
+  0xb7, 0xb1, 0xa1, 0xa9, 0xd1, 0x29, 0x82, 0xc5, 0x4a, 0xbc, 0xd2, 0xe3,
+  0xa4, 0xba, 0xe7, 0x88, 0xcc, 0xef, 0x27, 0x8b, 0xbc, 0x6c, 0x89, 0x13,
+  0x97, 0x50, 0x57, 0x9f, 0x7a, 0x22, 0x4f, 0x8b, 0x2b, 0xd4, 0x87, 0xa3,
+  0x1f, 0x9f, 0x5f, 0x5c, 0x62, 0xa2, 0xa7, 0xfc, 0x8b, 0x1a, 0x6f, 0xeb,
+  0xe3, 0x80, 0xd1, 0x41, 0x63, 0x51, 0x39, 0x02, 0x2c, 0x81, 0xdd, 0xcb,
+  0xe5, 0x43, 0x0d, 0x82, 0xa4, 0x2a, 0x97, 0xee, 0x13, 0x4f, 0xef, 0x39,
+  0x69, 0x06, 0x12, 0x5d, 0x63, 0x6d, 0x25, 0xf1, 0xca, 0xc2, 0x11, 0x78,
+  0x0c, 0x3d, 0xb9, 0x33, 0x31, 0x0a, 0xb1, 0x58, 0x9b, 0x5d, 0xea, 0x8c,
+  0xbf, 0x64, 0x17, 0x85, 0x8a, 0xd6, 0x6b, 0x5c, 0xb5, 0x3d, 0xc9, 0x27,
+  0x98, 0x4e, 0xd1, 0x24, 0xbf, 0x15, 0xe5, 0x48, 0xd3, 0x8b, 0x69, 0x1c,
+  0x03, 0x3f, 0x4f, 0xe9, 0x42, 0x2c, 0x51, 0x44, 0x7b, 0x41, 0x4e, 0xb6,
+  0x29, 0xa0, 0x12, 0xdc, 0xcf, 0x7a, 0x98, 0x88, 0xad, 0xd4, 0x0c, 0xb2,
+  0x7c, 0x30, 0x69, 0x97, 0xb8, 0x27, 0xfe, 0x65, 0xd6, 0xe1, 0xf9, 0x06,
+  0x44, 0x00, 0x2d, 0xa7, 0x50, 0x34, 0x0c, 0x28, 0x1a, 0xb1, 0x6e, 0x5e,
+  0x96, 0x64, 0xa5, 0xc9, 0x17, 0xa2, 0xb4, 0x5f, 0xa9, 0x05, 0x37, 0x9e,
+  0xa6, 0xe5, 0x4a, 0x84, 0xfd, 0x91, 0x28, 0x0e, 0x6a, 0x02, 0x6a, 0x8b,
+  0x18, 0xa5, 0x85, 0x9f, 0xa4, 0xf2, 0x96, 0x4c, 0x54, 0xb7, 0xad, 0x41,
+  0x8e, 0xc3, 0x20, 0x8d, 0x49, 0x12, 0x1a, 0x98, 0xe0, 0x99, 0x5e, 0x4c,
+  0x90, 0x5b, 0xaa, 0x18, 0x47, 0xdc, 0x66, 0x9a, 0x8e, 0x53, 0xd6, 0x96,
+  0x74, 0x78, 0xbc, 0x60, 0xf5, 0x7d, 0xe3, 0xbc, 0x10, 0x3d, 0x15, 0xf3,
+  0x4c, 0xda, 0x61, 0x9e, 0xc1, 0xd3, 0x4e, 0x63, 0x49, 0x99, 0xab, 0x92,
+  0x65, 0x63, 0x44, 0x47, 0xf8, 0x92, 0xf7, 0x15, 0x1b, 0x02, 0x3f, 0xd3,
+  0xf8, 0x06, 0x19, 0xa6, 0xe2, 0xde, 0x17, 0xf2, 0x1a, 0x25, 0x37, 0xf1,
+  0x5d, 0x9a, 0xe5, 0x83, 0x4a, 0xaa, 0x51, 0xd3, 0x72, 0x58, 0x10, 0x4d,
+  0x8c, 0x6f, 0x64, 0xb3, 0xf8, 0x90, 0xf3, 0xbb, 0x1a, 0xbc, 0x04, 0xed,
+  0x4c, 0x13, 0x8d, 0xb0, 0x45, 0x30, 0xb5, 0x9c, 0x6f, 0x8b, 0x7d, 0x16,
+  0xee, 0xb3, 0x46, 0x9c, 0x1e, 0x42, 0xad, 0x5c, 0x5e, 0x8a, 0x3e, 0x19,
+  0x17, 0x77, 0xed, 0xa7, 0xae, 0xb8, 0xfb, 0xe5, 0xa7, 0x0e, 0x01, 0xd3,
+  0x20, 0xab, 0xe3, 0xf3, 0xe1, 0xb7, 0x91, 0xf3, 0x96, 0xb4, 0x45, 0xf3,
+  0xca, 0x81, 0xf3, 0xf3, 0x02, 0xf9, 0x05, 0x87, 0xee, 0x9f, 0x3c, 0x75,
+  0xee, 0xd0, 0x51, 0xff, 0x7a, 0xd2, 0xce, 0x0f, 0x86, 0xdf, 0xd6, 0xce,
+  0x98, 0x77, 0x23, 0x58, 0x12, 0x47, 0x5d, 0x1e, 0xe0, 0x24, 0xaa, 0xdc,
+  0x82, 0xd2, 0xb8, 0xb5, 0x8f, 0x26, 0xbf, 0xe2, 0xee, 0xd7, 0x21, 0x3f,
+  0x6a, 0xe7, 0x31, 0xf2, 0x0b, 0xf7, 0xad, 0x85, 0xfc, 0x68, 0xfa, 0x0d,
+  0xf2, 0xb3, 0xb5, 0x6e, 0xa7, 0xbf, 0x75, 0xe4, 0x57, 0x66, 0x46, 0xb7,
+  0x20, 0xbd, 0x20, 0xc3, 0xad, 0x49, 0x74, 0x01, 0x29, 0xd5, 0xe2, 0x1a,
+  0xdb, 0x2d, 0xf7, 0xdf, 0x21, 0x7e, 0x40, 0x93, 0xfc, 0x24, 0x03, 0x39,
+  0x08, 0x94, 0xac, 0x26, 0x7e, 0x23, 0x6c, 0x73, 0xa3, 0x35, 0x74, 0x3f,
+  0x70, 0xb2, 0x4a, 0x58, 0xad, 0xcb, 0xe0, 0x25, 0xa6, 0x1b, 0x4c, 0x50,
+  0x23, 0x3e, 0xb9, 0x5d, 0xed, 0x66, 0xa3, 0x45, 0x4e, 0x89, 0x35, 0xd2,
+  0x3b, 0x45, 0x4c, 0x00, 0x5b, 0xc1, 0xe9, 0x4d, 0x6a, 0x65, 0xa0, 0xf1,
+  0xd7, 0x45, 0x28, 0xe7, 0xd9, 0x70, 0x25, 0x12, 0xb4, 0xc9, 0xce, 0xe6,
+  0xe2, 0x01, 0x10, 0x1b, 0x19, 0x82, 0x59, 0x62, 0x8b, 0x67, 0x71, 0x60,
+  0x13, 0x73, 0xe7, 0x6f, 0x00, 0xd6, 0x84, 0x8f, 0x10, 0xa8, 0x5b, 0x85,
+  0x83, 0x70, 0x58, 0x99, 0xf2, 0xef, 0x20, 0xe4, 0xad, 0x09, 0x51, 0xe5,
+  0xd5, 0x90, 0xac, 0x33, 0xe1, 0xbb, 0xcd, 0x38, 0x05, 0xe5, 0xc3, 0xb5,
+  0x48, 0xd8, 0xc6, 0x22, 0xc3, 0x31, 0xe7, 0x72, 0x23, 0x2c, 0xb4, 0x33,
+  0x09, 0xfd, 0xa2, 0x2e, 0xa4, 0x49, 0x8c, 0x30, 0x71, 0x1e, 0x3a, 0x3d,
+  0x1a, 0x0e, 0x11, 0x9e, 0x5f, 0x47, 0x57, 0xae, 0xa3, 0xd1, 0x47, 0x4b,
+  0x79, 0x8b, 0xa3, 0x68, 0x61, 0x4c, 0xcc, 0x93, 0xdf, 0xd0, 0x0b, 0x99,
+  0xd0, 0x82, 0x21, 0x4f, 0x91, 0x09, 0x93, 0x84, 0xcf, 0x75, 0x69, 0x53,
+  0xb2, 0xfb, 0x1c, 0x0c, 0x7e, 0xa1, 0x4f, 0x9f, 0xc7, 0xd7, 0x09, 0x27,
+  0x33, 0x8a, 0x33, 0xc9, 0x47, 0x1d, 0x69, 0x3e, 0x7c, 0x7b, 0xda, 0xd4,
+  0xa5, 0xc5, 0xc1, 0xb6, 0xa6, 0x1d, 0x55, 0x12, 0x8d, 0x90, 0x2c, 0xe6,
+  0xd3, 0x8c, 0x64, 0xf1, 0x9b, 0xa1, 0xc9, 0x16, 0x20, 0x5d, 0x89, 0x01,
+  0x77, 0xc8, 0x07, 0x62, 0x5c, 0xea, 0xfc, 0x99, 0x9d, 0xcb, 0x1d, 0x1b,
+  0x60, 0xe4, 0xa6, 0xdc, 0xb4, 0x96, 0xf2, 0x33, 0x5e, 0x2b, 0xad, 0xfa,
+  0xa4, 0x79, 0xa8, 0x72, 0x42, 0x35, 0x5e, 0x80, 0x9f, 0xc7, 0xc9, 0x22,
+  0xde, 0x49, 0x82, 0x5e, 0x9d, 0xac, 0x48, 0xf0, 0x63, 0x49, 0xfb, 0x54,
+  0x47, 0xb5, 0xaf, 0x47, 0x44, 0xf4, 0x11, 0x1b, 0x93, 0xa6, 0x6a, 0x29,
+  0xa3, 0xb4, 0x90, 0xee, 0x29, 0xe3, 0x84, 0xd4, 0x9d, 0x0d, 0xac, 0x47,
+  0xb9, 0xc4, 0x15, 0xb6, 0x5e, 0xf0, 0x80, 0x62, 0xd6, 0x75, 0x52, 0x00,
+  0x45, 0xb8, 0x69, 0xfd, 0x96, 0x5e, 0xeb, 0x64, 0x7e, 0xcd, 0xc9, 0x8c,
+  0x2f, 0x5b, 0x63, 0xa5, 0x92, 0xa9, 0x4f, 0xef, 0xb5, 0x88, 0xca, 0x71,
+  0xbe, 0x5a, 0x30, 0xeb, 0x97, 0xf7, 0x94, 0x1f, 0x31, 0x0f, 0x97, 0xb8,
+  0xc9, 0x20, 0x1b, 0x7c, 0xd0, 0x12, 0x2c, 0xe0, 0x3a, 0x94, 0x90, 0x52,
+  0x08, 0x00, 0xb4, 0x60, 0x25, 0xb8, 0x87, 0x7c, 0xc6, 0x57, 0xed, 0x68,
+  0x99, 0x4e, 0x27, 0x12, 0x3a, 0xe6, 0x41, 0x43, 0x1a, 0xce, 0x1a, 0x6e,
+  0xa8, 0x18, 0x54, 0x93, 0x85, 0x90, 0xec, 0x8b, 0x10, 0xa9, 0x4d, 0x8e,
+  0xd3, 0x9d, 0xd3, 0xdc, 0xb7, 0x4c, 0x68, 0xd6, 0x37, 0x34, 0x51, 0xa1,
+  0x7e, 0x4d, 0xdd, 0xc5, 0xe9, 0x14, 0x77, 0x18, 0x35, 0x93, 0x2f, 0xe7,
+  0xe8, 0xbd, 0xba, 0x52, 0x77, 0x69, 0x9e, 0xcd, 0x67, 0x4d, 0x3b, 0xc8,
+  0xe6, 0xc5, 0xc9, 0xf0, 0x30, 0x3a, 0x1b, 0x46, 0x67, 0x6f, 0x4f, 0x7f,
+  0xe0, 0xc3, 0x85, 0x88, 0x63, 0x00, 0x70, 0x70, 0xd7, 0xc1, 0x8b, 0xd1,
+  0x5d, 0x9c, 0xa7, 0x50, 0xeb, 0x7a, 0xeb, 0xb9, 0xa1, 0x40, 0x42, 0xe0,
+  0xfc, 0xdc, 0xdb, 0x16, 0xfb, 0xf0, 0x48, 0xbe, 0xb5, 0x10, 0x23, 0x98,
+  0xc4, 0x45, 0x9a, 0xe4, 0x62, 0x0f, 0x1f, 0x5b, 0x12, 0xdf, 0xb2, 0x99,
+  0x53, 0xc6, 0x36, 0xb3, 0xf0, 0x58, 0x4b, 0x20, 0x1b, 0x5f, 0x94, 0xd4,
+  0x3d, 0x4d, 0xb4, 0x16, 0xd9, 0x41, 0x13, 0xbd, 0x16, 0xfd, 0x77, 0x8d,
+  0x4f, 0x3a, 0x88, 0x54, 0x5e, 0xe9, 0xed, 0xcb, 0xa6, 0x79, 0xa8, 0xe3,
+  0x4e, 0xfa, 0x3e, 0x9e, 0x97, 0x79, 0xb6, 0x20, 0x9e, 0xff, 0x55, 0xcc,
+  0x2c, 0x0f, 0x33, 0x3d, 0x8a, 0x93, 0x59, 0x23, 0xfa, 0xa0, 0xc8, 0xc6,
+  0xb7, 0x49, 0xa9, 0x1e, 0x11, 0xfd, 0x2b, 0x48, 0x59, 0x83, 0x5e, 0x28,
+  0x7c, 0x93, 0x17, 0x74, 0x42, 0xd7, 0x93, 0x12, 0x10, 0x93, 0x1c, 0x0d,
+  0xa5, 0x69, 0x9e, 0x34, 0x28, 0x88, 0x6a, 0x78, 0x22, 0x9f, 0x26, 0xbc,
+  0x2f, 0x53, 0xab, 0x07, 0x24, 0xf6, 0x8f, 0xf9, 0xa6, 0x61, 0x4f, 0xfe,
+  0xcb, 0xc0, 0xff, 0xfd, 0xe3, 0xbe, 0xa9, 0xa0, 0x3f, 0xb5, 0x2f, 0x43,
+  0x33, 0x44, 0xbe, 0x7a, 0xb5, 0x07, 0x6d, 0x69, 0xd0, 0x1c, 0xb3, 0x97,
+  0xeb, 0x96, 0x2b, 0xcb, 0x32, 0xf1, 0x34, 0xb4, 0x8e, 0x56, 0x14, 0xbe,
+  0xff, 0x48, 0x32, 0x0e, 0x86, 0xc2, 0x64, 0xc2, 0xe6, 0x2c, 0xf1, 0x8c,
+  0xee, 0xad, 0xf3, 0xe3, 0x37, 0x8f, 0x84, 0xd6, 0xc1, 0x34, 0xb9, 0x50,
+  0xbd, 0xc3, 0x69, 0xfd, 0x92, 0xbe, 0xea, 0x46, 0x5a, 0xcb, 0xfa, 0xad,
+  0x35, 0xf7, 0xb7, 0x25, 0x43, 0x14, 0x4d, 0x34, 0xb5, 0x20, 0xb3, 0xdc,
+  0x55, 0x97, 0x2a, 0x5f, 0x4f, 0x0c, 0xb6, 0xc4, 0x74, 0xc0, 0x96, 0x14,
+  0x0d, 0xb7, 0x49, 0x27, 0x98, 0x47, 0x47, 0xa3, 0xb4, 0x34, 0x8e, 0x4d,
+  0xf8, 0x31, 0x92, 0x95, 0xa2, 0xdb, 0x64, 0xe5, 0x02, 0x78, 0xed, 0x33,
+  0x5e, 0x82, 0xe6, 0xda, 0xe9, 0x92, 0x20, 0x59, 0x9c, 0x7e, 0x99, 0xb3,
+  0xb2, 0xff, 0xbb, 0x08, 0xfb, 0x1f, 0xe9, 0xb6, 0x8a, 0x12, 0xd9, 0xef,
+  0x73, 0xa3, 0xa5, 0x87, 0xcf, 0xe1, 0x54, 0xf3, 0x46, 0xba, 0x8d, 0x03,
+  0xa7, 0x9a, 0xae, 0xda, 0x58, 0xaf, 0xa0, 0x68, 0x14, 0x60, 0x52, 0x9a,
+  0x75, 0x5f, 0x94, 0x16, 0x28, 0x8e, 0x28, 0xfa, 0x69, 0x3a, 0xca, 0x11,
+  0x9a, 0x23, 0x72, 0x52, 0x18, 0x30, 0xd7, 0x10, 0x55, 0x3c, 0x01, 0xb1,
+  0x15, 0x29, 0x1d, 0xdf, 0xe2, 0x24, 0x29, 0xc7, 0x0a, 0x37, 0xdc, 0x44,
+  0x3f, 0x01, 0xa7, 0xd2, 0xee, 0xea, 0xba, 0x47, 0x5c, 0xc6, 0x0c, 0x4c,
+  0xc3, 0x49, 0x17, 0xe9, 0x5c, 0x02, 0xb7, 0x24, 0x72, 0x2d, 0xe0, 0x41,
+  0x8e, 0x09, 0x21, 0xe4, 0xff, 0xfd, 0xd1, 0xc9, 0x85, 0x32, 0xcb, 0xd1,
+  0x6a, 0x4d, 0xea, 0x46, 0xb4, 0x9d, 0x94, 0xe3, 0xed, 0xc5, 0x6d, 0xba,
+  0x3d, 0x2f, 0x8a, 0xc9, 0x68, 0x2b, 0x4c, 0x28, 0xe7, 0x39, 0x73, 0x10,
+  0xca, 0xf9, 0x37, 0x87, 0xc3, 0x4f, 0x76, 0x77, 0x59, 0x96, 0x5e, 0x52,
+  0xd3, 0x9b, 0xb4, 0x06, 0x8d, 0x4c, 0xb9, 0x82, 0x96, 0x7d, 0x36, 0x28,
+  0xb2, 0x2d, 0x28, 0x00, 0x8e, 0xe1, 0x62, 0x95, 0x10, 0xc8, 0x02, 0x47,
+  0xa6, 0xe6, 0x91, 0xb1, 0xfd, 0xf1, 0xb7, 0x8c, 0x27, 0x11, 0xc2, 0x40,
+  0xb4, 0x43, 0xf4, 0x92, 0xff, 0xfd, 0xe0, 0x11, 0x07, 0x38, 0x4d, 0x65,
+  0x4b, 0xf8, 0x5d, 0x15, 0xf2, 0x39, 0x34, 0x67, 0x12, 0x85, 0x5f, 0xd7,
+  0xe9, 0x8a, 0xcd, 0x64, 0x03, 0x9e, 0x67, 0x2f, 0x3a, 0x3a, 0xbe, 0x00,
+  0x41, 0x1e, 0xbf, 0xfd, 0x0a, 0xc2, 0x21, 0xe7, 0xda, 0x5d, 0xcf, 0xd3,
+  0x9f, 0x99, 0xd3, 0x51, 0x9b, 0x85, 0x2c, 0x30, 0xdf, 0x65, 0xfe, 0x84,
+  0xd6, 0x9a, 0xe3, 0xf5, 0xe2, 0x55, 0xc4, 0x19, 0xfb, 0x6d, 0x97, 0x29,
+  0x16, 0xc6, 0x78, 0x78, 0x10, 0xce, 0xee, 0x57, 0x62, 0x88, 0x8c, 0x2a,
+  0x44, 0xcc, 0xe5, 0x6a, 0xd5, 0xe6, 0x38, 0xe7, 0x78, 0x24, 0xbb, 0x1a,
+  0x24, 0x2a, 0x92, 0x69, 0x43, 0x9d, 0x3c, 0x1e, 0x8a, 0xa7, 0x3a, 0x30,
+  0x24, 0xc3, 0x37, 0x62, 0x73, 0xfd, 0xf7, 0x9b, 0xc5, 0x56, 0x8d, 0x79,
+  0x3a, 0x76, 0xf9, 0xd6, 0xf4, 0xf1, 0xea, 0x11, 0x6f, 0x6a, 0x90, 0x3c,
+  0xb1, 0xd8, 0x1d, 0x0f, 0xcb, 0x05, 0xc4, 0x8a, 0xf7, 0xc4, 0x41, 0x55,
+  0x59, 0x7a, 0xda, 0x53, 0x95, 0x39, 0xf5, 0x52, 0x6b, 0xa4, 0x8d, 0x95,
+  0xb0, 0xb9, 0xb2, 0x45, 0x3c, 0x68, 0xb3, 0xb1, 0xa9, 0x18, 0x96, 0xa3,
+  0x95, 0x42, 0x85, 0x9a, 0xa6, 0x74, 0xa1, 0xbe, 0xfc, 0xa8, 0x7b, 0x48,
+  0x22, 0xed, 0xfb, 0xc3, 0x83, 0xf7, 0x5f, 0xbe, 0x7b, 0x7b, 0x74, 0x7a,
+  0xdc, 0xad, 0x53, 0xe4, 0x95, 0x70, 0x7d, 0xe4, 0xf8, 0x26, 0x65, 0xcf,
+  0x65, 0xc7, 0x87, 0x51, 0x96, 0xb8, 0xdd, 0x91, 0xfc, 0x8a, 0xdf, 0x10,
+  0x8e, 0xad, 0x0b, 0x5e, 0x57, 0x7f, 0x96, 0xf3, 0x09, 0x12, 0x10, 0x83,
+  0xc9, 0x5b, 0xce, 0x89, 0xba, 0xd9, 0x6c, 0x80, 0x2d, 0xea, 0x2e, 0xd3,
+  0x1f, 0xdd, 0xcf, 0x24, 0x62, 0x07, 0x48, 0x20, 0x01, 0x04, 0x56, 0x45,
+  0x74, 0x47, 0xe4, 0x88, 0x61, 0x16, 0x46, 0x34, 0x9e, 0x96, 0xed, 0x2e,
+  0x2a, 0x61, 0x0d, 0xdc, 0x12, 0x51, 0x72, 0x5f, 0x07, 0x39, 0xce, 0xcb,
+  0x6e, 0x2f, 0x4a, 0x52, 0xb8, 0xec, 0xc2, 0x10, 0xae, 0x49, 0x6b, 0x1a,
+  0x0e, 0x87, 0x55, 0xc6, 0x42, 0xd7, 0x83, 0xe4, 0x21, 0x41, 0x14, 0x88,
+  0xbe, 0x75, 0x08, 0x23, 0x70, 0x19, 0x7d, 0x97, 0xe5, 0x48, 0xef, 0x3f,
+  0xb2, 0x38, 0x4c, 0x7b, 0x28, 0x9e, 0xaf, 0x9a, 0x1e, 0x5e, 0xd6, 0x88,
+  0x58, 0x2b, 0xb8, 0x16, 0xbc, 0xc6, 0xf3, 0x83, 0xcb, 0xaf, 0x5b, 0x83,
+  0x15, 0x3c, 0x6a, 0xe3, 0x87, 0x6f, 0x1b, 0xb0, 0xd1, 0x72, 0x6d, 0x9c,
+  0xe7, 0x07, 0xae, 0x9a, 0xea, 0x21, 0xaa, 0xdd, 0x36, 0x2d, 0x52, 0x2a,
+  0xf7, 0xbe, 0xf6, 0xbe, 0x69, 0x25, 0x4a, 0xbb, 0x6c, 0xf8, 0xae, 0x59,
+  0x7b, 0xd5, 0xb4, 0xde, 0x34, 0x36, 0x5b, 0x3e, 0xab, 0xee, 0xa2, 0xb1,
+  0x9b, 0xe6, 0xff, 0x8c, 0xab, 0x26, 0xc6, 0xe9, 0xa9, 0xf1, 0x50, 0x1f,
+  0xb4, 0xdb, 0xce, 0x4d, 0x95, 0x9d, 0x7e, 0x24, 0x3f, 0xf5, 0x11, 0xc0,
+  0x0d, 0x06, 0x23, 0x2c, 0x56, 0xae, 0xaa, 0xc4, 0x54, 0xd6, 0x4a, 0xa0,
+  0x67, 0x2b, 0x47, 0xec, 0x99, 0xfc, 0x55, 0xdf, 0x2c, 0xd7, 0x93, 0xbc,
+  0xc7, 0xda, 0x04, 0x42, 0xd6, 0x99, 0x5f, 0xe4, 0xd9, 0x58, 0x92, 0xb5,
+  0x82, 0xc8, 0xc2, 0xf7, 0x79, 0x72, 0x13, 0x17, 0x37, 0xd1, 0xb2, 0x4c,
+  0xd9, 0x62, 0x5e, 0xd7, 0x01, 0x96, 0x1c, 0x5e, 0x68, 0xaa, 0xbf, 0xa5,
+  0x04, 0x6a, 0x6a, 0xbb, 0x5b, 0x3b, 0x20, 0x33, 0x8a, 0xea, 0x13, 0xc4,
+  0x5c, 0xb1, 0x72, 0x5f, 0x57, 0x5b, 0x87, 0xa7, 0xfd, 0x10, 0x12, 0x6e,
+  0xc6, 0xb9, 0x9c, 0x30, 0xdb, 0x27, 0x57, 0x34, 0xdd, 0x34, 0x48, 0x13,
+  0x5c, 0xba, 0x2e, 0x70, 0xc5, 0xa5, 0x57, 0x6d, 0xc6, 0x29, 0xfb, 0x16,
+  0xec, 0x44, 0x2f, 0x9f, 0x42, 0x40, 0xe3, 0xea, 0x37, 0xcf, 0x6f, 0x47,
+  0x41, 0x57, 0x6c, 0x8c, 0x24, 0x2a, 0x6e, 0xb7, 0xe7, 0xbc, 0xe6, 0x2c,
+  0x93, 0x82, 0xbd, 0xbc, 0x3c, 0xb5, 0x4d, 0x46, 0x49, 0x12, 0x0c, 0x2e,
+  0xb6, 0xfa, 0x4d, 0xa7, 0x5b, 0x2c, 0xb3, 0x5b, 0x0e, 0x1c, 0x52, 0x4f,
+  0x0a, 0xcd, 0x17, 0x6b, 0xca, 0x28, 0x86, 0xdb, 0x84, 0x88, 0x2f, 0x38,
+  0x31, 0xe1, 0xd7, 0x50, 0xfb, 0x2e, 0x10, 0x59, 0x89, 0xb5, 0xd2, 0x29,
+  0x0d, 0xbe, 0x9c, 0x24, 0x8a, 0xdf, 0x57, 0x67, 0x74, 0x82, 0xe4, 0xaa,
+  0x26, 0x6c, 0xea, 0xf3, 0x64, 0x6e, 0x0e, 0x41, 0x09, 0x93, 0x80, 0x3a,
+  0x14, 0x47, 0x15, 0x1b, 0x93, 0xbc, 0x56, 0xb4, 0xdc, 0xba, 0x93, 0x64,
+  0x9a, 0xe2, 0x01, 0x86, 0x89, 0xd5, 0x4c, 0x40, 0x55, 0x5c, 0x24, 0x61,
+  0x50, 0x9d, 0xc0, 0x88, 0x9e, 0xb5, 0x07, 0x38, 0xd4, 0x0b, 0xda, 0x55,
+  0x51, 0x6f, 0x6e, 0x53, 0x12, 0xc0, 0x80, 0xdf, 0x28, 0x7a, 0xa2, 0x45,
+  0x2b, 0xf1, 0xc0, 0x56, 0x0e, 0x92, 0x77, 0x4b, 0xaf, 0x34, 0x58, 0xb0,
+  0x54, 0x45, 0x5a, 0xe4, 0x0d, 0x3d, 0x9b, 0x5d, 0xab, 0x42, 0x98, 0x02,
+  0xaa, 0x8c, 0x0d, 0x28, 0xe5, 0x08, 0xc4, 0x65, 0x98, 0xd6, 0x28, 0xc9,
+  0x3f, 0x7b, 0x7b, 0x6b, 0x8c, 0xbe, 0x9a, 0x83, 0xac, 0x41, 0x1a, 0xbc,
+  0x18, 0xfd, 0x22, 0xbe, 0x4a, 0xec, 0x2c, 0x12, 0x1d, 0xb3, 0xc8, 0x98,
+  0x8d, 0x69, 0x09, 0x25, 0xc2, 0x09, 0x9f, 0xcd, 0xb3, 0xa6, 0x4b, 0x6c,
+  0x39, 0xe6, 0xa3, 0xc8, 0x06, 0x00, 0x67, 0xc6, 0x64, 0x57, 0xb4, 0x79,
+  0xfb, 0x8b, 0x69, 0xba, 0x60, 0xd6, 0x9e, 0x67, 0xcb, 0xeb, 0x1b, 0x0e,
+  0x3c, 0x03, 0x5f, 0x91, 0x0b, 0xb6, 0xc5, 0xb1, 0x51, 0x4b, 0x95, 0x86,
+  0x3c, 0x7b, 0x97, 0x4d, 0xd9, 0xac, 0xb9, 0x59, 0x6b, 0xff, 0xe9, 0xce,
+  0x2e, 0x86, 0xfb, 0x74, 0xe7, 0xd3, 0x4a, 0xb4, 0x3b, 0x9b, 0xd3, 0xe3,
+  0x31, 0x72, 0x61, 0xa2, 0x1f, 0xf9, 0xf2, 0xf8, 0xa9, 0xd5, 0x17, 0x03,
+  0xbb, 0x6c, 0x3c, 0x0f, 0xed, 0xb0, 0x71, 0x71, 0x2b, 0xae, 0x82, 0x8e,
+  0xbd, 0xcf, 0xaf, 0x77, 0xd4, 0x9a, 0xe1, 0xfc, 0xc6, 0x2d, 0x68, 0x3f,
+  0x4e, 0xe5, 0xe5, 0xdc, 0x46, 0x63, 0x51, 0x90, 0xd6, 0x7b, 0x01, 0x36,
+  0x20, 0xc0, 0x07, 0x80, 0x51, 0x78, 0xb5, 0xde, 0x32, 0x73, 0x70, 0x78,
+  0xe8, 0xbd, 0x76, 0xd5, 0xb8, 0xb0, 0x27, 0x1c, 0x17, 0xb6, 0x2e, 0x59,
+  0xaa, 0x76, 0xfc, 0x01, 0x2e, 0xd3, 0xd3, 0x20, 0x6c, 0x18, 0xcc, 0x2b,
+  0xf9, 0xb9, 0x66, 0x94, 0x6c, 0x10, 0x18, 0x8c, 0x94, 0xcb, 0x22, 0xa9,
+  0xaf, 0xe8, 0xfa, 0xcc, 0x93, 0x3a, 0xf0, 0x98, 0xae, 0xa9, 0xa6, 0x3e,
+  0xb0, 0xc1, 0x73, 0xdb, 0x27, 0xac, 0x41, 0xf0, 0x43, 0xa4, 0x6e, 0x2c,
+  0xee, 0xfb, 0x46, 0x64, 0x91, 0x43, 0x0a, 0x13, 0xcf, 0x37, 0xfc, 0x3e,
+  0x0f, 0x48, 0x9d, 0x9e, 0x07, 0x21, 0xe5, 0x3a, 0xb3, 0x92, 0x16, 0x29,
+  0xce, 0x27, 0xce, 0x29, 0xd3, 0x84, 0xeb, 0x30, 0x29, 0x9b, 0xf3, 0x74,
+  0x18, 0xd2, 0x26, 0x04, 0x33, 0x31, 0x3f, 0x96, 0x97, 0x00, 0x2d, 0xb0,
+  0xbb, 0x89, 0xf7, 0x5a, 0xc9, 0xd6, 0x88, 0x66, 0xa9, 0x84, 0x81, 0x06,
+  0xa9, 0x1f, 0xf5, 0x05, 0xd3, 0x13, 0xf6, 0xa3, 0xfc, 0x6c, 0xa7, 0x41,
+  0x24, 0x96, 0xe5, 0x19, 0xa7, 0xe2, 0x20, 0x4d, 0x42, 0x5e, 0x91, 0x5c,
+  0x65, 0x89, 0xe5, 0xf3, 0x80, 0x2f, 0x8c, 0x15, 0x20, 0xd7, 0x03, 0x5b,
+  0x3d, 0x9a, 0x49, 0x56, 0x9b, 0xc3, 0x2d, 0x33, 0xa0, 0xe3, 0xe6, 0xd5,
+  0xc6, 0xe2, 0xfc, 0x5a, 0x59, 0x94, 0x8b, 0x30, 0x0d, 0xc2, 0xc9, 0x34,
+  0xd6, 0xa0, 0xdf, 0x30, 0x4f, 0x5c, 0x8b, 0xbe, 0xc0, 0xb1, 0x16, 0x77,
+  0x2d, 0x11, 0x7a, 0x50, 0x8b, 0xc6, 0xf7, 0x93, 0xf6, 0x80, 0x15, 0xb9,
+  0x39, 0x25, 0x29, 0x21, 0x76, 0x58, 0x62, 0x87, 0xdf, 0x1d, 0x05, 0x99,
+  0x8b, 0x7c, 0xcc, 0x30, 0x29, 0x10, 0x82, 0x44, 0x5c, 0xcd, 0xd7, 0xc5,
+  0xbf, 0x98, 0x9e, 0x00, 0xec, 0xd8, 0xd7, 0x80, 0x02, 0x4f, 0x16, 0x2e,
+  0x07, 0x09, 0x10, 0x31, 0x02, 0x4e, 0xc3, 0x38, 0xb0, 0x00, 0x7c, 0xc5,
+  0xd5, 0xb9, 0x66, 0x74, 0x1a, 0xc8, 0x30, 0x08, 0xb1, 0xab, 0x90, 0x2b,
+  0x76, 0xf1, 0xfa, 0x70, 0xf7, 0xd3, 0x27, 0x9f, 0x91, 0x90, 0xbe, 0x42,
+  0xda, 0x90, 0x5f, 0x32, 0x09, 0x70, 0x5d, 0x1f, 0xd9, 0xa4, 0x56, 0x25,
+  0x13, 0x30, 0xd5, 0x9f, 0x4f, 0xcc, 0x2f, 0xbb, 0x4f, 0x20, 0xf3, 0xa8,
+  0xcf, 0xb0, 0x11, 0x39, 0x95, 0xd1, 0x22, 0x1a, 0x98, 0xa8, 0xe0, 0x48,
+  0x62, 0x9d, 0xe4, 0x4a, 0x1d, 0x04, 0x94, 0xc9, 0x18, 0xbb, 0x9c, 0x37,
+  0x47, 0x2c, 0xf4, 0xe2, 0xf8, 0xf2, 0x82, 0x51, 0xef, 0x2f, 0xcf, 0x2e,
+  0xd6, 0x84, 0xa3, 0xd1, 0xc5, 0xc9, 0x5c, 0x89, 0x17, 0x8d, 0x89, 0x86,
+  0xe1, 0x07, 0x4c, 0xb1, 0x0a, 0xb2, 0x32, 0x78, 0x0b, 0x62, 0x81, 0x27,
+  0x2e, 0x5a, 0xb3, 0x01, 0x82, 0xa4, 0x80, 0xa2, 0x82, 0xbe, 0x41, 0x47,
+  0x89, 0xce, 0xc9, 0x63, 0x13, 0x93, 0x3d, 0x7f, 0x9c, 0x42, 0x30, 0x61,
+  0x26, 0x46, 0x9e, 0xb1, 0xf3, 0xe7, 0x60, 0xb4, 0x0a, 0x3b, 0xe8, 0x65,
+  0x40, 0xbd, 0x97, 0xd6, 0x50, 0x88, 0x90, 0x55, 0x52, 0x04, 0x76, 0x43,
+  0x51, 0xe5, 0x3b, 0xe6, 0xfd, 0xee, 0xb0, 0x04, 0x7f, 0xeb, 0xe0, 0x2d,
+  0x3e, 0x40, 0xbf, 0x24, 0x37, 0x6c, 0xf9, 0x09, 0x33, 0xc2, 0x20, 0xce,
+  0xa7, 0x08, 0x78, 0x8e, 0xeb, 0x14, 0x9a, 0x9a, 0x9d, 0x4a, 0x00, 0x42,
+  0x33, 0x20, 0xc3, 0xe5, 0x19, 0xf0, 0x2e, 0x77, 0x9d, 0x13, 0x3d, 0x53,
+  0xea, 0x90, 0x7d, 0x21, 0xa1, 0x67, 0x5a, 0x22, 0x81, 0xa3, 0x6b, 0xa3,
+  0xea, 0x3a, 0x52, 0xab, 0xb0, 0xff, 0x67, 0x83, 0xdd, 0xad, 0x1a, 0x93,
+  0xe1, 0x08, 0x84, 0x76, 0xce, 0xc2, 0x8e, 0x90, 0x5a, 0xdc, 0x83, 0x58,
+  0x0f, 0x34, 0x18, 0x9d, 0xae, 0x04, 0xc3, 0xf7, 0x38, 0xd7, 0xa7, 0x5a,
+  0x91, 0x55, 0x50, 0xf1, 0x80, 0xad, 0xba, 0x8e, 0xb6, 0x75, 0xcb, 0x25,
+  0x28, 0x60, 0x59, 0xe7, 0xa6, 0x15, 0xf7, 0x7d, 0x93, 0x7f, 0xba, 0xfb,
+  0x27, 0x48, 0xa1, 0x65, 0x27, 0xb8, 0x0f, 0xbc, 0xd0, 0xe4, 0x99, 0xca,
+  0xcc, 0x77, 0x7f, 0xc1, 0xc5, 0xf7, 0x68, 0x40, 0xd5, 0x2f, 0x8a, 0xa7,
+  0x8a, 0xde, 0xcd, 0x35, 0xb0, 0x89, 0x83, 0xfe, 0x0c, 0x6c, 0xc7, 0x2f,
+  0x2a, 0x31, 0x65, 0x88, 0x31, 0x30, 0x73, 0x37, 0x6e, 0x31, 0x31, 0x7e,
+  0xf2, 0x1a, 0x49, 0x46, 0xcf, 0xb2, 0xd0, 0x0c, 0x53, 0xbb, 0x63, 0xb4,
+  0x45, 0x8d, 0x5d, 0x15, 0x54, 0x6b, 0x17, 0x0f, 0xd0, 0x80, 0x42, 0xcb,
+  0x55, 0x2f, 0x6f, 0x9c, 0x34, 0xdb, 0x3d, 0x6c, 0xb1, 0x70, 0x40, 0xc8,
+  0x82, 0x9e, 0x75, 0x94, 0xa2, 0xb7, 0x4b, 0x5c, 0x83, 0x45, 0x95, 0x48,
+  0x38, 0x7d, 0x13, 0x30, 0x4f, 0x94, 0x57, 0x04, 0x7d, 0x28, 0x4c, 0x4e,
+  0x35, 0x6e, 0xc2, 0xd6, 0xb9, 0x21, 0x71, 0xf9, 0xeb, 0xa2, 0x5f, 0x66,
+  0x88, 0xc2, 0x8b, 0x5e, 0x6a, 0x67, 0x9f, 0xb7, 0x93, 0x28, 0x72, 0x97,
+  0x02, 0x79, 0xcf, 0xa0, 0xc9, 0x81, 0xb3, 0x39, 0x54, 0xeb, 0x25, 0x0d,
+  0x65, 0xe8, 0x58, 0xb6, 0x48, 0xed, 0xbd, 0x46, 0x18, 0x95, 0xa1, 0xfe,
+  0x78, 0xb9, 0xc9, 0xfc, 0xee, 0xa6, 0xa3, 0x41, 0xd6, 0x22, 0x16, 0x7a,
+  0xb9, 0x9c, 0xd1, 0x4c, 0xee, 0x93, 0x64, 0xd2, 0x2d, 0xd8, 0x78, 0xcf,
+  0xb8, 0x8c, 0x75, 0x01, 0x99, 0xc3, 0x68, 0xb0, 0xe0, 0x4e, 0x59, 0x40,
+  0xb8, 0x22, 0x7c, 0x24, 0x16, 0x60, 0x10, 0x1b, 0x36, 0x5f, 0xa0, 0x9a,
+  0xa9, 0xbb, 0xad, 0xee, 0x88, 0x18, 0x9e, 0x5c, 0x1e, 0x47, 0x07, 0xef,
+  0x2e, 0xbf, 0xee, 0x04, 0xd8, 0xab, 0x01, 0x1b, 0xc6, 0xf5, 0x5e, 0x92,
+  0x08, 0x71, 0x27, 0xb4, 0x00, 0x41, 0x53, 0x5c, 0x5d, 0x2d, 0x70, 0x0b,
+  0x35, 0x8b, 0xfd, 0xa0, 0xce, 0x22, 0x9e, 0xd5, 0x59, 0x04, 0x67, 0x87,
+  0x83, 0x4f, 0xf4, 0xd3, 0xc5, 0x87, 0x83, 0x92, 0x2c, 0x1a, 0x8a, 0xbb,
+  0x39, 0x39, 0x67, 0xd0, 0x5b, 0xa0, 0x10, 0x07, 0xc3, 0x2d, 0x96, 0xd7,
+  0x1c, 0x26, 0xda, 0x02, 0xb4, 0xc6, 0x70, 0x20, 0x4e, 0x46, 0xd7, 0xf8,
+  0x7f, 0x5a, 0x65, 0x26, 0x26, 0x47, 0x76, 0x50, 0xc6, 0xd0, 0x99, 0xee,
+  0x4c, 0xe1, 0xd3, 0x97, 0xd6, 0xba, 0xd9, 0xd8, 0x40, 0x63, 0xa8, 0x92,
+  0x61, 0xe6, 0xb2, 0x42, 0xb3, 0x7b, 0xc3, 0x5a, 0x30, 0xe2, 0x06, 0xa6,
+  0x93, 0xe5, 0x3b, 0x41, 0x02, 0x35, 0x56, 0x38, 0x56, 0xf9, 0x2b, 0xec,
+  0xab, 0xb2, 0xa0, 0x4f, 0x07, 0x7b, 0x5b, 0xad, 0x1a, 0x94, 0x72, 0x1d,
+  0x96, 0xf7, 0x89, 0x6b, 0x90, 0xd2, 0xcf, 0xc7, 0x97, 0x74, 0x7b, 0x89,
+  0x49, 0x94, 0x08, 0xb6, 0x5c, 0x8e, 0x9c, 0x71, 0x26, 0x3b, 0xf9, 0x4d,
+  0x1c, 0x25, 0x5e, 0xa2, 0xfa, 0x81, 0x22, 0xf6, 0xd8, 0x1e, 0xba, 0x29,
+  0x1b, 0xe6, 0x76, 0x0c, 0xd4, 0x1f, 0x47, 0xe7, 0x24, 0x15, 0xb8, 0x55,
+  0x0e, 0x62, 0xb7, 0xa2, 0x4d, 0xf8, 0x00, 0x68, 0x1c, 0x5b, 0x75, 0x01,
+  0x86, 0x93, 0x78, 0xe3, 0x34, 0xd4, 0x80, 0x88, 0x5f, 0xce, 0xe8, 0x13,
+  0xd6, 0xcc, 0x73, 0x1a, 0x03, 0x7b, 0xec, 0x0c, 0xbc, 0x52, 0x0f, 0x18,
+  0x6b, 0x80, 0x76, 0xff, 0x6d, 0xb4, 0xca, 0x55, 0x6a, 0x31, 0x0d, 0xcc,
+  0x37, 0xec, 0x72, 0xa7, 0x73, 0x81, 0x2a, 0x27, 0x80, 0x18, 0x89, 0x19,
+  0x6c, 0x1c, 0xa7, 0x7b, 0x92, 0xdd, 0xcf, 0x81, 0x1c, 0xd0, 0xa4, 0x26,
+  0x0c, 0x9e, 0x99, 0xda, 0xa0, 0x7a, 0x0d, 0xee, 0xed, 0x0c, 0x1e, 0x42,
+  0x1a, 0x2f, 0x8a, 0xa9, 0xac, 0x4c, 0x8f, 0xd6, 0xfe, 0xfc, 0x49, 0x2f,
+  0x3a, 0x79, 0x73, 0x40, 0xbf, 0x0f, 0xdf, 0x80, 0xb6, 0x73, 0x17, 0xce,
+  0x34, 0x1c, 0x9e, 0x6e, 0x5f, 0x9e, 0x0e, 0x83, 0xea, 0x15, 0xc1, 0xa6,
+  0x37, 0x93, 0x98, 0x61, 0xdc, 0x85, 0x21, 0x1a, 0x53, 0x16, 0x00, 0xd7,
+  0x00, 0xe6, 0x26, 0xbd, 0x0a, 0x0f, 0x85, 0x29, 0x2d, 0xea, 0x42, 0x6f,
+  0x1a, 0x8b, 0xb6, 0x05, 0x1b, 0x2a, 0x88, 0x31, 0xc6, 0xd9, 0x2c, 0xa6,
+  0x7d, 0x23, 0x41, 0x09, 0x5e, 0xe3, 0x4f, 0x68, 0xc9, 0x27, 0xb6, 0x88,
+  0x7c, 0x19, 0x35, 0x33, 0x48, 0xcb, 0x68, 0x4a, 0x23, 0x9c, 0x16, 0xe2,
+  0xf9, 0x47, 0xb4, 0x04, 0x8f, 0x49, 0xf7, 0xaa, 0xa6, 0x36, 0xd2, 0x82,
+  0xed, 0x6c, 0x3d, 0x1e, 0xfa, 0x75, 0x1f, 0x17, 0xe2, 0xcf, 0x4d, 0x72,
+  0xda, 0x7b, 0xa0, 0xb5, 0x08, 0x30, 0x99, 0x0e, 0xb2, 0xe5, 0x36, 0x6e,
+  0xea, 0xc0, 0x72, 0xeb, 0xd0, 0x5d, 0x49, 0xbb, 0xed, 0xcd, 0x4b, 0x2a,
+  0xf5, 0xc8, 0x07, 0x9c, 0x30, 0x7f, 0x67, 0x99, 0x6b, 0x57, 0x4b, 0xae,
+  0xf8, 0x03, 0xbb, 0x61, 0x5b, 0x9c, 0x6d, 0xfd, 0x3c, 0x04, 0x6b, 0xd5,
+  0x7e, 0x2c, 0x2e, 0x8c, 0x52, 0x6d, 0xa7, 0xfd, 0x56, 0x33, 0x85, 0x4f,
+  0xb3, 0x6b, 0x46, 0x3c, 0x95, 0xd0, 0x72, 0x9c, 0x7f, 0xc3, 0x7e, 0xa8,
+  0x2b, 0xe0, 0x53, 0x04, 0xe1, 0xe8, 0x96, 0x57, 0x0d, 0x12, 0x22, 0xf4,
+  0x30, 0x45, 0xe8, 0xb2, 0x27, 0x2e, 0x7d, 0xc1, 0x45, 0x5f, 0x36, 0xdd,
+  0xe4, 0x91, 0x33, 0x0a, 0x8e, 0x57, 0x7c, 0x35, 0xbd, 0x86, 0xed, 0x49,
+  0xc3, 0x75, 0x05, 0x38, 0x64, 0x2d, 0x39, 0xb5, 0x4a, 0x02, 0x9e, 0xa0,
+  0x2a, 0x1b, 0xf3, 0x3c, 0xdc, 0x68, 0x4f, 0x4b, 0x2d, 0xcb, 0xd5, 0x76,
+  0x56, 0x1e, 0x5b, 0xc0, 0x47, 0xce, 0xca, 0xa5, 0x38, 0xe8, 0x0d, 0xdd,
+  0xe1, 0x63, 0x8f, 0x88, 0x9b, 0xc3, 0x23, 0xa9, 0xf7, 0xeb, 0x29, 0x57,
+  0x09, 0xb7, 0x4a, 0xb7, 0x4a, 0xb8, 0x9a, 0x01, 0x69, 0x34, 0x83, 0xd3,
+  0x44, 0x5c, 0x10, 0xcd, 0x36, 0xd9, 0x8c, 0x5e, 0x9a, 0x91, 0xe1, 0xf0,
+  0xb2, 0x98, 0x2f, 0xf5, 0x79, 0x4a, 0xcb, 0x72, 0x7e, 0x94, 0x8c, 0x1b,
+  0x81, 0x30, 0x20, 0x6a, 0x75, 0x2f, 0xb5, 0xd2, 0xf0, 0x78, 0xdc, 0x4a,
+  0xbf, 0x2c, 0xb0, 0x1f, 0x1e, 0x1e, 0x46, 0x9b, 0x87, 0xa0, 0xd0, 0x43,
+  0xe5, 0xa6, 0x87, 0x37, 0x9c, 0xd7, 0x39, 0x65, 0x4c, 0x81, 0x9b, 0x25,
+  0x67, 0xa0, 0x4c, 0x30, 0x47, 0x6c, 0x8a, 0x2e, 0x61, 0x3d, 0x84, 0x2c,
+  0x5e, 0xb1, 0x2d, 0x4b, 0xa0, 0xa4, 0x2a, 0xe2, 0x95, 0x18, 0x06, 0x90,
+  0x6f, 0x6a, 0xbe, 0x7f, 0xbb, 0xff, 0xa4, 0x97, 0xd6, 0x94, 0xf0, 0xe5,
+  0xdc, 0xac, 0x71, 0xce, 0x6c, 0x3c, 0x77, 0xd4, 0xaf, 0x5a, 0x52, 0x2c,
+  0x67, 0xe6, 0xed, 0xc1, 0x25, 0x23, 0x45, 0x97, 0x1a, 0x82, 0xba, 0x26,
+  0xc0, 0xcd, 0x1d, 0x49, 0x50, 0x7f, 0x1c, 0xa0, 0x0c, 0x9a, 0x8e, 0x01,
+  0x59, 0x96, 0x93, 0x25, 0x45, 0xb6, 0x95, 0x28, 0x9b, 0x56, 0xc1, 0x58,
+  0x57, 0xb4, 0xef, 0x14, 0x1c, 0x49, 0x90, 0xe3, 0x3f, 0x8b, 0xe6, 0xf1,
+  0x68, 0xe8, 0x4f, 0x95, 0xd7, 0x7f, 0x94, 0x48, 0xdd, 0x6d, 0xed, 0xf5,
+  0xa7, 0x7f, 0x6a, 0x9b, 0x10, 0x98, 0x25, 0xdb, 0xc3, 0x8f, 0xd9, 0x0d,
+  0xd6, 0xf4, 0x16, 0xd7, 0x62, 0xd2, 0x45, 0xa2, 0x91, 0x8c, 0xb9, 0x14,
+  0x78, 0xd5, 0x72, 0x78, 0x68, 0xd3, 0x27, 0x00, 0xcf, 0x62, 0x02, 0x34,
+  0xd5, 0xe1, 0x3e, 0x6e, 0x88, 0x37, 0x26, 0xd1, 0x78, 0xa1, 0x72, 0xc2,
+  0x35, 0x77, 0xc4, 0xbb, 0xe2, 0xb0, 0x76, 0xf2, 0x64, 0x31, 0x5d, 0x39,
+  0x33, 0x80, 0xb6, 0xbd, 0x4e, 0xcc, 0x0c, 0xad, 0x49, 0x61, 0x10, 0xb3,
+  0x0d, 0xb0, 0xa8, 0xb6, 0x82, 0x8e, 0x62, 0x16, 0x02, 0xaf, 0x1a, 0xd1,
+  0xf3, 0xb1, 0xf6, 0x5c, 0x03, 0x6b, 0x6e, 0xee, 0x50, 0x20, 0x6d, 0x39,
+  0x80, 0x07, 0x45, 0x9c, 0xd6, 0x4c, 0xa9, 0xc7, 0xf2, 0x76, 0xa7, 0xbc,
+  0xf8, 0x10, 0x8c, 0x12, 0xd2, 0xa5, 0x91, 0xa7, 0xa3, 0xa0, 0x17, 0xfd,
+  0x74, 0x2e, 0x18, 0x0b, 0xf4, 0x53, 0x4c, 0xf2, 0x06, 0x94, 0x51, 0xc7,
+  0x8d, 0x64, 0xee, 0x61, 0x50, 0x80, 0x9a, 0xa0, 0x29, 0x70, 0x18, 0x55,
+  0x3c, 0x0c, 0xc5, 0x4b, 0x35, 0x29, 0x0c, 0x80, 0x1e, 0x2d, 0x42, 0xac,
+  0xf7, 0x4f, 0x1d, 0x2a, 0xf2, 0xc5, 0x25, 0xc7, 0x73, 0x48, 0x58, 0x41,
+  0x9c, 0x97, 0xdb, 0xc0, 0xb8, 0x90, 0x14, 0xb5, 0x31, 0x63, 0x21, 0x6b,
+  0x49, 0x81, 0x8b, 0xd7, 0x87, 0x7b, 0x4f, 0x3e, 0xfb, 0xac, 0x3d, 0x16,
+  0x36, 0xd1, 0xac, 0xad, 0x00, 0xd4, 0x9b, 0x71, 0xa2, 0x24, 0x0b, 0x5e,
+  0x9c, 0x8e, 0x5c, 0xbc, 0x86, 0x93, 0x86, 0xbd, 0x8a, 0xd9, 0x1d, 0x37,
+  0x8d, 0xf7, 0x3c, 0xa0, 0xae, 0x18, 0xdf, 0x24, 0x95, 0xcc, 0x6a, 0xa9,
+  0x68, 0x19, 0x0e, 0x87, 0x18, 0xa0, 0x18, 0x5a, 0xec, 0xa5, 0x9f, 0x73,
+  0x6a, 0x6b, 0x7a, 0x0d, 0x7c, 0x8b, 0x5a, 0x73, 0x7f, 0x65, 0x1d, 0xf7,
+  0x3a, 0x29, 0x9b, 0xe9, 0x98, 0x8a, 0x39, 0xf7, 0x81, 0xc6, 0xdb, 0x68,
+  0x50, 0x92, 0x49, 0x5f, 0x2a, 0x7f, 0x70, 0xca, 0xb9, 0x95, 0x1f, 0xa2,
+  0xc1, 0x80, 0x71, 0xbf, 0x74, 0x58, 0x1f, 0x0e, 0x94, 0xf5, 0x8b, 0x16,
+  0x0d, 0xbf, 0xf0, 0xf1, 0x6f, 0x82, 0x4f, 0x56, 0x96, 0xb1, 0x15, 0x50,
+  0x83, 0x45, 0x9c, 0xf1, 0x23, 0x1c, 0x0a, 0xb7, 0x2b, 0x9c, 0x41, 0x14,
+  0x33, 0x6d, 0x43, 0x48, 0x7a, 0xa9, 0x8d, 0xc6, 0x02, 0x8d, 0x2b, 0xf8,
+  0x1d, 0x3c, 0x9e, 0xb6, 0x95, 0x30, 0xad, 0x83, 0x03, 0xd8, 0x92, 0x87,
+  0xc6, 0xf9, 0xc5, 0xbb, 0xc1, 0x3a, 0x35, 0x14, 0xfd, 0xe3, 0x87, 0x78,
+  0x86, 0xba, 0x5e, 0x4e, 0xea, 0x87, 0x5b, 0xdf, 0xe7, 0xd8, 0x69, 0xa8,
+  0x4b, 0x68, 0x24, 0x17, 0xb7, 0x4d, 0x97, 0x9f, 0xa9, 0xef, 0x3d, 0xbf,
+  0xd3, 0x35, 0x7b, 0x5e, 0xe8, 0xa4, 0x07, 0x45, 0xca, 0x70, 0x1c, 0x80,
+  0xa1, 0x78, 0xcc, 0xb9, 0xa7, 0xc9, 0x1a, 0x10, 0x32, 0x7e, 0x13, 0x28,
+  0x59, 0xfb, 0xad, 0x01, 0x25, 0xfd, 0xd7, 0x6e, 0xa0, 0xaf, 0xbe, 0xa8,
+  0xb4, 0x76, 0x7f, 0x3f, 0x98, 0xad, 0xec, 0xbb, 0xa2, 0x52, 0xdd, 0xd0,
+  0xe7, 0xbe, 0x6b, 0x06, 0x80, 0x91, 0x4c, 0xb7, 0x70, 0xe4, 0xe5, 0x11,
+  0x2f, 0xc2, 0x22, 0x39, 0xbe, 0x26, 0x10, 0xdd, 0x1b, 0xcd, 0x8c, 0x35,
+  0x4d, 0x63, 0xf0, 0xd4, 0x27, 0x96, 0xde, 0x2e, 0xd2, 0x3b, 0x12, 0x3b,
+  0xe2, 0xd7, 0x99, 0x6a, 0x8a, 0x23, 0xba, 0x54, 0x88, 0xd0, 0x94, 0xd2,
+  0x9a, 0x6a, 0x6a, 0x51, 0xe6, 0xcb, 0x71, 0xd9, 0xf4, 0xcc, 0xfa, 0x62,
+  0x7f, 0x82, 0xd9, 0x5c, 0x7a, 0xc5, 0x4d, 0x0c, 0xfe, 0x55, 0xa6, 0x80,
+  0x2b, 0x93, 0x47, 0x6c, 0x78, 0xce, 0x75, 0xbc, 0x12, 0xc0, 0x38, 0x77,
+  0x7b, 0x22, 0x3e, 0x2b, 0xde, 0x83, 0x87, 0x27, 0x58, 0xbb, 0xf0, 0x9d,
+  0xfb, 0x64, 0xf4, 0xea, 0x0b, 0x0e, 0x39, 0x7c, 0x00, 0x0c, 0xac, 0xc0,
+  0x41, 0x33, 0x0d, 0x6e, 0xf3, 0x9f, 0x9d, 0x88, 0x23, 0x4e, 0x5a, 0xd6,
+  0x9d, 0xb8, 0xf8, 0xba, 0x16, 0x03, 0xe4, 0x94, 0xa0, 0xb5, 0xab, 0x2c,
+  0x5b, 0xdb, 0xd8, 0x0f, 0x61, 0x61, 0xc1, 0x20, 0xa7, 0x47, 0x52, 0x6c,
+  0x3c, 0x11, 0x0a, 0xe1, 0xf1, 0x16, 0xce, 0xf5, 0x9c, 0xca, 0x21, 0x6c,
+  0x43, 0x1c, 0x18, 0xad, 0x5c, 0x81, 0x09, 0xcb, 0x3e, 0x7e, 0xd5, 0x93,
+  0x3a, 0xab, 0xac, 0xad, 0xae, 0x5f, 0x10, 0x7e, 0xfa, 0xd5, 0x17, 0xc0,
+  0x34, 0xe3, 0x5f, 0xff, 0xec, 0xde, 0xe6, 0x7f, 0x88, 0x8a, 0x89, 0x0b,
+  0xac, 0x9d, 0x08, 0x8b, 0x22, 0x57, 0xcb, 0x1c, 0x62, 0x46, 0x22, 0x47,
+  0xb2, 0x10, 0x5d, 0x56, 0x11, 0x8b, 0x95, 0x95, 0xbc, 0x39, 0x78, 0xfb,
+  0xee, 0xe0, 0x74, 0xf0, 0x98, 0xf8, 0x1a, 0x9a, 0x4a, 0x5d, 0xa0, 0x19,
+  0xec, 0x96, 0x15, 0xc1, 0x91, 0xcf, 0xa3, 0x86, 0xfc, 0xcb, 0x4d, 0xf8,
+  0x68, 0xb5, 0x9a, 0x68, 0x68, 0x88, 0x20, 0x4c, 0x4e, 0x7a, 0x83, 0x2a,
+  0xdc, 0x87, 0xcb, 0x24, 0x16, 0xe4, 0x21, 0x6d, 0x54, 0x45, 0x87, 0x96,
+  0x08, 0x71, 0x76, 0x6c, 0xe6, 0xb1, 0xd4, 0xee, 0x32, 0x2b, 0xc6, 0x34,
+  0xe5, 0x12, 0xb8, 0x53, 0x46, 0x94, 0x3c, 0xd5, 0x62, 0x9e, 0xdd, 0x2f,
+  0xba, 0x72, 0x36, 0xba, 0x2f, 0xbb, 0x8c, 0xbe, 0x43, 0xef, 0x8c, 0x5b,
+  0xf2, 0x65, 0x0a, 0x17, 0xea, 0x11, 0x75, 0x85, 0x6a, 0xba, 0x36, 0x04,
+  0x5d, 0x33, 0x19, 0x16, 0x02, 0x3d, 0xe6, 0x1a, 0x3f, 0xcb, 0xc5, 0x2c,
+  0x93, 0x78, 0xde, 0xe2, 0xa1, 0xaa, 0xa6, 0x06, 0x4b, 0xe5, 0x2c, 0x5c,
+  0x0d, 0x65, 0x66, 0xd3, 0x16, 0x0d, 0x24, 0x67, 0x7e, 0xc1, 0x91, 0x14,
+  0x02, 0x41, 0xd9, 0x16, 0x1d, 0x22, 0x37, 0x46, 0x50, 0x2c, 0x27, 0xd2,
+  0xb1, 0x70, 0xf0, 0x0e, 0x5d, 0xcc, 0x29, 0x47, 0xea, 0xc2, 0xda, 0x4b,
+  0xdf, 0x5e, 0x5f, 0x6b, 0xf2, 0x32, 0xcf, 0x9b, 0xd6, 0x8e, 0x66, 0xdd,
+  0xc0, 0xc1, 0xd4, 0xca, 0xb9, 0x44, 0xc7, 0x75, 0x90, 0xaa, 0xfe, 0x35,
+  0x89, 0x35, 0xd7, 0xd3, 0x6c, 0x94, 0x5d, 0x5d, 0x3d, 0x42, 0x1b, 0x92,
+  0x3f, 0x86, 0x26, 0x84, 0x2d, 0x77, 0x38, 0x73, 0x84, 0xdf, 0x1b, 0x69,
+  0x3d, 0x59, 0xae, 0xab, 0x30, 0x10, 0x33, 0x27, 0xa0, 0xa9, 0x1a, 0xe6,
+  0xa2, 0x30, 0x24, 0xb8, 0xe7, 0xf2, 0x5b, 0x2c, 0x2a, 0x19, 0x85, 0x46,
+  0x45, 0x67, 0xd7, 0x58, 0x47, 0x0f, 0x4d, 0x53, 0x44, 0x7f, 0xff, 0xc7,
+  0x8f, 0x3f, 0xb5, 0x80, 0x39, 0xb1, 0xeb, 0x42, 0xa3, 0xfa, 0x39, 0xaa,
+  0x59, 0xb3, 0x91, 0xe0, 0x23, 0x60, 0x7b, 0x95, 0x47, 0x71, 0xd4, 0xca,
+  0x38, 0x83, 0x20, 0x6f, 0xa2, 0x79, 0x61, 0xb0, 0xed, 0xce, 0x3a, 0x8c,
+  0x11, 0x5e, 0x50, 0x5a, 0xe8, 0xc6, 0x34, 0xb9, 0x8e, 0x81, 0xf0, 0xe0,
+  0x6f, 0x4f, 0x97, 0x24, 0x2b, 0xcc, 0xba, 0x09, 0x14, 0xe7, 0x72, 0xe0,
+  0x43, 0x41, 0x0a, 0xc6, 0xe4, 0x8b, 0x13, 0xe7, 0xb4, 0x09, 0x36, 0xe2,
+  0x2b, 0xde, 0x88, 0xc6, 0xaa, 0x39, 0x20, 0xc5, 0x5e, 0x1d, 0x85, 0x34,
+  0x84, 0x2f, 0x40, 0xf6, 0x87, 0x28, 0xfe, 0x15, 0x60, 0xac, 0x86, 0x10,
+  0x13, 0x80, 0x91, 0x09, 0xa6, 0x7b, 0x88, 0x58, 0x84, 0x23, 0xea, 0x52,
+  0x78, 0xc0, 0xd6, 0x11, 0xa5, 0xf2, 0xd5, 0xb1, 0x43, 0x87, 0x6b, 0xd0,
+  0x7d, 0xa5, 0x10, 0x5c, 0x15, 0x47, 0x0e, 0x00, 0x94, 0xae, 0xba, 0xdf,
+  0xbd, 0xab, 0xf1, 0x21, 0x06, 0xfb, 0x36, 0x25, 0x44, 0x71, 0x89, 0x44,
+  0xad, 0x33, 0xd8, 0x02, 0xbf, 0x6c, 0xa7, 0x86, 0xf7, 0xd7, 0xfd, 0x8f,
+  0xae, 0x07, 0x89, 0x69, 0x0d, 0x22, 0x74, 0x09, 0x6e, 0xcd, 0x24, 0xfd,
+  0xfe, 0x49, 0xcf, 0x0f, 0xd6, 0xf7, 0x68, 0x53, 0x19, 0xb5, 0x00, 0xc1,
+  0xad, 0x1b, 0xc7, 0xd7, 0xc7, 0x07, 0x47, 0x36, 0xdf, 0x7f, 0x4b, 0x86,
+  0x3d, 0xe0, 0xa0, 0x42, 0x9f, 0x90, 0x39, 0x05, 0x47, 0x89, 0xc0, 0xdf,
+  0x2d, 0xcd, 0x47, 0x84, 0x4d, 0x33, 0x23, 0x47, 0x4b, 0xc4, 0x18, 0x49,
+  0x6c, 0x0c, 0x8b, 0x6d, 0x55, 0x88, 0x5d, 0x0d, 0x16, 0x11, 0x59, 0x5d,
+  0xd5, 0x24, 0xf3, 0x0a, 0x09, 0x33, 0x0a, 0xbc, 0x2a, 0xad, 0x75, 0x92,
+  0x82, 0xa2, 0x81, 0x01, 0x61, 0xdf, 0x20, 0x23, 0x6e, 0xba, 0x68, 0xe4,
+  0x46, 0xc5, 0xd7, 0x9c, 0xbb, 0x39, 0x5d, 0x04, 0xcf, 0x06, 0xd9, 0x73,
+  0x2f, 0xe5, 0xe7, 0xba, 0x7b, 0xe5, 0x58, 0x40, 0xb1, 0xf4, 0x61, 0x27,
+  0xac, 0xb8, 0x74, 0x93, 0x52, 0x96, 0x81, 0x84, 0x0d, 0xe2, 0x4e, 0xd7,
+  0x09, 0x8a, 0x6e, 0x33, 0xff, 0xac, 0xaf, 0x83, 0x15, 0x15, 0x26, 0x86,
+  0xec, 0x41, 0x6e, 0x05, 0x71, 0x4b, 0xb3, 0x1a, 0xc3, 0x5c, 0x0f, 0x4d,
+  0x5e, 0xb3, 0xf2, 0x46, 0x93, 0x46, 0xed, 0x19, 0xbe, 0xd6, 0x8b, 0x92,
+  0x53, 0x4a, 0xdd, 0xc8, 0xf8, 0xbd, 0x9b, 0xb8, 0xf0, 0x7e, 0x01, 0x41,
+  0x7b, 0x28, 0xc2, 0xc8, 0x07, 0xf3, 0x6b, 0x36, 0x2b, 0x7c, 0x58, 0x20,
+  0xbe, 0xc5, 0x5f, 0xf4, 0x44, 0xce, 0x66, 0x40, 0x00, 0x7e, 0x41, 0x93,
+  0xfa, 0x5c, 0x6f, 0x1e, 0x0c, 0x6f, 0xd9, 0x04, 0xb2, 0xaf, 0x1d, 0x57,
+  0xe7, 0x4c, 0xcd, 0xe6, 0x49, 0xd5, 0x72, 0xc2, 0x73, 0xb4, 0x34, 0x42,
+  0x24, 0xed, 0xa1, 0x68, 0x7c, 0xe3, 0xd6, 0x63, 0x81, 0xaf, 0x5c, 0xe2,
+  0x46, 0x88, 0xe7, 0xe1, 0x38, 0x5d, 0x96, 0xf7, 0x24, 0x93, 0x85, 0x77,
+  0xf4, 0x85, 0x64, 0x35, 0xd6, 0xbe, 0xe3, 0xf1, 0x3a, 0xdf, 0xae, 0xab,
+  0x6a, 0xe1, 0xf2, 0x71, 0x8d, 0xd7, 0xc3, 0xa4, 0x26, 0xa9, 0xe6, 0x49,
+  0xce, 0x2e, 0x0e, 0x84, 0x6d, 0xb1, 0x18, 0x7b, 0xdf, 0xe4, 0xe8, 0x5a,
+  0x8b, 0x07, 0xe7, 0x81, 0xeb, 0x3e, 0xb0, 0x91, 0x4c, 0x72, 0x0d, 0x75,
+  0xd6, 0xba, 0x64, 0x74, 0x45, 0x5c, 0xa7, 0x77, 0x42, 0x2d, 0x36, 0xb2,
+  0x96, 0x8c, 0x37, 0x37, 0x06, 0x13, 0xf5, 0xbd, 0x73, 0x5f, 0xd0, 0x1b,
+  0xa2, 0x02, 0xe5, 0x39, 0x2c, 0x6d, 0x7e, 0x9c, 0x4d, 0xf9, 0x9e, 0x93,
+  0xb2, 0xe6, 0x44, 0xd8, 0x75, 0x3f, 0xdc, 0xd7, 0x24, 0xd5, 0xed, 0x77,
+  0xda, 0xe3, 0xdd, 0x3d, 0xb2, 0x50, 0xe1, 0xa0, 0x7c, 0x11, 0x9d, 0x62,
+  0xbb, 0x8c, 0x23, 0x4b, 0xd4, 0xb7, 0xad, 0xe3, 0xb5, 0x80, 0xf6, 0xd6,
+  0x51, 0x5b, 0xba, 0xc6, 0x02, 0x31, 0x8d, 0x93, 0x7e, 0x76, 0xd5, 0x47,
+  0x35, 0x47, 0x2e, 0xa3, 0xc7, 0x5a, 0x59, 0x40, 0xd0, 0x48, 0xdd, 0xe5,
+  0x2d, 0xa2, 0xb6, 0xdb, 0x6e, 0x49, 0x0d, 0x8a, 0xcf, 0x9d, 0xc5, 0x4e,
+  0x07, 0xa4, 0x6b, 0xb2, 0xcf, 0x56, 0x1e, 0x7b, 0xdd, 0xa1, 0xb8, 0x71,
+  0xa2, 0x64, 0x9c, 0xe7, 0x29, 0x9d, 0xc2, 0x06, 0xf8, 0x31, 0x42, 0x18,
+  0x7b, 0x72, 0x91, 0x4a, 0x44, 0x18, 0xbb, 0x7b, 0x66, 0xe2, 0xe4, 0x83,
+  0x97, 0x66, 0xb9, 0x80, 0x44, 0xc8, 0x39, 0xdb, 0x6d, 0xb2, 0xaf, 0x4f,
+  0x76, 0xab, 0x95, 0x52, 0x84, 0x03, 0x23, 0xcc, 0x0d, 0x5e, 0x87, 0x84,
+  0x52, 0xf5, 0x3d, 0x40, 0x3f, 0x72, 0x77, 0x60, 0x55, 0x0c, 0x86, 0x03,
+  0xc6, 0x2f, 0xfa, 0xb6, 0x18, 0x5e, 0xdb, 0x62, 0x91, 0xf8, 0x15, 0xe3,
+  0x1e, 0x81, 0xec, 0xcc, 0xe5, 0xaf, 0x17, 0xcb, 0xd1, 0x6c, 0xf2, 0x2c,
+  0x7a, 0x49, 0xff, 0x7c, 0xde, 0xe2, 0x3b, 0x47, 0x75, 0x73, 0x11, 0xf9,
+  0x54, 0x10, 0xc2, 0xef, 0x4f, 0xf6, 0xf8, 0x38, 0x3c, 0x50, 0x8b, 0xe3,
+  0x14, 0xe0, 0x32, 0x93, 0xf4, 0x3a, 0x2d, 0x0b, 0x97, 0x44, 0x88, 0x57,
+  0xd6, 0x97, 0xd5, 0xc2, 0x0a, 0xed, 0xee, 0x7d, 0x16, 0x8d, 0xd2, 0x32,
+  0x7a, 0x73, 0xf4, 0x4c, 0x4a, 0xf3, 0x15, 0xcb, 0x99, 0x2f, 0xe1, 0x0a,
+  0xec, 0x60, 0x1e, 0x20, 0x49, 0xa7, 0x34, 0xc6, 0x69, 0xa3, 0x46, 0xce,
+  0x6d, 0xb2, 0xea, 0x55, 0xaa, 0x43, 0x5c, 0x99, 0x67, 0x36, 0x30, 0xb2,
+  0x3b, 0x7a, 0x93, 0x52, 0xdf, 0xe6, 0xb4, 0x6f, 0x11, 0xe8, 0x69, 0xfe,
+  0xd4, 0x7f, 0x11, 0x59, 0x55, 0xaf, 0x8a, 0xb8, 0x69, 0x55, 0x1d, 0x90,
+  0xf1, 0x78, 0x78, 0x8e, 0xcd, 0x1c, 0x56, 0x91, 0x5c, 0x1e, 0xc3, 0xc8,
+  0xfd, 0xb4, 0x6a, 0x5a, 0x95, 0xf2, 0x9c, 0x86, 0x6d, 0xd4, 0x27, 0xe5,
+  0xea, 0x7a, 0x5d, 0xcd, 0xc5, 0x13, 0x3c, 0x5a, 0xb1, 0x90, 0x9d, 0xe2,
+  0x71, 0x97, 0xf9, 0x1c, 0x44, 0x69, 0xf1, 0x41, 0x48, 0xc7, 0x5c, 0xfa,
+  0xb6, 0x81, 0xd2, 0xba, 0x14, 0x18, 0x64, 0x4c, 0xc0, 0x2a, 0x81, 0xe6,
+  0x4b, 0xc1, 0x3e, 0x3f, 0x58, 0xb0, 0x91, 0x27, 0xda, 0x1d, 0x3c, 0xf4,
+  0xc2, 0x42, 0x64, 0x8a, 0x94, 0xcf, 0xe5, 0xc6, 0x1a, 0x1e, 0x28, 0x44,
+  0x63, 0xd4, 0x06, 0xc4, 0x4d, 0x8b, 0x75, 0x6d, 0xca, 0xe1, 0x49, 0xb9,
+  0x30, 0xe1, 0x3d, 0x62, 0x66, 0xd7, 0x31, 0x40, 0xda, 0x03, 0xca, 0x4b,
+  0xe9, 0x1c, 0x28, 0xf4, 0xd9, 0x9a, 0x79, 0xcb, 0x97, 0x2e, 0xfb, 0xdd,
+  0x2e, 0x61, 0x95, 0xc3, 0x35, 0xb4, 0xd7, 0xc8, 0x2d, 0x78, 0xa2, 0x59,
+  0x2c, 0x8d, 0xdb, 0xc1, 0x8e, 0xe3, 0xf8, 0x8a, 0xfe, 0xab, 0x6b, 0xd0,
+  0xe7, 0x9b, 0xaf, 0x17, 0xa1, 0x9e, 0xba, 0x12, 0x9e, 0x0f, 0x6a, 0x46,
+  0xa3, 0xcd, 0x20, 0xfe, 0xc2, 0xea, 0xfd, 0x72, 0xb4, 0xd3, 0x60, 0x10,
+  0x1e, 0x27, 0x70, 0xf2, 0x2b, 0x66, 0x7f, 0xad, 0xb9, 0xdc, 0xe7, 0x82,
+  0x6d, 0x58, 0xad, 0x63, 0x6d, 0xf1, 0x12, 0x5e, 0x4c, 0x76, 0xad, 0x0c,
+  0x9c, 0x55, 0x80, 0x7d, 0x9a, 0x2d, 0x53, 0xb3, 0xde, 0x22, 0x99, 0x46,
+  0xe8, 0xdf, 0x0f, 0x6b, 0xdb, 0x0f, 0xa2, 0x83, 0xb9, 0xe9, 0xe2, 0x5a,
+  0x54, 0x8c, 0x73, 0x77, 0x1a, 0x55, 0x60, 0x6e, 0x93, 0x86, 0x49, 0x40,
+  0x6d, 0x02, 0xc1, 0xcc, 0x48, 0xae, 0xda, 0xd9, 0xdf, 0x0d, 0xeb, 0x07,
+  0xcd, 0xb5, 0xd0, 0x04, 0x8a, 0xea, 0xfc, 0x76, 0xd1, 0xf7, 0x27, 0x2a,
+  0x89, 0xb5, 0xd1, 0x0b, 0xc3, 0x73, 0x6f, 0xbf, 0x3e, 0x39, 0x3d, 0xde,
+  0x8a, 0x5e, 0x27, 0xc0, 0x15, 0xa9, 0x91, 0x0d, 0x1f, 0xde, 0xdf, 0xc9,
+  0x27, 0x46, 0xfd, 0xaa, 0x84, 0xb6, 0xe5, 0xbc, 0x39, 0x57, 0x3d, 0xe4,
+  0x69, 0x39, 0x12, 0x98, 0x85, 0xe4, 0x65, 0x65, 0x30, 0x5d, 0x1a, 0x08,
+  0xbb, 0x05, 0x33, 0xb6, 0x92, 0x1f, 0x6c, 0x6d, 0xbe, 0x62, 0x8e, 0x47,
+  0xa1, 0x47, 0x39, 0x79, 0x8d, 0x03, 0xe6, 0x81, 0x47, 0x6a, 0x91, 0xb3,
+  0xe0, 0x50, 0xad, 0x9c, 0xde, 0x32, 0x3a, 0xa9, 0x65, 0x97, 0xfe, 0x2c,
+  0xc1, 0xe8, 0x58, 0xb5, 0x59, 0x36, 0x71, 0x30, 0x94, 0x52, 0xd9, 0x86,
+  0xe7, 0x1b, 0xac, 0xdd, 0x5f, 0x69, 0xed, 0xfe, 0xba, 0x9c, 0xdf, 0xf6,
+  0xb5, 0x82, 0xa1, 0x02, 0x7a, 0x14, 0xed, 0x67, 0xef, 0x3b, 0x17, 0x84,
+  0x82, 0xc0, 0x60, 0x31, 0x74, 0x36, 0x0b, 0xf9, 0xc5, 0x1a, 0x75, 0x2a,
+  0x03, 0x5f, 0x5f, 0x08, 0xc8, 0x0b, 0x0f, 0x52, 0x7c, 0x7d, 0xcc, 0x11,
+  0xc9, 0x50, 0x10, 0x3b, 0x56, 0x50, 0xd1, 0x1a, 0xee, 0x0c, 0x42, 0x08,
+  0xc6, 0x06, 0xb4, 0x6d, 0x61, 0xa9, 0x67, 0x37, 0xae, 0x1c, 0x1e, 0xe4,
+  0x57, 0x0d, 0x2f, 0x61, 0xd1, 0x86, 0xd7, 0x9b, 0x2e, 0x7a, 0x5f, 0xaa,
+  0xb1, 0x10, 0x9c, 0x59, 0x26, 0xa5, 0xda, 0x35, 0x2b, 0x09, 0x81, 0x86,
+  0x12, 0x5e, 0x18, 0x00, 0x90, 0x8d, 0x30, 0xaa, 0x0f, 0xce, 0x10, 0xc4,
+  0x59, 0x36, 0xe8, 0x36, 0x08, 0x67, 0x3c, 0xcd, 0xa4, 0x3a, 0xd2, 0x7d,
+  0xe8, 0xd6, 0xfc, 0x4f, 0xdc, 0xf7, 0x7c, 0x95, 0x29, 0x25, 0xf6, 0x5b,
+  0x22, 0xe4, 0x5d, 0xb1, 0xb7, 0xe0, 0xa0, 0x48, 0xa6, 0x18, 0xe4, 0x88,
+  0x33, 0xdf, 0xc6, 0x3c, 0x28, 0x0d, 0xee, 0x73, 0x91, 0x5a, 0x61, 0xb3,
+  0xfa, 0x81, 0xde, 0xed, 0x38, 0xf5, 0x11, 0x91, 0x55, 0x56, 0xa4, 0x22,
+  0x59, 0x38, 0xa3, 0x60, 0x20, 0x88, 0xb7, 0x14, 0x74, 0x34, 0x70, 0x03,
+  0x70, 0x29, 0xf7, 0x8a, 0xf3, 0x54, 0x71, 0xcc, 0xb1, 0x9f, 0xef, 0x2d,
+  0xf8, 0x7a, 0xd1, 0x16, 0x37, 0x66, 0xe9, 0x54, 0xa1, 0x74, 0x13, 0x18,
+  0x3a, 0x55, 0xd0, 0x77, 0x70, 0xe9, 0xca, 0x2b, 0x3b, 0xd6, 0x5a, 0xa7,
+  0x19, 0x34, 0x12, 0x22, 0x0d, 0x88, 0xe9, 0xcc, 0x23, 0x3c, 0x1d, 0x10,
+  0x7d, 0x35, 0x1e, 0xe1, 0x78, 0x05, 0x89, 0x5c, 0x4f, 0x5a, 0xea, 0x79,
+  0x0b, 0x62, 0x37, 0x6d, 0x92, 0xc5, 0x36, 0xb8, 0xba, 0x81, 0x2d, 0xb9,
+  0x79, 0x92, 0xc3, 0x88, 0x75, 0x8b, 0xd9, 0x81, 0x56, 0xa7, 0xd5, 0x95,
+  0x39, 0x6b, 0x55, 0x8f, 0x31, 0xef, 0x8a, 0x14, 0x0e, 0xf2, 0x63, 0x0a,
+  0xe1, 0xfb, 0xd7, 0x4f, 0x16, 0x15, 0x6c, 0x2c, 0xde, 0x30, 0x5c, 0xe3,
+  0x66, 0xb8, 0x61, 0x20, 0x8a, 0x7a, 0x23, 0x17, 0xca, 0xd2, 0xb0, 0x88,
+  0x8d, 0xab, 0xdb, 0x8a, 0x9c, 0x68, 0x00, 0x43, 0xe4, 0xec, 0xb5, 0x91,
+  0xab, 0x2b, 0xb7, 0xa6, 0x5c, 0x1c, 0x92, 0x2f, 0x6f, 0xe2, 0x87, 0x87,
+  0x41, 0x91, 0x48, 0xfd, 0xb4, 0xa2, 0x98, 0x22, 0xd1, 0xb3, 0x5a, 0x27,
+  0x8e, 0x73, 0xfc, 0x93, 0x45, 0x3c, 0x45, 0xb4, 0x23, 0xf3, 0xa3, 0x75,
+  0xf5, 0xb8, 0x2a, 0x26, 0xbd, 0x44, 0xa3, 0xdd, 0xf0, 0x46, 0x5c, 0xad,
+  0x9a, 0xc5, 0xa8, 0x50, 0x85, 0x41, 0x7c, 0x73, 0x10, 0x16, 0xd1, 0xec,
+  0xa4, 0xe1, 0x74, 0xd2, 0xc0, 0x2e, 0xb8, 0x7f, 0x78, 0xe3, 0xdc, 0x28,
+  0x58, 0xdd, 0x18, 0xa9, 0x21, 0xda, 0x75, 0x61, 0x3e, 0xb2, 0x94, 0x1e,
+  0xbe, 0x4b, 0x27, 0xcb, 0x86, 0xb6, 0x5b, 0x7f, 0xdd, 0xaa, 0xf1, 0x06,
+  0xa9, 0x17, 0xe0, 0x3c, 0xfc, 0x44, 0xe6, 0x2e, 0x75, 0x40, 0xf7, 0xa2,
+  0xca, 0x63, 0xe3, 0x32, 0xb8, 0x52, 0x18, 0x0e, 0xdc, 0x32, 0x97, 0x87,
+  0xe7, 0xef, 0xbf, 0x39, 0x3e, 0x3e, 0x3f, 0x39, 0x62, 0xf6, 0x8f, 0xfb,
+  0xc6, 0x7d, 0xf4, 0xf6, 0xf2, 0xdb, 0x53, 0x0f, 0xc5, 0xa1, 0x9a, 0x42,
+  0xfd, 0x40, 0xb1, 0xe1, 0x97, 0x9b, 0x3b, 0x4d, 0xe7, 0xcb, 0x87, 0x1e,
+  0xca, 0x50, 0x91, 0x9e, 0x71, 0x70, 0xf2, 0x3d, 0xc9, 0x2e, 0xe7, 0xfd,
+  0x77, 0xdf, 0x37, 0xb2, 0xa7, 0x82, 0xa0, 0x3c, 0xba, 0xbe, 0xea, 0xe7,
+  0xdc, 0xc5, 0xe8, 0x01, 0x23, 0xcc, 0xcf, 0xdd, 0x48, 0xac, 0x05, 0x84,
+  0xf9, 0x23, 0x63, 0x8e, 0xab, 0x5a, 0x4b, 0x78, 0xdd, 0x3b, 0xeb, 0x12,
+  0x76, 0xbf, 0xe5, 0xb6, 0x8b, 0x67, 0x9c, 0x68, 0x34, 0x08, 0x09, 0x6b,
+  0x15, 0xbd, 0xa4, 0x7f, 0xda, 0xb2, 0x35, 0xb7, 0xb9, 0x98, 0x7d, 0x74,
+  0x1e, 0x60, 0x57, 0x38, 0x17, 0xd6, 0xc0, 0xe2, 0x96, 0xd4, 0x92, 0xa0,
+  0xf9, 0x47, 0xea, 0x23, 0xcc, 0x1b, 0x20, 0x96, 0xae, 0x05, 0x5f, 0xfb,
+  0x17, 0xe6, 0xbd, 0xa4, 0xdd, 0xf9, 0xf8, 0x2b, 0xa6, 0xa9, 0x52, 0xa7,
+  0x1f, 0x04, 0x44, 0x68, 0xce, 0x91, 0x9f, 0x1d, 0x38, 0x48, 0x18, 0x15,
+  0x59, 0xb8, 0x15, 0x4c, 0x50, 0x96, 0xad, 0x05, 0xaf, 0x5d, 0x10, 0x13,
+  0x42, 0xb4, 0x8f, 0x94, 0xa8, 0xfc, 0xe8, 0xf8, 0xa2, 0x27, 0x20, 0x09,
+  0x21, 0x40, 0x82, 0x47, 0x01, 0x1a, 0x58, 0x01, 0xe7, 0xb2, 0xd5, 0x78,
+  0x05, 0x2c, 0x93, 0x7f, 0x1f, 0x36, 0xc2, 0x6d, 0x3e, 0x8a, 0x5e, 0x22,
+  0xe0, 0x6f, 0x4d, 0x20, 0xb5, 0x16, 0x98, 0xfd, 0x26, 0xc9, 0x47, 0x49,
+  0x9e, 0x15, 0xf5, 0x24, 0x3a, 0x4d, 0xb8, 0xd7, 0x42, 0x9e, 0xdc, 0x8e,
+  0x65, 0xe2, 0x36, 0x03, 0x0b, 0xc1, 0xa7, 0xf9, 0x85, 0x46, 0xba, 0x50,
+  0x17, 0x91, 0x73, 0xdd, 0x5e, 0xd4, 0xe5, 0x44, 0x41, 0xfe, 0x49, 0xec,
+  0xeb, 0x0a, 0x8e, 0x91, 0x34, 0x9e, 0x76, 0x7b, 0x4d, 0xc8, 0xc4, 0xae,
+  0x2e, 0x7b, 0x97, 0x03, 0x1f, 0x55, 0x35, 0x86, 0x1d, 0x05, 0x66, 0x43,
+  0xc6, 0x62, 0xc2, 0x58, 0x0c, 0x96, 0x85, 0xcd, 0x18, 0xde, 0x40, 0x57,
+  0x34, 0xb0, 0xac, 0x5c, 0x73, 0x75, 0xf3, 0x71, 0xfb, 0x05, 0x11, 0x32,
+  0x04, 0x0d, 0x8c, 0x64, 0x5d, 0xdf, 0x12, 0xd9, 0x25, 0xd5, 0x5d, 0x40,
+  0x64, 0x6f, 0x75, 0xe1, 0x9e, 0x8a, 0x8d, 0xfe, 0xab, 0xe1, 0xf0, 0xe0,
+  0xfc, 0xa4, 0xbe, 0xd4, 0xf4, 0x69, 0xff, 0xad, 0xd5, 0x92, 0xdf, 0x72,
+  0xc4, 0xe2, 0x2d, 0xc2, 0x3c, 0x7e, 0xe4, 0x1e, 0xb1, 0x74, 0xcd, 0x71,
+  0x22, 0xc0, 0xa2, 0xfa, 0x96, 0x2e, 0xb3, 0x35, 0x11, 0x8e, 0x0a, 0x3c,
+  0xa4, 0x26, 0xce, 0x3c, 0xaa, 0xd4, 0xa8, 0x24, 0x59, 0xf2, 0x37, 0xa4,
+  0xa9, 0x6f, 0xa4, 0xee, 0xd9, 0x55, 0x7a, 0xcd, 0x41, 0xfa, 0xf8, 0xd9,
+  0x86, 0xc3, 0x54, 0x3d, 0x6e, 0xc1, 0x83, 0x5e, 0x60, 0x06, 0xe4, 0x99,
+  0xe6, 0x98, 0x89, 0xdc, 0xac, 0xd8, 0xc9, 0x2d, 0xe1, 0x26, 0xfc, 0xb6,
+  0x3a, 0x75, 0xd3, 0x20, 0x68, 0x02, 0x62, 0x86, 0xeb, 0x63, 0xe6, 0x6a,
+  0x90, 0x04, 0xed, 0x8a, 0xa7, 0xb4, 0x6e, 0x6a, 0xd3, 0x7a, 0x79, 0xa6,
+  0xbf, 0x24, 0xf3, 0xca, 0x74, 0x55, 0x5c, 0x16, 0x4b, 0x17, 0xbb, 0xfc,
+  0xed, 0x79, 0xb3, 0x23, 0xd6, 0x4d, 0x6d, 0xe3, 0x92, 0x71, 0x9d, 0xc3,
+  0x11, 0x0c, 0xa2, 0xb3, 0x45, 0x20, 0x7d, 0xdd, 0x24, 0x69, 0xee, 0x3d,
+  0xa2, 0x3e, 0x9f, 0x1d, 0x5c, 0xa1, 0x39, 0x59, 0xd1, 0x82, 0x82, 0x72,
+  0x2b, 0xf3, 0x60, 0x01, 0xa4, 0xc8, 0x8a, 0xe3, 0xba, 0x82, 0xc4, 0xcf,
+  0x53, 0x29, 0x93, 0x62, 0x41, 0x7a, 0x68, 0xa3, 0x4a, 0xa8, 0x58, 0x37,
+  0x05, 0xf9, 0x80, 0x01, 0xa8, 0x0b, 0x44, 0xe1, 0x44, 0xc0, 0xec, 0x5f,
+  0x55, 0x9c, 0x2e, 0x70, 0x79, 0xd2, 0x29, 0xda, 0x54, 0x00, 0xc3, 0xb6,
+  0xaa, 0x6c, 0xe2, 0x33, 0xc8, 0x41, 0x3d, 0x86, 0xfd, 0xaf, 0xb1, 0x20,
+  0x41, 0xeb, 0x52, 0xcc, 0x51, 0xf0, 0xb7, 0x02, 0x3f, 0x70, 0x4b, 0x5a,
+  0xa4, 0xba, 0x10, 0xc3, 0x09, 0x18, 0xbe, 0x8a, 0x7b, 0x53, 0xf3, 0xf8,
+  0x47, 0x80, 0x0a, 0x52, 0x75, 0x42, 0xc1, 0x1f, 0x1a, 0x58, 0x50, 0x19,
+  0x30, 0x56, 0xbe, 0x13, 0x64, 0x88, 0x49, 0xb6, 0x64, 0xfe, 0x26, 0x9f,
+  0xd6, 0x3d, 0x38, 0x89, 0x14, 0x81, 0x2c, 0xd8, 0x29, 0xc4, 0x5e, 0x9c,
+  0x96, 0x22, 0x15, 0x0e, 0x9a, 0x61, 0x3f, 0x8a, 0xfe, 0xf2, 0x97, 0x5e,
+  0xf4, 0x97, 0x0e, 0xfd, 0x57, 0xd2, 0x7f, 0xb4, 0xa0, 0x7f, 0x91, 0x9a,
+  0x07, 0x7f, 0xb9, 0xa3, 0x0b, 0x34, 0xe2, 0xda, 0x85, 0xc5, 0x94, 0x41,
+  0x04, 0x3c, 0xa0, 0x7d, 0x33, 0x8f, 0x50, 0x42, 0x0c, 0xb5, 0x88, 0x07,
+  0x9f, 0x7d, 0x98, 0xb0, 0x26, 0x6e, 0xad, 0x24, 0xb5, 0x86, 0x36, 0x6c,
+  0x39, 0x9b, 0x8b, 0x82, 0xac, 0x5b, 0x0f, 0xa2, 0x6e, 0x68, 0x91, 0xc4,
+  0x08, 0xbb, 0x9f, 0x74, 0xd5, 0x6d, 0x5e, 0x5a, 0x6a, 0x6b, 0x18, 0xa5,
+  0x89, 0xf7, 0x5c, 0x55, 0x72, 0x2d, 0x18, 0x09, 0xcb, 0x70, 0x5b, 0xbc,
+  0x26, 0x14, 0xf1, 0x33, 0x36, 0xe6, 0x49, 0x81, 0x51, 0xf0, 0x54, 0xe1,
+  0x18, 0x6c, 0x90, 0x8e, 0x16, 0x37, 0x2b, 0xe8, 0x99, 0x42, 0x83, 0xe2,
+  0xb3, 0xb3, 0x18, 0x5f, 0x1a, 0x65, 0x4b, 0xf9, 0x91, 0xa6, 0xf0, 0x1d,
+  0x20, 0xb3, 0x39, 0x8d, 0x89, 0xdd, 0xee, 0x01, 0x5f, 0xa1, 0xf1, 0x75,
+  0xfb, 0xdd, 0x2a, 0x36, 0xa2, 0xd5, 0xba, 0x69, 0xab, 0x87, 0x13, 0x94,
+  0xae, 0x69, 0xd4, 0xd0, 0xf4, 0xc8, 0x5f, 0x12, 0xa5, 0x36, 0x12, 0x0e,
+  0xe4, 0x5c, 0x49, 0x70, 0x11, 0x9a, 0xe5, 0x2c, 0x3c, 0x67, 0x3d, 0xdc,
+  0x38, 0x8d, 0x9a, 0x25, 0x92, 0x9a, 0xe6, 0x7d, 0x51, 0x48, 0xef, 0xf7,
+  0xaa, 0x50, 0xbf, 0x2f, 0x55, 0x36, 0xc5, 0x71, 0xce, 0xe4, 0x81, 0x3a,
+  0x85, 0x2b, 0x0e, 0xb6, 0x59, 0x34, 0x2c, 0x8f, 0xbc, 0xca, 0xf6, 0x26,
+  0x8f, 0x83, 0x39, 0x33, 0x17, 0xdc, 0xb9, 0x9f, 0x2b, 0x0f, 0x19, 0x66,
+  0x00, 0xa0, 0x16, 0xc3, 0x94, 0xa2, 0xca, 0x14, 0x3e, 0x48, 0xa3, 0xc5,
+  0x6b, 0xdf, 0x30, 0x53, 0xf1, 0x78, 0x5e, 0x45, 0x9d, 0xb5, 0x5a, 0x4a,
+  0xa7, 0xfe, 0xc2, 0x69, 0x06, 0xe7, 0xa6, 0xda, 0xd8, 0x05, 0xed, 0x4f,
+  0x2c, 0x6d, 0x06, 0xd3, 0x36, 0x05, 0x2a, 0x89, 0x58, 0x38, 0x7c, 0xd1,
+  0x6f, 0x63, 0xf0, 0x6b, 0x7c, 0x31, 0xe2, 0xc4, 0x12, 0xe8, 0x48, 0x3d,
+  0x95, 0x5c, 0x2f, 0x75, 0x1d, 0xec, 0xa9, 0xd9, 0x58, 0x38, 0x87, 0xff,
+  0x96, 0x85, 0xa6, 0xb4, 0x34, 0x2b, 0xc4, 0xa6, 0x69, 0x7b, 0x7f, 0xb3,
+  0x7b, 0x6c, 0x4b, 0x6d, 0xe4, 0x92, 0x97, 0xba, 0x0e, 0x25, 0xac, 0xca,
+  0x45, 0xa1, 0x54, 0xc0, 0x68, 0x95, 0x42, 0xb2, 0xbf, 0x22, 0x61, 0x7a,
+  0x52, 0x8d, 0x25, 0x5e, 0x4b, 0xd5, 0x50, 0x74, 0xb8, 0xc7, 0x44, 0xb2,
+  0x2d, 0x74, 0x11, 0x3c, 0x67, 0x81, 0xcf, 0xa1, 0x70, 0x02, 0x72, 0x96,
+  0x93, 0x16, 0xdb, 0xd8, 0x99, 0xdd, 0x2d, 0x55, 0xe9, 0x51, 0xfe, 0x0f,
+  0xd5, 0x20, 0x55, 0x05, 0xeb, 0xdc, 0x64, 0x82, 0xf5, 0xd3, 0xd9, 0x67,
+  0xb5, 0x4a, 0xb8, 0x82, 0xcd, 0xd1, 0x85, 0xd6, 0xd7, 0x73, 0x72, 0x18,
+  0x4c, 0xe9, 0xeb, 0xb3, 0x37, 0xc7, 0x2e, 0xe3, 0x55, 0x4c, 0x7d, 0xfc,
+  0x49, 0x2b, 0xc6, 0xe3, 0x00, 0xd9, 0x04, 0x86, 0x00, 0xd1, 0x6b, 0xd6,
+  0xf2, 0xc4, 0xea, 0x5c, 0x27, 0xe5, 0xe2, 0x7e, 0x99, 0x4e, 0x36, 0x81,
+  0xd2, 0xf1, 0xee, 0xed, 0xc9, 0xf7, 0x7d, 0x98, 0x89, 0x55, 0x8f, 0x33,
+  0x98, 0x0a, 0x43, 0xb8, 0x50, 0x7f, 0xc2, 0xac, 0x05, 0x93, 0xc5, 0x8a,
+  0x33, 0x80, 0x5e, 0x14, 0x96, 0x08, 0xc9, 0x7e, 0xe9, 0x5c, 0xa4, 0x18,
+  0x69, 0x72, 0x8b, 0x59, 0x10, 0xf1, 0x6f, 0xa0, 0x2d, 0x61, 0xdf, 0x5b,
+  0xb2, 0x77, 0x83, 0xfd, 0xe6, 0xe6, 0x0e, 0xce, 0xcf, 0x8f, 0x0e, 0x2e,
+  0x0f, 0xdc, 0xdc, 0x00, 0x6e, 0x04, 0x36, 0x07, 0x71, 0x86, 0xf5, 0xfa,
+  0x5c, 0x48, 0xb0, 0xfb, 0x7b, 0xce, 0x0f, 0xac, 0x73, 0xbe, 0xf3, 0x8b,
+  0x33, 0xb6, 0x34, 0xfe, 0xfe, 0x2f, 0x07, 0xbe, 0x92, 0x1c, 0x6a, 0x26,
+  0x35, 0x0b, 0x7a, 0xed, 0x91, 0x00, 0x77, 0x86, 0x90, 0x0e, 0x1b, 0xa0,
+  0x46, 0x0a, 0x89, 0x20, 0x17, 0xbd, 0xe7, 0x3d, 0xcd, 0xc7, 0x4e, 0x38,
+  0x81, 0xfd, 0x53, 0xb7, 0xb3, 0xd7, 0xcc, 0x2d, 0x0b, 0x26, 0xc2, 0xdc,
+  0xb6, 0x86, 0xf5, 0x64, 0x6b, 0x35, 0x8d, 0x92, 0x87, 0x64, 0xbc, 0x2c,
+  0xc1, 0xbe, 0x38, 0xba, 0x9d, 0xe9, 0x6b, 0xc2, 0x0b, 0x55, 0x77, 0xd4,
+  0xbb, 0xfd, 0xb1, 0x0d, 0x12, 0x04, 0x12, 0x5c, 0x01, 0xc2, 0x83, 0x24,
+  0xa9, 0x33, 0x93, 0x02, 0x1a, 0x03, 0x1b, 0xad, 0xda, 0xac, 0x1a, 0x67,
+  0x47, 0x40, 0x14, 0x89, 0xce, 0x6d, 0x0e, 0x8d, 0x05, 0xf9, 0x84, 0x98,
+  0x5e, 0xdf, 0x42, 0x4c, 0x65, 0xda, 0xf4, 0x41, 0xe3, 0xa1, 0xd2, 0xd5,
+  0x82, 0x60, 0x31, 0xa9, 0xe9, 0xfd, 0x54, 0x3e, 0x15, 0x32, 0xa8, 0xba,
+  0xa9, 0x47, 0x41, 0x63, 0xf4, 0x29, 0x40, 0x15, 0x23, 0x0a, 0xb1, 0xe9,
+  0xcf, 0x31, 0xc7, 0x22, 0x3d, 0x4a, 0x52, 0x31, 0x89, 0xb8, 0xfc, 0xd7,
+  0xf6, 0xee, 0x60, 0xa7, 0xd3, 0x1c, 0x3d, 0x52, 0x5a, 0x61, 0x19, 0x8f,
+  0xe7, 0x72, 0x3f, 0x0b, 0x30, 0x6f, 0xf6, 0xe1, 0x01, 0x0a, 0x07, 0x25,
+  0x99, 0x0f, 0x51, 0x0b, 0x6d, 0x63, 0xe9, 0x9f, 0x35, 0xbc, 0x43, 0xe2,
+  0xe1, 0xf4, 0x2c, 0x79, 0x9e, 0x21, 0xac, 0x34, 0x66, 0x63, 0x19, 0xfc,
+  0x04, 0x9d, 0xf6, 0x05, 0x9e, 0x4f, 0x24, 0xda, 0xa1, 0xb6, 0xce, 0xff,
+  0x54, 0x90, 0xa0, 0xdb, 0x7f, 0xff, 0xf9, 0x7a, 0x6e, 0x57, 0x71, 0x8b,
+  0x92, 0x12, 0x04, 0x7a, 0x6c, 0x05, 0x5f, 0x3d, 0x10, 0x00, 0xe4, 0x5a,
+  0xf0, 0x13, 0x7b, 0x62, 0xb9, 0xce, 0x20, 0x07, 0x56, 0xb1, 0xfe, 0xa4,
+  0x39, 0x9c, 0xb3, 0xa0, 0x62, 0x60, 0x2c, 0x21, 0xc9, 0x8d, 0xab, 0xc3,
+  0xd5, 0x97, 0xd6, 0x6e, 0xfb, 0x72, 0xd3, 0xaa, 0x95, 0x0e, 0x85, 0x5a,
+  0x82, 0x3a, 0xda, 0x61, 0xfa, 0xfe, 0x1a, 0x78, 0x10, 0x13, 0x53, 0x49,
+  0x1d, 0x9c, 0x0a, 0x9e, 0x8a, 0x84, 0xd3, 0x8a, 0x16, 0x25, 0x63, 0x12,
+  0x8f, 0xbb, 0x77, 0x43, 0xf1, 0x7b, 0xbf, 0x6b, 0x2b, 0xce, 0xbd, 0xaf,
+  0x33, 0x55, 0xf8, 0x85, 0x52, 0x1d, 0xf7, 0x1c, 0xe6, 0xa1, 0x99, 0x4a,
+  0xfd, 0xd7, 0xce, 0xac, 0x66, 0x76, 0x37, 0xea, 0x91, 0xd6, 0xbc, 0x09,
+  0x12, 0x2a, 0xc1, 0xee, 0x59, 0x3e, 0x43, 0x05, 0x31, 0xc0, 0xf4, 0x81,
+  0x19, 0x64, 0x0c, 0xb0, 0x10, 0x1b, 0xe8, 0x9d, 0x1e, 0x01, 0xea, 0xe8,
+  0x9a, 0x64, 0xe3, 0xb5, 0x88, 0xa8, 0x06, 0x32, 0xe2, 0xcb, 0xf0, 0xb2,
+  0x77, 0xa0, 0xb0, 0xd4, 0xda, 0xf7, 0xc0, 0xcf, 0x9a, 0x4c, 0x36, 0x9f,
+  0x6c, 0xc9, 0xda, 0xbb, 0x0a, 0xdb, 0x70, 0xdc, 0x7d, 0xb0, 0xaa, 0xf6,
+  0x87, 0xd4, 0x47, 0xef, 0xfc, 0x68, 0x43, 0xbd, 0xa9, 0x28, 0x96, 0x8f,
+  0xe6, 0xd9, 0x4c, 0x49, 0xd4, 0x29, 0xfb, 0x30, 0x2d, 0xbd, 0x24, 0x81,
+  0x2b, 0x99, 0x7c, 0xfe, 0x88, 0x34, 0x39, 0x8b, 0x1f, 0xd2, 0xd9, 0x72,
+  0xe6, 0x13, 0xe3, 0xf0, 0x9e, 0x2f, 0xf3, 0xe0, 0x41, 0xb9, 0x60, 0xd1,
+  0x68, 0xc3, 0x97, 0x52, 0xbf, 0x97, 0xce, 0x0f, 0xc8, 0xc4, 0x12, 0x43,
+  0x04, 0xa7, 0x0a, 0x53, 0x21, 0x8d, 0x87, 0x8d, 0x42, 0xe9, 0x22, 0x31,
+  0x9a, 0xed, 0x4e, 0xc4, 0x6d, 0xca, 0x14, 0x54, 0xdf, 0x54, 0x1b, 0x09,
+  0xaa, 0x1a, 0x88, 0x4f, 0x42, 0x02, 0x82, 0xe6, 0x25, 0x67, 0xcb, 0x8d,
+  0xa8, 0x89, 0xfb, 0x74, 0x52, 0xde, 0xb4, 0xe2, 0x0d, 0xca, 0x22, 0x62,
+  0xda, 0x91, 0x20, 0x94, 0x70, 0x80, 0x09, 0x56, 0x0a, 0x2e, 0xe3, 0x6d,
+  0xb1, 0x1b, 0xbb, 0x64, 0xfb, 0x98, 0xa8, 0xee, 0x8a, 0xb3, 0x23, 0x5a,
+  0xf4, 0x04, 0x0d, 0x8b, 0x1b, 0xb8, 0x33, 0x2a, 0x55, 0x33, 0x6f, 0x25,
+  0x08, 0xf5, 0x1b, 0xb5, 0x8b, 0x08, 0x70, 0x11, 0xe2, 0xa9, 0x25, 0xba,
+  0x8a, 0x6e, 0xd0, 0xdb, 0x74, 0xda, 0x2c, 0xa4, 0xb8, 0x82, 0x32, 0xd5,
+  0x9d, 0xe1, 0xf5, 0x37, 0x5d, 0xb5, 0xe0, 0xa3, 0x5a, 0xb2, 0xfa, 0xb3,
+  0x35, 0xf1, 0x21, 0xea, 0x5e, 0x4b, 0x17, 0x5f, 0x75, 0x5d, 0x16, 0x45,
+  0xe3, 0x0a, 0xf4, 0x4e, 0x70, 0xbb, 0x45, 0x8a, 0xfd, 0x68, 0x6f, 0x67,
+  0xe7, 0x9b, 0x5e, 0xf4, 0x44, 0x2a, 0xcc, 0xee, 0x7e, 0xd5, 0xba, 0x42,
+  0x56, 0xec, 0x49, 0x6a, 0x78, 0xaa, 0x0e, 0x1a, 0xdf, 0x81, 0xdd, 0xeb,
+  0xc2, 0x61, 0x4a, 0xec, 0x7b, 0x5a, 0xe6, 0x26, 0x68, 0xcb, 0xe2, 0xaf,
+  0xd9, 0x2a, 0x98, 0xb1, 0xeb, 0x50, 0x08, 0x33, 0xc4, 0x0c, 0xf1, 0xee,
+  0xdd, 0xd0, 0x6f, 0x89, 0xcf, 0xff, 0x94, 0x4e, 0x5a, 0x32, 0x90, 0x8b,
+  0x1b, 0x3e, 0xfd, 0xa3, 0x65, 0x8e, 0xa3, 0xcc, 0x6e, 0x50, 0x29, 0x5b,
+  0xc4, 0xa6, 0x75, 0x13, 0xac, 0x48, 0x56, 0xf0, 0x15, 0x56, 0x3d, 0x50,
+  0x0d, 0x4f, 0x66, 0xb0, 0xae, 0x2e, 0xa4, 0x24, 0x03, 0xb8, 0xda, 0xb1,
+  0x3f, 0x90, 0xce, 0x84, 0x21, 0xc8, 0x49, 0x71, 0x7a, 0x87, 0x84, 0x73,
+  0x7a, 0x17, 0x63, 0x7d, 0xb2, 0xac, 0x55, 0x89, 0x9a, 0x0a, 0xfb, 0x32,
+  0x6c, 0xe1, 0x98, 0x23, 0xc3, 0xa7, 0x2d, 0xb4, 0xb0, 0x08, 0x0f, 0x44,
+  0xda, 0x05, 0xcb, 0x9d, 0xf2, 0x03, 0xd3, 0x55, 0xaf, 0xa9, 0x76, 0x70,
+  0x58, 0x20, 0xfc, 0x01, 0xb6, 0xc2, 0xe1, 0x90, 0x38, 0x77, 0x76, 0x8c,
+  0x42, 0x36, 0x1c, 0xda, 0xf5, 0xdb, 0x99, 0xa5, 0xa6, 0x0c, 0xc8, 0x9f,
+  0x16, 0x65, 0x9f, 0xdd, 0xbb, 0xed, 0xb6, 0x4e, 0xe8, 0x15, 0x9a, 0x51,
+  0x6e, 0x50, 0x53, 0x13, 0x0f, 0x87, 0x29, 0xa6, 0x6c, 0xa9, 0xbd, 0x81,
+  0x40, 0x4a, 0x3e, 0x52, 0xcc, 0xbe, 0xfa, 0x8d, 0x40, 0x3f, 0x62, 0x94,
+  0x77, 0x69, 0x72, 0x4f, 0xc7, 0xe9, 0xd8, 0x63, 0x92, 0x55, 0x39, 0x86,
+  0x55, 0xbe, 0x20, 0xaa, 0x1f, 0xdf, 0xd0, 0x7d, 0xd2, 0x47, 0xd8, 0x75,
+  0x9b, 0xdc, 0xee, 0xa2, 0x94, 0x11, 0x8e, 0xc6, 0x7a, 0x16, 0x4a, 0xb2,
+  0xf8, 0x2c, 0xf8, 0x02, 0x05, 0x4f, 0x70, 0x2c, 0x25, 0xc2, 0xd9, 0x7f,
+  0xc5, 0xa3, 0x58, 0x03, 0x82, 0x25, 0x18, 0xb0, 0x0e, 0xe6, 0x0a, 0xba,
+  0x63, 0x96, 0x1b, 0x96, 0xec, 0xe3, 0x62, 0x03, 0xe8, 0x53, 0x57, 0xe8,
+  0xed, 0xe9, 0xd0, 0xa3, 0x03, 0x98, 0x2b, 0xb0, 0x80, 0xa5, 0x80, 0xf8,
+  0x2f, 0x0b, 0x85, 0xfc, 0x58, 0x7b, 0x79, 0x22, 0x87, 0x99, 0x8f, 0xf8,
+  0x20, 0xc4, 0xbf, 0x88, 0x80, 0x9b, 0xe6, 0x15, 0xb8, 0x07, 0xee, 0xe3,
+  0xcf, 0x62, 0x6e, 0x93, 0xa0, 0xb4, 0xf6, 0x48, 0x15, 0x4e, 0xa7, 0x0b,
+  0x2b, 0xa6, 0xc3, 0xd8, 0x8c, 0x2c, 0x2f, 0x22, 0x31, 0xba, 0xb4, 0x6f,
+  0xab, 0x92, 0x0a, 0xe7, 0x68, 0x08, 0x32, 0xcc, 0x4b, 0xe2, 0x67, 0x9f,
+  0xff, 0xd8, 0xa7, 0x7f, 0x7f, 0x6a, 0xf8, 0x02, 0x4b, 0xc1, 0x93, 0x51,
+  0x93, 0x96, 0x85, 0x95, 0xe6, 0x1e, 0x1f, 0x5f, 0xea, 0xd7, 0xa3, 0x1d,
+  0xf9, 0xb6, 0x08, 0xca, 0x0a, 0xb4, 0x87, 0x48, 0x98, 0x6f, 0x6e, 0xb3,
+  0x60, 0x84, 0xd0, 0x4a, 0x01, 0x00, 0x41, 0x07, 0xb1, 0x86, 0xd8, 0x32,
+  0x30, 0x97, 0x3b, 0x07, 0x1e, 0xd8, 0xfa, 0x32, 0x8e, 0x63, 0x96, 0x73,
+  0x9c, 0x5b, 0xd2, 0xd7, 0x82, 0x1c, 0xb1, 0x9b, 0xb5, 0x58, 0x31, 0xda,
+  0x93, 0x08, 0x74, 0x45, 0xe6, 0x12, 0x5a, 0x40, 0xc8, 0x18, 0x7e, 0xd3,
+  0x91, 0xcb, 0x80, 0x44, 0x12, 0x9b, 0x41, 0x02, 0x2e, 0x75, 0x9d, 0xe7,
+  0xd9, 0xbd, 0x9d, 0x7d, 0x0d, 0x4a, 0x0e, 0x64, 0x06, 0xef, 0x64, 0xa4,
+  0xb6, 0x97, 0x8b, 0x16, 0xcf, 0x2b, 0xa7, 0x2a, 0x34, 0x80, 0x44, 0xc2,
+  0x4c, 0xcc, 0xb0, 0x50, 0x46, 0x6b, 0x78, 0x0a, 0x70, 0xe4, 0xb7, 0xcc,
+  0x00, 0xe6, 0xca, 0x9a, 0x88, 0x25, 0xdb, 0x65, 0x9d, 0x68, 0xe0, 0xb6,
+  0x80, 0xe8, 0x5c, 0x27, 0x6d, 0x25, 0xca, 0x25, 0xb1, 0x1a, 0xb8, 0x0b,
+  0x16, 0x75, 0x5d, 0x46, 0xae, 0x46, 0xc7, 0x26, 0x7b, 0x32, 0xc7, 0x30,
+  0x7f, 0x69, 0x40, 0x78, 0xbd, 0x50, 0x46, 0x0b, 0x2e, 0x41, 0x1c, 0x3d,
+  0xf9, 0xfe, 0xfb, 0x2a, 0x38, 0xe1, 0x56, 0xaf, 0xc2, 0xb1, 0x7c, 0x00,
+  0x87, 0xca, 0x17, 0x44, 0x44, 0x59, 0xdb, 0x29, 0xb7, 0x48, 0x7b, 0xb3,
+  0xeb, 0x72, 0x20, 0x06, 0xb4, 0x38, 0xd8, 0xfe, 0x14, 0x77, 0x59, 0x2a,
+  0x61, 0x6b, 0xe8, 0x7b, 0x10, 0x07, 0xd6, 0x74, 0x90, 0xb8, 0x90, 0x9f,
+  0x9e, 0x8b, 0xbc, 0x95, 0xc0, 0x13, 0x04, 0xa7, 0xd9, 0x5a, 0xf1, 0x52,
+  0x15, 0x8e, 0x60, 0xe8, 0x52, 0xba, 0x9f, 0xb7, 0x57, 0x36, 0xa9, 0xb9,
+  0x7d, 0x5c, 0x81, 0x03, 0x0d, 0x22, 0xc4, 0xf9, 0x95, 0x92, 0x3c, 0x6c,
+  0x9f, 0x1a, 0xe7, 0x89, 0xfa, 0x6e, 0xac, 0x5c, 0x50, 0xe3, 0xbc, 0x8a,
+  0x9d, 0x87, 0xc3, 0xac, 0x30, 0x3f, 0x4e, 0xe2, 0x95, 0x93, 0x8b, 0xcb,
+  0xc7, 0xc7, 0x32, 0x84, 0x7b, 0x85, 0xc7, 0x7b, 0x2d, 0x02, 0xc2, 0x3d,
+  0xca, 0x8f, 0x80, 0xf1, 0x98, 0xfd, 0x0e, 0x41, 0x57, 0x9a, 0x98, 0x84,
+  0xbb, 0x20, 0xff, 0x53, 0x6b, 0x39, 0x3e, 0xde, 0xff, 0xb6, 0x8a, 0x83,
+  0xfd, 0x32, 0x5f, 0x62, 0x89, 0xd8, 0xe7, 0xcb, 0x79, 0xe5, 0x99, 0x4f,
+  0x27, 0x63, 0x37, 0x9f, 0x45, 0x97, 0xc9, 0x25, 0xe6, 0xbd, 0xad, 0x2d,
+  0x41, 0x20, 0x36, 0x33, 0x31, 0xe1, 0xc0, 0x04, 0x54, 0x0d, 0x8f, 0xe8,
+  0xf7, 0x49, 0x34, 0xed, 0xe3, 0xb1, 0xa2, 0x51, 0xd9, 0x21, 0xb4, 0x79,
+  0x29, 0x3c, 0x67, 0x36, 0xd5, 0x52, 0x2e, 0x6e, 0xcd, 0x4c, 0x87, 0x30,
+  0x22, 0x52, 0x97, 0x51, 0xcc, 0x14, 0x44, 0x87, 0xee, 0xab, 0xe3, 0x7a,
+  0x51, 0xab, 0x4d, 0x60, 0xe4, 0xa9, 0xaa, 0x88, 0xe4, 0x09, 0xfa, 0xfb,
+  0xfc, 0xdd, 0xe5, 0x96, 0xaf, 0x67, 0x37, 0xc9, 0x6a, 0x36, 0x2b, 0x6b,
+  0xbc, 0x25, 0x13, 0x45, 0x32, 0x14, 0x14, 0x94, 0x01, 0x69, 0x26, 0xee,
+  0x4c, 0x30, 0x8e, 0xc2, 0x93, 0x9d, 0x5d, 0x12, 0xd5, 0x76, 0xf6, 0x60,
+  0x75, 0x79, 0xb2, 0xf3, 0xc4, 0x99, 0xb3, 0xed, 0xa9, 0xc6, 0x8d, 0x37,
+  0x91, 0x17, 0xa1, 0x16, 0x82, 0xe4, 0x9f, 0x3c, 0x3c, 0xe0, 0xe3, 0x5e,
+  0x1d, 0xa5, 0xa7, 0x50, 0x85, 0x32, 0x09, 0x6a, 0x3c, 0xaf, 0x39, 0x5a,
+  0x7e, 0xc5, 0x61, 0x3e, 0x59, 0xce, 0x25, 0xf6, 0x8b, 0x95, 0x5f, 0x64,
+  0x3c, 0xd4, 0x2f, 0x87, 0x90, 0x0e, 0x1e, 0x63, 0x4d, 0xa7, 0x2c, 0xde,
+  0x57, 0x18, 0x59, 0xcf, 0x63, 0x3a, 0x08, 0xe2, 0xaf, 0x29, 0x77, 0x96,
+  0x8b, 0x58, 0x6b, 0xee, 0x4f, 0x3e, 0xd5, 0x56, 0xea, 0xa3, 0x80, 0xd4,
+  0x03, 0xf6, 0x86, 0x9a, 0x57, 0x9c, 0x30, 0xe6, 0x8f, 0x49, 0x36, 0x30,
+  0xbc, 0xd5, 0x46, 0x1e, 0x04, 0xad, 0xb2, 0x55, 0x08, 0x4c, 0x19, 0x84,
+  0x61, 0xb2, 0x1c, 0xe3, 0xae, 0xe7, 0xb0, 0x17, 0x2e, 0xf8, 0x37, 0x12,
+  0xcc, 0x47, 0x03, 0xd1, 0xe0, 0xb6, 0x3d, 0x91, 0x36, 0xd5, 0x6c, 0x1c,
+  0x43, 0x3c, 0xe5, 0x92, 0x76, 0x59, 0xaf, 0x61, 0x83, 0x91, 0x4b, 0x15,
+  0x6e, 0x30, 0x88, 0xf9, 0x55, 0x66, 0x10, 0xb5, 0x4d, 0x90, 0x5e, 0x90,
+  0x25, 0x5c, 0x74, 0x66, 0x1e, 0x8e, 0xa5, 0x36, 0x24, 0x68, 0xe7, 0x4b,
+  0x0e, 0x56, 0xab, 0xb5, 0x58, 0x81, 0x61, 0x9d, 0x31, 0xa6, 0x6c, 0x3e,
+  0xa6, 0xc3, 0xfd, 0x52, 0x63, 0x36, 0x9b, 0xae, 0x7e, 0xc1, 0x1d, 0x31,
+  0xfd, 0x0f, 0x13, 0x00, 0x54, 0xa4, 0x87, 0x9d, 0xd2, 0xa5, 0x15, 0xa9,
+  0x7a, 0x06, 0x04, 0x62, 0xf1, 0x24, 0x37, 0x13, 0xb7, 0x00, 0xad, 0xea,
+  0x56, 0xfc, 0xa3, 0xac, 0x27, 0xce, 0xfe, 0xdf, 0x82, 0x16, 0x49, 0x0b,
+  0x9d, 0x2e, 0x18, 0xe2, 0xab, 0x69, 0xdb, 0x5e, 0x8f, 0x51, 0xa2, 0xd3,
+  0x06, 0x17, 0xff, 0x77, 0x4e, 0x1b, 0x7e, 0xd7, 0x5f, 0x36, 0xcc, 0x07,
+  0x14, 0xa9, 0x41, 0x9c, 0xe5, 0x4b, 0x28, 0x6e, 0x1f, 0xa3, 0x96, 0xe3,
+  0xf1, 0x4d, 0x53, 0x5e, 0xb7, 0x7c, 0xaa, 0xb5, 0xe8, 0xe4, 0x06, 0xe7,
+  0x84, 0xf8, 0x89, 0x36, 0xa9, 0x0a, 0x8f, 0xfa, 0xab, 0x2d, 0xad, 0x86,
+  0x52, 0xe3, 0x4e, 0x46, 0xde, 0x65, 0xaf, 0x8a, 0x8e, 0xb3, 0xa6, 0xc6,
+  0x20, 0x02, 0x1f, 0xa5, 0x48, 0x7d, 0x10, 0x25, 0x0f, 0xf8, 0x63, 0xdc,
+  0xbe, 0xc9, 0x03, 0xdc, 0x2e, 0xc4, 0xa7, 0x9e, 0x3f, 0x19, 0xb4, 0xdb,
+  0x7e, 0x2e, 0x2b, 0x01, 0xa7, 0xc6, 0x92, 0xc5, 0x45, 0x21, 0x70, 0x32,
+  0x8b, 0x9c, 0x71, 0x65, 0xc3, 0xd9, 0x49, 0x0d, 0x83, 0x16, 0xfc, 0x8d,
+  0x82, 0x41, 0xc0, 0x45, 0x42, 0x2e, 0xd7, 0x62, 0x84, 0x59, 0x49, 0x2e,
+  0x17, 0xea, 0x8a, 0x59, 0x36, 0xbc, 0xc7, 0x92, 0x3a, 0x82, 0x6c, 0x0c,
+  0x49, 0xb2, 0x6c, 0x2c, 0x94, 0xea, 0xcd, 0xb8, 0xdc, 0x5c, 0x58, 0x29,
+  0x57, 0xa7, 0x49, 0xf2, 0x46, 0x28, 0x15, 0x32, 0xd8, 0x59, 0x11, 0xe0,
+  0xc5, 0xc2, 0xf9, 0x0d, 0xe2, 0xfa, 0x1d, 0x55, 0xcc, 0xb6, 0x85, 0x30,
+  0x1e, 0x8d, 0x68, 0x7b, 0xa3, 0xa4, 0x20, 0x7a, 0x30, 0xbc, 0x87, 0xfa,
+  0xa4, 0xd0, 0x2d, 0xeb, 0x4d, 0xc2, 0x4f, 0x51, 0xdf, 0xf7, 0x26, 0x9b,
+  0x86, 0x66, 0xb8, 0xa6, 0xbb, 0x8b, 0x24, 0x89, 0x81, 0x47, 0x51, 0x55,
+  0xfd, 0x8b, 0x57, 0x53, 0x2b, 0x09, 0xa7, 0x56, 0xbf, 0x60, 0x84, 0x5a,
+  0xe8, 0x7f, 0xcd, 0x46, 0x56, 0x42, 0x90, 0xaf, 0xfa, 0x36, 0xe4, 0x5a,
+  0xf1, 0xad, 0xdc, 0x70, 0x0d, 0x38, 0xda, 0xb4, 0xa5, 0xd0, 0x26, 0x43,
+  0xb1, 0x92, 0xbc, 0x56, 0xb2, 0x12, 0x8b, 0xe8, 0x71, 0xa8, 0x1a, 0xd1,
+  0x35, 0x92, 0xf7, 0x26, 0x22, 0x53, 0x91, 0xc8, 0xd1, 0x00, 0x8d, 0x73,
+  0x95, 0x9d, 0x54, 0x8e, 0xc6, 0xe2, 0xb0, 0x2b, 0x6c, 0x8d, 0x0c, 0xf0,
+  0xeb, 0x29, 0xc3, 0x6f, 0xb0, 0x1b, 0xf3, 0x66, 0xd4, 0xde, 0x1b, 0x7c,
+  0x38, 0xe0, 0x8a, 0x95, 0x1c, 0x43, 0x2d, 0xce, 0x89, 0xa5, 0xa6, 0xf6,
+  0x49, 0xd5, 0x64, 0xdf, 0xca, 0x7c, 0x9b, 0xcb, 0x18, 0x97, 0xf9, 0xb8,
+  0xd1, 0x88, 0x93, 0xe0, 0x8a, 0xb1, 0xda, 0x2e, 0x06, 0x78, 0x90, 0x18,
+  0xc7, 0x7b, 0xfd, 0x85, 0x2f, 0x09, 0xf5, 0xe1, 0x6c, 0xb9, 0xc8, 0x8d,
+  0xd6, 0xe0, 0x09, 0x16, 0xde, 0xba, 0x85, 0xf3, 0x2f, 0xa8, 0x66, 0xcb,
+  0x1b, 0x01, 0xdc, 0xad, 0xb6, 0x7a, 0xcb, 0x0e, 0x4f, 0x76, 0xb5, 0x68,
+  0x04, 0x4f, 0x04, 0x85, 0x4c, 0xae, 0xa4, 0x3a, 0x95, 0xf9, 0xad, 0xbc,
+  0xa4, 0xed, 0x0a, 0x58, 0x85, 0x49, 0x32, 0x8a, 0x8d, 0xd2, 0x32, 0xba,
+  0xa8, 0x51, 0xd8, 0x1a, 0x22, 0x26, 0x66, 0xba, 0xf9, 0x74, 0x0b, 0x6a,
+  0x75, 0xb9, 0xd8, 0xdc, 0xdd, 0x42, 0x8f, 0x96, 0xcc, 0x2f, 0x82, 0x7e,
+  0xab, 0xbf, 0x5a, 0xeb, 0xb9, 0x84, 0x95, 0x56, 0x4b, 0x01, 0x84, 0x65,
+  0x71, 0x0e, 0x27, 0x9c, 0x75, 0x45, 0x59, 0x35, 0x87, 0x6a, 0xcd, 0x46,
+  0xc8, 0x36, 0xce, 0x28, 0x29, 0x6d, 0x0b, 0x76, 0xd4, 0x14, 0x02, 0xb9,
+  0xbe, 0xe9, 0x11, 0x88, 0xe1, 0x7e, 0x4e, 0xac, 0x94, 0x08, 0x2d, 0xdf,
+  0x74, 0xd2, 0xe7, 0x01, 0x5f, 0xe7, 0x59, 0x13, 0x21, 0x8c, 0x9d, 0xec,
+  0xbc, 0x06, 0x5b, 0xe2, 0x07, 0x6d, 0x2d, 0x93, 0xd1, 0x61, 0x87, 0x62,
+  0xc7, 0x83, 0x85, 0x33, 0x56, 0x53, 0xaa, 0x32, 0x5a, 0xdd, 0x30, 0x54,
+  0xd9, 0xd2, 0x06, 0xbd, 0x1f, 0x70, 0xb4, 0x46, 0x3a, 0xbe, 0x55, 0x5f,
+  0xac, 0x80, 0x2f, 0xc3, 0x47, 0x85, 0x22, 0xca, 0x22, 0xbc, 0xd2, 0x35,
+  0xa1, 0xf2, 0x39, 0x54, 0x50, 0xba, 0x33, 0x94, 0xd4, 0x5a, 0xaa, 0xd4,
+  0xf0, 0x39, 0x35, 0xc5, 0x02, 0x09, 0x48, 0x99, 0xde, 0x40, 0xb0, 0xc0,
+  0x88, 0x36, 0x32, 0xc9, 0x38, 0x42, 0x96, 0xfd, 0x2c, 0x42, 0x05, 0xb2,
+  0xbf, 0x2d, 0x32, 0x5b, 0x77, 0xb6, 0xe2, 0x34, 0xf4, 0x6e, 0x15, 0xa4,
+  0xbd, 0x4b, 0x0c, 0x8b, 0xee, 0x89, 0xae, 0x2d, 0x2f, 0xcc, 0x2a, 0x8f,
+  0x00, 0x69, 0xac, 0xeb, 0x5b, 0x48, 0x5b, 0xba, 0xf0, 0xad, 0x4b, 0xe3,
+  0xc1, 0x5d, 0x8b, 0xa9, 0xf6, 0xcd, 0xef, 0x5e, 0x6b, 0xfb, 0x5b, 0x5b,
+  0x30, 0xed, 0xdc, 0x9e, 0xb7, 0xa2, 0xd0, 0x9e, 0x95, 0x88, 0xe5, 0x35,
+  0x38, 0xa7, 0xcb, 0xa2, 0x99, 0xe0, 0xe7, 0x8a, 0xb0, 0x59, 0xd4, 0x02,
+  0x5b, 0x7c, 0x62, 0xab, 0x2d, 0x23, 0x9c, 0x4c, 0xde, 0xd6, 0x56, 0x99,
+  0x30, 0x07, 0x95, 0xc1, 0x6a, 0x88, 0xdb, 0xe3, 0x05, 0xe3, 0x2b, 0xd1,
+  0x70, 0xcd, 0x93, 0x05, 0xc3, 0x6e, 0xe5, 0x99, 0xf6, 0xf4, 0x65, 0xd6,
+  0x1f, 0x26, 0x09, 0x87, 0x1a, 0x09, 0x74, 0xc0, 0x9b, 0x74, 0x9c, 0x67,
+  0x45, 0x76, 0x25, 0xb7, 0xba, 0x91, 0xa7, 0x33, 0x37, 0x71, 0x6e, 0x71,
+  0xcc, 0xce, 0xdd, 0x26, 0xbf, 0xd0, 0x72, 0x7c, 0x12, 0xbf, 0xcc, 0x97,
+  0xf6, 0x8c, 0x68, 0x9d, 0x53, 0x29, 0xd8, 0x0e, 0x5c, 0x0a, 0x28, 0x5c,
+  0xec, 0xa2, 0xf6, 0xf4, 0x8e, 0xb0, 0x88, 0xc9, 0x67, 0x8f, 0x6b, 0xd2,
+  0xbc, 0x13, 0x5a, 0xc5, 0x05, 0x17, 0x82, 0x44, 0x97, 0xa1, 0xb2, 0x8e,
+  0x62, 0x22, 0x89, 0xfe, 0x63, 0xaf, 0xb5, 0x8f, 0xce, 0x14, 0x18, 0x00,
+  0x98, 0xc3, 0x68, 0x1c, 0x56, 0x4c, 0xe4, 0x40, 0xc0, 0x93, 0xe3, 0xcb,
+  0xd7, 0xd1, 0x24, 0x8f, 0x69, 0xfa, 0xf8, 0xb7, 0x4f, 0x3a, 0xc0, 0xcf,
+  0x71, 0x23, 0x0b, 0xb8, 0x58, 0xf0, 0x26, 0xf5, 0xd9, 0xf3, 0xd8, 0xdf,
+  0x79, 0x3a, 0x28, 0x1f, 0x5a, 0x23, 0x05, 0xc5, 0xd6, 0x6c, 0x16, 0x4c,
+  0x2d, 0xad, 0xe1, 0xb7, 0x4c, 0x53, 0x3c, 0xf9, 0x9a, 0xcd, 0x1e, 0x56,
+  0x75, 0x98, 0xc3, 0x36, 0x50, 0x60, 0x60, 0xe9, 0xf4, 0xf1, 0xb8, 0xa7,
+  0x92, 0x7f, 0x21, 0xec, 0x52, 0xc2, 0x2c, 0x83, 0x40, 0xca, 0x35, 0xc5,
+  0x42, 0x1e, 0x8d, 0xab, 0x6c, 0x8b, 0xa3, 0xb4, 0x8f, 0xd7, 0xa0, 0x27,
+  0xd6, 0x88, 0xb7, 0x5d, 0x8b, 0x5f, 0x36, 0xab, 0x04, 0x38, 0x14, 0x67,
+  0xd0, 0x80, 0xc5, 0x57, 0x33, 0x9c, 0x14, 0x2c, 0x47, 0xfd, 0xa5, 0xa6,
+  0xc3, 0xb6, 0x27, 0x09, 0x81, 0xc7, 0x02, 0x45, 0xcd, 0xa0, 0xdd, 0x6a,
+  0x44, 0x06, 0x39, 0xd5, 0x7c, 0x8f, 0x03, 0x54, 0xcf, 0x85, 0x89, 0xbb,
+  0xce, 0xd1, 0xfa, 0xcb, 0x68, 0x1f, 0xb8, 0x4d, 0xc9, 0x9c, 0x4b, 0x6a,
+  0xd8, 0xb1, 0xf6, 0x2c, 0x50, 0x39, 0xb1, 0xe3, 0x47, 0x61, 0xc1, 0xe5,
+  0xfe, 0xb2, 0x7d, 0x74, 0x71, 0x9e, 0xf0, 0xed, 0x24, 0x21, 0x90, 0x7a,
+  0xf3, 0x0e, 0xfe, 0xfd, 0x88, 0xdb, 0x9e, 0x0f, 0xbd, 0xdd, 0x46, 0x90,
+  0xfe, 0x68, 0xc9, 0xdf, 0xb5, 0x56, 0xea, 0x56, 0x5e, 0x28, 0x4f, 0xa8,
+  0x4f, 0x36, 0x70, 0xae, 0x16, 0x1c, 0x27, 0x37, 0x0b, 0xab, 0xc1, 0xb0,
+  0xe4, 0xc7, 0x1a, 0x72, 0x9d, 0x26, 0x96, 0xc2, 0x3b, 0x7a, 0x55, 0x6c,
+  0xe1, 0x9a, 0xe5, 0x5d, 0xba, 0x61, 0x53, 0x53, 0xd8, 0x7c, 0x9b, 0x83,
+  0x1a, 0xaf, 0xc3, 0xd5, 0x08, 0x3f, 0x95, 0x08, 0xfd, 0x12, 0xe3, 0xac,
+  0xd6, 0x06, 0x6d, 0xc2, 0x41, 0xb1, 0x13, 0x7b, 0x1b, 0xdf, 0x2c, 0x49,
+  0x1a, 0xed, 0xb5, 0x58, 0xcd, 0xcd, 0x90, 0x0b, 0x5e, 0x46, 0xf7, 0xa9,
+  0xa6, 0xe0, 0x5b, 0xa2, 0x96, 0xb4, 0xc0, 0xc9, 0xde, 0x77, 0x00, 0x3c,
+  0x6c, 0x54, 0xb7, 0x68, 0x1b, 0x9d, 0xaf, 0x3c, 0x1f, 0x97, 0x7e, 0x01,
+  0x1f, 0x0b, 0xbb, 0x0b, 0xa0, 0xff, 0xe9, 0xe8, 0xc3, 0x00, 0xab, 0x44,
+  0x20, 0x14, 0x67, 0x19, 0x80, 0xf0, 0x4e, 0x1a, 0xec, 0x55, 0x83, 0x89,
+  0x48, 0x65, 0x11, 0x62, 0x22, 0xd2, 0xa7, 0xf0, 0x25, 0x8f, 0x50, 0xd7,
+  0x32, 0x92, 0x6a, 0xa6, 0xc6, 0x63, 0x74, 0xb0, 0x14, 0xdb, 0x84, 0xcf,
+  0xea, 0xe0, 0x94, 0x76, 0x58, 0x4e, 0xd5, 0x56, 0x7b, 0x79, 0x78, 0x1e,
+  0xd8, 0xc2, 0x19, 0x27, 0x60, 0x6d, 0x4a, 0x93, 0x06, 0xeb, 0xcc, 0x5d,
+  0xeb, 0xb3, 0x7f, 0xe3, 0xda, 0xf8, 0x19, 0x04, 0xcb, 0xe3, 0x3e, 0xac,
+  0x2d, 0x8d, 0xa6, 0xf0, 0xa5, 0x93, 0xf6, 0x2c, 0x0a, 0x5d, 0x21, 0x43,
+  0xe2, 0xd6, 0x35, 0xe2, 0xb4, 0x31, 0xcb, 0x93, 0x3c, 0x39, 0xa2, 0xd1,
+  0xb0, 0x74, 0x73, 0x4d, 0x83, 0xfb, 0xd2, 0xad, 0x40, 0x53, 0x2a, 0xf3,
+  0x0a, 0x23, 0x9c, 0x1c, 0xa8, 0xdc, 0x14, 0x14, 0xdf, 0xe2, 0x04, 0xeb,
+  0x10, 0xb6, 0x43, 0x1c, 0xc7, 0x96, 0x43, 0xba, 0x26, 0x4f, 0x1e, 0xd5,
+  0xd5, 0x11, 0x1b, 0x42, 0xfa, 0x0b, 0x5f, 0xca, 0xa3, 0x95, 0xe5, 0xaf,
+  0x29, 0x7a, 0x4f, 0x9e, 0x28, 0x74, 0x73, 0x30, 0xe0, 0xa2, 0xe5, 0x76,
+  0xe2, 0xda, 0xe7, 0x49, 0x32, 0xd3, 0xf8, 0xd0, 0x51, 0x9e, 0xdd, 0xd2,
+  0xf9, 0xe0, 0xd7, 0x20, 0x88, 0xf2, 0xea, 0xcb, 0x21, 0x37, 0x53, 0x16,
+  0x1d, 0x03, 0x05, 0x2c, 0x6e, 0x1a, 0xe6, 0x1c, 0xe2, 0xb5, 0x66, 0xd2,
+  0xf8, 0xd3, 0x22, 0x48, 0x53, 0x88, 0x03, 0xb4, 0xfb, 0x13, 0x77, 0x0f,
+  0x97, 0x40, 0xf2, 0x51, 0x10, 0x0d, 0x8d, 0xb4, 0x01, 0xcd, 0xfb, 0x9b,
+  0xd3, 0x90, 0x23, 0x8b, 0x90, 0x86, 0x5a, 0xb6, 0xbc, 0x42, 0x4c, 0x22,
+  0x08, 0xbc, 0x24, 0xaa, 0x92, 0x3b, 0x9e, 0xbd, 0x7e, 0x75, 0xe5, 0x1f,
+  0x70, 0xa7, 0xfd, 0x20, 0x68, 0xdd, 0x95, 0xd3, 0x16, 0x5b, 0xa8, 0x18,
+  0x1e, 0x27, 0x1e, 0x47, 0x3e, 0x16, 0xf9, 0x02, 0x01, 0x76, 0x44, 0x32,
+  0xcd, 0xdb, 0xdd, 0x65, 0xd4, 0xa8, 0xd4, 0x08, 0x2f, 0x05, 0x6f, 0x0f,
+  0x72, 0x54, 0x11, 0x6a, 0xa6, 0xd6, 0xb1, 0x3f, 0x86, 0x21, 0xd2, 0x51,
+  0x9b, 0xd1, 0x12, 0xc0, 0x06, 0x49, 0xe1, 0x6d, 0xb3, 0x12, 0x17, 0xe3,
+  0x72, 0xd8, 0x18, 0x1e, 0x25, 0xe4, 0x19, 0x18, 0xda, 0x20, 0x3a, 0x66,
+  0x3b, 0x6b, 0x8b, 0xf2, 0x60, 0x81, 0x9f, 0x98, 0x23, 0x52, 0x1c, 0x4b,
+  0x60, 0x45, 0xd2, 0x8d, 0xab, 0x9a, 0x18, 0xa7, 0x3e, 0xcf, 0x2c, 0xee,
+  0x9d, 0x31, 0x45, 0x5d, 0xe5, 0xb6, 0x56, 0x45, 0xaa, 0x28, 0x35, 0x8f,
+  0xdd, 0x60, 0x95, 0xed, 0x23, 0x87, 0x96, 0xf5, 0xda, 0x5b, 0xfc, 0x7b,
+  0xe2, 0xb3, 0x14, 0x25, 0xa7, 0x05, 0xf0, 0x0a, 0xa3, 0x89, 0xfc, 0x43,
+  0xbd, 0xe0, 0xf7, 0xfd, 0xcf, 0x76, 0xb4, 0xd0, 0x26, 0xf0, 0x15, 0xc3,
+  0x67, 0x50, 0x90, 0xa2, 0xe5, 0x9e, 0x41, 0xa2, 0x7b, 0x56, 0xba, 0x47,
+  0xeb, 0xd0, 0xac, 0x2f, 0x06, 0x4f, 0x2b, 0xe6, 0xdd, 0x79, 0x39, 0x9d,
+  0x79, 0x68, 0x20, 0x03, 0x24, 0x7d, 0x7b, 0x79, 0xfa, 0x26, 0x5a, 0xa3,
+  0x0e, 0xe0, 0xbb, 0xea, 0x57, 0xff, 0x8a, 0x52, 0x40, 0x5f, 0x9c, 0x9c,
+  0x0c, 0xa1, 0x12, 0xa8, 0xa3, 0xba, 0x11, 0x70, 0x51, 0x6a, 0x9e, 0x09,
+  0x4b, 0x55, 0x79, 0x4a, 0x1a, 0x7d, 0x8e, 0x1c, 0xb1, 0x32, 0x1b, 0x67,
+  0x53, 0x4e, 0x27, 0xe4, 0x97, 0x12, 0x2d, 0x16, 0x8f, 0xcb, 0x9d, 0xc1,
+  0xcb, 0xa6, 0xe0, 0x4a, 0x8b, 0xa4, 0x11, 0x30, 0xc3, 0x8a, 0x2c, 0x06,
+  0x60, 0x2c, 0x45, 0xd6, 0x06, 0x77, 0x05, 0xd7, 0xa7, 0xb4, 0x6c, 0x0f,
+  0xd2, 0x53, 0x88, 0xe2, 0x58, 0xd0, 0x54, 0x1b, 0xc7, 0x6d, 0x8a, 0xa8,
+  0xbf, 0x46, 0x2a, 0xa7, 0x96, 0xac, 0xaa, 0x20, 0xf5, 0x00, 0xc6, 0x6c,
+  0x92, 0xe5, 0x70, 0xdb, 0x05, 0x38, 0x31, 0x8c, 0x6d, 0xb6, 0x44, 0x48,
+  0x0c, 0x0f, 0x6f, 0xd5, 0x3c, 0x4a, 0xf7, 0x37, 0x99, 0x44, 0xa4, 0x60,
+  0x99, 0x99, 0x2b, 0x49, 0x10, 0x04, 0xfc, 0x02, 0x02, 0x2f, 0x22, 0x04,
+  0xe1, 0x59, 0x49, 0xb8, 0x51, 0x6d, 0xee, 0x35, 0x57, 0x24, 0x4e, 0x32,
+  0xad, 0x7a, 0x62, 0xdf, 0xa4, 0xcd, 0x39, 0x4a, 0xaf, 0xd7, 0xe0, 0x6f,
+  0xb5, 0x2b, 0x1d, 0x3c, 0xa2, 0xc7, 0xf5, 0x8d, 0xb6, 0xe8, 0xe0, 0x8a,
+  0xbe, 0x41, 0xd4, 0xf6, 0xb1, 0xaa, 0x86, 0xaf, 0x8c, 0xad, 0x95, 0x75,
+  0x25, 0xc9, 0x8b, 0x6f, 0x83, 0x40, 0xd7, 0x78, 0xd7, 0x70, 0x68, 0x3d,
+  0xa6, 0x52, 0x54, 0x53, 0xb3, 0x78, 0x42, 0xff, 0x5b, 0xa5, 0xe3, 0x8c,
+  0x46, 0xaa, 0x52, 0x64, 0x6b, 0x08, 0xe7, 0x77, 0x92, 0xf8, 0xa1, 0x72,
+  0x66, 0xa6, 0x0f, 0x85, 0x68, 0x54, 0x45, 0x39, 0xc9, 0x96, 0xe2, 0xd6,
+  0x85, 0xc1, 0x36, 0xb7, 0xdb, 0xfc, 0xef, 0xff, 0x68, 0xfa, 0xa9, 0x7f,
+  0xfc, 0x49, 0xd4, 0x17, 0x09, 0xb0, 0xf5, 0x7e, 0x14, 0x23, 0xa5, 0xc2,
+  0xa3, 0x0b, 0xf2, 0xa6, 0x71, 0x36, 0x8b, 0x4c, 0x51, 0x8e, 0x54, 0x5d,
+  0x85, 0xd1, 0xf0, 0x0c, 0xbd, 0x8a, 0x75, 0x6c, 0x76, 0x0f, 0x00, 0x6f,
+  0x3a, 0xa8, 0xe2, 0x1b, 0xe0, 0x6b, 0x29, 0x0a, 0xd0, 0x64, 0x1d, 0xe2,
+  0x92, 0x85, 0xa3, 0x57, 0x61, 0x2d, 0x11, 0x08, 0x2c, 0x26, 0x74, 0x8c,
+  0x9f, 0x6f, 0x9a, 0x53, 0x29, 0x05, 0xd5, 0x44, 0x03, 0x91, 0x8d, 0xd6,
+  0x98, 0xde, 0xbf, 0xd3, 0x29, 0xeb, 0x95, 0xf7, 0xd9, 0x3f, 0x06, 0xec,
+  0x57, 0x03, 0x23, 0xee, 0x67, 0x02, 0x1e, 0xfa, 0xfe, 0x93, 0x5d, 0xd6,
+  0xbb, 0x3b, 0x4d, 0xc8, 0x54, 0xac, 0x80, 0xed, 0xb9, 0x8b, 0xd2, 0x5f,
+  0x03, 0x3e, 0x52, 0xed, 0x8e, 0x7b, 0xe9, 0xf1, 0x95, 0xf0, 0x8f, 0x01,
+  0xff, 0xfb, 0xe3, 0x6e, 0xff, 0xd9, 0x4f, 0xae, 0xd7, 0x4f, 0x76, 0xdf,
+  0x7f, 0xb2, 0xd7, 0x69, 0x45, 0x98, 0x65, 0xd3, 0xc4, 0xd2, 0xa0, 0x30,
+  0x4d, 0xa1, 0xd3, 0xe2, 0xa1, 0xe2, 0xea, 0x52, 0x1d, 0xd1, 0xc3, 0xad,
+  0x01, 0xfc, 0xb1, 0xe9, 0x44, 0x64, 0xb5, 0xe5, 0x03, 0xa0, 0x4f, 0x61,
+  0x21, 0xc0, 0x00, 0xa9, 0x41, 0xeb, 0xe2, 0x41, 0xc9, 0x94, 0x58, 0x1b,
+  0xb3, 0x19, 0x36, 0xcc, 0x93, 0x40, 0x9a, 0x98, 0xac, 0xe8, 0xde, 0x13,
+  0xb4, 0x8b, 0x81, 0x73, 0x35, 0x99, 0x34, 0x69, 0x75, 0x45, 0x25, 0x83,
+  0x68, 0xd3, 0x49, 0x00, 0x9c, 0x6a, 0xb2, 0xd5, 0xa6, 0xd0, 0x78, 0x1d,
+  0xc2, 0xd3, 0xbc, 0x56, 0x6d, 0xc3, 0x49, 0x16, 0x62, 0xf7, 0xe7, 0xa7,
+  0x86, 0x38, 0xf1, 0x81, 0xd3, 0x13, 0xeb, 0x8c, 0x82, 0x52, 0xcf, 0x8a,
+  0x31, 0xeb, 0x60, 0x9c, 0xf0, 0xd5, 0xbd, 0x80, 0x4a, 0x37, 0x80, 0x92,
+  0x90, 0x8b, 0xe5, 0xfd, 0x3d, 0x21, 0x9a, 0x57, 0xf8, 0xba, 0x32, 0x8c,
+  0x9e, 0xe6, 0xdb, 0x11, 0x51, 0x23, 0x13, 0xbf, 0x6c, 0x26, 0xd9, 0x0f,
+  0xb6, 0xda, 0x02, 0x29, 0xc3, 0xb6, 0x2c, 0x21, 0x4b, 0x03, 0x9c, 0xa2,
+  0x42, 0x30, 0x3b, 0x61, 0x1b, 0x53, 0xbc, 0x8b, 0x24, 0xb4, 0x0c, 0x34,
+  0x82, 0x39, 0xb5, 0xda, 0x5e, 0xcf, 0xa1, 0xc0, 0x24, 0xd3, 0x22, 0x19,
+  0xfc, 0x5b, 0xc9, 0xaf, 0xb2, 0x45, 0xfd, 0xb8, 0xe1, 0x01, 0xac, 0xb8,
+  0x79, 0x11, 0xf6, 0x51, 0x2d, 0xc2, 0x27, 0x85, 0x05, 0x5c, 0x95, 0x3b,
+  0x37, 0xa7, 0x42, 0x03, 0xe0, 0x1a, 0x59, 0x12, 0xb1, 0xbb, 0x2c, 0x24,
+  0x73, 0xb4, 0x01, 0x4c, 0x82, 0x2c, 0x52, 0xe7, 0x94, 0x80, 0x7b, 0x3e,
+  0x93, 0x04, 0x2f, 0x7a, 0xbc, 0x09, 0x86, 0xe7, 0xee, 0xc1, 0x8a, 0xbe,
+  0x8d, 0xf1, 0x18, 0xbb, 0x1b, 0x83, 0x3b, 0x49, 0xad, 0x86, 0xea, 0x7c,
+  0x5b, 0x34, 0x30, 0xc1, 0x35, 0x40, 0x75, 0x51, 0x03, 0x28, 0xc5, 0x75,
+  0x0b, 0xa3, 0x14, 0xef, 0x40, 0x87, 0x18, 0x45, 0xbf, 0xc3, 0x4c, 0x08,
+  0xca, 0x61, 0xd0, 0xdc, 0xa3, 0xe0, 0x5d, 0x2f, 0xaa, 0xae, 0x61, 0x36,
+  0x1c, 0x45, 0x2f, 0x17, 0x37, 0x39, 0xc9, 0x34, 0x8f, 0x80, 0x10, 0xd0,
+  0x53, 0xf2, 0x8c, 0x63, 0xb4, 0x41, 0x96, 0xfd, 0x6f, 0x98, 0x0d, 0xcf,
+  0x91, 0xf5, 0x4f, 0x76, 0x76, 0x1b, 0x55, 0x48, 0x7c, 0xe1, 0xf1, 0x0c,
+  0x21, 0x2b, 0x6c, 0x76, 0x61, 0x18, 0xfd, 0x28, 0xda, 0x7b, 0xbe, 0xfb,
+  0x7c, 0x7b, 0x77, 0x67, 0xf0, 0x64, 0xb0, 0xa7, 0x42, 0x31, 0x30, 0x11,
+  0x49, 0x56, 0xe7, 0x2a, 0x3f, 0x11, 0x42, 0x6b, 0xda, 0xa3, 0x51, 0x58,
+  0xdf, 0xa3, 0xe6, 0x02, 0x38, 0x56, 0x2d, 0x27, 0xec, 0x6f, 0xf0, 0x98,
+  0x03, 0x67, 0x5c, 0x64, 0x86, 0x55, 0xb2, 0x68, 0x38, 0xab, 0xe7, 0x7d,
+  0x1e, 0x8a, 0xca, 0x7c, 0x4b, 0x41, 0x53, 0x1e, 0xa5, 0x24, 0xb3, 0x94,
+  0x5c, 0x01, 0x8f, 0xd3, 0x9f, 0x49, 0x8e, 0x35, 0xa4, 0x1e, 0xce, 0x0b,
+  0xce, 0xc2, 0x32, 0x9a, 0x6b, 0x02, 0x14, 0x4d, 0x58, 0x41, 0xea, 0xb0,
+  0x91, 0x3d, 0x12, 0x2e, 0x53, 0x49, 0xc7, 0x05, 0xf6, 0x0a, 0xdd, 0xf9,
+  0xa8, 0x3b, 0xf3, 0xb5, 0x65, 0x03, 0xc7, 0xad, 0x71, 0x9e, 0x1a, 0xb9,
+  0x22, 0xba, 0x6f, 0x2c, 0xf1, 0x46, 0x58, 0x4a, 0x28, 0x38, 0xfa, 0x81,
+  0x50, 0xaa, 0x08, 0x82, 0x82, 0xde, 0x38, 0x49, 0xdb, 0xa0, 0xd3, 0x52,
+  0x57, 0x27, 0xc1, 0xef, 0xb8, 0xa2, 0x79, 0xb0, 0x7b, 0x57, 0x94, 0x3c,
+  0x6f, 0x67, 0x7d, 0x34, 0xc0, 0xf0, 0x11, 0x9c, 0x39, 0xa1, 0x85, 0xbd,
+  0xff, 0x3f, 0xd1, 0xc2, 0xde, 0xff, 0xa3, 0x85, 0x7f, 0x13, 0x2d, 0xbc,
+  0xa8, 0xd1, 0x02, 0x14, 0x05, 0xba, 0x74, 0x58, 0xb5, 0x78, 0x94, 0x22,
+  0x16, 0xec, 0xae, 0xe4, 0x44, 0x8b, 0x54, 0x52, 0xf1, 0x6a, 0x86, 0x78,
+  0xd3, 0x42, 0xb5, 0x7e, 0xe0, 0x6c, 0xb6, 0xac, 0xcf, 0x6a, 0x6e, 0xe5,
+  0x0a, 0x55, 0xb5, 0x28, 0x83, 0x34, 0x06, 0xb5, 0x29, 0x58, 0xd8, 0x97,
+  0x00, 0x95, 0x4a, 0x54, 0x2e, 0x07, 0x63, 0xe3, 0xf2, 0x6d, 0x27, 0xb0,
+  0x6d, 0x17, 0x8e, 0x97, 0x73, 0x16, 0x6b, 0x9f, 0xa4, 0xd8, 0x45, 0xa3,
+  0x00, 0xf4, 0x5e, 0x73, 0xca, 0x80, 0x0d, 0x7b, 0x74, 0xc2, 0xdc, 0xf9,
+  0xda, 0xa0, 0xad, 0x28, 0x9c, 0xa9, 0xcd, 0x6c, 0x9d, 0x88, 0x2d, 0x93,
+  0xd4, 0x39, 0xbe, 0x13, 0x5b, 0x2e, 0xda, 0xc4, 0x85, 0xc8, 0xea, 0x1e,
+  0x2f, 0x4b, 0xd0, 0x97, 0x5c, 0xa7, 0x8d, 0x09, 0x3b, 0xec, 0xcb, 0x81,
+  0x3e, 0x97, 0x5a, 0x1d, 0x40, 0xcb, 0xf3, 0xad, 0x0f, 0x52, 0x77, 0x05,
+  0x73, 0x6a, 0x2a, 0x8a, 0x85, 0x74, 0xc4, 0x03, 0xab, 0x95, 0x62, 0x96,
+  0x35, 0x9a, 0x40, 0x63, 0x6d, 0x5d, 0xa4, 0xe6, 0x2a, 0x89, 0x7a, 0x5b,
+  0x1f, 0x81, 0x54, 0x2e, 0xfc, 0x27, 0x17, 0x49, 0xfa, 0x6f, 0x59, 0x25,
+  0xed, 0xab, 0x35, 0x5c, 0x33, 0x5c, 0xa6, 0xc6, 0x8c, 0xd6, 0xf9, 0x69,
+  0xd7, 0xec, 0xfc, 0x3a, 0x5f, 0x6d, 0x7d, 0x5a, 0x6d, 0xf1, 0x34, 0xed,
+  0x13, 0x93, 0x0a, 0xb3, 0x81, 0xc3, 0xd8, 0x4a, 0x9d, 0xd9, 0xfc, 0xd0,
+  0x71, 0xdd, 0xe4, 0xe9, 0x1e, 0xd6, 0xf8, 0xed, 0x0a, 0x29, 0x3c, 0xca,
+  0xea, 0x9d, 0x1d, 0xe0, 0x91, 0x5d, 0x74, 0xa0, 0xd4, 0x32, 0xe7, 0xa6,
+  0xc1, 0xe9, 0x5f, 0xdb, 0x45, 0xd8, 0xbc, 0x2a, 0x7b, 0x88, 0x2e, 0x2a,
+  0x53, 0x69, 0x31, 0xfa, 0x35, 0x36, 0x6f, 0x77, 0xb0, 0x43, 0x02, 0x16,
+  0xff, 0x06, 0x3d, 0x6f, 0x9f, 0xad, 0x0a, 0x3f, 0x7d, 0xde, 0x40, 0xeb,
+  0x36, 0x10, 0xf0, 0x00, 0xe8, 0x0e, 0xf3, 0x8a, 0xf8, 0x7d, 0x1b, 0x99,
+  0xe1, 0x73, 0xf8, 0xcc, 0x06, 0xf5, 0x99, 0xae, 0x47, 0x2e, 0x4a, 0xcb,
+  0x00, 0xb8, 0x88, 0x93, 0x0f, 0xf0, 0xf2, 0xee, 0xce, 0x67, 0x3b, 0xad,
+  0x09, 0x5a, 0x60, 0xd0, 0x2d, 0x95, 0x77, 0x34, 0x9b, 0x30, 0x76, 0xa1,
+  0xbd, 0x32, 0x38, 0xb1, 0xef, 0xb4, 0x7b, 0x9f, 0x36, 0xfb, 0x0f, 0xdb,
+  0xba, 0x06, 0x5b, 0x3d, 0x4d, 0xf6, 0x8a, 0x4b, 0xb3, 0xf9, 0xbb, 0x94,
+  0x8c, 0xc3, 0xb3, 0xb7, 0x6f, 0x8f, 0x0f, 0xe9, 0xca, 0xb9, 0xc9, 0xe1,
+  0xe2, 0x74, 0xb6, 0xda, 0x36, 0xdd, 0xcf, 0xe3, 0x89, 0xcb, 0x00, 0x78,
+  0x71, 0xcc, 0xc8, 0x17, 0x5a, 0x3c, 0x6a, 0xfc, 0xa5, 0x85, 0x38, 0x77,
+  0x07, 0xbb, 0xc1, 0x56, 0x2d, 0x6c, 0xa4, 0x25, 0x67, 0x53, 0x4c, 0x5b,
+  0x43, 0xbd, 0xad, 0x4f, 0x99, 0xb3, 0x49, 0xb5, 0xd5, 0x59, 0x36, 0x12,
+  0x0d, 0x70, 0x19, 0xb4, 0x08, 0x05, 0xd6, 0x12, 0x46, 0xae, 0x50, 0x70,
+  0x56, 0x87, 0x5e, 0x12, 0x63, 0x31, 0x90, 0xc8, 0x2d, 0x8b, 0xe2, 0xab,
+  0xb4, 0x2c, 0x8c, 0x43, 0x3b, 0xe4, 0x3c, 0x55, 0xda, 0xb6, 0xa9, 0x45,
+  0xb2, 0xa7, 0xa5, 0x56, 0x06, 0x03, 0x52, 0x28, 0xb4, 0x58, 0x17, 0x9b,
+  0x57, 0x48, 0xbc, 0x10, 0xf5, 0xd2, 0xb8, 0xef, 0xa8, 0xd7, 0x78, 0x41,
+  0x1d, 0x21, 0x20, 0xb9, 0x10, 0x0c, 0x41, 0x77, 0x50, 0x2a, 0xdb, 0x6e,
+  0x5b, 0xe7, 0x53, 0x25, 0x9a, 0xa1, 0x92, 0xce, 0x56, 0xe7, 0xe2, 0x5c,
+  0xd5, 0x26, 0x28, 0x21, 0xf3, 0x1a, 0x3b, 0xad, 0xbe, 0x3a, 0x8b, 0xff,
+  0x51, 0x46, 0xd1, 0x52, 0x5d, 0x53, 0xa9, 0x5e, 0x62, 0xc0, 0xe2, 0xb9,
+  0x90, 0x91, 0xae, 0x95, 0xa3, 0xa0, 0xac, 0x72, 0x08, 0x97, 0xa3, 0x47,
+  0x50, 0xd6, 0x58, 0xb9, 0x11, 0x7b, 0xe9, 0xa3, 0x00, 0x6b, 0x2e, 0x02,
+  0x40, 0x2c, 0x84, 0x6b, 0x21, 0x9c, 0xff, 0xed, 0x00, 0x6b, 0x56, 0x42,
+  0x5a, 0x92, 0xa6, 0xd6, 0x05, 0x21, 0x5b, 0xcd, 0x4c, 0xd8, 0xc0, 0x8b,
+  0xda, 0xe9, 0xd0, 0x0a, 0x6f, 0x59, 0xbe, 0x3d, 0x85, 0xc8, 0xc8, 0xc9,
+  0x3c, 0x19, 0x9b, 0xb1, 0x94, 0x7d, 0xb6, 0x50, 0xc8, 0xd8, 0xd7, 0x6f,
+  0xa6, 0xa6, 0x55, 0xe0, 0x53, 0x1b, 0xf4, 0xcc, 0xc7, 0x1a, 0x2a, 0xf6,
+  0x97, 0x40, 0x0a, 0x5a, 0x71, 0xbc, 0x93, 0x79, 0x03, 0x9d, 0x88, 0x9f,
+  0x18, 0x7b, 0xb8, 0x58, 0xad, 0xeb, 0x25, 0xac, 0x5e, 0x98, 0xa2, 0xab,
+  0x73, 0x67, 0x84, 0xc2, 0xe0, 0x3d, 0xed, 0x99, 0x2c, 0x52, 0xaa, 0xb9,
+  0x1b, 0x38, 0x9b, 0x5c, 0xa8, 0xb5, 0xe4, 0x4d, 0xe7, 0xa5, 0xa5, 0xba,
+  0x2e, 0xc2, 0x6a, 0xda, 0x71, 0x71, 0x5b, 0xac, 0xc5, 0x1f, 0x55, 0x04,
+  0x19, 0xc4, 0xb3, 0x21, 0xe1, 0x2f, 0x00, 0x27, 0xb6, 0x56, 0x05, 0x57,
+  0xa4, 0x0c, 0x47, 0xc9, 0x94, 0x58, 0x6d, 0xce, 0x6d, 0x51, 0x03, 0x73,
+  0xad, 0x61, 0x30, 0x74, 0x28, 0xc5, 0xed, 0x85, 0xe6, 0xd3, 0x41, 0x12,
+  0x75, 0x18, 0xbf, 0xb8, 0x13, 0x06, 0xb7, 0x8b, 0x6b, 0xca, 0xbd, 0xca,
+  0x75, 0xaf, 0x69, 0xa8, 0x6e, 0xac, 0x2d, 0x76, 0x18, 0x63, 0xaf, 0x6a,
+  0xbe, 0xe0, 0x2d, 0xdb, 0x7c, 0x37, 0x4f, 0x1f, 0x70, 0x15, 0x34, 0x41,
+  0x11, 0xdd, 0xbc, 0x1f, 0x19, 0xd5, 0xee, 0x8b, 0xbd, 0xc1, 0xee, 0xf3,
+  0xcf, 0x06, 0xa4, 0x7a, 0xed, 0x56, 0x46, 0x87, 0x20, 0x09, 0x0e, 0x6b,
+  0x08, 0xdb, 0x69, 0xb9, 0x44, 0xdb, 0x1c, 0x74, 0x61, 0x07, 0xb3, 0xd5,
+  0x20, 0x08, 0xcf, 0x6b, 0x74, 0xa1, 0x21, 0x7c, 0xf5, 0x96, 0xfb, 0x81,
+  0xb1, 0x5d, 0x49, 0x0d, 0xda, 0x41, 0x5b, 0x45, 0x69, 0xc3, 0xa9, 0x0b,
+  0x0a, 0x49, 0x4f, 0xda, 0x07, 0xb4, 0xbe, 0xba, 0xb4, 0xeb, 0xff, 0x5f,
+  0x38, 0xee, 0x56, 0xcd, 0xe5, 0x28, 0xf5, 0x51, 0xe3, 0x52, 0x6c, 0xde,
+  0xaa, 0x87, 0x4b, 0x4d, 0xe9, 0xb3, 0x8b, 0x4b, 0x4d, 0x42, 0x13, 0x76,
+  0x10, 0x17, 0x77, 0x03, 0x17, 0x11, 0x80, 0x00, 0x24, 0xbd, 0x5c, 0x9a,
+  0x40, 0xbb, 0x28, 0x5f, 0x6d, 0xe9, 0xa2, 0xc1, 0x1d, 0x8a, 0x36, 0x5d,
+  0x5a, 0x54, 0x58, 0x18, 0x1e, 0x3e, 0x15, 0xbc, 0x06, 0x1b, 0x23, 0xad,
+  0xd0, 0xd4, 0x67, 0xf0, 0xf2, 0x6b, 0x7f, 0xfa, 0x93, 0x67, 0x51, 0x43,
+  0x8e, 0xdb, 0xd7, 0xb2, 0x4f, 0x50, 0xe4, 0x9e, 0x79, 0x07, 0x82, 0x64,
+  0xb9, 0x47, 0x9d, 0xfd, 0x1f, 0x11, 0xdd, 0xff, 0x53, 0xff, 0x47, 0xfa,
+  0xf3, 0xa7, 0x8e, 0xbb, 0x06, 0xa0, 0x50, 0x89, 0xf5, 0xd4, 0x4d, 0x5e,
+  0x36, 0xa8, 0x87, 0x67, 0x5c, 0x31, 0x73, 0x20, 0x42, 0x70, 0xd0, 0x07,
+  0x0e, 0xa2, 0x24, 0x82, 0xca, 0x4c, 0xd5, 0xc3, 0x20, 0x09, 0xe2, 0x52,
+  0x8b, 0x85, 0x28, 0xc5, 0xad, 0xa5, 0xe6, 0x64, 0x68, 0x92, 0x27, 0x5e,
+  0xec, 0x99, 0xa9, 0x94, 0x4d, 0xc1, 0xf7, 0xc2, 0x76, 0x62, 0xcb, 0x23,
+  0x97, 0xfb, 0x87, 0xe1, 0xc3, 0xd4, 0x4c, 0x2d, 0x1f, 0x6c, 0xb8, 0xbc,
+  0x37, 0x0e, 0x38, 0xd7, 0xd2, 0xd7, 0x12, 0xd5, 0x29, 0xfe, 0xf1, 0xc4,
+  0x45, 0x05, 0xa5, 0x73, 0x36, 0x9f, 0x1b, 0x3a, 0x44, 0x9e, 0x16, 0xb7,
+  0x3c, 0x43, 0xcd, 0xcc, 0x8c, 0x24, 0x75, 0x78, 0x23, 0xd0, 0xf7, 0x31,
+  0x32, 0x4b, 0x1e, 0xe2, 0xa0, 0x44, 0xc3, 0x37, 0x0b, 0x6e, 0x81, 0xbf,
+  0x39, 0xa7, 0x94, 0x54, 0xe6, 0x51, 0x1b, 0xac, 0xa0, 0x10, 0x79, 0x4c,
+  0xb6, 0xcc, 0x90, 0x9f, 0x42, 0x20, 0x0f, 0xc3, 0xab, 0x69, 0x04, 0x8d,
+  0x87, 0x08, 0x80, 0x2e, 0xe4, 0x19, 0x05, 0x71, 0xe3, 0x89, 0xc1, 0x4c,
+  0x6a, 0xea, 0x9e, 0x84, 0x9b, 0x05, 0x78, 0x60, 0x2d, 0x89, 0xb6, 0xd5,
+  0x20, 0xeb, 0x1a, 0x62, 0x93, 0xa6, 0x65, 0x24, 0x71, 0x4e, 0xdc, 0x8b,
+  0xcd, 0xe1, 0xc1, 0xe4, 0xfe, 0x07, 0x35, 0x0b, 0x34, 0x38, 0x46, 0x2f,
+  0xc4, 0xc8, 0xdb, 0xee, 0xb7, 0xed, 0xa1, 0x5c, 0x72, 0x43, 0x64, 0x9f,
+  0x31, 0x6d, 0xe5, 0xa3, 0xb4, 0xcc, 0x63, 0x0d, 0x25, 0xd4, 0x54, 0xe8,
+  0x40, 0xb8, 0x50, 0xb8, 0xf2, 0xe1, 0xba, 0x54, 0xe8, 0x41, 0xf4, 0x3f,
+  0xd0, 0xa9, 0xbe, 0x2d, 0x91, 0x30, 0xc8, 0xbf, 0xf9, 0xf2, 0xf8, 0xf5,
+  0xd9, 0xc5, 0x71, 0x35, 0x69, 0x45, 0x72, 0x24, 0xa3, 0xb6, 0xc2, 0x2b,
+  0x9b, 0xa8, 0x0f, 0x69, 0x16, 0x14, 0x2c, 0x95, 0x65, 0x5b, 0x9e, 0x7f,
+  0x77, 0x14, 0x9c, 0x3c, 0xcb, 0xdf, 0xb6, 0x46, 0x7b, 0xe2, 0xd9, 0x68,
+  0x20, 0x58, 0x13, 0xff, 0xdc, 0x42, 0xbd, 0x4f, 0xc1, 0x5a, 0xb3, 0xf1,
+  0x09, 0x46, 0x00, 0xea, 0x95, 0x68, 0x3d, 0x60, 0x09, 0x56, 0x29, 0x0a,
+  0xb6, 0xbc, 0xb8, 0x46, 0x5b, 0xb0, 0x01, 0x19, 0x81, 0x02, 0x15, 0xbe,
+  0xd4, 0xc4, 0x11, 0x47, 0xf0, 0xbe, 0xb0, 0x43, 0x66, 0x10, 0x35, 0x3b,
+  0x1a, 0xe9, 0x3a, 0xa0, 0x97, 0x06, 0xee, 0xbe, 0x80, 0xcd, 0xb0, 0xf5,
+  0x5a, 0xec, 0xf4, 0xa6, 0x30, 0x28, 0xa0, 0x40, 0x14, 0x26, 0xf0, 0x4b,
+  0xe9, 0x4c, 0x07, 0x74, 0xdc, 0xbc, 0x7d, 0xdd, 0xfa, 0x6a, 0xe7, 0x9b,
+  0xc5, 0x56, 0xa5, 0xa4, 0xa8, 0x2d, 0x9e, 0x55, 0xae, 0xfa, 0x53, 0x37,
+  0xda, 0xb4, 0xf8, 0x9a, 0x16, 0x58, 0x01, 0x87, 0xf9, 0x6a, 0x89, 0x06,
+  0x5b, 0xae, 0x70, 0xd1, 0x9a, 0x52, 0x45, 0x6e, 0xd6, 0x6b, 0xb3, 0x9c,
+  0x4c, 0x40, 0x30, 0x38, 0x2d, 0x3b, 0xc9, 0x86, 0x0f, 0xe5, 0x8a, 0x2f,
+  0x4b, 0x3b, 0xbd, 0xf5, 0x88, 0x16, 0x3e, 0x71, 0xc6, 0x15, 0xe9, 0x1a,
+  0x29, 0x42, 0xed, 0x0f, 0x16, 0x8e, 0x2a, 0xc9, 0x95, 0xc5, 0x6a, 0x5e,
+  0x42, 0x68, 0x12, 0x00, 0xf9, 0x71, 0x96, 0xf3, 0x92, 0xd6, 0x9a, 0x03,
+  0x26, 0x81, 0xdb, 0x34, 0xc4, 0x44, 0x5f, 0xbc, 0x3e, 0x7c, 0xf1, 0xec,
+  0x05, 0x44, 0x3f, 0xd4, 0x8e, 0xd1, 0xa8, 0x7b, 0x0d, 0xa9, 0x40, 0x32,
+  0xa8, 0x1f, 0x72, 0x83, 0x1d, 0x68, 0x4b, 0x90, 0x12, 0x59, 0x70, 0x99,
+  0x4a, 0x94, 0xff, 0x30, 0x68, 0x62, 0xd0, 0x0a, 0x67, 0xd4, 0x76, 0x7b,
+  0xae, 0x2b, 0x81, 0x68, 0xb7, 0x06, 0x46, 0x9f, 0x4a, 0x1c, 0xb7, 0x16,
+  0x50, 0x33, 0x75, 0x89, 0x34, 0xf4, 0x39, 0xb4, 0x19, 0xdd, 0xc4, 0x9e,
+  0xa3, 0x3a, 0x57, 0x9b, 0xae, 0x68, 0x6b, 0xee, 0x6f, 0xd5, 0xf3, 0xac,
+  0x54, 0x17, 0x24, 0x82, 0xce, 0xaa, 0x15, 0x55, 0x51, 0xbd, 0x1d, 0xf6,
+  0xde, 0x36, 0x43, 0x89, 0x1a, 0xb1, 0x10, 0x2f, 0xc4, 0x99, 0x71, 0xd3,
+  0x69, 0x40, 0x5e, 0x2d, 0xfd, 0x35, 0x0b, 0x54, 0xde, 0x5c, 0xe7, 0x0b,
+  0xc9, 0xea, 0x68, 0x43, 0xe1, 0x0b, 0x51, 0x53, 0xe4, 0x51, 0x23, 0x76,
+  0x07, 0x2d, 0x2e, 0xef, 0x9e, 0x1c, 0xb9, 0x62, 0xae, 0xde, 0x67, 0x39,
+  0x5a, 0xb5, 0x37, 0xe7, 0x1e, 0x03, 0xb1, 0x79, 0xa6, 0xe8, 0x9a, 0xf2,
+  0x52, 0xf3, 0x68, 0x65, 0xc6, 0x4e, 0xfe, 0xae, 0xbd, 0x39, 0x6d, 0x45,
+  0x94, 0x49, 0x69, 0xc3, 0x1a, 0x46, 0x30, 0x8e, 0x15, 0xd4, 0xe1, 0x8d,
+  0xe1, 0x84, 0x36, 0xeb, 0xa6, 0x59, 0x98, 0xe9, 0x86, 0x84, 0x70, 0x11,
+  0xc4, 0x3f, 0xb8, 0x16, 0x33, 0x98, 0x06, 0xad, 0xaa, 0x85, 0xa6, 0x0c,
+  0x17, 0x61, 0xd2, 0x21, 0xda, 0x19, 0x01, 0x98, 0xb1, 0x8d, 0x94, 0xeb,
+  0x56, 0x12, 0x51, 0xd2, 0xd0, 0x3c, 0xde, 0x0c, 0xa7, 0x30, 0x8f, 0xb2,
+  0x71, 0x19, 0xcc, 0x80, 0x1f, 0x68, 0x6f, 0x4e, 0x45, 0x83, 0xe6, 0xcc,
+  0x38, 0xb1, 0x10, 0x11, 0xdb, 0x8f, 0xcf, 0x4c, 0x1e, 0x6c, 0x6c, 0x32,
+  0x7d, 0x28, 0xac, 0xa8, 0xb1, 0xc3, 0xeb, 0x67, 0xd6, 0xb6, 0xc3, 0x18,
+  0x41, 0x7d, 0x83, 0x4d, 0x88, 0xcc, 0x65, 0x2b, 0xfb, 0xed, 0xcd, 0xb9,
+  0x1d, 0xc6, 0x93, 0x8f, 0x6e, 0xb0, 0xf6, 0xd2, 0x58, 0x85, 0xe9, 0x5c,
+  0x21, 0xc0, 0xde, 0x4b, 0x1a, 0x24, 0xe7, 0x37, 0x96, 0xef, 0x1f, 0x5f,
+  0x90, 0xe9, 0xdc, 0xf0, 0x42, 0x38, 0x7d, 0xcf, 0x1f, 0x5c, 0x0d, 0x3f,
+  0x88, 0xab, 0x48, 0x22, 0x91, 0x98, 0x17, 0xd6, 0x90, 0xbd, 0xef, 0xcf,
+  0x03, 0x4c, 0x2c, 0xb2, 0x74, 0x6e, 0xb1, 0xa7, 0xca, 0xcb, 0x83, 0x21,
+  0x46, 0x6d, 0x40, 0x04, 0x41, 0xc0, 0x54, 0x63, 0x8a, 0xb3, 0x5b, 0x86,
+  0xff, 0x73, 0xb7, 0xdb, 0xfb, 0xf5, 0x3a, 0x0c, 0xe8, 0x58, 0x1e, 0xf7,
+  0x74, 0x2c, 0xb3, 0x72, 0xca, 0xb9, 0x4b, 0xab, 0xfb, 0xf0, 0x6e, 0x57,
+  0xbb, 0x74, 0x67, 0xb2, 0x3e, 0xbe, 0xc5, 0xfd, 0xc4, 0x3a, 0xe7, 0x5f,
+  0xad, 0xe3, 0x10, 0x06, 0x32, 0x1e, 0x15, 0xd9, 0x74, 0x59, 0x4a, 0x44,
+  0x42, 0x58, 0x26, 0x9a, 0xb8, 0xeb, 0x9a, 0xa5, 0x40, 0x10, 0x8e, 0xdd,
+  0xed, 0xeb, 0x33, 0xc7, 0x72, 0x81, 0x8d, 0x35, 0x54, 0x14, 0x6c, 0xc7,
+  0xfa, 0xc5, 0xd1, 0xa7, 0xfd, 0x10, 0x05, 0xd3, 0xd4, 0x33, 0xaf, 0xbc,
+  0x65, 0x81, 0xd6, 0x33, 0x3c, 0xed, 0xb5, 0x76, 0x20, 0x26, 0x09, 0xe3,
+  0x0a, 0x29, 0x29, 0x70, 0x04, 0x86, 0x34, 0x64, 0x7c, 0xef, 0x31, 0x42,
+  0x5a, 0xbb, 0xc6, 0xf9, 0xec, 0x03, 0x87, 0x9c, 0x1e, 0xf0, 0xb3, 0x62,
+  0xfc, 0x93, 0x60, 0x56, 0x8d, 0x93, 0xa9, 0xc7, 0x78, 0xcd, 0xca, 0xaf,
+  0x1b, 0x41, 0x85, 0x0a, 0x1f, 0x1b, 0x09, 0x3f, 0xd8, 0x36, 0x18, 0xbf,
+  0xb4, 0x2c, 0xa7, 0x20, 0x63, 0xcd, 0x46, 0xd6, 0xde, 0x9c, 0x0e, 0xd7,
+  0xbf, 0xa7, 0xcb, 0xd3, 0x33, 0xb3, 0xd9, 0x44, 0xcd, 0xd0, 0xac, 0x81,
+  0x36, 0x69, 0xc3, 0x0e, 0xf8, 0x2f, 0x62, 0x10, 0xac, 0x76, 0x4c, 0xe7,
+  0x95, 0x00, 0x12, 0xea, 0x31, 0x9b, 0x21, 0xd1, 0xbd, 0x3d, 0x50, 0x4e,
+  0xe2, 0xe4, 0xc3, 0x4c, 0x77, 0xb7, 0xed, 0x82, 0xe5, 0x3a, 0x4d, 0xc2,
+  0xaa, 0x70, 0xf7, 0x21, 0x74, 0x4f, 0x8b, 0x19, 0xcc, 0x0a, 0x9d, 0xc4,
+  0x80, 0xee, 0xa1, 0xae, 0x91, 0x9e, 0xa1, 0x78, 0xb4, 0x48, 0xf5, 0x28,
+  0x4c, 0x1f, 0x13, 0xe3, 0x91, 0x13, 0x85, 0xe5, 0xf1, 0x06, 0x1e, 0x3f,
+  0x47, 0xa6, 0x4a, 0x4d, 0xb6, 0x6a, 0xa9, 0x97, 0x41, 0x23, 0x2c, 0x2b,
+  0xb9, 0x9e, 0xf4, 0x95, 0x38, 0xaa, 0xac, 0xa8, 0x9f, 0x6f, 0x63, 0x21,
+  0x48, 0xfd, 0x7d, 0x89, 0x1f, 0x9f, 0xaf, 0x2d, 0x30, 0x35, 0xf4, 0x55,
+  0xa6, 0xa2, 0x8b, 0x84, 0x11, 0x6d, 0x01, 0x98, 0xc7, 0xb9, 0xfe, 0xaa,
+  0x40, 0x6f, 0xb2, 0xad, 0x45, 0x0a, 0x12, 0x0a, 0x04, 0xf0, 0x78, 0xd9,
+  0x86, 0x3f, 0xbd, 0x65, 0x05, 0x94, 0xd0, 0xf4, 0xee, 0x60, 0xb7, 0x67,
+  0xba, 0x95, 0x4a, 0x71, 0x26, 0x21, 0xf3, 0x27, 0xb1, 0x8b, 0x18, 0xe3,
+  0xae, 0xeb, 0xd6, 0xb1, 0x0b, 0x09, 0xec, 0x51, 0xb1, 0x31, 0x2c, 0x22,
+  0xc6, 0xc0, 0x5e, 0x4e, 0x28, 0xe7, 0x84, 0xfd, 0x06, 0x15, 0xed, 0xf4,
+  0x9f, 0xbe, 0x78, 0x51, 0xb9, 0xd7, 0x43, 0x25, 0xf8, 0xd9, 0xce, 0x8e,
+  0xc0, 0x18, 0xd4, 0x5f, 0xa3, 0x2f, 0xfa, 0x2f, 0xf0, 0x62, 0xf5, 0x35,
+  0x49, 0x73, 0x5f, 0xff, 0x5e, 0x9f, 0xbf, 0x69, 0xe9, 0x0e, 0x16, 0x9c,
+  0xb5, 0x6f, 0xbd, 0xe0, 0xee, 0x5a, 0xde, 0xc2, 0xc3, 0xb2, 0x8e, 0xd9,
+  0xd5, 0x15, 0x97, 0xe7, 0xe4, 0x27, 0x05, 0xe8, 0x34, 0xcb, 0xef, 0xe3,
+  0x7c, 0xd2, 0x9c, 0xee, 0x4e, 0xaf, 0xbf, 0xbb, 0x6e, 0xba, 0xae, 0x98,
+  0x16, 0xb6, 0x93, 0x35, 0xa1, 0xcd, 0x3f, 0x6e, 0x6d, 0x7e, 0xbd, 0xd5,
+  0x36, 0xfb, 0x4f, 0x77, 0x76, 0x7a, 0xcf, 0xf9, 0xe7, 0x8b, 0x17, 0xed,
+  0x47, 0xad, 0xd2, 0xc7, 0x13, 0x9b, 0x5a, 0x65, 0xb4, 0xd4, 0x4e, 0x4b,
+  0xeb, 0xbb, 0xd4, 0xea, 0xee, 0x8b, 0x17, 0x3d, 0xee, 0xe5, 0xd9, 0x47,
+  0xb5, 0x5e, 0xde, 0x67, 0xde, 0x74, 0xce, 0xaf, 0x7b, 0x72, 0x2c, 0x6a,
+  0x33, 0xa0, 0x3f, 0xa3, 0xe8, 0x95, 0x40, 0x3b, 0x44, 0x41, 0x66, 0x85,
+  0x77, 0xbb, 0x84, 0xf0, 0x54, 0x08, 0x68, 0x58, 0x20, 0xdb, 0x00, 0x9a,
+  0xa2, 0xa8, 0x1f, 0xb1, 0xf7, 0x2f, 0x98, 0x3f, 0xde, 0xc3, 0x86, 0x9e,
+  0x89, 0x2b, 0xec, 0x9a, 0x61, 0x25, 0x2c, 0x17, 0xa1, 0x88, 0x36, 0x89,
+  0x5c, 0xb6, 0x60, 0x0b, 0xb8, 0x8b, 0xa7, 0xa9, 0xa5, 0xab, 0x46, 0x5d,
+  0x18, 0xb0, 0x24, 0xf5, 0x98, 0x7e, 0xcf, 0x16, 0xdd, 0x48, 0xaa, 0xdb,
+  0x3b, 0x4d, 0xc4, 0xbc, 0x52, 0xf2, 0x64, 0x5f, 0x9e, 0x91, 0x83, 0x06,
+  0x75, 0xee, 0x41, 0x61, 0x97, 0xd8, 0x3b, 0x54, 0xeb, 0x35, 0x72, 0x00,
+  0x10, 0x1e, 0xb6, 0x50, 0xf0, 0xfe, 0x60, 0xae, 0xf2, 0xd3, 0xec, 0x16,
+  0x01, 0xcc, 0x8f, 0x39, 0x0c, 0xe6, 0x81, 0x37, 0x70, 0x92, 0x18, 0x94,
+  0x64, 0xad, 0x2c, 0x82, 0x7b, 0x5f, 0xec, 0x31, 0x4b, 0x51, 0x44, 0xfd,
+  0x21, 0xab, 0x54, 0x99, 0x15, 0x4c, 0x43, 0xd6, 0x4f, 0xef, 0x63, 0x2b,
+  0xa0, 0x8a, 0x08, 0x40, 0xe3, 0x00, 0x0e, 0x4d, 0x4e, 0x93, 0x43, 0x34,
+  0x43, 0xce, 0x27, 0x7c, 0x1a, 0x6c, 0xa7, 0x04, 0x8d, 0x4f, 0x80, 0x9d,
+  0xaa, 0xa9, 0x44, 0x6c, 0xfb, 0x17, 0xe4, 0xc4, 0xd0, 0x1d, 0x86, 0xbc,
+  0xa1, 0xd8, 0x5b, 0xe8, 0x04, 0xee, 0x66, 0xa3, 0xe6, 0x02, 0xe3, 0xa7,
+  0x3c, 0x10, 0x85, 0xab, 0x54, 0xe7, 0x66, 0x01, 0x76, 0xe4, 0xaa, 0x5d,
+  0xca, 0xe2, 0x1b, 0xd0, 0x87, 0xd6, 0xc4, 0xb4, 0x9c, 0x61, 0xc1, 0xe1,
+  0x41, 0x42, 0x7b, 0x65, 0xc7, 0x68, 0xaf, 0x1c, 0x13, 0xa4, 0x4d, 0x8b,
+  0x36, 0x03, 0x88, 0x75, 0xd0, 0x56, 0xa0, 0xf3, 0x1b, 0x66, 0x5c, 0x36,
+  0x63, 0xc0, 0xdb, 0xc9, 0xd6, 0x40, 0x06, 0x00, 0xa3, 0xad, 0xec, 0x04,
+  0x43, 0x08, 0x56, 0xb6, 0x94, 0x0b, 0x0f, 0xa3, 0x1c, 0x36, 0x3f, 0x69,
+  0x97, 0xf3, 0xf0, 0xe4, 0x7f, 0x1e, 0x0f, 0x7e, 0x0d, 0x6b, 0x72, 0x3d,
+  0xbc, 0x2e, 0x8f, 0xef, 0xcd, 0xbb, 0x29, 0x31, 0x86, 0x52, 0xd3, 0x4e,
+  0xa2, 0x98, 0xe3, 0xe9, 0xd4, 0x57, 0xf3, 0x85, 0xdf, 0x8f, 0x84, 0xfd,
+  0xcc, 0x10, 0x71, 0xad, 0x4e, 0x6f, 0xb6, 0x16, 0x42, 0x15, 0x15, 0xda,
+  0x51, 0xa5, 0x32, 0x34, 0x2c, 0xbb, 0xc4, 0xf6, 0x19, 0xdc, 0x2f, 0x7c,
+  0x27, 0x32, 0x29, 0x2e, 0xe7, 0xa8, 0x7e, 0x4d, 0x63, 0xa8, 0xcb, 0x33,
+  0xf1, 0x7d, 0x03, 0x71, 0x36, 0x8c, 0x8b, 0xb9, 0xf0, 0x61, 0x9b, 0x3c,
+  0xf3, 0x56, 0xcf, 0x6d, 0xa5, 0xc0, 0x7b, 0x58, 0xd8, 0xdd, 0xec, 0x06,
+  0x81, 0x71, 0x1c, 0xc4, 0x8f, 0x80, 0xe0, 0x36, 0x73, 0x14, 0xaf, 0x6d,
+  0x19, 0xcf, 0x16, 0x2d, 0x21, 0xbd, 0x92, 0x7e, 0x64, 0x48, 0x10, 0xac,
+  0x1c, 0x99, 0xa1, 0x56, 0x3b, 0x6b, 0x36, 0x17, 0x44, 0x1a, 0x0b, 0xe5,
+  0xd2, 0x8b, 0x70, 0x44, 0xb8, 0x7e, 0xaa, 0x01, 0xb2, 0x2c, 0x8b, 0x01,
+  0x18, 0xb1, 0x25, 0x1b, 0x21, 0xd6, 0x95, 0x4f, 0x81, 0xcb, 0x96, 0xe4,
+  0xb9, 0xd4, 0xf8, 0x10, 0xe9, 0x3e, 0xd1, 0x08, 0xa7, 0x2a, 0x78, 0xbd,
+  0x55, 0xa5, 0x8b, 0xd7, 0xec, 0xa0, 0x47, 0x1e, 0x93, 0xae, 0xb1, 0x7e,
+  0xfe, 0x16, 0x96, 0x70, 0x5f, 0xb3, 0xdd, 0x69, 0x91, 0xe7, 0x68, 0xb9,
+  0x18, 0x34, 0x01, 0x1b, 0x4b, 0x5f, 0x27, 0x4c, 0xdf, 0xa7, 0xee, 0x77,
+  0x42, 0x57, 0x21, 0x18, 0x05, 0xfa, 0xe1, 0xc1, 0x29, 0x42, 0x7d, 0x5a,
+  0xb4, 0x02, 0x9c, 0xc3, 0x70, 0xcc, 0x16, 0x50, 0x37, 0x5f, 0x99, 0xae,
+  0xd8, 0xf8, 0x25, 0x5b, 0x6b, 0x9f, 0x2b, 0xce, 0x08, 0x78, 0x4b, 0x2f,
+  0x80, 0xe8, 0x7c, 0xfa, 0xf0, 0xd0, 0x50, 0x4c, 0x02, 0xa8, 0x40, 0x29,
+  0xb0, 0x22, 0xc4, 0xfe, 0xec, 0xe1, 0xa1, 0xfa, 0xe5, 0x63, 0x08, 0x70,
+  0xd8, 0xef, 0x51, 0x26, 0x21, 0xe4, 0xb2, 0x5a, 0x71, 0xcb, 0x3a, 0xca,
+  0xe5, 0x7c, 0x1f, 0xa7, 0x65, 0x4b, 0x7e, 0x9c, 0x4a, 0x1c, 0xae, 0x14,
+  0x80, 0xc5, 0x32, 0x73, 0x76, 0xd1, 0x0d, 0xb1, 0x02, 0x41, 0x7c, 0x93,
+  0x05, 0xb2, 0x06, 0xad, 0x2e, 0x43, 0xcb, 0x3a, 0x71, 0x2f, 0xb2, 0xec,
+  0x29, 0xa0, 0xd5, 0xca, 0x74, 0xca, 0xaf, 0x01, 0x68, 0x8c, 0x5a, 0xd8,
+  0xa5, 0xe5, 0x4f, 0xe7, 0xcb, 0x32, 0x29, 0xda, 0x4a, 0xea, 0xb4, 0x2d,
+  0xfb, 0x14, 0xa0, 0x08, 0x12, 0x0e, 0x52, 0x2f, 0x5a, 0xa2, 0xe3, 0x92,
+  0xb4, 0x52, 0xf5, 0x18, 0x19, 0xc9, 0xf6, 0xf1, 0x6a, 0x4b, 0xc4, 0x74,
+  0xe4, 0x62, 0xa5, 0xf5, 0x68, 0x26, 0x0f, 0xb4, 0xda, 0x02, 0x53, 0x18,
+  0xc1, 0xc3, 0x4b, 0xd2, 0x05, 0xdf, 0x36, 0xd7, 0x59, 0x4e, 0x9b, 0x3a,
+  0x53, 0x39, 0x18, 0xd7, 0x4f, 0x5d, 0x1a, 0xd3, 0xae, 0x1c, 0xa0, 0x11,
+  0xa3, 0xa5, 0x3b, 0x20, 0xc0, 0x32, 0x2b, 0x95, 0x31, 0x2a, 0xe6, 0x08,
+  0xc2, 0xe1, 0x33, 0x31, 0xda, 0x62, 0xdc, 0x8f, 0x85, 0x1e, 0xee, 0x0d,
+  0x9e, 0x6c, 0x7d, 0x10, 0x5f, 0x3b, 0x10, 0xf6, 0x3d, 0x3e, 0xfb, 0xfa,
+  0x02, 0x71, 0x8d, 0xc5, 0x1d, 0xa7, 0x5a, 0x1e, 0xd8, 0x4a, 0xc4, 0xd5,
+  0xce, 0xbd, 0x2c, 0xe2, 0x23, 0x38, 0x4d, 0x56, 0x75, 0xa5, 0x98, 0x26,
+  0xc9, 0x42, 0xc6, 0xa6, 0xf8, 0x87, 0x7a, 0x54, 0xdd, 0x49, 0x45, 0x28,
+  0xbb, 0x12, 0xa9, 0xde, 0xb7, 0xeb, 0x38, 0x80, 0x46, 0xa1, 0xb3, 0x49,
+  0xdb, 0xca, 0xf7, 0xb4, 0x73, 0x9a, 0x4d, 0x11, 0x57, 0x2c, 0x2c, 0x7f,
+  0x4d, 0x3d, 0x0f, 0xdb, 0x52, 0x29, 0x89, 0x68, 0xdb, 0xea, 0x88, 0x4a,
+  0x37, 0xa3, 0x56, 0xdf, 0xaf, 0x89, 0x8d, 0x8d, 0x7b, 0x5a, 0xae, 0xa6,
+  0x44, 0xa0, 0x81, 0x51, 0xe6, 0x4f, 0x66, 0x04, 0x9f, 0xad, 0xc2, 0x76,
+  0x0c, 0x1c, 0xef, 0x11, 0xd0, 0x77, 0x2c, 0x61, 0x03, 0x85, 0xe6, 0xe7,
+  0x24, 0xcf, 0x02, 0x54, 0x50, 0xac, 0xa2, 0x49, 0x8f, 0x2e, 0x82, 0xc8,
+  0x51, 0x23, 0x8f, 0x7d, 0xe0, 0x49, 0xa4, 0x09, 0x24, 0xfd, 0xef, 0xa2,
+  0x18, 0x2d, 0xf3, 0x50, 0x3c, 0x4a, 0x35, 0x1f, 0x04, 0xf8, 0xba, 0xd4,
+  0xc3, 0x2b, 0xd9, 0x1b, 0x7a, 0x65, 0xb0, 0x44, 0x1f, 0x3a, 0x65, 0x22,
+  0xab, 0x67, 0xe2, 0xe9, 0x42, 0x6f, 0xcc, 0x86, 0x02, 0xa7, 0xfc, 0xc9,
+  0xf8, 0x08, 0x92, 0x72, 0x62, 0x96, 0x50, 0xb8, 0xda, 0xd6, 0x26, 0x67,
+  0xd9, 0xe9, 0xd0, 0xb6, 0xf8, 0x63, 0xa0, 0xaa, 0xc4, 0xbe, 0x4e, 0x66,
+  0xde, 0xc8, 0x11, 0x01, 0x8e, 0x92, 0xf0, 0xac, 0x49, 0x88, 0x84, 0xa6,
+  0x40, 0x68, 0x6f, 0x33, 0x8e, 0x1c, 0xd1, 0x2b, 0xf7, 0xca, 0xb7, 0xa3,
+  0x6f, 0x36, 0xc1, 0x92, 0xd0, 0x8e, 0x66, 0x2e, 0x71, 0x13, 0xbd, 0x0a,
+  0x4a, 0xa7, 0x0d, 0x1b, 0x31, 0x4f, 0xf0, 0x2b, 0x49, 0x9c, 0x88, 0x5c,
+  0x94, 0x2d, 0x5e, 0x00, 0xb0, 0x76, 0xf6, 0x1e, 0xc1, 0xf9, 0xc6, 0xd3,
+  0x69, 0x41, 0x6d, 0xc3, 0x06, 0x50, 0x1b, 0x29, 0xe3, 0xc1, 0x5c, 0x1a,
+  0x63, 0x6a, 0x46, 0x63, 0x8b, 0x43, 0xd9, 0x06, 0xd3, 0x05, 0x90, 0x64,
+  0x00, 0xbf, 0xd6, 0x53, 0xc9, 0xb1, 0x82, 0xdc, 0x36, 0x10, 0x40, 0xe4,
+  0xf5, 0xf5, 0x8a, 0x89, 0x11, 0x82, 0xc0, 0x4b, 0x91, 0xc4, 0x0d, 0xd0,
+  0xcc, 0x31, 0xec, 0x8f, 0x61, 0x75, 0x35, 0x71, 0x73, 0x1d, 0xd5, 0xea,
+  0xb2, 0xc6, 0x48, 0x12, 0xff, 0x67, 0x09, 0xb7, 0x60, 0x80, 0x74, 0xae,
+  0x32, 0x55, 0xdf, 0xbc, 0x21, 0x3e, 0x14, 0x2b, 0xc2, 0xdf, 0x96, 0x29,
+  0x93, 0xa8, 0x44, 0x14, 0x1d, 0x01, 0x6b, 0x96, 0xa1, 0x72, 0xa5, 0xc8,
+  0x02, 0x87, 0x6f, 0xa8, 0xbf, 0x3b, 0x77, 0x92, 0x41, 0x03, 0x73, 0x0f,
+  0x70, 0x11, 0x03, 0x83, 0x46, 0x03, 0xae, 0xd7, 0x6c, 0x19, 0x02, 0xc4,
+  0xf4, 0x87, 0x3c, 0x12, 0x6a, 0xb5, 0x8f, 0x36, 0xda, 0x71, 0x63, 0x0c,
+  0x99, 0xac, 0x2f, 0x58, 0xfa, 0x01, 0xcc, 0x1a, 0x0f, 0x07, 0x72, 0x87,
+  0x8c, 0xc0, 0x10, 0x2a, 0x38, 0xe2, 0xa0, 0x05, 0x2f, 0x97, 0x39, 0x6c,
+  0x25, 0x92, 0x99, 0x8b, 0xa5, 0x16, 0x4f, 0xa3, 0x97, 0x1f, 0x88, 0x19,
+  0x55, 0xec, 0x76, 0x35, 0x93, 0x0c, 0xcf, 0x0e, 0xbf, 0x19, 0x3e, 0xfd,
+  0x60, 0xb0, 0xe8, 0xfa, 0x12, 0x76, 0x8f, 0x86, 0x8b, 0x3e, 0x82, 0x19,
+  0xdd, 0x92, 0xa4, 0xc5, 0xe8, 0xf9, 0x79, 0x3a, 0x49, 0x04, 0x32, 0x96,
+  0xe1, 0xfd, 0xd2, 0x6c, 0xe9, 0x50, 0x29, 0x22, 0x1f, 0x35, 0xd9, 0x13,
+  0xd7, 0x24, 0x43, 0x89, 0xd7, 0x83, 0xa2, 0x89, 0xfd, 0xd0, 0x9e, 0x08,
+  0x48, 0x4d, 0xf2, 0x30, 0x9e, 0x2e, 0x8b, 0xf4, 0xee, 0x37, 0xad, 0x56,
+  0x2a, 0xab, 0x1e, 0xff, 0x53, 0xcb, 0x1e, 0x7f, 0xdc, 0xba, 0x37, 0x98,
+  0xc8, 0x2f, 0x5c, 0xf7, 0xb6, 0x4a, 0xb5, 0xff, 0x77, 0xac, 0xfb, 0xb3,
+  0xbe, 0x43, 0x48, 0x78, 0xf9, 0x4b, 0x43, 0xa5, 0xb1, 0x05, 0xcf, 0x34,
+  0xb4, 0x74, 0x13, 0xd6, 0xaf, 0x24, 0x8c, 0x36, 0x65, 0x3c, 0xf6, 0xe9,
+  0x5d, 0xb2, 0x06, 0xa8, 0x01, 0x26, 0xe0, 0xad, 0x0f, 0x9e, 0x18, 0xb7,
+  0x53, 0xe2, 0x97, 0x96, 0xbd, 0xaa, 0xaf, 0xdd, 0x3f, 0xb1, 0x73, 0x4e,
+  0x22, 0xf0, 0x7b, 0xd7, 0xba, 0x79, 0xe1, 0xde, 0xc9, 0xa5, 0xf9, 0xbf,
+  0x6b, 0xe7, 0x6a, 0xd2, 0x72, 0x75, 0x16, 0x8c, 0xe8, 0xe0, 0xc6, 0x0e,
+  0xfc, 0xa2, 0x9c, 0xee, 0x45, 0xfe, 0xa5, 0x82, 0x46, 0xa0, 0x01, 0x44,
+  0x4d, 0x68, 0x1e, 0x25, 0x87, 0x4a, 0x19, 0x3a, 0xab, 0x6e, 0x62, 0x55,
+  0x51, 0xb6, 0x1a, 0xc4, 0xf3, 0xcf, 0x9c, 0x59, 0x23, 0x18, 0x8e, 0x0c,
+  0x04, 0x54, 0x86, 0x91, 0x89, 0xd5, 0x44, 0xe3, 0x9b, 0xac, 0xc5, 0x8d,
+  0x07, 0xbd, 0x1d, 0xb9, 0xcc, 0x27, 0x57, 0xd1, 0xc7, 0x91, 0x4c, 0xe5,
+  0x70, 0xb7, 0xe0, 0x94, 0xad, 0x8b, 0xc8, 0xff, 0x3f, 0xf2, 0x60, 0xb7,
+  0x91, 0x87, 0x05, 0xc5, 0x7f, 0x34, 0x71, 0xb8, 0x50, 0xb6, 0x7f, 0x89,
+  0x3c, 0xda, 0xce, 0xd9, 0xa6, 0xc6, 0xe7, 0xf1, 0x32, 0x19, 0xcf, 0xdf,
+  0xf2, 0x25, 0xa1, 0x00, 0x1d, 0x86, 0x5b, 0xfd, 0xe4, 0xfc, 0xdb, 0xe7,
+  0x70, 0x66, 0x0c, 0x9b, 0x99, 0xff, 0xa7, 0x47, 0x07, 0xe7, 0x2d, 0x2c,
+  0xec, 0x9a, 0x6e, 0xf9, 0x45, 0xda, 0x67, 0xfb, 0x27, 0x0b, 0xa6, 0x2f,
+  0xf5, 0x17, 0x26, 0xa2, 0x36, 0xd1, 0xdb, 0xf4, 0x0b, 0x7b, 0x1e, 0xdc,
+  0x4f, 0x93, 0x86, 0x31, 0x4b, 0x35, 0x5f, 0xb3, 0x58, 0x3e, 0x9e, 0x4d,
+  0xb6, 0xe5, 0xcf, 0xfe, 0xd5, 0xdf, 0x26, 0xf3, 0xc1, 0x23, 0xb4, 0x12,
+  0x57, 0x82, 0xd7, 0x15, 0x26, 0xbf, 0xa5, 0xc6, 0xb0, 0x2b, 0xde, 0x53,
+  0x37, 0xcd, 0xbb, 0x53, 0x15, 0x69, 0x2a, 0x0e, 0x80, 0x89, 0xd6, 0xcd,
+  0x92, 0x3f, 0x9d, 0x20, 0xfa, 0x91, 0xcd, 0xc3, 0xcd, 0x84, 0x07, 0x7c,
+  0xbf, 0xed, 0x5b, 0xfa, 0xd7, 0x7a, 0xb3, 0xf6, 0x38, 0xec, 0xb4, 0xad,
+  0x39, 0x19, 0x85, 0xc8, 0xca, 0xb5, 0x27, 0x45, 0xeb, 0x97, 0xda, 0x5c,
+  0x28, 0xe1, 0xe6, 0xaf, 0x08, 0xf9, 0xbe, 0x25, 0xe7, 0x52, 0x70, 0x35,
+  0xcb, 0xb1, 0x65, 0xa6, 0xa4, 0xf3, 0xf1, 0x82, 0x4e, 0x41, 0x5b, 0xa2,
+  0xf5, 0xe3, 0x20, 0x3a, 0xd5, 0xd9, 0xcc, 0x93, 0x7a, 0xbc, 0xe5, 0x41,
+  0x51, 0x41, 0x0b, 0x90, 0xe7, 0x22, 0xcb, 0xb8, 0xc2, 0xb6, 0x22, 0x04,
+  0x4a, 0xeb, 0x7b, 0x20, 0x52, 0x05, 0x37, 0x91, 0x3c, 0xd2, 0x48, 0x22,
+  0x2f, 0x1d, 0xcc, 0x52, 0x94, 0x5f, 0x8d, 0x77, 0x5f, 0x3c, 0xdf, 0x65,
+  0xa9, 0x77, 0x55, 0x38, 0x18, 0x67, 0x34, 0xf3, 0x74, 0xf0, 0x64, 0xfb,
+  0xe9, 0xe0, 0x69, 0xe4, 0xf1, 0x67, 0x47, 0x49, 0x5b, 0x6d, 0x75, 0xee,
+  0x96, 0x79, 0xd9, 0x48, 0x8f, 0xdc, 0xdb, 0xe3, 0x43, 0x2b, 0x8d, 0xc7,
+  0x79, 0x42, 0x35, 0xec, 0x2d, 0x2d, 0xdd, 0xc6, 0x8b, 0x37, 0x10, 0x52,
+  0x5f, 0x03, 0x94, 0xd8, 0xb2, 0x2c, 0x91, 0x91, 0xaf, 0x84, 0xad, 0xcc,
+  0x75, 0xce, 0xb4, 0xae, 0xc4, 0xb2, 0x6e, 0xb4, 0xc6, 0x4b, 0x4b, 0x24,
+  0x5e, 0x7d, 0x6d, 0x82, 0x95, 0x1b, 0x7c, 0x60, 0x67, 0xca, 0x09, 0xf1,
+  0xd6, 0x76, 0xa7, 0xf1, 0x85, 0xab, 0xe8, 0x40, 0x0c, 0x03, 0x35, 0x76,
+  0x0b, 0x45, 0x99, 0xe0, 0x57, 0x2c, 0x5e, 0xac, 0x12, 0x49, 0x64, 0xb6,
+  0xee, 0xc7, 0x81, 0xd1, 0xe5, 0xac, 0x0b, 0x64, 0x11, 0x40, 0x84, 0xbb,
+  0xfd, 0xae, 0x5d, 0x15, 0x66, 0x2c, 0x0f, 0x2a, 0xe5, 0x19, 0xac, 0xc5,
+  0xfa, 0x43, 0xaf, 0xc8, 0xe3, 0x88, 0x6a, 0x11, 0xbb, 0x0e, 0x3b, 0x49,
+  0x1c, 0xd6, 0x0b, 0x71, 0x94, 0x1b, 0x66, 0x7a, 0x6a, 0xc5, 0x99, 0x24,
+  0xe3, 0xa6, 0x8e, 0xe5, 0xb2, 0x99, 0xe9, 0xf9, 0x71, 0xbc, 0x88, 0x47,
+  0xe9, 0x34, 0x2d, 0xd3, 0x96, 0xf0, 0xbc, 0x5f, 0x51, 0xf6, 0x2b, 0xc7,
+  0x8b, 0xfe, 0x3c, 0x6b, 0xb3, 0x11, 0x5e, 0x32, 0xb6, 0x7b, 0x80, 0xe8,
+  0xf7, 0xfe, 0xed, 0xd9, 0xd1, 0xf1, 0xe9, 0xc1, 0x0f, 0xe6, 0xf5, 0x76,
+  0xa1, 0xc7, 0x28, 0x90, 0x97, 0xc4, 0xc5, 0xea, 0x7d, 0x91, 0x94, 0xf4,
+  0xe5, 0xe6, 0x93, 0x2d, 0xf6, 0x47, 0xd5, 0xaf, 0x59, 0x56, 0xbf, 0x42,
+  0xb8, 0x67, 0x35, 0xd8, 0xfa, 0x79, 0xd4, 0xc8, 0x64, 0xb7, 0xe2, 0x68,
+  0x28, 0xe9, 0x7e, 0x2d, 0x93, 0xe9, 0x3c, 0x29, 0x15, 0xdd, 0x37, 0x7a,
+  0x79, 0x76, 0x7e, 0xf9, 0xea, 0x2e, 0x9e, 0xd6, 0x49, 0x86, 0xd1, 0x12,
+  0xb4, 0x45, 0xab, 0xb6, 0x12, 0xc9, 0x9b, 0x41, 0x08, 0xe3, 0xd0, 0xc5,
+  0x0a, 0xda, 0x93, 0x74, 0x3b, 0x37, 0x62, 0x04, 0x2f, 0x2f, 0x7f, 0x38,
+  0x3f, 0x7e, 0xf5, 0x92, 0x55, 0xe6, 0xcf, 0x59, 0xd1, 0x57, 0x53, 0x09,
+  0x34, 0x68, 0x5e, 0xe7, 0xd5, 0xa2, 0x79, 0x7d, 0x7f, 0x7f, 0x74, 0x32,
+  0x3c, 0x3f, 0x3d, 0x3b, 0x7c, 0xf5, 0xf2, 0x7b, 0x36, 0xb0, 0x32, 0x6a,
+  0x78, 0xf0, 0xae, 0xfb, 0xcc, 0xc5, 0x41, 0x35, 0xe1, 0x0e, 0x8f, 0xbf,
+  0x7b, 0x7f, 0xfc, 0xf6, 0xdb, 0x57, 0x2f, 0xef, 0xe2, 0xbc, 0xc7, 0xf3,
+  0x93, 0xb7, 0x39, 0xa1, 0xb9, 0x05, 0x5e, 0xba, 0xb2, 0x97, 0x9c, 0x7b,
+  0x30, 0x9a, 0xde, 0x4a, 0xa1, 0x01, 0x80, 0xfb, 0x37, 0x02, 0x10, 0x2e,
+  0x11, 0xa7, 0xcd, 0x46, 0x0b, 0xfe, 0x2d, 0xfa, 0xf2, 0xf4, 0x1b, 0x76,
+  0x6f, 0xb9, 0xbb, 0xd9, 0xca, 0xac, 0x7f, 0xfe, 0x6c, 0x77, 0x6f, 0x2b,
+  0xc0, 0x0d, 0x67, 0x27, 0x39, 0x8d, 0xf8, 0xb6, 0x61, 0x34, 0xf9, 0xd9,
+  0x0a, 0x35, 0x79, 0x5c, 0x70, 0x2d, 0x97, 0xca, 0x37, 0x00, 0xce, 0x01,
+  0x9b, 0xad, 0xb8, 0x5a, 0x14, 0x42, 0x94, 0x38, 0x32, 0x83, 0xbe, 0x64,
+  0x04, 0xf0, 0xbc, 0x11, 0x84, 0x11, 0xcb, 0xa0, 0x2c, 0xfe, 0xd3, 0x63,
+  0x24, 0x46, 0x34, 0x1c, 0xf5, 0x7b, 0xb7, 0x13, 0xf2, 0xaf, 0x7d, 0x30,
+  0x5a, 0x6e, 0x94, 0x5a, 0x59, 0x87, 0x4b, 0x86, 0xa0, 0x5d, 0xb0, 0xeb,
+  0xf2, 0x91, 0x98, 0x17, 0xac, 0x9f, 0x47, 0x73, 0xac, 0x32, 0xab, 0xc0,
+  0xff, 0xa4, 0x64, 0x6a, 0x0e, 0x2d, 0x46, 0x2a, 0x59, 0xc3, 0xbe, 0x5c,
+  0xd9, 0x5c, 0x8f, 0x6f, 0x63, 0x25, 0x70, 0x5d, 0xc3, 0x00, 0x93, 0xf1,
+  0x58, 0xe9, 0x9a, 0xe6, 0xf1, 0xa8, 0x03, 0x4c, 0xb2, 0xee, 0xe0, 0xcc,
+  0x77, 0x95, 0x05, 0x1c, 0xd6, 0x09, 0x7c, 0x29, 0x52, 0xf8, 0x78, 0xdb,
+  0x18, 0x02, 0xaf, 0xdf, 0xc6, 0x9a, 0x40, 0xb8, 0x48, 0xdc, 0x30, 0x90,
+  0x73, 0x39, 0x04, 0x09, 0xf3, 0xc3, 0x78, 0x2c, 0x0b, 0xb1, 0x3a, 0x0b,
+  0x09, 0x75, 0xab, 0xdb, 0x78, 0x02, 0x82, 0xba, 0xe1, 0xf8, 0xa4, 0xd2,
+  0x95, 0x1d, 0xc5, 0xde, 0x55, 0x23, 0xd0, 0x8c, 0x48, 0x03, 0x8f, 0x60,
+  0x5d, 0x90, 0xf0, 0x30, 0x3d, 0x9a, 0x94, 0x22, 0x46, 0x67, 0xd6, 0x32,
+  0x38, 0x9c, 0x79, 0xba, 0x0a, 0xc2, 0x16, 0x64, 0x63, 0x1f, 0xab, 0xa5,
+  0xc0, 0x26, 0xa3, 0x81, 0xa3, 0x37, 0x23, 0x34, 0x48, 0x09, 0xec, 0xbf,
+  0xda, 0x1c, 0x6e, 0x29, 0x19, 0x0b, 0xb9, 0x9d, 0xbf, 0xf3, 0x49, 0x3e,
+  0x6d, 0x25, 0x36, 0xd6, 0x11, 0xa0, 0x53, 0xb7, 0xfd, 0x42, 0x75, 0xfa,
+  0x9d, 0x3a, 0x4e, 0x93, 0x1d, 0x37, 0x94, 0x74, 0x0f, 0x93, 0x88, 0xe2,
+  0x56, 0xb0, 0x21, 0x89, 0xb7, 0x8d, 0x0e, 0xa6, 0xf0, 0x2e, 0x13, 0x6f,
+  0x5c, 0xf5, 0xea, 0x7d, 0x0c, 0x3a, 0x11, 0x77, 0xe2, 0xac, 0xa2, 0x62,
+  0x3f, 0xdd, 0x6a, 0x00, 0xa7, 0xad, 0xb4, 0xbc, 0x9d, 0xb7, 0x05, 0x84,
+  0xf9, 0xb0, 0x3c, 0xd4, 0xda, 0xd0, 0x10, 0x60, 0x01, 0x56, 0xd2, 0xcc,
+  0x07, 0x87, 0xdc, 0x80, 0x54, 0x5c, 0x20, 0xd3, 0x23, 0xd5, 0x05, 0xae,
+  0x2c, 0x17, 0xc2, 0x24, 0x38, 0x51, 0x86, 0x78, 0x2a, 0x6d, 0x42, 0x08,
+  0x03, 0xe8, 0x58, 0x1d, 0xab, 0x00, 0x9b, 0xd8, 0xb2, 0xa8, 0x56, 0xab,
+  0xca, 0x72, 0x0e, 0x98, 0x0d, 0xf4, 0x2f, 0x3d, 0xd0, 0x90, 0x56, 0x96,
+  0xaf, 0x27, 0xeb, 0x28, 0x7a, 0x65, 0xff, 0xb2, 0x51, 0xac, 0x88, 0x5f,
+  0x58, 0xc4, 0x69, 0x1e, 0x84, 0xd2, 0x20, 0x7c, 0x8d, 0xe7, 0x2e, 0x94,
+  0xa4, 0x81, 0x8f, 0x90, 0x7a, 0x07, 0x42, 0xda, 0xf0, 0x93, 0xac, 0xc5,
+  0xcd, 0xee, 0x5c, 0x4f, 0xb3, 0xd1, 0x88, 0x26, 0xd5, 0x31, 0x89, 0x94,
+  0x46, 0x18, 0xe7, 0xd7, 0x50, 0xd2, 0x7a, 0x06, 0xea, 0xe1, 0x0f, 0x2b,
+  0x00, 0xe1, 0xd0, 0xd7, 0xba, 0x48, 0x7f, 0x2d, 0x96, 0x92, 0x79, 0x94,
+  0x4f, 0xa0, 0xb5, 0x85, 0x85, 0xb7, 0xc4, 0xfd, 0x8d, 0xcf, 0x23, 0xeb,
+  0xbf, 0xce, 0xf1, 0xcb, 0x15, 0xc7, 0x4a, 0xba, 0xeb, 0x53, 0x99, 0x0f,
+  0x58, 0x8e, 0x22, 0x75, 0xa5, 0x2d, 0xc1, 0xf6, 0x3c, 0x61, 0x9a, 0x40,
+  0xe7, 0xef, 0x3c, 0x8a, 0xdd, 0x1e, 0xff, 0xbb, 0xf7, 0x8f, 0x8e, 0xc1,
+  0xb1, 0x31, 0x20, 0xa6, 0x0c, 0xbe, 0x64, 0x08, 0xac, 0xc2, 0x30, 0xe0,
+  0x5a, 0x20, 0xdf, 0xb8, 0x4e, 0xc9, 0xda, 0xd6, 0xd3, 0xd9, 0xf5, 0x8f,
+  0xbb, 0xfd, 0xdd, 0x9d, 0x9d, 0x9d, 0x9f, 0x06, 0x0b, 0x5e, 0xba, 0x2b,
+  0x34, 0x4f, 0xff, 0x0e, 0x16, 0xe9, 0x98, 0x43, 0x5e, 0x68, 0x33, 0xd3,
+  0x18, 0x45, 0xa3, 0xa5, 0xbf, 0xed, 0xf0, 0xfa, 0xcc, 0x39, 0x79, 0xa7,
+  0x95, 0x8f, 0x3b, 0xd0, 0x4d, 0x86, 0x20, 0x5f, 0xb2, 0x18, 0x27, 0x0f,
+  0x47, 0x93, 0xa5, 0x44, 0x23, 0x48, 0xb4, 0x86, 0xba, 0x89, 0x79, 0xb3,
+  0x89, 0x54, 0xb5, 0xde, 0x09, 0xdd, 0x78, 0xbd, 0xd6, 0xf2, 0x8c, 0xf8,
+  0x36, 0x29, 0xb8, 0x84, 0x28, 0x52, 0x74, 0x03, 0x88, 0xfa, 0x9e, 0x4b,
+  0x0c, 0xc0, 0x81, 0x55, 0xba, 0x97, 0x73, 0xdb, 0x44, 0x53, 0xe4, 0x63,
+  0x46, 0xd2, 0x27, 0x7f, 0x6d, 0x5c, 0xce, 0x81, 0x62, 0x1b, 0x86, 0xb6,
+  0x14, 0x6c, 0x6a, 0xc0, 0xb3, 0xb5, 0x29, 0xe8, 0xde, 0xd4, 0x11, 0x9a,
+  0x39, 0x10, 0xcc, 0xdf, 0xbf, 0x13, 0xdc, 0xc6, 0x11, 0x17, 0x59, 0x06,
+  0xf6, 0x15, 0xd6, 0xa1, 0xa1, 0xfc, 0x14, 0xe3, 0x34, 0xfd, 0x4d, 0xa5,
+  0x56, 0xf4, 0x8a, 0x6e, 0x1e, 0xdf, 0xb0, 0x58, 0xb6, 0x4b, 0x76, 0x2b,
+  0xdc, 0x2c, 0xbf, 0x5b, 0x62, 0xee, 0x70, 0xfb, 0xf5, 0x7f, 0xd0, 0x86,
+  0x71, 0x05, 0xa7, 0x04, 0xf5, 0x4e, 0x83, 0x8a, 0x16, 0x98, 0xaa, 0x28,
+  0x8a, 0xd3, 0x24, 0xe6, 0xa0, 0x62, 0x33, 0xd3, 0xdc, 0x24, 0x0f, 0x22,
+  0x30, 0x34, 0x61, 0x02, 0xc4, 0xa7, 0xcb, 0x5e, 0x13, 0xd5, 0xfb, 0x0e,
+  0x86, 0x87, 0x27, 0x27, 0x15, 0x85, 0x98, 0x17, 0x4f, 0x8a, 0xfd, 0xc2,
+  0xcd, 0x52, 0xcc, 0x68, 0x15, 0xd9, 0xc9, 0x83, 0xe1, 0x36, 0xe4, 0x14,
+  0x0e, 0x49, 0x43, 0xfa, 0x28, 0x83, 0xac, 0xc6, 0x45, 0x6a, 0x31, 0x80,
+  0xb1, 0xe4, 0x7e, 0x2d, 0xe7, 0x2c, 0x51, 0x70, 0x60, 0xcc, 0xcd, 0x92,
+  0x8e, 0x64, 0xf1, 0x91, 0xa6, 0xb7, 0x8f, 0xa5, 0xc7, 0xdf, 0x9e, 0xf4,
+  0x5a, 0x82, 0x9d, 0xce, 0x73, 0x8d, 0x29, 0x93, 0xd0, 0x97, 0x48, 0x22,
+  0x95, 0x18, 0x9a, 0x95, 0x6f, 0x0d, 0xa1, 0xc0, 0x0c, 0x15, 0x13, 0x30,
+  0x5a, 0x5c, 0x29, 0x56, 0xe4, 0xb4, 0x05, 0x69, 0x47, 0xf5, 0x84, 0xa2,
+  0x0e, 0x0e, 0xfc, 0xb4, 0x22, 0x85, 0x5a, 0x21, 0x84, 0xe8, 0x25, 0xff,
+  0xbb, 0x6f, 0x85, 0x08, 0x1e, 0xab, 0x2f, 0x86, 0xc7, 0x1b, 0x35, 0x82,
+  0x2a, 0x08, 0x86, 0x72, 0xdd, 0x3e, 0x8e, 0x58, 0x3b, 0x88, 0xce, 0xdc,
+  0xbe, 0xf8, 0xca, 0x47, 0x68, 0xb3, 0x5e, 0x86, 0xa5, 0x6d, 0x3b, 0xf8,
+  0xce, 0x42, 0xfa, 0xe1, 0x75, 0xaa, 0x84, 0xef, 0xc7, 0xb5, 0x69, 0xc6,
+  0x45, 0xb6, 0x47, 0xe6, 0xa2, 0x3d, 0xd3, 0x4d, 0x3c, 0xcd, 0xe6, 0x5b,
+  0xad, 0x4b, 0x85, 0xad, 0x22, 0x41, 0x93, 0x63, 0xc8, 0xc4, 0x7a, 0xe7,
+  0x2a, 0x1f, 0xad, 0xc5, 0xcd, 0x85, 0x5c, 0xcb, 0xb8, 0xe5, 0xe7, 0x27,
+  0x7d, 0x0d, 0x83, 0x54, 0x78, 0x61, 0xc9, 0x76, 0xe3, 0x79, 0x4c, 0xb2,
+  0x3a, 0xae, 0x4d, 0xdb, 0x42, 0xf8, 0x7c, 0x6a, 0x81, 0xc6, 0xac, 0x40,
+  0x5f, 0x2d, 0x17, 0xb5, 0xb9, 0x55, 0x0b, 0x46, 0xd4, 0x85, 0x4a, 0x24,
+  0x3e, 0x0b, 0xc6, 0x45, 0xa8, 0xec, 0x8d, 0x56, 0x12, 0x0c, 0xe9, 0xd2,
+  0x24, 0xd5, 0xa2, 0x20, 0xd7, 0x38, 0x56, 0xa6, 0x0d, 0xd6, 0x28, 0x20,
+  0xf9, 0x7d, 0xe2, 0x39, 0xcb, 0x68, 0xbf, 0xf3, 0x1b, 0x9e, 0x8c, 0x77,
+  0x66, 0x01, 0xff, 0xf5, 0x09, 0x52, 0xfd, 0x04, 0x1f, 0x20, 0xc8, 0xff,
+  0xb7, 0xd7, 0x7e, 0xaf, 0xdf, 0xfd, 0xb6, 0x7b, 0xdd, 0xe7, 0x79, 0xbf,
+  0x24, 0xa1, 0x6f, 0xdd, 0xbe, 0xc6, 0x10, 0x22, 0x39, 0xa0, 0x93, 0x71,
+  0x80, 0x1b, 0x98, 0x74, 0x50, 0xbb, 0xf8, 0xca, 0xb9, 0xa1, 0x25, 0x72,
+  0x71, 0x50, 0x4d, 0x74, 0x0c, 0x83, 0xc5, 0x30, 0x49, 0x9d, 0x1a, 0xdd,
+  0x2c, 0xb6, 0x24, 0x21, 0x21, 0x48, 0x5d, 0x7f, 0x5c, 0x9e, 0x71, 0x6a,
+  0x8a, 0x38, 0xbc, 0x2a, 0x09, 0xc6, 0x92, 0xfe, 0xca, 0x61, 0x21, 0x06,
+  0x20, 0x01, 0x11, 0xbd, 0x6d, 0x71, 0x79, 0x42, 0x1c, 0xe0, 0x2e, 0x46,
+  0xc1, 0x9e, 0x2f, 0x2a, 0x1f, 0x20, 0x44, 0x2b, 0x18, 0xc5, 0x07, 0x40,
+  0x6f, 0xd5, 0xe4, 0x14, 0xac, 0x67, 0x70, 0x8d, 0xb5, 0xd6, 0x8e, 0x53,
+  0xc3, 0x25, 0xaf, 0x25, 0x64, 0x14, 0x94, 0x34, 0xb2, 0xab, 0x64, 0xbb,
+  0x8c, 0xa7, 0xb7, 0x31, 0x4b, 0x24, 0x83, 0xe8, 0x8d, 0xac, 0xab, 0x2f,
+  0xed, 0xd7, 0x88, 0xff, 0x18, 0x2d, 0xaf, 0xaf, 0x51, 0x82, 0xe2, 0x40,
+  0x6e, 0xa0, 0xc2, 0x00, 0x22, 0x60, 0x98, 0xec, 0x7e, 0xde, 0xd5, 0x40,
+  0xce, 0x8e, 0x94, 0x49, 0x86, 0x38, 0xd4, 0x11, 0x71, 0xa4, 0x99, 0xe5,
+  0xc5, 0xf4, 0xdf, 0x8b, 0xba, 0x2f, 0xdb, 0x5f, 0x22, 0x05, 0x3d, 0x49,
+  0xef, 0x14, 0xeb, 0xdd, 0xa9, 0xff, 0xb4, 0x86, 0x37, 0x29, 0x5d, 0x68,
+  0xf3, 0x66, 0xf0, 0x96, 0x56, 0x8f, 0x81, 0x87, 0xa0, 0xa7, 0x05, 0xa5,
+  0xdb, 0x06, 0xf9, 0x47, 0xeb, 0x2f, 0x9e, 0x4c, 0x52, 0x2d, 0xc2, 0xc5,
+  0xc2, 0x58, 0x23, 0xb9, 0x5e, 0xd3, 0x9f, 0xb4, 0xff, 0xf6, 0xca, 0x22,
+  0x7a, 0x05, 0xa7, 0xc6, 0x2d, 0x44, 0x16, 0x02, 0xe5, 0x29, 0xde, 0x92,
+  0x15, 0x8c, 0xb6, 0x7a, 0x7c, 0xa6, 0x88, 0xd6, 0xa5, 0xc4, 0x4a, 0x05,
+  0x6a, 0x27, 0xfe, 0x40, 0xa8, 0x13, 0x4a, 0x54, 0x8b, 0x30, 0xd7, 0x40,
+  0x53, 0xd4, 0xec, 0x75, 0x57, 0xa3, 0x99, 0x3c, 0xfc, 0xa9, 0x29, 0x4a,
+  0x29, 0x42, 0x2c, 0xb5, 0xed, 0x70, 0x6b, 0xf2, 0x83, 0x5a, 0x99, 0xc8,
+  0xac, 0xaa, 0xbd, 0x26, 0x8a, 0x04, 0x12, 0xa5, 0x1c, 0x8c, 0x88, 0x93,
+  0x43, 0xaa, 0x42, 0xb4, 0xd9, 0xcc, 0xff, 0x59, 0x39, 0xac, 0xd2, 0xd8,
+  0x23, 0x82, 0x18, 0xc0, 0xdd, 0x86, 0x2e, 0xc8, 0x48, 0x50, 0x33, 0x2d,
+  0xec, 0x0f, 0x71, 0x45, 0xc1, 0xa9, 0x08, 0x40, 0xe2, 0x9b, 0xe5, 0x68,
+  0x20, 0x1c, 0x55, 0xca, 0x7a, 0x89, 0x41, 0x59, 0x74, 0x6b, 0xad, 0xff,
+  0x6c, 0x11, 0xe6, 0x86, 0xd8, 0x99, 0xc2, 0xa0, 0x55, 0x0c, 0x5a, 0x7c,
+  0x81, 0x16, 0x64, 0x27, 0x62, 0x99, 0xee, 0xa2, 0x26, 0xf5, 0xb0, 0x0a,
+  0x61, 0x4d, 0x70, 0xf0, 0x3d, 0xa8, 0xde, 0x45, 0xaf, 0x37, 0xa5, 0x69,
+  0xa9, 0xd0, 0x9c, 0x4f, 0x20, 0x40, 0xaf, 0x14, 0x24, 0x3f, 0x05, 0x34,
+  0xf9, 0xfc, 0xd6, 0x82, 0x96, 0x24, 0xdf, 0x20, 0x19, 0x2f, 0xcb, 0xaa,
+  0x1d, 0x37, 0x18, 0x93, 0xc6, 0x24, 0x63, 0x48, 0x9b, 0x38, 0x03, 0x0a,
+  0xbe, 0xd8, 0x39, 0x37, 0xec, 0xb2, 0xfd, 0xce, 0x96, 0xc9, 0xed, 0x50,
+  0x6b, 0x1c, 0xa8, 0x59, 0x9b, 0x48, 0x6e, 0x43, 0x76, 0xd5, 0xe2, 0x33,
+  0x87, 0xd2, 0xdf, 0xd6, 0x3d, 0x91, 0x5f, 0xde, 0xda, 0xfb, 0x6b, 0xc9,
+  0x1f, 0x09, 0x3a, 0x77, 0x18, 0xcb, 0x9a, 0x5a, 0x52, 0xac, 0x01, 0xa6,
+  0x08, 0x7a, 0xce, 0x18, 0xe5, 0x8e, 0xd8, 0x90, 0x8b, 0xd3, 0xb7, 0x57,
+  0x6d, 0xf1, 0xf7, 0x9b, 0xe8, 0x47, 0x77, 0xcf, 0x03, 0xf3, 0x0d, 0x33,
+  0x60, 0x7c, 0xa4, 0xcb, 0x99, 0x36, 0xd5, 0x88, 0xdb, 0x7c, 0xf4, 0x94,
+  0x7e, 0x7c, 0xc3, 0x3f, 0xac, 0xb8, 0x25, 0x63, 0x65, 0x99, 0xf9, 0xa2,
+  0x09, 0x7c, 0xc0, 0x95, 0x0b, 0xe4, 0xdc, 0x0f, 0x41, 0x45, 0xaf, 0xf1,
+  0x4b, 0x9e, 0x3c, 0xf2, 0x0e, 0xcd, 0xed, 0x67, 0x76, 0x20, 0x2e, 0xcb,
+  0x8c, 0x29, 0x71, 0x8c, 0x44, 0x8d, 0xd9, 0x22, 0x97, 0x1a, 0x30, 0x92,
+  0xad, 0x21, 0x7f, 0xaa, 0x87, 0xaa, 0xc0, 0x51, 0x52, 0xe6, 0x92, 0xae,
+  0x81, 0x72, 0x5a, 0xdf, 0x9f, 0x14, 0xfe, 0x68, 0x85, 0x5c, 0x7c, 0x74,
+  0x6e, 0x8f, 0xd5, 0x08, 0x6c, 0x60, 0x46, 0xd6, 0x1a, 0xe6, 0xa5, 0xa0,
+  0xc5, 0x7c, 0xf6, 0x71, 0xab, 0x78, 0xc4, 0xb7, 0x8c, 0x2b, 0x93, 0x6b,
+  0x58, 0x64, 0x5a, 0x9b, 0x4e, 0x24, 0x2f, 0x5f, 0x9b, 0x0e, 0x0f, 0xab,
+  0x84, 0xa0, 0x75, 0xa0, 0xda, 0x07, 0x87, 0x4b, 0x0f, 0xf1, 0x7c, 0x60,
+  0x2e, 0xb7, 0x66, 0x6a, 0x99, 0xd1, 0x45, 0x9b, 0xaf, 0xfc, 0xd5, 0x16,
+  0xd1, 0x35, 0x39, 0x88, 0x50, 0xdf, 0x05, 0x9d, 0xaf, 0x49, 0xe0, 0x9d,
+  0x90, 0xd8, 0x33, 0x65, 0x0b, 0xaf, 0xa4, 0x1e, 0xfd, 0xae, 0x51, 0x6d,
+  0xb3, 0x58, 0xcd, 0xc7, 0x37, 0x47, 0x6f, 0x87, 0xeb, 0x92, 0x78, 0xd3,
+  0xc2, 0x45, 0x2b, 0x73, 0x78, 0x09, 0x3f, 0x4d, 0x42, 0x1c, 0xb3, 0x45,
+  0x48, 0x7f, 0x1a, 0xcd, 0xd2, 0x02, 0xae, 0x71, 0xfe, 0xf6, 0xf8, 0xab,
+  0x33, 0xfb, 0xb1, 0x76, 0xc9, 0x1f, 0x5d, 0xe1, 0x53, 0x4e, 0xd0, 0x7d,
+  0x2c, 0xd7, 0xd9, 0x06, 0xe7, 0x0a, 0x69, 0x78, 0x2f, 0x04, 0x11, 0x24,
+  0x0a, 0x1c, 0x0b, 0x2d, 0xf6, 0x94, 0x24, 0xa5, 0xe6, 0xf1, 0xba, 0x2c,
+  0x6e, 0x3a, 0x6e, 0x7b, 0x5f, 0x7d, 0xd9, 0xbc, 0xad, 0x8e, 0xde, 0xae,
+  0xe9, 0x8e, 0xbf, 0xe9, 0x5b, 0x02, 0x93, 0x5e, 0xd1, 0x5a, 0xc0, 0x07,
+  0xd9, 0xe4, 0x2d, 0x27, 0x8f, 0x0b, 0x14, 0xca, 0x8f, 0xca, 0xd4, 0xed,
+  0x4a, 0xe4, 0xe3, 0x2e, 0x34, 0x2f, 0xf8, 0x0c, 0x80, 0x26, 0x99, 0xc6,
+  0x74, 0x4d, 0x46, 0x2d, 0xa5, 0x00, 0x03, 0xab, 0x7f, 0xb5, 0xda, 0x5c,
+  0xb0, 0xca, 0x0a, 0xac, 0x68, 0x55, 0x47, 0x90, 0x4b, 0x0f, 0xe9, 0xbd,
+  0xc9, 0xd2, 0x9d, 0x13, 0xb3, 0xae, 0x57, 0xf6, 0xef, 0xe9, 0x92, 0x82,
+  0x63, 0x9a, 0x65, 0xc0, 0xe8, 0xa5, 0x5c, 0x47, 0x9f, 0x37, 0x0e, 0x84,
+  0x20, 0xbe, 0x98, 0x55, 0xd8, 0x9c, 0x80, 0xb8, 0xd7, 0xd9, 0xc0, 0xe3,
+  0x30, 0x83, 0x50, 0xd4, 0x36, 0x29, 0x13, 0x31, 0x19, 0x2b, 0x82, 0x50,
+  0x23, 0x58, 0x94, 0x64, 0x3b, 0xef, 0x9c, 0xb0, 0x30, 0x03, 0xe9, 0x5a,
+  0xeb, 0xf0, 0x68, 0x61, 0x0e, 0xab, 0xbb, 0x65, 0x99, 0xd5, 0xe2, 0xec,
+  0x6e, 0x04, 0x17, 0x3c, 0xb0, 0xb9, 0xe6, 0xc1, 0x6e, 0xa6, 0xaa, 0x88,
+  0xec, 0x0a, 0x6b, 0x48, 0x6e, 0xb5, 0x36, 0x1c, 0x24, 0x09, 0xb7, 0xc6,
+  0x54, 0x22, 0x0a, 0xaa, 0x23, 0x0f, 0x77, 0x60, 0x1d, 0xe3, 0x1c, 0x2b,
+  0x31, 0x00, 0x49, 0xbe, 0x32, 0x12, 0x9b, 0xc7, 0x4b, 0x36, 0x5c, 0xc1,
+  0xf1, 0x80, 0x0a, 0x3c, 0xad, 0xcd, 0xad, 0xf8, 0xde, 0xee, 0x7c, 0x61,
+  0xe6, 0xb2, 0x8e, 0x59, 0xd3, 0x3d, 0x00, 0x19, 0xbc, 0x06, 0x68, 0x5c,
+  0x25, 0x65, 0x5d, 0x8a, 0x16, 0x1f, 0xa3, 0x38, 0x0d, 0x50, 0x32, 0x00,
+  0xb5, 0x27, 0x3a, 0x5f, 0xf4, 0x3b, 0xad, 0xb7, 0x5f, 0x50, 0x51, 0x84,
+  0x05, 0x1e, 0x48, 0xc0, 0x6a, 0xed, 0x36, 0xf3, 0x9e, 0xf4, 0x62, 0x3a,
+  0x52, 0xb1, 0x1c, 0x91, 0x90, 0x56, 0x2e, 0xcb, 0x46, 0x58, 0xa2, 0x66,
+  0xe8, 0xc3, 0x23, 0x0b, 0x1d, 0x81, 0x17, 0xdc, 0x7b, 0x4d, 0x21, 0xec,
+  0xb1, 0x39, 0xb0, 0x44, 0x64, 0xa1, 0xda, 0x18, 0x47, 0x40, 0x43, 0x60,
+  0x98, 0x9f, 0xba, 0xb8, 0x72, 0xc0, 0x17, 0xbd, 0x1f, 0x1d, 0x6e, 0x27,
+  0x8f, 0xb6, 0x58, 0x44, 0xbf, 0xff, 0xbb, 0x7d, 0x09, 0x48, 0x8a, 0x7f,
+  0xd8, 0x7a, 0x59, 0xad, 0x8f, 0x76, 0xa9, 0xfb, 0xf7, 0xde, 0x26, 0x23,
+  0x2b, 0x83, 0x2c, 0x41, 0x6e, 0xee, 0xf7, 0x03, 0x77, 0xe7, 0x5a, 0x13,
+  0xd1, 0x3c, 0xb9, 0x17, 0x49, 0xa9, 0xa1, 0x13, 0x88, 0xa4, 0xf9, 0x17,
+  0x2e, 0xfb, 0x47, 0xaf, 0x90, 0xc4, 0xc8, 0x8e, 0xff, 0xb0, 0x54, 0xfc,
+  0x5f, 0x72, 0x15, 0xed, 0x49, 0xf0, 0xa1, 0x81, 0xb3, 0x3c, 0x2a, 0x9f,
+  0x97, 0x8f, 0x14, 0x8e, 0xff, 0x7d, 0x5f, 0xe0, 0x46, 0x94, 0xba, 0x79,
+  0xba, 0x34, 0x66, 0xfb, 0xcc, 0x2a, 0xcd, 0xcd, 0x9f, 0xec, 0xf5, 0x03,
+  0x65, 0xba, 0xd7, 0x28, 0xdc, 0xc4, 0x9e, 0x47, 0x96, 0x93, 0x82, 0x62,
+  0x40, 0x4c, 0xe3, 0xbf, 0xd7, 0xca, 0x0e, 0x70, 0x66, 0x49, 0x52, 0xd7,
+  0xc4, 0xb4, 0x52, 0x4d, 0xa7, 0x5a, 0x1b, 0xe3, 0xdf, 0x4a, 0x3c, 0xc1,
+  0xee, 0x38, 0xf9, 0xc6, 0x52, 0xa4, 0x25, 0x44, 0xa4, 0x2d, 0xde, 0x00,
+  0x81, 0x14, 0x56, 0x41, 0x4d, 0x1a, 0x82, 0x1a, 0x0d, 0x6f, 0x25, 0x1b,
+  0x8c, 0xa5, 0xa8, 0x0e, 0xd4, 0x73, 0xef, 0x9c, 0x87, 0x0b, 0x93, 0xf5,
+  0xa1, 0xfe, 0xda, 0x14, 0x6f, 0x4b, 0x98, 0x60, 0xc6, 0x21, 0x75, 0x96,
+  0xba, 0xf0, 0xca, 0x4e, 0x27, 0xc1, 0xf9, 0x11, 0x70, 0xfd, 0xc8, 0x45,
+  0x26, 0xec, 0x3f, 0xde, 0x9c, 0x6a, 0x45, 0x8d, 0xe9, 0xb3, 0x4f, 0xe7,
+  0x3d, 0xd2, 0xf9, 0xdc, 0x6a, 0x10, 0x33, 0x49, 0x72, 0x86, 0xcb, 0xaa,
+  0xe5, 0xfb, 0xf9, 0x89, 0x31, 0x0a, 0xbb, 0x6e, 0xe3, 0xe3, 0xbd, 0xc2,
+  0x32, 0x91, 0x2b, 0x60, 0xc2, 0xc4, 0xf9, 0x5a, 0x91, 0x97, 0x40, 0x72,
+  0x09, 0x5b, 0x07, 0xdc, 0x55, 0xd7, 0x06, 0x77, 0x1a, 0x35, 0xd2, 0x85,
+  0x3e, 0xe3, 0xf2, 0x04, 0x48, 0x86, 0x98, 0xa6, 0xb1, 0xcf, 0xe0, 0x96,
+  0x29, 0xf0, 0xe0, 0x62, 0x58, 0x5f, 0x59, 0x56, 0x26, 0x51, 0xf7, 0xf1,
+  0xe6, 0x1c, 0x96, 0x25, 0xeb, 0x25, 0xeb, 0x56, 0x46, 0xc0, 0x49, 0xeb,
+  0x2b, 0x53, 0x5d, 0x10, 0x5d, 0x11, 0xaf, 0x71, 0xb6, 0xf8, 0xdb, 0xa3,
+  0x35, 0xa9, 0x94, 0x51, 0xb4, 0x69, 0x08, 0x8a, 0x62, 0x39, 0xdb, 0x52,
+  0x80, 0x63, 0xbb, 0x07, 0x15, 0x38, 0xf8, 0x43, 0xcd, 0x21, 0x0f, 0xa6,
+  0x91, 0xa2, 0xf2, 0xb4, 0x11, 0xdd, 0xc9, 0x36, 0x94, 0xf7, 0x92, 0xe4,
+  0xe7, 0x34, 0x07, 0x97, 0xf2, 0xd7, 0xe3, 0x17, 0x35, 0xfb, 0xa9, 0xe7,
+  0x51, 0x88, 0xc5, 0x89, 0x86, 0x2b, 0xec, 0x03, 0x54, 0x0b, 0x59, 0x88,
+  0x67, 0x9f, 0x28, 0x0a, 0x12, 0x8c, 0xeb, 0x2e, 0xc3, 0x49, 0x2e, 0x52,
+  0xbb, 0xb9, 0x66, 0xe9, 0xf4, 0x03, 0xcd, 0x4d, 0x53, 0x55, 0xaa, 0x20,
+  0x9e, 0x2d, 0x5b, 0x0f, 0x30, 0x26, 0xc4, 0x9c, 0x93, 0x15, 0xf5, 0x75,
+  0xd8, 0x5b, 0x15, 0x45, 0xa9, 0x31, 0x51, 0xc4, 0xa9, 0x97, 0x5c, 0xeb,
+  0x3c, 0x2c, 0x09, 0x0c, 0x25, 0xea, 0xf1, 0xe6, 0x24, 0x53, 0x14, 0x51,
+  0xb5, 0x5e, 0x88, 0x84, 0xe5, 0x83, 0x21, 0xfd, 0x4c, 0x38, 0x68, 0x1f,
+  0x72, 0x95, 0xb4, 0x2c, 0x6b, 0x49, 0xc3, 0x0d, 0xeb, 0xe3, 0xc2, 0xb0,
+  0x40, 0xaf, 0xbf, 0x64, 0x50, 0x41, 0x65, 0xd7, 0xc8, 0x03, 0x37, 0x59,
+  0xd8, 0x8a, 0x84, 0x6c, 0x6f, 0x66, 0xf9, 0xe3, 0xcd, 0x29, 0x51, 0x7e,
+  0xc4, 0x8c, 0xe2, 0xc5, 0x42, 0x7b, 0xfb, 0xf0, 0x26, 0xfc, 0x26, 0xf3,
+  0xd5, 0x1a, 0x3c, 0xdb, 0xc4, 0x78, 0x23, 0x9b, 0xf8, 0x36, 0x1b, 0x2d,
+  0x8b, 0x1b, 0xc9, 0x2a, 0xcf, 0xa2, 0x0f, 0xf3, 0xac, 0x00, 0x78, 0xbf,
+  0x36, 0xe9, 0x47, 0x8a, 0x03, 0x85, 0xcb, 0xc0, 0x98, 0x7a, 0xca, 0xd3,
+  0xfe, 0x37, 0xad, 0x83, 0x44, 0x29, 0x59, 0xfe, 0x21, 0x4f, 0x02, 0x82,
+  0x82, 0x4b, 0xba, 0xa6, 0xb3, 0x48, 0xaa, 0xd7, 0xe0, 0x43, 0xa3, 0x4b,
+  0x0b, 0x6f, 0x59, 0x89, 0xe1, 0xb4, 0x49, 0xfa, 0x75, 0x90, 0x49, 0x01,
+  0x2c, 0x40, 0xd9, 0xf5, 0x0f, 0x71, 0x06, 0x2d, 0x34, 0x2b, 0xc0, 0xf6,
+  0x5e, 0x0a, 0x1a, 0x9b, 0x33, 0x36, 0x10, 0x31, 0x5b, 0x62, 0x6a, 0xeb,
+  0xcd, 0xb1, 0xd9, 0x44, 0xac, 0xcb, 0x77, 0xac, 0xb8, 0xad, 0x21, 0x49,
+  0x0b, 0xd2, 0x5c, 0x77, 0xf2, 0x01, 0x41, 0xcd, 0xeb, 0xac, 0xf9, 0xe3,
+  0x41, 0x89, 0x9a, 0xc7, 0xfb, 0x27, 0x0e, 0xb7, 0x70, 0xcb, 0x23, 0xa7,
+  0x5f, 0xf8, 0x4f, 0xcf, 0x51, 0x5e, 0x0f, 0x92, 0xe8, 0xc7, 0x91, 0x82,
+  0xd4, 0x0a, 0x70, 0x19, 0xa3, 0xb5, 0x7c, 0x52, 0x84, 0x2f, 0xf2, 0x97,
+  0x5a, 0xb9, 0xeb, 0x3e, 0x2e, 0x3e, 0x34, 0xba, 0x58, 0xb4, 0xb1, 0xea,
+  0x22, 0x88, 0xf5, 0x47, 0x23, 0x65, 0x40, 0xd4, 0x91, 0x18, 0xb5, 0x3e,
+  0x86, 0xab, 0x6b, 0x4e, 0x38, 0x52, 0xc1, 0x5d, 0x98, 0x4a, 0xb0, 0x5e,
+  0x61, 0x7e, 0xe4, 0x07, 0xaf, 0xf1, 0xb6, 0xe4, 0x49, 0x8c, 0x15, 0x23,
+  0xff, 0xf8, 0xe3, 0xf3, 0xab, 0xf3, 0xf2, 0x00, 0x17, 0x08, 0x70, 0x3a,
+  0xcd, 0xc3, 0x33, 0xd2, 0xa3, 0xf5, 0x81, 0x35, 0xe3, 0x18, 0x4a, 0xb9,
+  0x04, 0xc3, 0x63, 0x54, 0x67, 0x10, 0xba, 0xf3, 0x2d, 0x59, 0xfa, 0x2d,
+  0xb2, 0x8a, 0xee, 0x40, 0x05, 0x49, 0x75, 0x9e, 0x24, 0x13, 0x43, 0xcd,
+  0x22, 0xc1, 0x84, 0x8f, 0x4f, 0x99, 0x7c, 0x0c, 0x93, 0x2b, 0x68, 0x0b,
+  0x9b, 0xe8, 0x62, 0xe9, 0xcf, 0xc9, 0x7b, 0x03, 0x79, 0x09, 0x85, 0x03,
+  0x9f, 0x1e, 0x2f, 0x71, 0x9d, 0x22, 0xfa, 0x24, 0xb9, 0x87, 0x84, 0x69,
+  0x39, 0x81, 0x68, 0x4d, 0x43, 0xaa, 0xa2, 0x8f, 0x6b, 0x6d, 0x6d, 0x14,
+  0x18, 0xda, 0x52, 0x7f, 0xc5, 0xa3, 0x6d, 0x59, 0x00, 0x84, 0x1b, 0x16,
+  0x44, 0xdf, 0x0f, 0x6c, 0x56, 0x9b, 0x64, 0x8c, 0x1e, 0x5d, 0xb1, 0x06,
+  0x65, 0xd6, 0x22, 0x37, 0xad, 0x1f, 0x7f, 0xa0, 0x77, 0x3e, 0xde, 0x23,
+  0xcc, 0x89, 0x26, 0xb5, 0x6d, 0x34, 0x4b, 0x92, 0x24, 0x13, 0xbf, 0x0f,
+  0xdc, 0x75, 0xcc, 0x5e, 0xbf, 0x00, 0x81, 0x47, 0x9e, 0x09, 0xd4, 0x52,
+  0x52, 0x29, 0x8a, 0x65, 0x2e, 0x68, 0xbd, 0x1f, 0x26, 0x25, 0x77, 0xfe,
+  0xad, 0x3d, 0x8e, 0xdf, 0xe5, 0xa9, 0x90, 0x8c, 0xa7, 0x67, 0x69, 0xcd,
+  0xa8, 0xdc, 0x7e, 0x62, 0x41, 0x6c, 0x58, 0x16, 0x39, 0xf7, 0x2b, 0x8d,
+  0x4a, 0x5a, 0xfb, 0x88, 0x31, 0x29, 0xb2, 0xce, 0x7b, 0x0e, 0xee, 0xd6,
+  0x31, 0x1d, 0xca, 0x47, 0xfd, 0x4b, 0xfe, 0x48, 0xa9, 0xc1, 0x56, 0x3a,
+  0x09, 0xca, 0xfc, 0x32, 0xab, 0xb8, 0xfa, 0xe0, 0x98, 0x72, 0xd5, 0x2a,
+  0xe6, 0x4d, 0x28, 0x3e, 0xd2, 0x06, 0x4c, 0x88, 0x2b, 0x58, 0xfb, 0x15,
+  0x1b, 0x0c, 0x77, 0x49, 0xea, 0x76, 0xe4, 0xbe, 0x41, 0x7e, 0x7c, 0x6a,
+  0x30, 0x20, 0x63, 0xf8, 0x51, 0x3e, 0x8e, 0x7f, 0x7c, 0x44, 0xc2, 0x39,
+  0x8f, 0xc1, 0x78, 0x70, 0xe1, 0xc6, 0x40, 0x43, 0xf0, 0x1f, 0x8a, 0xc3,
+  0x0c, 0xd4, 0xe9, 0x8b, 0xcf, 0x9a, 0xaa, 0xf2, 0xcf, 0x69, 0x15, 0xcd,
+  0x71, 0x58, 0x77, 0xef, 0xa1, 0xb2, 0x48, 0xc6, 0x77, 0x5c, 0x21, 0x72,
+  0x2c, 0xa3, 0xab, 0x8f, 0xc2, 0xbc, 0xb4, 0x2f, 0x2e, 0x67, 0x0c, 0xe9,
+  0x43, 0xe3, 0xd0, 0xc9, 0x68, 0xd1, 0x98, 0x6a, 0x09, 0x5c, 0xa4, 0x8f,
+  0x43, 0x25, 0x1c, 0x73, 0xba, 0x1e, 0x2b, 0xe1, 0x1f, 0xb8, 0x6c, 0x5d,
+  0x83, 0x9a, 0xff, 0x04, 0x40, 0x02, 0x49, 0x00, 0x6b, 0xe4, 0xa1, 0x36,
+  0x33, 0xb7, 0xaf, 0x48, 0x2f, 0x04, 0xd6, 0xe3, 0x7b, 0x40, 0x22, 0x32,
+  0xcd, 0x19, 0x46, 0x39, 0x3e, 0x30, 0xab, 0xb9, 0x60, 0x53, 0x2d, 0x17,
+  0x28, 0x5c, 0xc7, 0x0b, 0x32, 0xcd, 0x60, 0xf1, 0x7e, 0x7c, 0x70, 0x02,
+  0x43, 0x50, 0xc3, 0x5e, 0xb7, 0x18, 0xfb, 0x5a, 0x56, 0x79, 0x53, 0xbb,
+  0x2b, 0x8a, 0xe9, 0x7b, 0x7a, 0x32, 0xbd, 0x5a, 0xbd, 0x17, 0x16, 0xff,
+  0xe1, 0x2b, 0x54, 0x9e, 0xb3, 0x93, 0xc2, 0x2e, 0x15, 0x3a, 0xc3, 0x24,
+  0xdf, 0x25, 0x24, 0x8d, 0x5d, 0x89, 0xe1, 0x35, 0x42, 0x93, 0xe9, 0xf8,
+  0xa3, 0xb4, 0x3f, 0xa7, 0x15, 0xbb, 0x33, 0x37, 0x60, 0xf8, 0x22, 0x78,
+  0x80, 0x61, 0x57, 0xd3, 0xb6, 0x3e, 0x2c, 0x63, 0x71, 0x23, 0x1e, 0x95,
+  0xfd, 0x31, 0xf1, 0xfb, 0xd7, 0x8b, 0x95, 0x70, 0x99, 0xa1, 0x1f, 0x57,
+  0x87, 0xaa, 0x1a, 0xca, 0xef, 0x4b, 0x1e, 0xad, 0xcb, 0x8f, 0x96, 0xa2,
+  0x8a, 0xff, 0x1c, 0xa6, 0xc0, 0x47, 0xe7, 0x43, 0x27, 0x0f, 0xa9, 0x40,
+  0xbd, 0xb4, 0xa5, 0xa0, 0x28, 0x43, 0x28, 0x92, 0xb2, 0x3d, 0x2d, 0xec,
+  0x61, 0xe5, 0xe2, 0xee, 0x65, 0x0a, 0x39, 0x17, 0x46, 0x59, 0x93, 0xcf,
+  0x82, 0x32, 0x2f, 0x82, 0x9c, 0x14, 0x6f, 0xb4, 0xa8, 0x8d, 0x3e, 0x02,
+  0xa7, 0x90, 0x84, 0x1e, 0x69, 0xbd, 0x83, 0x40, 0x73, 0x1b, 0x71, 0x5b,
+  0xb2, 0x65, 0xe8, 0xeb, 0x8f, 0xa7, 0xa1, 0xfd, 0x3c, 0x50, 0x20, 0x14,
+  0x6a, 0x84, 0x23, 0xf9, 0x11, 0x01, 0x17, 0xac, 0x7f, 0x5b, 0xcc, 0x19,
+  0xb8, 0x2e, 0x29, 0x19, 0x34, 0x81, 0xe9, 0x4a, 0x71, 0x4a, 0xb9, 0xb6,
+  0xa5, 0x98, 0x8b, 0xf8, 0x5d, 0x89, 0x98, 0x04, 0xa5, 0x5a, 0xa8, 0x1f,
+  0x7d, 0xdf, 0x34, 0xc1, 0xbb, 0x2a, 0x5a, 0x4e, 0x85, 0x09, 0x86, 0x27,
+  0xa1, 0x04, 0x8d, 0x02, 0x14, 0xce, 0x00, 0xd8, 0xac, 0x40, 0x86, 0xab,
+  0x8f, 0xeb, 0xc5, 0x8a, 0xb1, 0x0f, 0xeb, 0x55, 0x2f, 0xd3, 0x64, 0x9b,
+  0x03, 0x9b, 0x33, 0x90, 0x62, 0x7c, 0x89, 0xc5, 0x7a, 0x60, 0x43, 0xad,
+  0x40, 0xd7, 0x3a, 0xcb, 0xa7, 0x2b, 0x36, 0x22, 0x2d, 0x21, 0x5a, 0x71,
+  0xb7, 0x17, 0xd0, 0x01, 0x54, 0xe0, 0x06, 0xbe, 0xa8, 0xab, 0x4b, 0xd3,
+  0x00, 0x09, 0x61, 0x4b, 0x4f, 0xbc, 0x32, 0x8c, 0x1a, 0x69, 0xa3, 0x95,
+  0x04, 0x7b, 0x41, 0x88, 0xae, 0x95, 0xea, 0x6a, 0x04, 0x70, 0x61, 0x81,
+  0xb5, 0x7c, 0xc1, 0xa6, 0x86, 0x9e, 0x6f, 0xb9, 0x58, 0x81, 0x84, 0x4e,
+  0x14, 0xb8, 0x01, 0x5c, 0x40, 0x7f, 0x7a, 0x34, 0x86, 0xf0, 0x57, 0x62,
+  0x0d, 0xdf, 0x23, 0x4c, 0x48, 0x2e, 0xb3, 0xb5, 0xd5, 0x35, 0x98, 0x8c,
+  0x0c, 0x37, 0x37, 0x85, 0x13, 0x75, 0x4c, 0xda, 0x03, 0xe9, 0x21, 0xf6,
+  0xa6, 0x96, 0x6b, 0x0c, 0x53, 0xae, 0x3e, 0xb2, 0xc8, 0x20, 0xa8, 0xdb,
+  0xa1, 0xed, 0x5f, 0x56, 0x38, 0x8f, 0x93, 0x53, 0x7d, 0x51, 0xf8, 0x96,
+  0x3a, 0x02, 0x61, 0xb6, 0x87, 0x2c, 0xbc, 0x8e, 0x06, 0x31, 0x10, 0xf7,
+  0x69, 0xa1, 0x51, 0x57, 0x0a, 0x29, 0xa7, 0xe9, 0x5c, 0xf0, 0xff, 0x7f,
+  0x75, 0x7c, 0xb9, 0xd5, 0x04, 0x30, 0x8a, 0x27, 0x7e, 0x64, 0x80, 0xb2,
+  0xd4, 0xf3, 0x10, 0xbb, 0x02, 0xd3, 0x2e, 0x81, 0x50, 0x14, 0x9d, 0xe4,
+  0x61, 0x31, 0x8d, 0xe7, 0x5a, 0x55, 0xad, 0xd6, 0xdc, 0x21, 0x2d, 0x03,
+  0x73, 0xb2, 0x20, 0x4c, 0x48, 0xbd, 0xee, 0xae, 0xac, 0xac, 0x53, 0xb8,
+  0x91, 0xa2, 0xc3, 0x2d, 0x1e, 0x1d, 0x9f, 0x1e, 0x5f, 0x1e, 0x23, 0x82,
+  0xba, 0x21, 0x92, 0xb0, 0x2a, 0x34, 0xe1, 0x64, 0xdc, 0x9b, 0x79, 0x46,
+  0x77, 0x6f, 0xaa, 0xd5, 0xe6, 0xa3, 0xef, 0x92, 0xd1, 0xd1, 0xc1, 0xb7,
+  0x12, 0xd2, 0x50, 0x44, 0xe7, 0x17, 0x67, 0xe7, 0xaf, 0x4f, 0xde, 0x1e,
+  0xf5, 0xa2, 0xc3, 0xb3, 0xf3, 0x1f, 0x7a, 0xd1, 0x9b, 0xb3, 0x6f, 0x8f,
+  0x5b, 0x7c, 0x8a, 0xec, 0xcf, 0x6e, 0x66, 0x9c, 0xbd, 0x5e, 0xb3, 0xdb,
+  0x21, 0x22, 0xa5, 0x6e, 0x75, 0x90, 0xe8, 0x73, 0x7a, 0x32, 0xbc, 0xc4,
+  0xd6, 0xd7, 0xe3, 0xbd, 0x10, 0xd3, 0x2e, 0xc0, 0xeb, 0x69, 0x61, 0x01,
+  0x1c, 0x5c, 0x35, 0xec, 0xb7, 0xa3, 0xea, 0x15, 0x87, 0xf7, 0xb0, 0xd4,
+  0xae, 0xd8, 0x57, 0xfc, 0x6f, 0x0b, 0x66, 0x62, 0xec, 0x35, 0x0f, 0xf6,
+  0xf7, 0x6a, 0xb1, 0x9f, 0x1b, 0xc9, 0xcb, 0xa1, 0x97, 0x05, 0xa7, 0x69,
+  0x54, 0x93, 0xd7, 0xa3, 0xc9, 0x32, 0x6f, 0x4a, 0x3c, 0x71, 0x14, 0x74,
+  0x28, 0xb9, 0x4a, 0xbd, 0x8a, 0xd2, 0xc6, 0xde, 0xc7, 0xc2, 0x17, 0xf4,
+  0xa0, 0xee, 0x83, 0x17, 0x1a, 0x8e, 0x1d, 0x5f, 0x1b, 0xde, 0x21, 0x04,
+  0x04, 0x43, 0xb2, 0x69, 0xef, 0x92, 0x82, 0x3f, 0x65, 0xb8, 0x23, 0xbe,
+  0x89, 0x04, 0x87, 0xe8, 0x87, 0x47, 0x03, 0xa8, 0x34, 0xc4, 0x30, 0xf4,
+  0xc5, 0x0b, 0xf3, 0x59, 0x3a, 0x60, 0x4c, 0x5c, 0xe6, 0x31, 0x5c, 0x40,
+  0x11, 0xd6, 0xa4, 0xa9, 0x9d, 0xa8, 0x76, 0x20, 0x41, 0x0e, 0x41, 0x02,
+  0x1a, 0x22, 0x22, 0xe9, 0x76, 0x91, 0x53, 0x42, 0x5c, 0xbf, 0x27, 0x99,
+  0x98, 0x80, 0xac, 0xd6, 0xf7, 0xfa, 0x2d, 0x06, 0x12, 0x16, 0x9c, 0xd7,
+  0xf0, 0xf3, 0x5f, 0x8f, 0x26, 0x7e, 0x70, 0x34, 0x21, 0x6b, 0xf8, 0x12,
+  0x7f, 0xfc, 0x22, 0xaa, 0x08, 0x20, 0xbd, 0x44, 0x27, 0xdc, 0x24, 0xb1,
+  0xad, 0x42, 0x1e, 0xfd, 0x46, 0x56, 0xc3, 0x64, 0x4b, 0xcd, 0x4b, 0xc1,
+  0x6e, 0xab, 0x5d, 0x87, 0xe5, 0xa2, 0x2a, 0x51, 0x54, 0x28, 0xa2, 0x45,
+  0x9c, 0x91, 0x2d, 0x96, 0x70, 0xe1, 0x94, 0xa1, 0x98, 0xf9, 0x76, 0x05,
+  0xd6, 0x48, 0x52, 0xfe, 0x86, 0x4b, 0xf7, 0x33, 0x67, 0x3e, 0xd3, 0xe3,
+  0x7d, 0x90, 0xff, 0xcb, 0x09, 0x8b, 0xcf, 0xc4, 0xf4, 0x34, 0xbc, 0x68,
+  0x2d, 0xc2, 0xf8, 0x16, 0x31, 0x53, 0xe1, 0xe0, 0xb1, 0x5a, 0x6f, 0x59,
+  0xfc, 0xe0, 0x2c, 0x75, 0x54, 0xb5, 0xd7, 0xba, 0x1d, 0xec, 0x4b, 0x2c,
+  0x6d, 0x85, 0x5b, 0x6e, 0x7e, 0xad, 0xb4, 0xac, 0xe0, 0x8d, 0x7c, 0xfc,
+  0xe8, 0x71, 0x57, 0xa9, 0x66, 0x4d, 0x93, 0x6a, 0x6b, 0xe4, 0x6f, 0x5b,
+  0xe8, 0xcd, 0x41, 0xb4, 0x87, 0xd3, 0x30, 0xa1, 0x00, 0x75, 0x5c, 0x10,
+  0x40, 0x42, 0x4c, 0x0d, 0xcf, 0x48, 0x08, 0x41, 0xc1, 0x5d, 0x36, 0x94,
+  0x6b, 0x36, 0xcc, 0x59, 0x44, 0xa4, 0xa2, 0x44, 0x20, 0x78, 0xc1, 0x03,
+  0xe7, 0xd2, 0x28, 0xd5, 0x26, 0x6b, 0xb0, 0xab, 0x06, 0x52, 0xdc, 0x92,
+  0xc1, 0xa1, 0x81, 0x09, 0x3e, 0x49, 0x52, 0xc3, 0xb8, 0x95, 0xcf, 0xfe,
+  0x4e, 0x01, 0x30, 0xa5, 0x0c, 0x38, 0xfb, 0x6a, 0xa9, 0x2d, 0x1e, 0x23,
+  0x27, 0xbc, 0xaf, 0xc9, 0x78, 0x2f, 0x24, 0xe5, 0xbd, 0x36, 0x59, 0xbd,
+  0xc1, 0xda, 0xe5, 0x27, 0xe1, 0x3b, 0xb5, 0x37, 0x14, 0x37, 0x1b, 0x75,
+  0xa1, 0x36, 0xfb, 0x5b, 0x2e, 0x6e, 0x12, 0x90, 0xa2, 0xb2, 0xcd, 0x4d,
+  0x7b, 0x48, 0xec, 0x2c, 0x13, 0x2e, 0xf2, 0x36, 0x9b, 0x4e, 0xfc, 0x79,
+  0xb2, 0x6c, 0x25, 0xee, 0x6c, 0x5b, 0xec, 0x9e, 0xae, 0x2a, 0x65, 0xd1,
+  0x94, 0xbf, 0x1b, 0x8d, 0xcd, 0x93, 0xfb, 0xb0, 0x31, 0x2f, 0x3b, 0xb8,
+  0x06, 0x7f, 0xcb, 0x10, 0x74, 0xc6, 0xe0, 0x83, 0xd6, 0x5d, 0xb4, 0xa2,
+  0xf2, 0x72, 0x8a, 0x7b, 0x00, 0xe1, 0x67, 0x1a, 0x13, 0x04, 0x95, 0xc0,
+  0xc6, 0xdc, 0x77, 0x25, 0xe5, 0x0b, 0x87, 0x4e, 0xda, 0x96, 0x7a, 0x5d,
+  0x29, 0x95, 0x6e, 0xe3, 0xae, 0x56, 0x9c, 0x55, 0x12, 0xc6, 0x84, 0xa4,
+  0x68, 0x29, 0x27, 0x2b, 0xb6, 0x67, 0xf7, 0x80, 0xd4, 0x7c, 0x35, 0xfb,
+  0xd0, 0xe8, 0x1d, 0x75, 0x38, 0xbc, 0x7d, 0x54, 0x2c, 0xf3, 0xc9, 0x72,
+  0xd6, 0x09, 0xb3, 0xe0, 0x75, 0x61, 0x98, 0x81, 0xd6, 0x0f, 0x82, 0x5c,
+  0x42, 0xd4, 0xeb, 0xb3, 0x9d, 0x9a, 0x05, 0xdd, 0xf0, 0x09, 0x03, 0x44,
+  0xc2, 0xfe, 0x6e, 0x48, 0x3f, 0xd4, 0x5e, 0x43, 0x48, 0x2c, 0xf9, 0x5e,
+  0xfb, 0x0d, 0x37, 0x6f, 0x87, 0x16, 0x93, 0x05, 0xf0, 0xdd, 0xc1, 0x4e,
+  0xbb, 0xb8, 0xcb, 0xd1, 0x7b, 0xe3, 0xc4, 0x17, 0xd7, 0x4e, 0x49, 0x7d,
+  0xe5, 0xd1, 0x16, 0x5e, 0x72, 0x93, 0xb8, 0x0c, 0x57, 0x87, 0x58, 0x0f,
+  0x69, 0xfd, 0x0a, 0xb8, 0x72, 0xd5, 0x78, 0x0b, 0xc7, 0x15, 0x90, 0x96,
+  0x9e, 0x88, 0x39, 0x7d, 0xdf, 0x89, 0x9a, 0xc1, 0xf0, 0x76, 0x99, 0xe5,
+  0x4e, 0x8b, 0xbb, 0xdd, 0xd6, 0x12, 0x16, 0xb5, 0xa1, 0xb1, 0x24, 0x76,
+  0x79, 0x3a, 0x74, 0x01, 0xc2, 0xbb, 0x22, 0x82, 0x3b, 0xfc, 0x13, 0x5f,
+  0xbb, 0x7e, 0x4d, 0x6d, 0x76, 0x7e, 0x59, 0x85, 0x70, 0x3f, 0x84, 0x3d,
+  0xbe, 0x30, 0x8b, 0xe9, 0xdd, 0x5e, 0xeb, 0x10, 0x6c, 0x0c, 0x95, 0x41,
+  0xb0, 0xa1, 0xc5, 0x06, 0xb1, 0xd7, 0x1c, 0xc4, 0x63, 0xe5, 0xe1, 0xf9,
+  0xd5, 0xc6, 0x10, 0x9e, 0xe8, 0x10, 0x9e, 0x7c, 0xec, 0x2a, 0x84, 0x03,
+  0x78, 0xf2, 0x4b, 0x57, 0xa1, 0x75, 0x08, 0x4f, 0x39, 0xa0, 0x7e, 0x71,
+  0xf7, 0xb4, 0x25, 0xb3, 0xc7, 0x6c, 0x62, 0x60, 0x55, 0x40, 0x4b, 0x99,
+  0x4a, 0x31, 0x4e, 0xef, 0x32, 0xe7, 0x32, 0x84, 0x56, 0x50, 0x34, 0xf3,
+  0x1e, 0xa6, 0x93, 0x7a, 0xc5, 0x41, 0x1d, 0xb3, 0x07, 0xbe, 0x16, 0x14,
+  0x98, 0x2b, 0xfd, 0x85, 0x63, 0x8c, 0xfb, 0xda, 0x43, 0xad, 0xc8, 0xb4,
+  0x94, 0xc9, 0x5d, 0x13, 0xeb, 0x8c, 0x84, 0x47, 0x41, 0x34, 0xd3, 0x02,
+  0x3a, 0x19, 0xb7, 0xf5, 0xd4, 0x06, 0x95, 0x48, 0xe0, 0x69, 0x30, 0xdd,
+  0xe7, 0x32, 0xdd, 0xe7, 0xff, 0x37, 0x4d, 0xf7, 0xf9, 0xfa, 0xe9, 0x7e,
+  0x22, 0x56, 0x05, 0x60, 0x86, 0xf6, 0x47, 0x71, 0xbe, 0x16, 0x55, 0xd9,
+  0xc2, 0x25, 0x1d, 0xc0, 0x68, 0x25, 0xec, 0xbf, 0x10, 0x64, 0x26, 0xf9,
+  0x86, 0x9a, 0x59, 0xcf, 0x0a, 0x2a, 0x12, 0x3d, 0x43, 0x25, 0x15, 0x65,
+  0x3a, 0x66, 0x3e, 0xc7, 0xd5, 0x50, 0x5c, 0x9c, 0xef, 0x7f, 0x6f, 0x0f,
+  0x5a, 0x2b, 0x72, 0x1e, 0x35, 0x6b, 0x66, 0xf6, 0x22, 0x60, 0xea, 0x06,
+  0xa5, 0x37, 0x03, 0x84, 0x1b, 0x6a, 0xf7, 0xf8, 0xed, 0xb7, 0x27, 0x17,
+  0x67, 0x6f, 0xdf, 0x1c, 0xbf, 0x75, 0xd1, 0x36, 0x97, 0xa8, 0x3f, 0xd8,
+  0x66, 0x45, 0x6b, 0xab, 0xbb, 0x22, 0xf2, 0x2f, 0x4c, 0x39, 0x9c, 0x36,
+  0xbb, 0x58, 0xe8, 0x5f, 0x83, 0xb0, 0xb9, 0xe0, 0x21, 0x3b, 0x7e, 0x2c,
+  0x94, 0x2d, 0xd8, 0x37, 0x30, 0xe1, 0x18, 0xb7, 0x81, 0x84, 0x1e, 0xb9,
+  0xd2, 0xe9, 0x6c, 0x7b, 0x7b, 0x18, 0x27, 0x0b, 0x5b, 0x3f, 0x7f, 0x9f,
+  0x68, 0xe1, 0xc6, 0x20, 0x6a, 0xad, 0x32, 0x08, 0xbf, 0x79, 0x41, 0x83,
+  0x3f, 0x9a, 0xf1, 0x6a, 0x7f, 0x7b, 0xfb, 0x27, 0xe0, 0x00, 0x7e, 0xae,
+  0xf6, 0xcd, 0xe6, 0x95, 0x1c, 0x1a, 0x72, 0x7c, 0x6d, 0x10, 0xcb, 0xf3,
+  0x83, 0xc5, 0x6c, 0x23, 0xf0, 0x67, 0x0d, 0xdf, 0x93, 0x2e, 0xfd, 0xfd,
+  0x0f, 0xbf, 0x72, 0x17, 0xc3, 0x4a, 0x49, 0x8a, 0x5f, 0xbd, 0x8b, 0x8a,
+  0x76, 0x7d, 0x70, 0x7a, 0xfa, 0xab, 0x76, 0x00, 0x95, 0xc3, 0xdb, 0x0b,
+  0xfb, 0xce, 0x5e, 0x68, 0x49, 0x92, 0x0d, 0x65, 0xb6, 0xa2, 0x9d, 0xbc,
+  0x3d, 0xd3, 0xd1, 0x88, 0xb9, 0xa9, 0x6f, 0xd5, 0x5e, 0x26, 0xae, 0x92,
+  0x22, 0x0f, 0xac, 0x81, 0x53, 0x8d, 0x2f, 0x21, 0x3a, 0x39, 0xc0, 0x4e,
+  0xb3, 0xfa, 0x02, 0xb5, 0x0c, 0x29, 0x49, 0x99, 0xb3, 0x2d, 0x0a, 0x44,
+  0xa2, 0x19, 0xad, 0x5b, 0x0c, 0xc3, 0x0c, 0x42, 0xc1, 0x21, 0x5d, 0xa8,
+  0xbf, 0xcb, 0xe9, 0x5c, 0x4c, 0x74, 0x8a, 0xe6, 0x5c, 0x02, 0x20, 0x9f,
+  0x15, 0x01, 0x0c, 0x85, 0x4f, 0xd1, 0xf7, 0x27, 0x97, 0xd1, 0xe1, 0xd9,
+  0x91, 0x3f, 0xa2, 0x97, 0x12, 0xc8, 0x99, 0xa3, 0x64, 0xd2, 0x72, 0x4e,
+  0x4c, 0x8c, 0xd5, 0x85, 0xf4, 0x0a, 0x78, 0x68, 0x0e, 0x16, 0x1d, 0x31,
+  0x75, 0x66, 0x27, 0xa2, 0x05, 0x95, 0x82, 0x6f, 0xb9, 0x04, 0xca, 0x4d,
+  0x02, 0x2b, 0x42, 0x15, 0x24, 0xd8, 0x99, 0x6a, 0x39, 0x6e, 0x9a, 0xc1,
+  0x73, 0x88, 0xa5, 0x88, 0xd5, 0x81, 0xb8, 0x0b, 0x57, 0x6e, 0x9b, 0x8b,
+  0x35, 0x89, 0x84, 0xab, 0x03, 0xaf, 0x4b, 0x04, 0xa8, 0x68, 0x52, 0x08,
+  0x27, 0x47, 0x01, 0x00, 0x2d, 0x38, 0xfa, 0xc0, 0x08, 0xed, 0x18, 0x4d,
+  0x25, 0xee, 0x73, 0x57, 0xed, 0xfe, 0x73, 0x0f, 0xa8, 0xe1, 0x31, 0xaa,
+  0x60, 0x3a, 0xe0, 0x44, 0x89, 0x89, 0x25, 0x1d, 0x19, 0xc8, 0x98, 0x55,
+  0x49, 0x91, 0xe2, 0xd7, 0x8d, 0x1d, 0x77, 0x4d, 0xb8, 0x7e, 0xf6, 0x94,
+  0xda, 0x05, 0x49, 0x9e, 0xe5, 0x29, 0x71, 0x2f, 0xa5, 0x3f, 0x07, 0x47,
+  0xfa, 0x89, 0x0e, 0xe6, 0xe2, 0x94, 0x66, 0x3e, 0x15, 0x3b, 0xb8, 0xc6,
+  0x7c, 0xa3, 0x42, 0x0e, 0xbc, 0x27, 0xac, 0xef, 0x6a, 0xc1, 0x53, 0xff,
+  0xe6, 0x33, 0x33, 0xb7, 0x29, 0x29, 0x78, 0x24, 0x4f, 0xa5, 0x02, 0x71,
+  0xed, 0xaa, 0x32, 0xa9, 0x84, 0x2a, 0xc1, 0x62, 0x63, 0xb8, 0xcb, 0xc4,
+  0xb6, 0xdd, 0xac, 0x0d, 0x51, 0x8b, 0xc3, 0x79, 0x5e, 0xeb, 0xc7, 0xba,
+  0x41, 0x35, 0x72, 0x29, 0x82, 0x89, 0x2e, 0xea, 0x01, 0x57, 0xdc, 0x7c,
+  0xb3, 0xb5, 0x4f, 0xeb, 0x8b, 0xe2, 0xeb, 0xc6, 0x4b, 0x8b, 0xee, 0xc9,
+  0xcf, 0x1c, 0xb3, 0x88, 0xee, 0x13, 0xce, 0x89, 0xd2, 0x33, 0x89, 0x9a,
+  0x46, 0x36, 0x3b, 0x8b, 0x9f, 0x90, 0x54, 0x49, 0x00, 0x5d, 0x69, 0xbc,
+  0xe5, 0x58, 0xc7, 0xdb, 0xd0, 0x0f, 0xf3, 0x90, 0xa3, 0xbe, 0xf0, 0x9d,
+  0x44, 0x31, 0x5c, 0x54, 0x6c, 0xea, 0x9c, 0xa7, 0x6e, 0x13, 0xa4, 0x7d,
+  0xf9, 0x88, 0x3d, 0x7f, 0xc4, 0x99, 0x33, 0xf7, 0xb7, 0xbe, 0xd1, 0xc0,
+  0x29, 0xaa, 0x85, 0x41, 0xf1, 0x2a, 0x48, 0x35, 0xbe, 0xb0, 0x86, 0x1f,
+  0xa2, 0xe1, 0xe3, 0xb9, 0xfa, 0x2d, 0x04, 0xa8, 0x9d, 0xc1, 0xb9, 0xb3,
+  0x46, 0xcc, 0x69, 0x76, 0x55, 0xba, 0x0a, 0x41, 0xac, 0x52, 0x4f, 0x02,
+  0x84, 0x4b, 0x9c, 0x6a, 0xdf, 0x28, 0xce, 0x90, 0x69, 0xe7, 0x70, 0x20,
+  0x45, 0x0d, 0xf7, 0x5c, 0x50, 0xed, 0xd5, 0x9f, 0x89, 0xdd, 0xda, 0x62,
+  0x9f, 0x1f, 0x0c, 0x87, 0xb6, 0xd4, 0x40, 0x91, 0xb2, 0xf5, 0x94, 0x15,
+  0x54, 0xcf, 0x26, 0x32, 0xa6, 0x35, 0xa5, 0xb0, 0xc5, 0x90, 0xa1, 0x8d,
+  0xd4, 0xa2, 0x23, 0x76, 0x9f, 0xf8, 0x35, 0x77, 0x9d, 0x7d, 0x2b, 0xad,
+  0xf5, 0x3e, 0xb2, 0xb3, 0xd6, 0xbe, 0xbe, 0x6d, 0xe9, 0xeb, 0x69, 0x6d,
+  0x5e, 0x7b, 0x7b, 0x9f, 0x6a, 0x0a, 0x01, 0xad, 0xf5, 0x61, 0x85, 0x52,
+  0x94, 0x38, 0xd4, 0xd6, 0x40, 0x0f, 0xf6, 0x0d, 0x2d, 0x22, 0x69, 0xad,
+  0x96, 0x8d, 0xc1, 0x04, 0x5d, 0x3d, 0xf3, 0xd3, 0x22, 0xa9, 0x82, 0xdb,
+  0x63, 0xb3, 0x87, 0x1c, 0x93, 0xc6, 0xe9, 0x01, 0x36, 0x08, 0x1f, 0x95,
+  0x13, 0x1e, 0x19, 0xf1, 0xf1, 0x35, 0xf1, 0x26, 0x36, 0x8c, 0xa0, 0x9f,
+  0x4f, 0x5d, 0x3f, 0x6e, 0xe4, 0xac, 0x87, 0x4a, 0x5e, 0xfd, 0x20, 0xe4,
+  0x08, 0x4a, 0x23, 0x41, 0x44, 0x9a, 0x3a, 0x0a, 0x9a, 0x24, 0xab, 0x6f,
+  0xfb, 0x5e, 0xe4, 0xf8, 0x9d, 0x6b, 0x21, 0x3c, 0x01, 0x55, 0x41, 0x79,
+  0xb0, 0xb8, 0x82, 0x50, 0x22, 0xa5, 0xd2, 0x63, 0x6f, 0x5e, 0xcd, 0xc3,
+  0xd3, 0xbe, 0xfb, 0x22, 0x58, 0x13, 0x1b, 0x96, 0xd9, 0x1a, 0xb7, 0xed,
+  0xf8, 0x38, 0x16, 0x22, 0xd2, 0x1d, 0xff, 0x7d, 0x71, 0x7c, 0x79, 0xc1,
+  0x31, 0xad, 0x80, 0x59, 0xa9, 0x6b, 0xca, 0x74, 0xa6, 0xb6, 0x9c, 0x59,
+  0x5e, 0x0a, 0x75, 0x04, 0x5c, 0xd7, 0x53, 0xb2, 0x14, 0x23, 0xc6, 0x3d,
+  0xc3, 0x99, 0xd7, 0x95, 0xda, 0xc4, 0xbe, 0x4a, 0x90, 0xdc, 0x43, 0x3e,
+  0x42, 0x53, 0x4f, 0x86, 0x5b, 0x7f, 0x1f, 0xe7, 0x03, 0x34, 0x45, 0x61,
+  0x6b, 0x1a, 0x0a, 0x3f, 0x50, 0xd7, 0xbb, 0x8b, 0x4a, 0x91, 0x94, 0xa7,
+  0xd8, 0x3c, 0xc4, 0x1a, 0x50, 0xde, 0x30, 0x12, 0xb9, 0xce, 0xe9, 0x9a,
+  0x94, 0xc4, 0x55, 0xbb, 0x0e, 0x9d, 0x37, 0x50, 0xba, 0x94, 0x4f, 0x11,
+  0xa6, 0x0e, 0xb4, 0xad, 0xe8, 0xe9, 0xce, 0x4e, 0xb3, 0xb9, 0x78, 0x94,
+  0xdd, 0x99, 0x6b, 0x52, 0x93, 0x3e, 0xa4, 0xb4, 0x0f, 0xf6, 0x0b, 0x97,
+  0x29, 0x74, 0x8d, 0xfe, 0x15, 0xc9, 0xcc, 0xbc, 0x60, 0x66, 0x46, 0x08,
+  0x96, 0x4d, 0x0e, 0xe5, 0x77, 0x48, 0x42, 0xd1, 0x25, 0xab, 0x1e, 0x45,
+  0xc9, 0x4f, 0x31, 0x2c, 0xc1, 0xd8, 0x6a, 0x1a, 0x22, 0x91, 0x6d, 0x45,
+  0xb3, 0x9f, 0xb5, 0xcc, 0x53, 0x41, 0x72, 0x82, 0x6e, 0x9e, 0xb5, 0x10,
+  0x44, 0x34, 0xbc, 0x3c, 0xbb, 0x88, 0x82, 0x8a, 0xc4, 0x55, 0xae, 0x8b,
+  0x78, 0x06, 0x7e, 0xc2, 0x79, 0x67, 0x7b, 0x2d, 0xae, 0x03, 0x97, 0x24,
+  0x29, 0x41, 0x47, 0x9c, 0x6d, 0xef, 0x7b, 0x7d, 0xee, 0x1d, 0x5d, 0x3a,
+  0xb7, 0x6f, 0x49, 0x03, 0xe0, 0xac, 0x41, 0x83, 0x3b, 0xa3, 0xfb, 0x91,
+  0x04, 0xef, 0x59, 0x60, 0x7f, 0xd9, 0x93, 0x73, 0x76, 0xb6, 0x04, 0xad,
+  0x4b, 0xbe, 0x23, 0x93, 0x91, 0x66, 0x3e, 0xb2, 0xd9, 0x4a, 0x0d, 0x53,
+  0xce, 0x18, 0x58, 0x27, 0x45, 0x39, 0x43, 0x67, 0x1e, 0xd0, 0x4e, 0x2c,
+  0xff, 0x83, 0x9a, 0xd7, 0x0f, 0x9f, 0x23, 0x93, 0x4d, 0xdd, 0x28, 0x4a,
+  0x42, 0x5a, 0xbb, 0xa3, 0xbe, 0xd9, 0x63, 0x12, 0x05, 0x26, 0x5a, 0xc3,
+  0x57, 0xc2, 0xad, 0x9c, 0x6c, 0xe4, 0xc5, 0x8a, 0x1d, 0xbf, 0xce, 0xe7,
+  0x67, 0x17, 0x97, 0x56, 0xd0, 0x46, 0xef, 0x4d, 0x7c, 0x54, 0x3b, 0x41,
+  0xec, 0xac, 0x87, 0x04, 0x18, 0xd4, 0x36, 0x6f, 0xaf, 0x25, 0x2f, 0xe0,
+  0x7a, 0x68, 0x55, 0xdb, 0xe0, 0x42, 0x18, 0xf9, 0xca, 0x3c, 0x5f, 0xae,
+  0x5c, 0x0e, 0x58, 0x8e, 0xa6, 0xf2, 0x30, 0x7f, 0x6e, 0xf7, 0x63, 0xfa,
+  0x24, 0xd0, 0x27, 0xbb, 0x2d, 0xd4, 0xc1, 0x02, 0xf8, 0xc5, 0xf1, 0xf0,
+  0x52, 0x56, 0x8d, 0x7f, 0x6b, 0x8c, 0x5c, 0x52, 0x21, 0xf5, 0xc3, 0x56,
+  0xc7, 0x12, 0xa8, 0x83, 0x43, 0x64, 0x66, 0x5a, 0x67, 0xce, 0x79, 0x83,
+  0x82, 0x35, 0x7b, 0x12, 0x84, 0xf4, 0x81, 0x71, 0x2a, 0xad, 0x5c, 0x5a,
+  0xdd, 0xc1, 0xa8, 0xa3, 0x9d, 0x74, 0xe8, 0xca, 0x95, 0x43, 0x91, 0xe5,
+  0xb7, 0x41, 0x0b, 0x4f, 0x03, 0x66, 0xc1, 0xcc, 0x5d, 0x1b, 0x38, 0x31,
+  0xcb, 0x38, 0x7f, 0xe8, 0x9c, 0xcf, 0xd7, 0xc9, 0xdc, 0x08, 0x43, 0x9e,
+  0xf3, 0xed, 0x3c, 0x73, 0x79, 0xd1, 0x26, 0x1e, 0x05, 0x43, 0xe1, 0x8f,
+  0x2d, 0x1a, 0x1e, 0x8e, 0xc6, 0x1a, 0xd9, 0x3d, 0x79, 0xee, 0x56, 0x91,
+  0x45, 0x67, 0xe7, 0xda, 0x91, 0xe9, 0x07, 0x77, 0x11, 0xbb, 0xc6, 0xd2,
+  0xf9, 0x32, 0xd1, 0xa2, 0x1d, 0x71, 0x3e, 0x4d, 0x11, 0xca, 0x2a, 0xbe,
+  0x99, 0x86, 0x21, 0x5a, 0x23, 0x0c, 0x7d, 0x3f, 0x7a, 0x11, 0x91, 0x1a,
+  0xef, 0x77, 0x4b, 0x92, 0x0d, 0x71, 0x92, 0xbd, 0x8c, 0x47, 0x07, 0x77,
+  0xee, 0x6e, 0x8b, 0x41, 0x74, 0xce, 0x58, 0xae, 0x30, 0xb1, 0x17, 0xff,
+  0xe1, 0x5b, 0x93, 0xc3, 0xc2, 0x18, 0xe3, 0x7c, 0x7d, 0x42, 0x38, 0x4d,
+  0xb9, 0x08, 0x37, 0x3e, 0xe1, 0x5f, 0x03, 0x64, 0xc8, 0xc6, 0x94, 0x5f,
+  0xf8, 0x97, 0x0b, 0x9a, 0x08, 0xe9, 0x26, 0xf5, 0x47, 0x9e, 0x2a, 0x6d,
+  0x91, 0xe2, 0x82, 0x26, 0xb8, 0x03, 0xb0, 0x67, 0x3e, 0xd3, 0xbc, 0x25,
+  0x29, 0xc7, 0x37, 0xa2, 0x85, 0x2b, 0x7b, 0xc6, 0xc4, 0x58, 0x79, 0xce,
+  0x37, 0x25, 0x77, 0xc2, 0x81, 0xac, 0x13, 0x80, 0x2e, 0xe8, 0xdc, 0x70,
+  0xb9, 0x24, 0x6a, 0x6b, 0xce, 0x0c, 0x77, 0x6a, 0xbe, 0x73, 0x9f, 0xed,
+  0xc5, 0x3c, 0x73, 0x64, 0x87, 0xa7, 0xad, 0xf0, 0x78, 0x0d, 0x98, 0xf6,
+  0xa9, 0x50, 0xa3, 0x23, 0x1d, 0x77, 0x8d, 0x55, 0x46, 0xc7, 0x1d, 0xbb,
+  0x0c, 0x52, 0x6c, 0x37, 0xab, 0x96, 0x28, 0x05, 0x13, 0x34, 0xf5, 0xcc,
+  0x37, 0x75, 0xc5, 0x99, 0x7f, 0xae, 0x2d, 0xcf, 0x83, 0x3c, 0x14, 0x5b,
+  0xea, 0x1e, 0x53, 0x3d, 0x41, 0xae, 0xb2, 0x86, 0xa6, 0x50, 0xbd, 0x3f,
+  0x9e, 0x0a, 0x31, 0x5c, 0x66, 0x99, 0x94, 0xc5, 0x74, 0xb1, 0x7e, 0x03,
+  0x89, 0x22, 0x6c, 0x9a, 0xdd, 0x8b, 0x9e, 0xaa, 0x57, 0x5a, 0xb1, 0x8c,
+  0xbd, 0x06, 0x8d, 0x5a, 0xbb, 0xcb, 0x59, 0xa3, 0x5c, 0xce, 0xd3, 0xcf,
+  0x54, 0x7d, 0xbb, 0x9d, 0x73, 0xf1, 0xf8, 0xcb, 0xe3, 0xd3, 0xb7, 0xc7,
+  0x97, 0x0e, 0xb0, 0xc3, 0x26, 0x14, 0x3c, 0xff, 0x42, 0x0d, 0x5b, 0xaa,
+  0x5d, 0x19, 0x2e, 0x71, 0xdd, 0xfd, 0xfa, 0x6c, 0xd7, 0xd9, 0x76, 0x38,
+  0x72, 0xae, 0x5b, 0xc8, 0xf9, 0x0b, 0xe2, 0xe7, 0x50, 0xa6, 0xf8, 0xeb,
+  0xe8, 0xcd, 0xd1, 0x33, 0x0e, 0xe6, 0xbf, 0x4e, 0x72, 0x46, 0x46, 0xf7,
+  0xca, 0x4e, 0x16, 0x70, 0x82, 0x67, 0x7b, 0x01, 0x9e, 0x84, 0x5c, 0x66,
+  0xa9, 0x9e, 0x0f, 0x16, 0x63, 0x69, 0x85, 0x38, 0xff, 0x94, 0x14, 0x55,
+  0xb1, 0x06, 0x42, 0xb3, 0x16, 0x2b, 0xa3, 0x62, 0x87, 0x88, 0x6c, 0x50,
+  0xaf, 0x97, 0x5c, 0x65, 0x13, 0xcf, 0x9e, 0x78, 0x36, 0x91, 0xaf, 0x16,
+  0x8c, 0x7a, 0x26, 0x05, 0x95, 0x5b, 0x68, 0xf6, 0x99, 0xb0, 0xa6, 0x43,
+  0x39, 0x59, 0x2c, 0x2f, 0x36, 0x5f, 0xe3, 0x90, 0x24, 0x31, 0xb7, 0x05,
+  0xef, 0x3d, 0x0b, 0xf5, 0xb5, 0x42, 0x2b, 0xa9, 0xd2, 0xfa, 0xa1, 0x64,
+  0x00, 0xaa, 0x3f, 0xfb, 0x67, 0x9f, 0xbb, 0x67, 0xb9, 0x9e, 0x64, 0x3a,
+  0x57, 0x30, 0x9a, 0x47, 0xde, 0x50, 0x29, 0x53, 0x2e, 0x5f, 0x1f, 0x23,
+  0x23, 0xb2, 0x45, 0xb0, 0xf6, 0xc1, 0x2b, 0x2f, 0xaa, 0xea, 0x28, 0x70,
+  0x4e, 0x7d, 0x8d, 0x0b, 0x9e, 0x54, 0xba, 0xb8, 0x09, 0xc9, 0xff, 0xb9,
+  0xdc, 0x85, 0xe7, 0x1c, 0x0e, 0x59, 0xd9, 0x4f, 0x63, 0x33, 0x15, 0x14,
+  0x00, 0x3b, 0x4d, 0x42, 0x5d, 0x87, 0x07, 0xf6, 0x46, 0x9d, 0x34, 0xf9,
+  0xd1, 0xe0, 0xf2, 0x78, 0xbe, 0xab, 0x54, 0x49, 0x53, 0xce, 0xae, 0xe7,
+  0xa4, 0xe3, 0x4f, 0x9a, 0x65, 0x41, 0x83, 0xc7, 0xf7, 0xf4, 0x48, 0x4a,
+  0x45, 0x5d, 0xb0, 0x1d, 0xc6, 0x1f, 0xf6, 0x0f, 0x3c, 0x51, 0xaa, 0x15,
+  0x57, 0x9a, 0x14, 0x4b, 0x67, 0xe0, 0x67, 0xb6, 0x21, 0x26, 0x95, 0xd0,
+  0xfa, 0xe7, 0x4f, 0x55, 0xba, 0x31, 0x29, 0x94, 0x39, 0x3f, 0x2f, 0xc4,
+  0x94, 0xc1, 0x16, 0x1a, 0x8c, 0xf0, 0xb9, 0x5e, 0x2e, 0xba, 0x95, 0xa5,
+  0x95, 0xee, 0x56, 0x1e, 0x58, 0x20, 0xae, 0xf6, 0x3e, 0x9d, 0x6b, 0xfc,
+  0x77, 0xe3, 0xf5, 0xe7, 0x6b, 0xac, 0x1a, 0xea, 0x8b, 0x38, 0x06, 0x2d,
+  0x05, 0xcf, 0x7f, 0xea, 0x4e, 0x82, 0x03, 0xe9, 0xea, 0xb9, 0x38, 0x2f,
+  0x78, 0xb5, 0x0d, 0x4a, 0xd1, 0x0e, 0x12, 0xf4, 0xea, 0x85, 0xaf, 0x8a,
+  0xd1, 0xe6, 0xca, 0x73, 0xdd, 0x93, 0x4e, 0x1e, 0xa5, 0xc1, 0x31, 0x7e,
+  0x2e, 0x24, 0xf5, 0x1a, 0x9e, 0x64, 0x3b, 0x07, 0x1c, 0x8e, 0x1b, 0xa2,
+  0x5c, 0xfb, 0xa7, 0x5f, 0x28, 0x6d, 0xd8, 0x8d, 0x64, 0x82, 0xe0, 0xda,
+  0x37, 0x3e, 0xdd, 0x09, 0xc5, 0xc2, 0x09, 0xdb, 0xd2, 0x24, 0x9d, 0x7a,
+  0xed, 0x0b, 0x42, 0x19, 0x27, 0xc4, 0xa8, 0xaf, 0x89, 0xa8, 0xf1, 0x8c,
+  0x87, 0x11, 0xf0, 0x8f, 0xed, 0x55, 0xd9, 0x5a, 0x28, 0xa4, 0x44, 0x27,
+  0x47, 0xc1, 0x83, 0x4f, 0xfc, 0x04, 0xe3, 0x29, 0xdf, 0xb7, 0x2b, 0xd1,
+  0xf4, 0x0b, 0x05, 0x1a, 0x0f, 0x1e, 0x7d, 0xaa, 0x51, 0x98, 0x1c, 0x7f,
+  0x7b, 0x23, 0xeb, 0xdf, 0x78, 0x46, 0xc8, 0xe1, 0xd0, 0x15, 0x5e, 0x96,
+  0x70, 0xca, 0xa2, 0xed, 0x9a, 0xfd, 0xf4, 0xf9, 0x23, 0xcf, 0xea, 0xb5,
+  0x54, 0xb8, 0xcb, 0x34, 0x78, 0xef, 0xd3, 0xe6, 0x31, 0x37, 0xc1, 0xdb,
+  0xa2, 0x95, 0xf5, 0xa4, 0x45, 0x9b, 0x1c, 0x7c, 0xfd, 0x1f, 0x66, 0x5a,
+  0xc9, 0x39, 0x0a, 0xb3, 0xf8, 0x8f, 0x70, 0xbc, 0x9f, 0x85, 0x21, 0xcf,
+  0x62, 0x57, 0x71, 0x35, 0x19, 0x42, 0x68, 0x5c, 0x5f, 0xdd, 0x04, 0xab,
+  0x13, 0xb4, 0x20, 0x7b, 0x4e, 0x37, 0x75, 0x50, 0x27, 0x5a, 0x35, 0x2d,
+  0x4d, 0x51, 0xb7, 0x88, 0x27, 0x1d, 0xdd, 0xd7, 0xb4, 0xa9, 0xa0, 0x8e,
+  0xc0, 0x3a, 0xb5, 0x53, 0x3b, 0x06, 0xc5, 0xcd, 0x52, 0x54, 0x5b, 0x37,
+  0x23, 0x5f, 0xce, 0x3e, 0x78, 0x6d, 0xcf, 0x73, 0x2f, 0xbd, 0x58, 0x25,
+  0x0f, 0xe3, 0x90, 0xe1, 0x7f, 0x45, 0xff, 0x8d, 0x40, 0x8a, 0x7c, 0x15,
+  0xd3, 0x80, 0x50, 0x2b, 0xc6, 0x40, 0x0f, 0x36, 0xe3, 0xf6, 0xc4, 0x2c,
+  0x8d, 0xa3, 0x0e, 0xba, 0x51, 0xe1, 0x81, 0x1d, 0xb8, 0xb4, 0x4b, 0x37,
+  0xc9, 0xf8, 0xd6, 0x8e, 0x8c, 0x6b, 0xa3, 0xf9, 0xd6, 0xf7, 0xdf, 0x0b,
+  0xcf, 0x71, 0x90, 0x2f, 0x6a, 0x3d, 0x75, 0x80, 0xe6, 0x74, 0x46, 0x05,
+  0x46, 0x9c, 0xb7, 0x1b, 0xc5, 0xac, 0xf3, 0x64, 0x9a, 0x30, 0x70, 0x98,
+  0x48, 0xa6, 0x58, 0xe8, 0xb6, 0xe0, 0x47, 0x8e, 0x08, 0x91, 0x52, 0x3c,
+  0x89, 0x82, 0xcb, 0xcd, 0xd9, 0x7f, 0xad, 0x06, 0x0a, 0x1a, 0xc1, 0xc1,
+  0xbb, 0xcb, 0xaf, 0xcf, 0x2e, 0x86, 0xd1, 0x36, 0xe7, 0x49, 0x5f, 0x5e,
+  0x9c, 0x7c, 0xf9, 0x8e, 0x14, 0x3e, 0x67, 0x79, 0x3e, 0x8a, 0x49, 0x11,
+  0x9c, 0x72, 0xa8, 0x46, 0x32, 0x1f, 0x25, 0xf9, 0xb5, 0x01, 0x8f, 0x03,
+  0xd9, 0x84, 0x79, 0x77, 0x96, 0xfb, 0x2a, 0x1d, 0x52, 0x08, 0xdb, 0x2c,
+  0xeb, 0x08, 0xff, 0x4a, 0xe9, 0xbb, 0xcc, 0x6b, 0x33, 0x69, 0x35, 0xf7,
+  0xdd, 0x57, 0x5f, 0xbf, 0xfc, 0xfa, 0xe0, 0xed, 0x37, 0x43, 0x43, 0xb7,
+  0xfb, 0xee, 0xbb, 0xef, 0x42, 0xc7, 0xcb, 0xfe, 0xf6, 0x36, 0xf0, 0xcc,
+  0x6e, 0xe2, 0x87, 0x87, 0x41, 0x91, 0x6c, 0x6c, 0xd0, 0x39, 0xda, 0xf0,
+  0xb9, 0x04, 0x0a, 0x79, 0x5c, 0x2c, 0xe9, 0xa6, 0xa3, 0xaf, 0xb7, 0x17,
+  0xcb, 0x11, 0x43, 0x2c, 0x6f, 0x2f, 0x4b, 0x2d, 0x28, 0x81, 0xb7, 0xb7,
+  0x37, 0x36, 0x86, 0xc7, 0xc7, 0xd1, 0xc1, 0xe9, 0xf0, 0x2c, 0x78, 0x77,
+  0x73, 0x77, 0x8b, 0x24, 0x81, 0xeb, 0xa4, 0xa4, 0x5f, 0x36, 0x36, 0x4e,
+  0x0f, 0x2e, 0x59, 0xc9, 0xf9, 0xf6, 0xf8, 0x62, 0x78, 0x72, 0xf6, 0x96,
+  0x77, 0x87, 0x81, 0x20, 0xe2, 0xe9, 0x3d, 0x63, 0x6f, 0x5d, 0xa5, 0xc8,
+  0xd3, 0xbc, 0xb7, 0x52, 0x0e, 0x0c, 0x6e, 0x42, 0xa2, 0x8a, 0xc8, 0x6e,
+  0xe2, 0x58, 0xb2, 0x3a, 0x3f, 0x12, 0x13, 0x50, 0xb2, 0xaa, 0x61, 0xde,
+  0xc7, 0x8d, 0xc8, 0x1b, 0x3a, 0x04, 0xea, 0x3d, 0x19, 0x49, 0xc8, 0x4c,
+  0x4f, 0x10, 0x08, 0x10, 0xac, 0x1e, 0x40, 0x24, 0xb4, 0x4e, 0x7c, 0x78,
+  0xf2, 0xe6, 0x9c, 0x64, 0xfe, 0x77, 0xc3, 0x83, 0xaf, 0x8e, 0xf9, 0xd1,
+  0xaf, 0x92, 0xd2, 0x6f, 0x87, 0x94, 0x9c, 0xe0, 0x4e, 0xde, 0x26, 0x65,
+  0x31, 0x8e, 0x17, 0x1c, 0x77, 0x4e, 0xdd, 0xf4, 0x85, 0x2f, 0x06, 0x6d,
+  0x8b, 0xf4, 0xe7, 0xc1, 0xa8, 0xe7, 0xfa, 0x3c, 0x90, 0xa2, 0xc3, 0x76,
+  0x2f, 0x8e, 0x0f, 0x8e, 0xde, 0x1c, 0x5b, 0x40, 0x95, 0xdc, 0x23, 0xd4,
+  0xe8, 0x4d, 0xc6, 0xd5, 0x6b, 0x9c, 0xe9, 0x93, 0xef, 0x2a, 0x5e, 0x7c,
+  0xfa, 0x86, 0x4b, 0x32, 0xb4, 0x77, 0xe7, 0x37, 0x0a, 0xcf, 0x0e, 0xae,
+  0xd2, 0x6d, 0x69, 0xdd, 0xfa, 0x8b, 0xdd, 0x92, 0x58, 0x64, 0x92, 0xca,
+  0x6f, 0xa2, 0xc6, 0x42, 0xfd, 0xfd, 0x6c, 0x67, 0x67, 0xe7, 0x91, 0x79,
+  0xc0, 0xd0, 0xa8, 0xb7, 0x00, 0x4d, 0x65, 0x9f, 0x1f, 0xdf, 0xf6, 0xed,
+  0x1b, 0x65, 0x86, 0x66, 0x5b, 0xfe, 0x73, 0x2e, 0x8a, 0x77, 0x5a, 0x26,
+  0xed, 0x83, 0x1e, 0x67, 0x99, 0xdb, 0x83, 0xca, 0xf2, 0x4c, 0x18, 0xe7,
+  0x26, 0x2d, 0x03, 0x9c, 0x34, 0x1b, 0xfa, 0x24, 0x05, 0xfb, 0x89, 0xf3,
+  0x55, 0xbd, 0x49, 0xfe, 0x86, 0xda, 0xe4, 0x1f, 0x83, 0x2c, 0xbf, 0xde,
+  0x9e, 0xed, 0xe3, 0x92, 0xa5, 0x87, 0x5e, 0x27, 0xa8, 0xfb, 0x73, 0x9f,
+  0xb9, 0xd0, 0xa3, 0x82, 0x97, 0x96, 0xa3, 0x1c, 0x3f, 0x62, 0x5c, 0xbf,
+  0x60, 0x1d, 0xb0, 0x9d, 0x5c, 0x5f, 0x56, 0x66, 0x6e, 0xe1, 0x18, 0x2d,
+  0x9d, 0x14, 0xbc, 0x65, 0x6c, 0x66, 0x1a, 0x10, 0x0b, 0xa1, 0x5e, 0xe8,
+  0x73, 0x21, 0x12, 0xfa, 0x35, 0x27, 0xa2, 0x19, 0x94, 0x0f, 0x25, 0xbf,
+  0xc5, 0xce, 0x5a, 0xb5, 0x16, 0x03, 0xb6, 0x8a, 0x58, 0x56, 0x9e, 0x91,
+  0x8c, 0x1e, 0x4b, 0xfa, 0xcd, 0x10, 0x61, 0xed, 0x41, 0x34, 0x1a, 0x42,
+  0xdd, 0xb9, 0xe1, 0x7a, 0x9f, 0xfd, 0x3e, 0x28, 0xa8, 0x70, 0xf4, 0xf2,
+  0x11, 0x9d, 0x07, 0x93, 0x92, 0xd5, 0x9f, 0xeb, 0xc5, 0x11, 0x50, 0xcf,
+  0x90, 0x46, 0xd1, 0xe8, 0x0b, 0x20, 0x4b, 0x39, 0x82, 0xde, 0x0a, 0xe9,
+  0x0e, 0x45, 0x6b, 0x06, 0x89, 0x14, 0xaa, 0x42, 0x5f, 0xb4, 0x27, 0xdb,
+  0x88, 0xc6, 0xf9, 0xe8, 0x9e, 0x0e, 0xcf, 0x5d, 0x0d, 0x1c, 0x5a, 0x81,
+  0x3b, 0x5e, 0x82, 0xdb, 0x04, 0xb3, 0x0f, 0x65, 0xdd, 0x47, 0x06, 0xb3,
+  0x4f, 0xab, 0xc0, 0x6f, 0xfc, 0xf7, 0xf6, 0xa0, 0x28, 0x6e, 0xb6, 0xd3,
+  0xc9, 0xfb, 0x49, 0x11, 0xd3, 0x67, 0xc4, 0xd7, 0x1a, 0x1f, 0x0f, 0xe8,
+  0xc3, 0xe8, 0x2f, 0x15, 0xbe, 0x5f, 0x8c, 0xdb, 0x67, 0xf2, 0xdf, 0xdb,
+  0x0c, 0xfe, 0x05, 0x80, 0xe2, 0x60, 0xe1, 0x5a, 0xb8, 0x07, 0xcd, 0x4a,
+  0x70, 0xe6, 0xe8, 0x38, 0xb6, 0x53, 0x46, 0xff, 0x3a, 0xea, 0x28, 0xb9,
+  0xfd, 0xb8, 0xb7, 0xb3, 0xb3, 0xbb, 0xbf, 0xfb, 0xd9, 0x8b, 0x9d, 0xfd,
+  0xdd, 0xdd, 0xdd, 0xbd, 0xfd, 0xdd, 0xfd, 0xfd, 0xbd, 0x9d, 0x9f, 0xb6,
+  0x3b, 0x1b, 0x1b, 0x47, 0x67, 0xdf, 0xbd, 0x3d, 0x3d, 0x3b, 0x38, 0x8a,
+  0x2e, 0xcf, 0x48, 0xdf, 0x65, 0x5b, 0x45, 0xcb, 0x49, 0x07, 0xea, 0x53,
+  0x99, 0xc9, 0xcd, 0x16, 0x07, 0x25, 0x3a, 0x1a, 0x5d, 0x66, 0x10, 0x8a,
+  0xf9, 0xa5, 0xc1, 0x4d, 0x39, 0xfb, 0x30, 0xfb, 0xfa, 0x98, 0x4e, 0x7a,
+  0x12, 0x15, 0xe6, 0xf5, 0x1e, 0x6c, 0xad, 0x11, 0xa9, 0x42, 0x99, 0xba,
+  0xa2, 0xe3, 0x70, 0xb2, 0xb9, 0xa8, 0xc0, 0x4d, 0x71, 0x4d, 0xfb, 0xb8,
+  0x49, 0x29, 0x4e, 0x52, 0x54, 0x03, 0x1a, 0x5c, 0xb1, 0x00, 0xf5, 0x5b,
+  0x4a, 0x61, 0x76, 0x92, 0x07, 0xb6, 0x1a, 0x13, 0x3c, 0x5b, 0x3b, 0x25,
+  0xba, 0x78, 0x92, 0x07, 0xcc, 0xba, 0xca, 0x26, 0x04, 0xc9, 0xcc, 0xcf,
+  0x0e, 0x08, 0x46, 0xa6, 0xc9, 0xa5, 0xb9, 0x0d, 0x19, 0xee, 0xeb, 0x96,
+  0xee, 0xb8, 0x1f, 0xe3, 0x1e, 0xbe, 0x0b, 0xfe, 0x26, 0xbc, 0x74, 0xb6,
+  0x9d, 0xf9, 0x49, 0x06, 0xf0, 0x6e, 0x78, 0xf2, 0xf6, 0x2b, 0xf8, 0x97,
+  0xbe, 0x3b, 0xbb, 0x38, 0x1a, 0x52, 0xb3, 0x7c, 0x1b, 0x6f, 0xc0, 0x02,
+  0xc1, 0x87, 0x56, 0x47, 0x25, 0x47, 0x80, 0xbb, 0xfe, 0x13, 0x34, 0x8e,
+  0x49, 0xcf, 0xa5, 0x1e, 0x60, 0x98, 0x81, 0xb4, 0xc8, 0x29, 0x05, 0xed,
+  0x0c, 0x0e, 0xa7, 0x41, 0x5e, 0xff, 0x62, 0x16, 0x33, 0x18, 0x6c, 0x32,
+  0x10, 0x54, 0x35, 0x44, 0x12, 0x6c, 0x33, 0xac, 0xca, 0x36, 0x4b, 0xad,
+  0xdb, 0x65, 0x06, 0x56, 0x81, 0x56, 0xb2, 0xdc, 0x01, 0xe8, 0x56, 0x56,
+  0x84, 0xcf, 0xd8, 0xd5, 0x34, 0xbe, 0x46, 0x87, 0xcd, 0xe3, 0x17, 0x74,
+  0xa6, 0xdd, 0x7f, 0x6c, 0x97, 0xa8, 0xd9, 0xc7, 0xed, 0x9d, 0x80, 0x00,
+  0x90, 0xed, 0x8e, 0x3c, 0x09, 0x35, 0x8c, 0x8b, 0x84, 0x84, 0x1a, 0x33,
+  0xec, 0x62, 0xe7, 0x42, 0x18, 0x75, 0xa4, 0x5f, 0x2d, 0x50, 0xb9, 0x21,
+  0x46, 0x85, 0x7e, 0x90, 0x16, 0x25, 0x92, 0x3d, 0x2a, 0xc9, 0x79, 0x05,
+  0xba, 0x40, 0x3c, 0x3c, 0xfa, 0x44, 0xa2, 0x17, 0xf4, 0x45, 0x59, 0x72,
+  0x1e, 0x0c, 0x8d, 0x3d, 0x92, 0x88, 0x18, 0xce, 0xfd, 0x51, 0x91, 0xad,
+  0xc3, 0x30, 0xcb, 0xe9, 0x38, 0x2d, 0x3b, 0x96, 0x64, 0xe4, 0x81, 0xb7,
+  0xbc, 0x03, 0xac, 0x28, 0x69, 0x28, 0x31, 0xdd, 0x1e, 0x5a, 0x75, 0x44,
+  0x93, 0x6e, 0xb3, 0xd9, 0x4c, 0xb2, 0x31, 0x3b, 0x9c, 0x80, 0xe2, 0x5b,
+  0x49, 0x35, 0x97, 0xca, 0xd5, 0xd5, 0x60, 0x3e, 0xcb, 0xbd, 0x4b, 0xfa,
+  0x87, 0x44, 0xe3, 0x1b, 0x4b, 0xf7, 0x76, 0x1f, 0x66, 0xc7, 0x24, 0x71,
+  0x12, 0xaf, 0x14, 0xca, 0xd1, 0x98, 0xfe, 0x00, 0xd9, 0xbf, 0xb2, 0x6c,
+  0x61, 0xf5, 0x92, 0x06, 0x57, 0xad, 0xa6, 0x86, 0x6c, 0x20, 0x10, 0xd8,
+  0x25, 0x33, 0x05, 0xcb, 0xa3, 0x05, 0xf5, 0xdc, 0xab, 0xbc, 0x17, 0x69,
+  0x59, 0x24, 0xd3, 0x2b, 0x2d, 0x42, 0xa7, 0x75, 0xdf, 0x46, 0xab, 0xa0,
+  0x01, 0x99, 0x84, 0xc4, 0xff, 0x2e, 0xe7, 0x2e, 0x23, 0x26, 0x53, 0x9e,
+  0x71, 0x0d, 0xc6, 0xa9, 0x08, 0xde, 0x55, 0x46, 0x21, 0x9e, 0x99, 0x81,
+  0x41, 0xdc, 0x6e, 0x44, 0x0e, 0xa0, 0xb7, 0x36, 0x05, 0x87, 0x06, 0x07,
+  0x48, 0x2e, 0x50, 0x47, 0xf0, 0xe0, 0x72, 0x44, 0xab, 0xed, 0x9e, 0xe3,
+  0xb5, 0x63, 0x1b, 0x37, 0x56, 0xed, 0x30, 0x2c, 0xab, 0x22, 0x30, 0x84,
+  0x06, 0xe7, 0xe7, 0x07, 0x45, 0x03, 0x84, 0x51, 0x9c, 0x0e, 0x1a, 0x82,
+  0x55, 0x97, 0x85, 0x5b, 0x51, 0xa0, 0x78, 0xc7, 0xae, 0x78, 0x50, 0xdb,
+  0x31, 0x54, 0x8e, 0xb4, 0xfe, 0x1c, 0x7e, 0xf8, 0x08, 0x36, 0x87, 0x64,
+  0x42, 0xff, 0x74, 0x25, 0xa7, 0x24, 0x9d, 0x3f, 0x7e, 0x18, 0x75, 0x10,
+  0x1f, 0xd5, 0x31, 0xe6, 0xaa, 0x79, 0x49, 0xb0, 0x86, 0xfa, 0x28, 0x19,
+  0x71, 0xc0, 0x22, 0xd2, 0xbe, 0x05, 0xed, 0xb3, 0x02, 0xe7, 0x88, 0x83,
+  0x20, 0x61, 0xbe, 0xfb, 0xd1, 0x97, 0x71, 0x91, 0x8e, 0x7b, 0xd1, 0x51,
+  0x4a, 0xb2, 0x7a, 0xd9, 0xf3, 0x98, 0x8c, 0x0e, 0xc9, 0x72, 0x10, 0x7d,
+  0x67, 0xd5, 0x41, 0xe9, 0xce, 0x45, 0xec, 0x29, 0x4c, 0x8b, 0x2e, 0x51,
+  0x6d, 0x43, 0x6c, 0xb6, 0x6a, 0x75, 0x0d, 0x93, 0xc2, 0xd0, 0xb6, 0x87,
+  0x9b, 0xc3, 0x66, 0xc6, 0xc5, 0x6d, 0x15, 0x68, 0x5d, 0xa4, 0xaa, 0x82,
+  0x6d, 0x87, 0x2c, 0x02, 0x61, 0x7d, 0xe7, 0x5a, 0xe8, 0x42, 0x69, 0x2e,
+  0x9b, 0x5b, 0x80, 0x92, 0x77, 0xa4, 0xaa, 0x2d, 0xa7, 0xd0, 0xb0, 0x19,
+  0xf3, 0xf4, 0xe2, 0x36, 0xb2, 0xe3, 0xba, 0x81, 0xd0, 0x72, 0x5a, 0x27,
+  0x5e, 0x11, 0xe5, 0x27, 0x67, 0x97, 0xc7, 0xbf, 0x8b, 0x86, 0x29, 0xd7,
+  0x59, 0x74, 0x94, 0xc3, 0x87, 0x9c, 0x9d, 0xdd, 0xea, 0x85, 0x6a, 0xec,
+  0xa9, 0x4b, 0x53, 0x55, 0xb3, 0xa0, 0xe5, 0x42, 0x48, 0xf9, 0x9c, 0x7b,
+  0x29, 0x5f, 0xce, 0x2b, 0x03, 0x9a, 0xbd, 0x4b, 0xe3, 0xc8, 0x15, 0xb0,
+  0xe6, 0xb9, 0xbf, 0x67, 0xd2, 0x7f, 0xef, 0x21, 0xc6, 0x97, 0xfa, 0x22,
+  0x00, 0xe0, 0xb8, 0x1d, 0xb5, 0x09, 0xc0, 0x96, 0x32, 0x4e, 0x73, 0xba,
+  0x82, 0x99, 0x4f, 0x8d, 0xc5, 0x0c, 0x88, 0x18, 0x37, 0x8c, 0x9d, 0xcd,
+  0x1c, 0xf1, 0x88, 0xe8, 0x0a, 0xcb, 0x35, 0x46, 0x3a, 0x9c, 0xc0, 0x83,
+  0xab, 0x69, 0xd1, 0xce, 0x5d, 0xc8, 0x4a, 0x91, 0x10, 0x8a, 0xb4, 0x3a,
+  0x54, 0xe8, 0x50, 0x08, 0xc2, 0x0d, 0xc4, 0x8d, 0x51, 0xab, 0x90, 0x25,
+  0xe6, 0xee, 0x66, 0x0b, 0x64, 0x3b, 0x0e, 0xeb, 0x61, 0x3a, 0x9d, 0x44,
+  0xb3, 0x95, 0xa6, 0x3c, 0x2b, 0x1f, 0xe6, 0x1c, 0x1d, 0xa8, 0x2b, 0x9f,
+  0x7d, 0xd6, 0xb8, 0x77, 0x1f, 0xdc, 0xd3, 0xfb, 0xf4, 0x75, 0xa0, 0x16,
+  0x4d, 0xd9, 0xe7, 0x68, 0xa5, 0x80, 0xbc, 0x6e, 0xd4, 0x90, 0x39, 0xc3,
+  0x34, 0x46, 0xe9, 0xd0, 0xd9, 0x0f, 0x5b, 0xf6, 0xc5, 0x55, 0x3b, 0xda,
+  0x10, 0xa1, 0x5b, 0xc6, 0x19, 0x17, 0xe2, 0xb9, 0x5e, 0x23, 0x85, 0xda,
+  0xc9, 0xab, 0x0f, 0x36, 0x10, 0x50, 0x48, 0x48, 0x1a, 0xb0, 0x4c, 0xc3,
+  0xf2, 0xd6, 0x30, 0xd3, 0x86, 0x39, 0xe7, 0x44, 0x07, 0xe3, 0x30, 0x0b,
+  0xab, 0x67, 0x6d, 0xe0, 0x20, 0xf3, 0xdd, 0x8d, 0xd1, 0x7f, 0xb7, 0x7e,
+  0x38, 0xef, 0xfe, 0x99, 0xe1, 0x1c, 0x44, 0x8f, 0x06, 0xfb, 0x69, 0xfd,
+  0x03, 0x66, 0x22, 0x85, 0x9e, 0xd4, 0x49, 0x06, 0x83, 0x90, 0xd1, 0x9f,
+  0xac, 0xd1, 0x98, 0x9d, 0x00, 0xa3, 0x2a, 0xd6, 0x64, 0x53, 0x5d, 0x99,
+  0x67, 0xf2, 0x34, 0xe4, 0x47, 0x6e, 0xbf, 0x67, 0x43, 0xf9, 0xd8, 0xe1,
+  0x5a, 0x9e, 0xbb, 0x45, 0xab, 0xfa, 0xfe, 0x24, 0x03, 0x4b, 0x5a, 0x08,
+  0x62, 0xfe, 0x05, 0x81, 0x5c, 0x9e, 0x67, 0xec, 0xf1, 0x07, 0x04, 0x6e,
+  0xd0, 0x60, 0x7d, 0x09, 0x39, 0x9e, 0x09, 0x32, 0xa3, 0x6a, 0xaf, 0xe9,
+  0x67, 0xbb, 0x02, 0xd7, 0x44, 0xec, 0x51, 0xb1, 0xf1, 0x48, 0xcf, 0xa4,
+  0xcb, 0x6a, 0x81, 0xf0, 0xc3, 0x6a, 0xb9, 0x2e, 0xb9, 0x57, 0xa4, 0xe8,
+  0x3c, 0x56, 0x2e, 0xa8, 0x65, 0x8d, 0xc2, 0x5f, 0x32, 0x46, 0xa9, 0x6b,
+  0xac, 0xe5, 0x50, 0xa4, 0xc8, 0x2a, 0xee, 0xf9, 0x24, 0x91, 0x96, 0xca,
+  0xb5, 0x61, 0xc0, 0x87, 0x01, 0xe3, 0x15, 0x72, 0x06, 0xfb, 0x8e, 0xae,
+  0x96, 0x39, 0xc2, 0x33, 0x34, 0x1b, 0x5d, 0x93, 0x09, 0xa9, 0xd1, 0x8b,
+  0x83, 0xb7, 0x5f, 0x1d, 0xe3, 0xbc, 0x33, 0xdb, 0xf5, 0xa9, 0xb3, 0x9c,
+  0x1b, 0xd7, 0x87, 0xb3, 0xb8, 0x10, 0xb0, 0x8e, 0x94, 0xdf, 0x98, 0x2c,
+  0xc7, 0xec, 0xa7, 0x7e, 0xa7, 0xc7, 0x20, 0x2d, 0x80, 0xd3, 0x39, 0x4d,
+  0x79, 0x10, 0xcc, 0x72, 0xd5, 0x25, 0xbc, 0x11, 0x99, 0x7a, 0x0a, 0x8e,
+  0xc1, 0x22, 0x0d, 0xad, 0x10, 0x74, 0xd9, 0x62, 0x39, 0x5a, 0xc4, 0x9a,
+  0xa2, 0x15, 0x87, 0x59, 0x3f, 0xaa, 0x09, 0x0c, 0x2a, 0x53, 0xe0, 0xbb,
+  0x43, 0x02, 0x22, 0x9d, 0xd4, 0x99, 0x43, 0xea, 0x1c, 0x84, 0x1a, 0x97,
+  0xe0, 0x23, 0xed, 0xee, 0xec, 0x78, 0xcc, 0x1d, 0x9f, 0xbd, 0xd4, 0x20,
+  0xb2, 0x3c, 0xda, 0xe9, 0xbf, 0x78, 0xb1, 0x8e, 0x7e, 0x5c, 0xa3, 0xc8,
+  0x42, 0x79, 0xf6, 0xd1, 0x6d, 0xf6, 0xf9, 0xd1, 0x75, 0x6d, 0xb6, 0xc8,
+  0x16, 0x28, 0xd3, 0xa1, 0xee, 0xf8, 0xc2, 0xc5, 0x7c, 0xa8, 0x0e, 0x22,
+  0xb6, 0x2f, 0xd8, 0x22, 0xe7, 0x4e, 0xc0, 0xe0, 0xa5, 0xdc, 0x88, 0x9c,
+  0x24, 0x00, 0x08, 0x29, 0x53, 0x57, 0x16, 0xec, 0x91, 0x4f, 0x9d, 0x89,
+  0xf6, 0xa3, 0x16, 0x26, 0x10, 0x31, 0xd7, 0x2c, 0xd1, 0x55, 0x73, 0x36,
+  0xc6, 0x48, 0xdf, 0x9d, 0xb3, 0x32, 0x4a, 0xba, 0x8b, 0x08, 0xec, 0x24,
+  0x7d, 0xc2, 0x30, 0xb1, 0x5d, 0x93, 0x45, 0xdf, 0x69, 0x01, 0x3b, 0x2e,
+  0x3e, 0xc0, 0xbe, 0x19, 0x81, 0x2c, 0x4e, 0xe7, 0x5a, 0x49, 0xce, 0xed,
+  0xfe, 0x1a, 0xc5, 0xf8, 0x32, 0xea, 0x07, 0x2c, 0x5d, 0x51, 0x78, 0x98,
+  0x9f, 0xcf, 0x56, 0x26, 0xa3, 0x68, 0x0f, 0x68, 0xdd, 0x0c, 0x5d, 0x95,
+  0x8a, 0xbe, 0x3d, 0x15, 0x2c, 0x41, 0x41, 0x0d, 0x96, 0xde, 0xd2, 0xa5,
+  0x74, 0x83, 0x2b, 0xa2, 0xc6, 0xc0, 0x3f, 0x6e, 0x28, 0x71, 0x4b, 0x6d,
+  0x4e, 0x93, 0x62, 0x53, 0xce, 0x7f, 0x54, 0xed, 0xa4, 0xae, 0x28, 0x2b,
+  0x64, 0x23, 0x3f, 0x88, 0xf3, 0x93, 0xfd, 0xeb, 0x63, 0x7b, 0x64, 0x54,
+  0x7c, 0x38, 0xad, 0xe6, 0x7a, 0x6d, 0x94, 0xad, 0x06, 0x83, 0x4b, 0x79,
+  0x5f, 0xba, 0x8e, 0xdb, 0xbb, 0x93, 0xf7, 0x6d, 0x39, 0x5a, 0x88, 0x9e,
+  0xaf, 0x7d, 0x45, 0x66, 0x72, 0xd1, 0xde, 0x86, 0x23, 0xc1, 0xda, 0x09,
+  0xb8, 0x45, 0x5a, 0xe5, 0xe0, 0x1b, 0x91, 0xe6, 0x4c, 0x00, 0xb7, 0x89,
+  0xe9, 0x06, 0x40, 0xb3, 0xe0, 0x6d, 0xb7, 0x88, 0xa6, 0xb8, 0x52, 0x74,
+  0x0a, 0x14, 0x26, 0x39, 0x41, 0x26, 0x0a, 0xbb, 0x4c, 0x3c, 0xd8, 0x47,
+  0xbe, 0x9c, 0xcb, 0x2c, 0xe0, 0x70, 0xa0, 0xc1, 0xc7, 0xc5, 0x0d, 0x9c,
+  0xec, 0x4e, 0x41, 0x6a, 0xde, 0x44, 0x21, 0x60, 0x05, 0x5d, 0x3d, 0x72,
+  0xef, 0x80, 0xab, 0x56, 0x96, 0xa2, 0xba, 0x02, 0x81, 0x3e, 0xf1, 0xb1,
+  0x94, 0xcf, 0x2c, 0xa3, 0xd5, 0x58, 0x0a, 0xe2, 0x6f, 0x94, 0x38, 0xac,
+  0x91, 0x5c, 0x55, 0x1f, 0x93, 0xb6, 0x44, 0x94, 0x81, 0xfa, 0x83, 0xba,
+  0x70, 0x48, 0xaf, 0xad, 0x2d, 0x21, 0x64, 0x59, 0x80, 0x16, 0x48, 0xba,
+  0xad, 0xb1, 0x59, 0xcd, 0x22, 0x81, 0x12, 0xea, 0xa1, 0x6e, 0x34, 0xef,
+  0x86, 0x31, 0xf1, 0x25, 0xc8, 0x0f, 0x16, 0x7c, 0x46, 0x22, 0xcf, 0xa4,
+  0x4f, 0xcc, 0x50, 0x06, 0x28, 0x49, 0x2d, 0x12, 0x58, 0x35, 0xbc, 0x74,
+  0xa5, 0xca, 0x4d, 0x0e, 0xfc, 0xf6, 0xf8, 0xe2, 0xcb, 0xb3, 0xe1, 0x31,
+  0x71, 0x88, 0xa3, 0xe3, 0x2f, 0xdf, 0x31, 0xf7, 0xe0, 0x1d, 0x13, 0x23,
+  0x05, 0x70, 0x19, 0x04, 0x65, 0x19, 0xc9, 0x44, 0x4e, 0x46, 0x96, 0x9c,
+  0xc8, 0x9e, 0x51, 0x86, 0xc6, 0x74, 0xa9, 0x14, 0x3d, 0x4d, 0x44, 0xab,
+  0x4d, 0x11, 0x4d, 0xe7, 0x21, 0x4b, 0x58, 0x76, 0x9e, 0x33, 0xc6, 0x70,
+  0x69, 0x18, 0x1d, 0x86, 0x71, 0x5b, 0xec, 0x7b, 0xd9, 0xf8, 0x4e, 0x6c,
+  0x18, 0x7a, 0x20, 0x7c, 0x15, 0x1d, 0xab, 0x96, 0x33, 0x08, 0x4a, 0xe1,
+  0x2a, 0x7c, 0xf5, 0x34, 0x93, 0xdb, 0x8b, 0xd3, 0x88, 0x70, 0x96, 0x81,
+  0xcb, 0x9e, 0xa2, 0xea, 0x9e, 0xe2, 0x4f, 0x6a, 0xed, 0x9a, 0x42, 0x08,
+  0x8e, 0xd8, 0x8c, 0xa4, 0x60, 0x4c, 0x95, 0x2d, 0x83, 0x0b, 0x15, 0x89,
+  0x24, 0x2c, 0xcb, 0xed, 0xa9, 0x66, 0x7e, 0x09, 0x5a, 0x51, 0x58, 0xc5,
+  0x4d, 0x3e, 0x12, 0x0c, 0x19, 0x20, 0xda, 0x82, 0xe0, 0x07, 0x4b, 0x7d,
+  0x17, 0x07, 0x2e, 0xc5, 0x2b, 0x1f, 0x78, 0xbe, 0x94, 0x74, 0xee, 0xd6,
+  0xb3, 0x83, 0x4b, 0x99, 0x29, 0x27, 0x97, 0xca, 0x85, 0xec, 0x2a, 0x6a,
+  0xc3, 0x8f, 0xe4, 0x33, 0xa3, 0x38, 0x30, 0xc7, 0xe1, 0xa6, 0xc9, 0x79,
+  0xe2, 0xd0, 0xb8, 0x40, 0x02, 0x5e, 0x5f, 0x10, 0xc6, 0xec, 0x2c, 0x1a,
+  0xce, 0x53, 0xcf, 0x89, 0x56, 0x6f, 0x37, 0x6f, 0x29, 0x8c, 0x47, 0x51,
+  0xbd, 0xee, 0xa7, 0x9e, 0x41, 0x69, 0x5d, 0x6a, 0xc1, 0x94, 0x0f, 0x65,
+  0x68, 0x62, 0xdb, 0xd8, 0xd8, 0x38, 0x3a, 0xbe, 0x3c, 0x38, 0x39, 0x3d,
+  0x3e, 0x8a, 0x4e, 0xde, 0xbe, 0x3e, 0xbb, 0x78, 0x73, 0x70, 0xa9, 0x4e,
+  0xa6, 0x23, 0xa7, 0xa3, 0xba, 0x72, 0x26, 0xce, 0x04, 0xe0, 0xf5, 0x57,
+  0x90, 0x30, 0xed, 0xe2, 0xb5, 0x02, 0x06, 0xc9, 0x32, 0x24, 0x95, 0x35,
+  0xd8, 0x88, 0xd4, 0x39, 0xe5, 0x0b, 0x94, 0xf0, 0xfd, 0xbc, 0xed, 0x1c,
+  0x0a, 0x03, 0x5b, 0x4e, 0xd3, 0x30, 0x81, 0xfd, 0xf5, 0x68, 0x53, 0xae,
+  0x18, 0x97, 0xdc, 0x4d, 0xc0, 0xad, 0x47, 0x16, 0x0c, 0x68, 0xb2, 0x7f,
+  0xc2, 0xb9, 0xad, 0x10, 0x2f, 0xb5, 0xaa, 0xf9, 0x49, 0xe9, 0x8a, 0xf9,
+  0x31, 0xb9, 0x70, 0x3b, 0x41, 0x76, 0x15, 0x51, 0x20, 0xaa, 0x06, 0x07,
+  0x6d, 0xba, 0x44, 0x25, 0xab, 0x40, 0x22, 0x2e, 0x4d, 0x7c, 0x12, 0xee,
+  0x2f, 0x67, 0x72, 0x6d, 0xb0, 0xd7, 0xb6, 0xd4, 0xda, 0x18, 0x0f, 0x65,
+  0x32, 0x2f, 0xb8, 0x0e, 0x94, 0x9d, 0x75, 0x7e, 0xc5, 0x33, 0x51, 0xb3,
+  0xe3, 0x2a, 0xe8, 0x61, 0xd8, 0xd4, 0xa6, 0x73, 0x42, 0x90, 0xe4, 0xd2,
+  0x3f, 0x51, 0x14, 0x33, 0x5e, 0x0b, 0xae, 0xf9, 0xcb, 0x3f, 0xe7, 0x3e,
+  0xad, 0x5f, 0xa3, 0x34, 0xbc, 0xc2, 0x12, 0xd4, 0x3d, 0xd2, 0xd3, 0xe6,
+  0xcf, 0x6d, 0x61, 0x94, 0x76, 0x44, 0x0f, 0x71, 0x11, 0xc9, 0xbe, 0x76,
+  0xaf, 0x61, 0x52, 0xd0, 0x85, 0x6d, 0x0b, 0x45, 0x78, 0x82, 0x10, 0x30,
+  0xca, 0x04, 0xa8, 0x04, 0x6b, 0x20, 0xf3, 0x00, 0x7d, 0x97, 0x66, 0x34,
+  0x66, 0x11, 0xdf, 0xdb, 0x79, 0x5d, 0x91, 0xa6, 0x46, 0x35, 0x6c, 0x57,
+  0x20, 0x6c, 0xe8, 0x9e, 0xc5, 0x4a, 0x06, 0x2f, 0xc4, 0xde, 0xef, 0x8a,
+  0xf5, 0xdf, 0x34, 0x6c, 0x73, 0x26, 0x59, 0x6d, 0x50, 0x3d, 0x07, 0x4d,
+  0x33, 0x75, 0x65, 0x52, 0xe1, 0x8b, 0x55, 0x4f, 0x65, 0xc8, 0xe9, 0xad,
+  0x6b, 0x8c, 0x7e, 0xd2, 0x36, 0x02, 0xe5, 0xe2, 0x28, 0xef, 0xa9, 0xc5,
+  0xbc, 0x62, 0x78, 0xec, 0x18, 0xad, 0x61, 0x43, 0x01, 0x19, 0x94, 0x53,
+  0xc2, 0x74, 0x1a, 0xe6, 0xe1, 0x8e, 0xb9, 0xbe, 0x14, 0xd7, 0xe8, 0xd4,
+  0x7a, 0x72, 0x41, 0x2c, 0xb9, 0x78, 0xd4, 0x15, 0x79, 0x14, 0x4c, 0x6f,
+  0xbe, 0x61, 0x48, 0x89, 0xf6, 0x92, 0xc5, 0x09, 0x80, 0xfb, 0x4b, 0x3e,
+  0x36, 0x98, 0x3c, 0xbb, 0x33, 0x93, 0xb8, 0x80, 0x8d, 0x11, 0x21, 0xa5,
+  0x72, 0x67, 0x80, 0x04, 0x30, 0x57, 0x67, 0xb6, 0xc4, 0xe5, 0xe3, 0xcb,
+  0x0a, 0xf7, 0x05, 0xb6, 0x22, 0xe6, 0xac, 0x32, 0x3b, 0x14, 0x12, 0xdc,
+  0xe6, 0x5a, 0xb1, 0xba, 0xf3, 0xd4, 0x0c, 0x22, 0x94, 0x34, 0x64, 0xe3,
+  0x3c, 0x2b, 0xe4, 0xbc, 0x41, 0xd2, 0xee, 0xf8, 0xea, 0x0f, 0x9d, 0xc5,
+  0x0d, 0xf5, 0xd1, 0x89, 0xae, 0x59, 0x57, 0x19, 0x65, 0x61, 0xbc, 0x9b,
+  0x6e, 0xcb, 0x44, 0x1e, 0x7f, 0x75, 0x11, 0x5f, 0xc5, 0xc9, 0xf4, 0xf7,
+  0x7b, 0x3b, 0xc3, 0xf8, 0x7a, 0x39, 0x8d, 0xff, 0x80, 0x17, 0x5f, 0x3d,
+  0x79, 0xb2, 0xb7, 0xf3, 0xe9, 0x67, 0x3b, 0x9d, 0x9a, 0xab, 0x28, 0xf0,
+  0x33, 0xc3, 0x6d, 0x88, 0x72, 0xcd, 0xcc, 0x77, 0xd1, 0xcf, 0x60, 0x7c,
+  0x9d, 0x72, 0x37, 0x5f, 0xb3, 0xf0, 0xa2, 0x6b, 0x10, 0x23, 0x20, 0x42,
+  0xd8, 0xa4, 0xd6, 0x85, 0xa2, 0x1b, 0x97, 0xe8, 0xfa, 0x93, 0xdd, 0x7d,
+  0x61, 0x65, 0xd7, 0xb0, 0x4b, 0xc5, 0x42, 0xb1, 0xd1, 0xcb, 0x74, 0x4e,
+  0x37, 0xd0, 0xe7, 0x51, 0x19, 0x5f, 0x3b, 0x5a, 0x45, 0x0b, 0xae, 0x92,
+  0xb3, 0x59, 0xc2, 0xaf, 0x52, 0xd4, 0x14, 0x1e, 0x44, 0x9b, 0x97, 0x02,
+  0x99, 0x06, 0xc1, 0x67, 0x91, 0xe4, 0x53, 0xc9, 0x76, 0x8d, 0x67, 0x16,
+  0x72, 0xc9, 0xef, 0xb3, 0x33, 0x7e, 0xb0, 0x98, 0xba, 0xba, 0xd5, 0xd0,
+  0xc0, 0x52, 0x4f, 0x70, 0xd3, 0x45, 0xe1, 0xeb, 0x24, 0xc9, 0x75, 0x13,
+  0x82, 0xb1, 0xd1, 0x62, 0xa1, 0x0a, 0x44, 0x07, 0xb3, 0xea, 0xb9, 0x82,
+  0x2b, 0xfd, 0x89, 0xcd, 0x74, 0x80, 0xdf, 0x51, 0x8d, 0x4e, 0x8b, 0xea,
+  0x76, 0x16, 0x92, 0x1f, 0xe4, 0x8a, 0x7c, 0x68, 0x3a, 0x71, 0x65, 0x5e,
+  0x71, 0xe9, 0x37, 0xe6, 0xa5, 0x29, 0xb9, 0xbb, 0x9f, 0xbf, 0x02, 0x41,
+  0xec, 0x7e, 0xfe, 0x07, 0xf7, 0xd9, 0x9e, 0x7e, 0xb6, 0xf7, 0xf9, 0x1f,
+  0x06, 0x03, 0x8c, 0x8f, 0x29, 0xa4, 0x6b, 0x5f, 0x77, 0x35, 0xe9, 0x30,
+  0xd6, 0x23, 0x2c, 0x7f, 0x39, 0xe4, 0x1d, 0xd9, 0xeb, 0x8e, 0xf5, 0x1c,
+  0xae, 0x72, 0x4f, 0x6d, 0xef, 0x8e, 0x6f, 0xa5, 0x06, 0x58, 0x0c, 0x54,
+  0xcf, 0xa2, 0x6d, 0xd1, 0x9d, 0x89, 0x10, 0xed, 0x14, 0x0e, 0xb2, 0x24,
+  0x8e, 0xfe, 0xc8, 0x94, 0xfa, 0xc7, 0x8d, 0x48, 0x4d, 0xe4, 0xbc, 0x1d,
+  0x28, 0x4b, 0x18, 0x19, 0xd9, 0x4a, 0x6d, 0x79, 0x81, 0x7c, 0xe3, 0x96,
+  0x39, 0xca, 0x92, 0xef, 0xc0, 0xa0, 0xd0, 0xc5, 0x9f, 0x14, 0xf6, 0x47,
+  0x36, 0x9c, 0xf9, 0x19, 0xf2, 0x19, 0x24, 0x2b, 0x88, 0x24, 0x8c, 0x92,
+  0x79, 0x03, 0x9e, 0xfc, 0xfd, 0xf7, 0xdf, 0xab, 0x38, 0x45, 0xbf, 0xe8,
+  0xb8, 0x6f, 0x88, 0x13, 0x4d, 0x88, 0xb9, 0xcd, 0x50, 0x4e, 0x41, 0x2b,
+  0x93, 0xe8, 0x85, 0x7f, 0xa5, 0xf3, 0x94, 0x46, 0x68, 0x63, 0xa5, 0x8e,
+  0x2f, 0x8f, 0x0c, 0x4b, 0x7a, 0x2c, 0x4c, 0x0c, 0x94, 0xb9, 0x09, 0x57,
+  0xa0, 0x0f, 0xb5, 0x08, 0x09, 0x9f, 0x77, 0x0e, 0x9b, 0x0e, 0xda, 0xa7,
+  0xc6, 0x4c, 0x0d, 0xd6, 0x8d, 0x04, 0xc5, 0x8a, 0x8c, 0xf3, 0xaa, 0x23,
+  0x0f, 0x5e, 0xa7, 0x1d, 0x35, 0xf0, 0xca, 0x27, 0x1d, 0x9f, 0x43, 0x2a,
+  0xbb, 0x81, 0x2d, 0x7b, 0x25, 0x82, 0x53, 0xfa, 0x73, 0xf2, 0x6a, 0x77,
+  0xa7, 0xfd, 0x09, 0xd6, 0x86, 0x22, 0x46, 0x5f, 0x7d, 0xe5, 0x0d, 0xe4,
+  0x8f, 0x3d, 0x9f, 0x4e, 0xe4, 0x69, 0x2d, 0x2a, 0x88, 0x22, 0x2b, 0xaf,
+  0x3a, 0x23, 0xbe, 0x5f, 0xf9, 0xff, 0xd7, 0x8c, 0x03, 0x01, 0x5f, 0xfa,
+  0x6c, 0xb1, 0x1c, 0xcd, 0xd2, 0xca, 0x80, 0xb7, 0x79, 0x82, 0x9f, 0xc3,
+  0xa4, 0x92, 0x38, 0xda, 0x40, 0x35, 0x5a, 0x91, 0xfc, 0xba, 0x57, 0x59,
+  0x36, 0x8a, 0xf3, 0xae, 0x1a, 0x51, 0x6d, 0x9c, 0xdd, 0xdd, 0xbd, 0x27,
+  0x4f, 0x9f, 0x75, 0x07, 0x2a, 0xa5, 0x81, 0x41, 0x40, 0x31, 0x4b, 0x55,
+  0x95, 0x91, 0x26, 0x62, 0x39, 0x9e, 0x61, 0x6d, 0xf9, 0x56, 0x67, 0x03,
+  0xf3, 0x30, 0xee, 0xee, 0x95, 0xf4, 0xf6, 0x07, 0xee, 0xe7, 0x15, 0xba,
+  0xf8, 0x43, 0x3a, 0x79, 0xe5, 0x66, 0xf8, 0x07, 0x9e, 0xcb, 0x2b, 0x9d,
+  0x04, 0xed, 0xab, 0xc5, 0xd2, 0x17, 0x5b, 0x1b, 0xad, 0x5c, 0xad, 0x75,
+  0x73, 0x6d, 0x13, 0x37, 0x30, 0x69, 0x78, 0xba, 0xfa, 0x13, 0xb1, 0xdc,
+  0x42, 0x56, 0xf5, 0x81, 0xe4, 0xdb, 0x0f, 0x7d, 0x6a, 0xa5, 0xcf, 0xad,
+  0xf4, 0x3d, 0xbb, 0x8e, 0x66, 0x9c, 0x38, 0xc2, 0x1b, 0xd1, 0xd3, 0x6c,
+  0x82, 0x29, 0x6c, 0x1d, 0x2a, 0x08, 0x64, 0x19, 0xfc, 0x48, 0x87, 0x5f,
+  0x9d, 0x74, 0xd5, 0x41, 0x2b, 0x8a, 0x5b, 0xaf, 0xcd, 0xb8, 0xe6, 0xa2,
+  0x26, 0x14, 0x85, 0x60, 0xc3, 0xe0, 0xc1, 0x63, 0xf6, 0x37, 0x72, 0xbf,
+  0x92, 0xfa, 0x43, 0x9d, 0xe9, 0x9d, 0x33, 0x65, 0x73, 0x5d, 0x8e, 0x4f,
+  0xc2, 0x66, 0x80, 0xea, 0x22, 0x8e, 0x47, 0x58, 0xaa, 0x17, 0x2e, 0x6b,
+  0xa0, 0xff, 0xda, 0x79, 0x03, 0x5c, 0x94, 0xba, 0x3e, 0x4a, 0x5f, 0x09,
+  0x37, 0x31, 0x06, 0xd1, 0x71, 0x25, 0xa8, 0x84, 0x12, 0x42, 0xde, 0x01,
+  0x5f, 0xc6, 0x28, 0xa9, 0x14, 0x36, 0x12, 0xb1, 0x90, 0xb9, 0xe7, 0x4b,
+  0x57, 0xb3, 0xe8, 0xf3, 0x08, 0xb8, 0xff, 0xf2, 0x96, 0xc6, 0xa1, 0x57,
+  0xea, 0xbb, 0xe2, 0x25, 0x55, 0x0e, 0x9c, 0xe7, 0x23, 0xf0, 0xda, 0xaa,
+  0x58, 0x20, 0x2d, 0xc8, 0x44, 0x47, 0x2b, 0x55, 0xff, 0xb9, 0x85, 0xee,
+  0x9f, 0x71, 0x08, 0x5e, 0xf2, 0x36, 0xe0, 0xeb, 0xcf, 0xbb, 0x62, 0xc2,
+  0x73, 0xef, 0xf2, 0x30, 0x6a, 0x9e, 0x15, 0x21, 0xd0, 0x70, 0x3e, 0xd9,
+  0x95, 0x83, 0x73, 0x11, 0x59, 0x8c, 0x93, 0x4c, 0xe7, 0x50, 0xa7, 0xd2,
+  0x64, 0x3a, 0xd1, 0xb2, 0x6a, 0x2a, 0x0b, 0xf5, 0xb4, 0xf1, 0x84, 0x33,
+  0x78, 0x59, 0x76, 0xec, 0x72, 0x00, 0x0e, 0xde, 0xeb, 0x3a, 0x74, 0x18,
+  0x16, 0xa9, 0x13, 0xb0, 0xbb, 0x3c, 0xb1, 0x92, 0x63, 0x1b, 0x9a, 0x5c,
+  0xe6, 0x65, 0xf9, 0x70, 0x62, 0x45, 0x20, 0x3a, 0xf8, 0x58, 0x7d, 0xc9,
+  0x41, 0x6e, 0x1c, 0x91, 0xd7, 0x9c, 0x08, 0xa3, 0x9d, 0xbe, 0xe2, 0xe5,
+  0xde, 0x1d, 0x5c, 0xa7, 0x57, 0xb2, 0x18, 0xc4, 0x22, 0xaf, 0x93, 0x6d,
+  0xfa, 0xb3, 0x47, 0x9f, 0xef, 0xb1, 0x4c, 0xc6, 0xbf, 0x3c, 0x81, 0xdf,
+  0x3e, 0xbc, 0xf9, 0x83, 0xb3, 0xe1, 0xce, 0x05, 0xff, 0x92, 0xba, 0x1b,
+  0x5f, 0x4d, 0xd2, 0x3a, 0x4a, 0x90, 0xb9, 0x02, 0x6f, 0x7a, 0x41, 0xb3,
+  0x17, 0x98, 0x9b, 0x01, 0xbc, 0x96, 0x41, 0x3a, 0x29, 0x7c, 0x98, 0x9b,
+  0x3a, 0x16, 0x55, 0x4c, 0x67, 0xa9, 0x3b, 0x55, 0x83, 0x09, 0x07, 0xda,
+  0xe2, 0x5e, 0x4d, 0xee, 0xb7, 0x7a, 0x61, 0xf0, 0x90, 0x55, 0xda, 0x74,
+  0xe5, 0x80, 0x91, 0x85, 0xc6, 0xdd, 0x6f, 0x6a, 0x6d, 0x2b, 0xc6, 0x72,
+  0xd0, 0x74, 0x19, 0x6c, 0x73, 0x5a, 0xdf, 0xc1, 0x6a, 0x79, 0x28, 0x09,
+  0xf8, 0x48, 0x8b, 0x72, 0x8b, 0xbb, 0x49, 0xa6, 0x05, 0x34, 0x75, 0x1e,
+  0xf4, 0x46, 0x14, 0xac, 0xbb, 0xa1, 0x64, 0xa0, 0xab, 0x2e, 0xd7, 0xab,
+  0xda, 0x86, 0x3f, 0x48, 0x78, 0xdb, 0xf1, 0x4c, 0x40, 0xe1, 0x41, 0xb6,
+  0xd3, 0xbe, 0xdc, 0x97, 0x2a, 0x04, 0xf5, 0x5f, 0x0f, 0xa2, 0x53, 0x84,
+  0xbe, 0x15, 0xb1, 0x64, 0x16, 0xdb, 0x9d, 0x6a, 0x14, 0x40, 0xe4, 0x22,
+  0x52, 0xf7, 0x86, 0x14, 0xea, 0xe2, 0x64, 0x4e, 0x23, 0x23, 0xe0, 0xd8,
+  0x79, 0x35, 0x53, 0x24, 0x0a, 0x95, 0x40, 0x7a, 0xb0, 0x42, 0xbb, 0xe7,
+  0x50, 0xb6, 0xcd, 0x95, 0x8d, 0x0e, 0x88, 0x34, 0x68, 0x44, 0x1c, 0xfa,
+  0x2a, 0x72, 0x06, 0xac, 0xdc, 0x11, 0xbe, 0xe4, 0x8c, 0x26, 0x62, 0x66,
+  0xd1, 0xd2, 0xbe, 0xe2, 0xc3, 0xa2, 0xd6, 0x40, 0x59, 0x3c, 0x77, 0x26,
+  0x9d, 0x0e, 0x34, 0xc5, 0x69, 0xe2, 0xd4, 0x69, 0x05, 0xe3, 0x15, 0x5c,
+  0xdc, 0x4c, 0xa1, 0x91, 0x44, 0xc0, 0xf0, 0xfe, 0x05, 0x1e, 0x24, 0x8f,
+  0x2b, 0xbe, 0xa3, 0x5f, 0xf8, 0x92, 0x1f, 0xe5, 0xb4, 0xd3, 0x49, 0x2e,
+  0xd7, 0x01, 0x7a, 0x05, 0x6e, 0x8a, 0x83, 0xbd, 0x7c, 0x73, 0x1a, 0x59,
+  0x86, 0xf6, 0x95, 0x17, 0x0e, 0x2d, 0x6a, 0x07, 0x53, 0x54, 0x5b, 0x88,
+  0x48, 0x40, 0xfa, 0x94, 0xdc, 0x6c, 0xb2, 0xb6, 0x9c, 0xe4, 0x15, 0xf1,
+  0xe2, 0x54, 0x8e, 0x69, 0xf0, 0x84, 0xbc, 0xca, 0xb4, 0x43, 0xa4, 0xd1,
+  0xe5, 0x25, 0xe8, 0xf6, 0xa2, 0x2e, 0x0f, 0x95, 0xbf, 0xe8, 0x62, 0x3d,
+  0xf1, 0x71, 0xb0, 0x7c, 0xdd, 0x41, 0xcb, 0xc9, 0xe3, 0x67, 0x5e, 0x7d,
+  0x51, 0x59, 0x25, 0x7c, 0x6e, 0x4d, 0xbd, 0x92, 0x68, 0xd9, 0x86, 0x94,
+  0x6d, 0xef, 0x06, 0xed, 0xbf, 0x3a, 0xa4, 0x56, 0xa4, 0x30, 0x9a, 0xec,
+  0x09, 0x04, 0x6a, 0xf7, 0x59, 0x8a, 0x54, 0x94, 0x46, 0x43, 0x1f, 0x3e,
+  0xb9, 0x97, 0xc6, 0x7e, 0x5c, 0x78, 0x90, 0x70, 0x34, 0x21, 0x01, 0xe3,
+  0xb6, 0xb4, 0x9b, 0xa9, 0x68, 0x7a, 0xf7, 0x19, 0xec, 0x0a, 0xe0, 0x33,
+  0xbb, 0x03, 0xa4, 0x26, 0x78, 0x28, 0x1d, 0xd7, 0x80, 0x53, 0xd7, 0x3b,
+  0x58, 0xd0, 0x8e, 0x99, 0x49, 0x9c, 0x12, 0x6f, 0xab, 0xdc, 0xc6, 0xaf,
+  0x16, 0xe9, 0x18, 0x75, 0x4e, 0x5f, 0x7d, 0x31, 0xc9, 0xae, 0x99, 0x5b,
+  0xf5, 0xe8, 0x62, 0xe5, 0x9f, 0x1d, 0x7e, 0x78, 0x4f, 0x3b, 0x95, 0x01,
+  0xe3, 0xac, 0x88, 0xdc, 0x6e, 0x7f, 0xaf, 0x09, 0x5f, 0xa2, 0x86, 0x27,
+  0xd9, 0x58, 0xdb, 0x76, 0x4d, 0xcb, 0x7e, 0x50, 0xfb, 0xee, 0x8b, 0xb0,
+  0x2f, 0x5b, 0x9c, 0x58, 0x5b, 0x96, 0x02, 0x75, 0xd3, 0xb4, 0x94, 0xeb,
+  0xdb, 0xe1, 0xaa, 0xc3, 0xa4, 0xc5, 0x35, 0x26, 0xe4, 0xae, 0x9a, 0x6a,
+  0xbc, 0x7c, 0xf7, 0x8b, 0xae, 0x84, 0x3a, 0x76, 0x5f, 0x76, 0xc1, 0xb5,
+  0x98, 0x17, 0x19, 0x8a, 0xae, 0x5e, 0x48, 0x5d, 0xb9, 0x09, 0xfb, 0x22,
+  0x2f, 0x68, 0xf1, 0xc0, 0x4a, 0x74, 0x0a, 0x33, 0x0c, 0x53, 0x1c, 0xc3,
+  0xc0, 0x1a, 0x18, 0x06, 0x7c, 0xd9, 0x3c, 0x46, 0xa6, 0x19, 0x95, 0xe2,
+  0x92, 0xd6, 0x8b, 0x16, 0xa2, 0x18, 0x12, 0x7d, 0x0b, 0x76, 0xb8, 0x8a,
+  0x61, 0x73, 0x39, 0x5f, 0x70, 0x5a, 0xd7, 0x18, 0x55, 0x75, 0xf5, 0x2c,
+  0x0d, 0xa2, 0x77, 0x73, 0xc1, 0xbd, 0x4b, 0x58, 0x3d, 0x0e, 0xfd, 0xe5,
+  0x3d, 0xe7, 0xf7, 0xa7, 0x85, 0xaa, 0xf8, 0x13, 0xc3, 0x01, 0x8b, 0x39,
+  0x44, 0xcc, 0xd6, 0xda, 0x2f, 0x5f, 0xad, 0x39, 0x47, 0x23, 0xa8, 0x59,
+  0x1a, 0x92, 0x80, 0x4b, 0xf8, 0x55, 0x06, 0xc4, 0xde, 0xb9, 0xe3, 0xd7,
+  0xc7, 0x17, 0x17, 0xc7, 0x17, 0xbc, 0xde, 0x07, 0x55, 0xfc, 0xfa, 0x1b,
+  0x8d, 0x8c, 0xf6, 0xc8, 0x6c, 0x16, 0x11, 0xd6, 0x2c, 0x6b, 0x2c, 0x9c,
+  0x50, 0xa1, 0x94, 0x36, 0x22, 0xf3, 0x73, 0x4b, 0x96, 0xbb, 0x18, 0x84,
+  0x61, 0x4d, 0x44, 0x3c, 0xa0, 0xb3, 0xdc, 0x4f, 0xf9, 0x5a, 0x11, 0x18,
+  0xfa, 0x50, 0x98, 0xd8, 0x88, 0xec, 0xd5, 0x5c, 0xeb, 0x8f, 0xe0, 0xaa,
+  0x36, 0xdd, 0x31, 0x90, 0x4b, 0x07, 0x1a, 0xc2, 0x95, 0xa8, 0xf7, 0xda,
+  0xd7, 0x16, 0xc7, 0x7c, 0xaf, 0xf8, 0x80, 0xb2, 0xaa, 0x84, 0x95, 0x28,
+  0xca, 0xe5, 0x22, 0x9d, 0x38, 0xe3, 0x2e, 0x7d, 0x4e, 0xf2, 0x5e, 0x24,
+  0x47, 0xbc, 0xb0, 0x11, 0xc3, 0x99, 0x68, 0xb6, 0x87, 0xd0, 0xb8, 0x26,
+  0x49, 0xe5, 0xde, 0x34, 0x86, 0x98, 0x7f, 0x29, 0x5a, 0xa9, 0x98, 0xd9,
+  0xb5, 0x8c, 0x2d, 0x25, 0xfc, 0x04, 0x46, 0x45, 0x66, 0x15, 0x16, 0x2b,
+  0x10, 0xb2, 0x05, 0x36, 0x5d, 0xcd, 0x7c, 0x20, 0xa4, 0x2f, 0x28, 0x78,
+  0x81, 0x44, 0x8d, 0x7c, 0x3f, 0xfa, 0xb1, 0x48, 0xc7, 0x3f, 0xf9, 0x9b,
+  0x03, 0x21, 0xcc, 0x3e, 0x56, 0x51, 0x62, 0x0b, 0x68, 0xf2, 0xba, 0x50,
+  0xaa, 0xfb, 0x4a, 0x82, 0xd4, 0xbb, 0xe1, 0xf1, 0x45, 0x74, 0xf0, 0x15,
+  0xa3, 0x3b, 0xfd, 0x6b, 0xbb, 0xcb, 0xcf, 0xe9, 0xcd, 0x60, 0x7b, 0xab,
+  0x29, 0xb9, 0x89, 0x19, 0xbe, 0xb5, 0x6e, 0x42, 0xb8, 0xb1, 0xa9, 0x55,
+  0x8f, 0x09, 0x72, 0x27, 0x2b, 0x5b, 0xb8, 0x11, 0x7d, 0x70, 0x13, 0x3f,
+  0x66, 0x0b, 0xf9, 0x80, 0x85, 0x9b, 0x28, 0xb9, 0xfc, 0xe2, 0x80, 0xb0,
+  0xad, 0xd1, 0xd1, 0x17, 0x0d, 0x35, 0x53, 0x36, 0xe9, 0x20, 0xea, 0xbe,
+  0xc9, 0x7e, 0x26, 0x41, 0x20, 0xde, 0x7e, 0x32, 0xd8, 0x89, 0x36, 0xbf,
+  0x4b, 0xe7, 0x2f, 0x9e, 0xfd, 0x39, 0x3a, 0xd9, 0xea, 0x56, 0x82, 0x3c,
+  0x05, 0xc6, 0x79, 0x14, 0xcf, 0x6f, 0xdd, 0x8e, 0x9d, 0xe1, 0x54, 0x4b,
+  0xe8, 0x8a, 0x81, 0x81, 0x4a, 0x65, 0xc2, 0xb5, 0x2d, 0x22, 0xd1, 0x48,
+  0xe3, 0x45, 0xa3, 0x6f, 0x1d, 0x20, 0x1d, 0xeb, 0xf4, 0xf4, 0xd4, 0x84,
+  0x97, 0xee, 0xc5, 0xb3, 0x46, 0x13, 0x4f, 0x5d, 0x1b, 0xef, 0xa4, 0x8d,
+  0x5f, 0xd8, 0xc4, 0xde, 0x60, 0x67, 0x2f, 0xda, 0x3c, 0x1b, 0x6e, 0xef,
+  0xb9, 0x16, 0x9a, 0x4d, 0xec, 0xa1, 0x09, 0x7e, 0xa8, 0xfa, 0xf2, 0x53,
+  0xee, 0xff, 0xc7, 0x64, 0xfe, 0x53, 0xb4, 0xf9, 0xfd, 0xee, 0x2e, 0x35,
+  0xf0, 0xe7, 0xe8, 0xe0, 0xe4, 0xfb, 0xe8, 0xe9, 0x80, 0x1a, 0x7b, 0x1b,
+  0xdf, 0x69, 0x73, 0x8a, 0xe1, 0x34, 0x44, 0x23, 0xf4, 0x7d, 0xa3, 0x8d,
+  0x67, 0xb5, 0x36, 0x4e, 0x49, 0x0f, 0x7c, 0xa0, 0x2b, 0x65, 0x67, 0xf0,
+  0x64, 0x2f, 0x4a, 0x9f, 0x7d, 0xf6, 0xdc, 0x1a, 0xd2, 0x36, 0xf0, 0x7d,
+  0xd5, 0x36, 0x29, 0x59, 0xbe, 0x24, 0xe6, 0x1c, 0x3f, 0x10, 0x33, 0x03,
+  0x87, 0x00, 0x74, 0xea, 0x4d, 0x9c, 0x4f, 0x94, 0xdc, 0xb8, 0xa8, 0x0a,
+  0xed, 0x94, 0xa2, 0x83, 0x25, 0x30, 0x52, 0xd2, 0xa5, 0xb9, 0xdf, 0x18,
+  0x0e, 0xeb, 0xa2, 0xf6, 0xe8, 0x9f, 0xa3, 0x37, 0xc3, 0x93, 0x63, 0x9a,
+  0xd1, 0x0e, 0x0d, 0xcd, 0xaf, 0xa1, 0x0c, 0x08, 0x5f, 0x61, 0x71, 0x69,
+  0x55, 0x37, 0x38, 0xef, 0x07, 0x6d, 0x98, 0x8c, 0x2d, 0x11, 0x5d, 0x0c,
+  0xdb, 0x98, 0x15, 0x05, 0xfa, 0x7d, 0x47, 0xb4, 0xd6, 0x3f, 0xb8, 0x66,
+  0x95, 0x41, 0xae, 0x59, 0x74, 0xfd, 0x4d, 0x36, 0xa7, 0x63, 0x92, 0x67,
+  0x39, 0x87, 0x79, 0x74, 0x2b, 0x92, 0xc2, 0x37, 0x47, 0xc7, 0x92, 0xa7,
+  0xf6, 0x26, 0x9e, 0x13, 0x8b, 0x64, 0x44, 0x87, 0xe2, 0x96, 0xbd, 0xee,
+  0xe2, 0xbc, 0x91, 0xf7, 0x4f, 0x57, 0xf3, 0x07, 0xda, 0xc7, 0x4f, 0x07,
+  0xbb, 0x8c, 0x6a, 0xc7, 0x5a, 0xee, 0xeb, 0x37, 0xf4, 0xf7, 0xee, 0xd3,
+  0x6e, 0xc4, 0x5f, 0x55, 0x35, 0x76, 0x3b, 0xaf, 0x1b, 0x87, 0x67, 0x67,
+  0xdf, 0x9c, 0x48, 0x00, 0xc6, 0xa1, 0x1a, 0x51, 0x59, 0xb0, 0x72, 0x5a,
+  0xb0, 0x30, 0x57, 0xd2, 0xd6, 0x7c, 0xfc, 0x38, 0x5c, 0x6f, 0xb7, 0x49,
+  0xb2, 0x00, 0x0c, 0x5d, 0x8d, 0x23, 0x94, 0xca, 0xa2, 0x65, 0x64, 0x2c,
+  0x48, 0xa7, 0x93, 0x2a, 0x1a, 0x45, 0xc1, 0x08, 0x61, 0x66, 0xb0, 0x1d,
+  0xad, 0x5c, 0x2e, 0x6c, 0xec, 0x8b, 0x40, 0x62, 0x88, 0x2e, 0x8a, 0xd5,
+  0x0c, 0xce, 0x52, 0x05, 0x9e, 0x5e, 0x54, 0x5d, 0xb7, 0x3b, 0x4c, 0xca,
+  0xbe, 0x0c, 0x7a, 0x5f, 0x6d, 0xb4, 0x5d, 0x35, 0x38, 0x39, 0x73, 0xd9,
+  0x42, 0x31, 0x69, 0x61, 0x28, 0x5e, 0x2d, 0xb8, 0x58, 0xe5, 0xd4, 0xd5,
+  0x13, 0x46, 0x31, 0xd6, 0x04, 0xb1, 0x44, 0x6f, 0x0f, 0xde, 0x1c, 0xbf,
+  0xfa, 0xf6, 0xe0, 0xf4, 0xdd, 0x31, 0xbd, 0xc2, 0xa8, 0xac, 0x9b, 0x3e,
+  0xde, 0x08, 0x63, 0x9c, 0xa5, 0xe3, 0x6c, 0xca, 0x3e, 0xa5, 0xee, 0x9f,
+  0xbb, 0x1b, 0x12, 0x5e, 0x19, 0x75, 0xf8, 0xad, 0x5d, 0x79, 0x8d, 0xe8,
+  0x82, 0xff, 0xda, 0x93, 0xbf, 0xf6, 0xfe, 0xdc, 0xd9, 0xaa, 0x4c, 0xba,
+  0xa1, 0x15, 0x33, 0xbd, 0xdc, 0x4b, 0x5c, 0x1d, 0xaa, 0xa4, 0x20, 0xa6,
+  0x57, 0x56, 0xa5, 0x63, 0x1e, 0x19, 0xbb, 0xda, 0xf8, 0xd9, 0xcd, 0xd1,
+  0x2a, 0xd4, 0xb9, 0x3b, 0xfc, 0xd2, 0x2b, 0x08, 0x17, 0x1d, 0xce, 0x79,
+  0x52, 0x71, 0x03, 0xce, 0x6a, 0x6e, 0xc3, 0x9a, 0x48, 0x1e, 0x16, 0x1c,
+  0xbe, 0xb5, 0xd9, 0x91, 0x5f, 0x5e, 0x1d, 0x1d, 0x5c, 0x1e, 0xf3, 0x0b,
+  0xd6, 0xbd, 0x95, 0xb5, 0xb6, 0xc8, 0x5b, 0x1e, 0xcf, 0x66, 0x47, 0x3e,
+  0x7c, 0xc5, 0x13, 0xea, 0x48, 0x8d, 0x01, 0x01, 0x58, 0xac, 0x8d, 0x2b,
+  0x9b, 0x6b, 0x10, 0x63, 0x90, 0xa2, 0x57, 0x58, 0x9c, 0xc8, 0x66, 0x47,
+  0xbe, 0xeb, 0x38, 0x7b, 0xad, 0x16, 0x6e, 0x55, 0xe7, 0xe4, 0x04, 0x71,
+  0xb9, 0x8d, 0xf4, 0x20, 0xa9, 0x95, 0xe4, 0xf7, 0x47, 0x5d, 0x13, 0x62,
+  0x61, 0x0a, 0x40, 0xe6, 0xdc, 0xc6, 0x6b, 0x46, 0x21, 0xdb, 0x94, 0xb2,
+  0x6c, 0x77, 0xef, 0xc9, 0x9f, 0xb1, 0x9e, 0xaf, 0x3a, 0xdb, 0x74, 0x37,
+  0x74, 0xfe, 0xcc, 0x5d, 0xa7, 0x65, 0x50, 0x6e, 0x45, 0xbb, 0x61, 0x5d,
+  0x4a, 0x29, 0x4a, 0x82, 0x54, 0x78, 0xd7, 0x61, 0x0b, 0x93, 0x79, 0x61,
+  0x41, 0xef, 0x25, 0x7b, 0xc0, 0x92, 0xcc, 0xcd, 0x7d, 0x8f, 0xfd, 0x42,
+  0xc9, 0xc0, 0xb9, 0x83, 0x26, 0x95, 0xee, 0xc2, 0xfb, 0xa3, 0x27, 0xef,
+  0xca, 0x1c, 0xb5, 0x08, 0x0c, 0xf7, 0x39, 0x5b, 0x59, 0x82, 0x01, 0xfa,
+  0x82, 0x3c, 0x2e, 0x7b, 0xd6, 0x90, 0x8a, 0x47, 0x6a, 0xcb, 0x31, 0x45,
+  0x04, 0x22, 0x01, 0xb1, 0x96, 0x15, 0xe4, 0x24, 0xf1, 0xf7, 0x07, 0x61,
+  0x0e, 0x76, 0x67, 0xc7, 0x23, 0xce, 0x94, 0x73, 0xd1, 0xd4, 0x81, 0x16,
+  0xee, 0x96, 0xde, 0x8e, 0x5f, 0x1a, 0x00, 0x0a, 0xf0, 0x45, 0x29, 0x6b,
+  0x59, 0x38, 0x9b, 0x11, 0x7c, 0x8b, 0xfa, 0x6c, 0x75, 0x9f, 0x6a, 0x79,
+  0x0a, 0x98, 0x86, 0xa8, 0xf0, 0xa2, 0x1b, 0x13, 0xab, 0x99, 0x27, 0xf9,
+  0xa3, 0x21, 0x0e, 0x2d, 0xae, 0x27, 0x4c, 0x31, 0x48, 0x73, 0xe1, 0x77,
+  0x06, 0x83, 0x81, 0x2f, 0x03, 0xc2, 0xdb, 0xa2, 0x1e, 0x27, 0x20, 0x8a,
+  0x07, 0xa8, 0x67, 0x58, 0xe3, 0x4d, 0x08, 0xf2, 0x10, 0xa6, 0xb7, 0x34,
+  0xdc, 0x45, 0xad, 0x11, 0xee, 0x68, 0x04, 0x36, 0x8d, 0xae, 0x76, 0xdb,
+  0xb5, 0x22, 0x03, 0xb7, 0x6d, 0x9b, 0xf0, 0xc8, 0xd8, 0xc4, 0xd6, 0x58,
+  0xc4, 0x48, 0xcd, 0x77, 0x7c, 0x2a, 0x73, 0x6b, 0xc1, 0x14, 0xcc, 0xe9,
+  0xfa, 0x52, 0x03, 0x15, 0x5b, 0x22, 0x8b, 0xa6, 0x43, 0xd1, 0x02, 0x37,
+  0xcc, 0xe4, 0xb2, 0x7b, 0x64, 0x72, 0x22, 0x5f, 0x94, 0xa3, 0x3f, 0xe6,
+  0x62, 0x1a, 0xb0, 0x1b, 0xc4, 0x61, 0xfe, 0x5a, 0x3b, 0x13, 0x31, 0xcd,
+  0xb2, 0xbe, 0x0c, 0xb9, 0x5f, 0xb3, 0x5f, 0x34, 0xc7, 0xbb, 0x88, 0x15,
+  0x1b, 0x8b, 0xc4, 0xb6, 0x6c, 0x06, 0x27, 0x97, 0x4e, 0xde, 0x9b, 0x49,
+  0x38, 0xc6, 0xab, 0x2f, 0x59, 0xd2, 0x96, 0xa0, 0x62, 0xdc, 0x43, 0xf3,
+  0x64, 0x1f, 0xf3, 0x8e, 0x8f, 0xad, 0x45, 0xe7, 0x1a, 0xaf, 0xad, 0x8d,
+  0xbf, 0x95, 0xab, 0xac, 0x8b, 0x56, 0x54, 0xac, 0xc9, 0x10, 0x94, 0x03,
+  0xbe, 0x17, 0xc5, 0xf7, 0x5c, 0x8d, 0x86, 0x68, 0x50, 0xdc, 0x64, 0x62,
+  0x91, 0x39, 0x0d, 0xec, 0x8a, 0x6e, 0x86, 0x56, 0xee, 0x39, 0xf6, 0xf5,
+  0x9e, 0x0d, 0x10, 0x56, 0x40, 0xde, 0xcc, 0x80, 0x97, 0xa2, 0x9c, 0x08,
+  0x83, 0x72, 0xa9, 0xa0, 0x6e, 0xaa, 0x39, 0x8f, 0x9c, 0x58, 0xf4, 0x50,
+  0xe9, 0x26, 0x45, 0x34, 0x20, 0xdb, 0x38, 0x24, 0x8a, 0xc2, 0x56, 0x4b,
+  0x6a, 0x7d, 0x5b, 0x27, 0xce, 0x1b, 0x0d, 0x73, 0x13, 0xcb, 0xd3, 0xf3,
+  0x6c, 0xde, 0x77, 0xf5, 0x85, 0x5c, 0xc4, 0x55, 0x9e, 0x5e, 0x5f, 0x8b,
+  0xc6, 0x16, 0xd5, 0xa7, 0xd6, 0x4e, 0x64, 0xa7, 0xbc, 0x2a, 0x1c, 0xb2,
+  0xb9, 0x5a, 0xb7, 0x9a, 0x97, 0xae, 0x8e, 0xa9, 0x5a, 0x5c, 0x2a, 0xc4,
+  0x6c, 0x1e, 0x48, 0xd9, 0xb7, 0x12, 0x75, 0x60, 0x90, 0x66, 0xc9, 0x66,
+  0xaf, 0xaa, 0xc7, 0xf8, 0xec, 0x62, 0x03, 0xe5, 0xed, 0xe7, 0x3e, 0xab,
+  0xd4, 0x36, 0x1d, 0xa0, 0x32, 0x3e, 0xde, 0x64, 0xc2, 0x76, 0xe5, 0x19,
+  0x5f, 0xc5, 0xf7, 0x2e, 0xd8, 0x49, 0x50, 0x76, 0x47, 0xb1, 0xd7, 0xb8,
+  0x36, 0xa2, 0x8a, 0x75, 0xb7, 0x40, 0xdd, 0x6a, 0xe5, 0x43, 0xd9, 0x5d,
+  0xe2, 0x91, 0x8d, 0xbc, 0x81, 0xd1, 0x83, 0xd1, 0xe9, 0xe9, 0x77, 0xcc,
+  0xa4, 0xe6, 0xce, 0x75, 0xfc, 0x0a, 0x93, 0xac, 0xad, 0xca, 0x20, 0x0a,
+  0x9a, 0x14, 0x33, 0x49, 0x16, 0xb2, 0x78, 0x19, 0x9b, 0x7a, 0xa9, 0xad,
+  0x45, 0x8d, 0xe5, 0x07, 0xda, 0x7e, 0xa0, 0x9a, 0x08, 0x8e, 0xac, 0x52,
+  0x55, 0xe1, 0x22, 0xe3, 0xbc, 0xb7, 0xd7, 0x66, 0xd9, 0x71, 0x9b, 0xd4,
+  0x41, 0xca, 0xc9, 0x48, 0x89, 0x00, 0x34, 0xc0, 0x02, 0x9d, 0x73, 0xd8,
+  0x1f, 0x4c, 0x63, 0x0e, 0x59, 0xc9, 0x24, 0x16, 0x00, 0x5b, 0x06, 0xa2,
+  0x86, 0x21, 0xad, 0xc6, 0x53, 0x1b, 0xc7, 0xcf, 0xc5, 0x66, 0x08, 0xad,
+  0x01, 0x96, 0x8e, 0x9b, 0x21, 0x2a, 0x41, 0x50, 0xee, 0xd8, 0x98, 0xfb,
+  0xe3, 0xe9, 0x97, 0xa3, 0xca, 0x19, 0xfd, 0xd0, 0x91, 0x3d, 0xbf, 0x38,
+  0xfb, 0xea, 0xe2, 0x78, 0x38, 0x8c, 0xde, 0x1c, 0x5f, 0x8a, 0xca, 0x7f,
+  0x29, 0x71, 0x70, 0x02, 0x4e, 0x0c, 0x37, 0x83, 0x21, 0x24, 0x58, 0xac,
+  0x89, 0xd9, 0x13, 0x80, 0xa6, 0x9a, 0xb1, 0x0b, 0x0d, 0xa2, 0x1c, 0xd4,
+  0xf9, 0xa9, 0x86, 0xcf, 0xdd, 0xc0, 0xd0, 0x8f, 0x60, 0x26, 0x78, 0x22,
+  0x9d, 0xdd, 0xdc, 0x5b, 0x53, 0x21, 0x23, 0x4b, 0x78, 0xd3, 0x8d, 0x71,
+  0x2e, 0x6f, 0x3d, 0xe7, 0xdb, 0x9b, 0x7e, 0x62, 0x7a, 0xbf, 0x8f, 0x2e,
+  0xad, 0x58, 0xf7, 0xef, 0x49, 0x0d, 0x56, 0xfa, 0xf8, 0x7d, 0xf4, 0x3d,
+  0xb5, 0x39, 0xa1, 0x55, 0xd7, 0x02, 0x8c, 0x43, 0x14, 0xd9, 0xf0, 0x85,
+  0x4c, 0x50, 0x02, 0x22, 0x2c, 0xae, 0xb3, 0xcc, 0xf3, 0x0f, 0x14, 0xfc,
+  0x45, 0xc2, 0xbc, 0x80, 0x0a, 0x68, 0x30, 0x9d, 0xeb, 0x99, 0xdf, 0x06,
+  0x50, 0xe6, 0x69, 0x72, 0x55, 0x42, 0x20, 0xe1, 0xee, 0xa8, 0xb9, 0x1d,
+  0x86, 0x2f, 0xdc, 0x7d, 0xc3, 0x1f, 0xed, 0x44, 0x4f, 0x3e, 0x7b, 0xbe,
+  0xf3, 0x99, 0xfc, 0x6a, 0xff, 0xbe, 0x78, 0xba, 0xa3, 0x30, 0xa0, 0xf4,
+  0xd7, 0xd3, 0xfd, 0xa7, 0xbb, 0xfb, 0x0c, 0x4f, 0xb4, 0xb3, 0xbf, 0x43,
+  0xff, 0xff, 0x54, 0x3f, 0x61, 0x0c, 0xa6, 0x17, 0x7b, 0x9f, 0x7d, 0x8a,
+  0x30, 0x18, 0xa6, 0x8f, 0x29, 0x75, 0xd2, 0x2f, 0xb3, 0x3e, 0x30, 0x1c,
+  0x20, 0x04, 0xfd, 0xbe, 0x6a, 0x90, 0x64, 0xbf, 0x3a, 0x17, 0x52, 0xe4,
+  0x89, 0xbb, 0xf2, 0xcc, 0x66, 0x5c, 0x95, 0x34, 0xfe, 0xb0, 0x84, 0xac,
+  0x9b, 0x86, 0xbe, 0x2d, 0x55, 0x3c, 0x01, 0x8a, 0x52, 0x79, 0x87, 0x44,
+  0x46, 0xc9, 0xa1, 0x0a, 0x5f, 0xfe, 0x25, 0x5d, 0x5b, 0xae, 0xe1, 0x06,
+  0x50, 0x55, 0x74, 0xab, 0xf4, 0xbd, 0xb1, 0x2c, 0x21, 0xd1, 0x48, 0x50,
+  0x9a, 0xb4, 0x56, 0x48, 0xf4, 0x97, 0xf6, 0x27, 0x06, 0x2c, 0x7e, 0x4b,
+  0xa9, 0x21, 0x6a, 0xf6, 0x66, 0x15, 0x55, 0xdb, 0xfa, 0xaa, 0x10, 0xcf,
+  0x86, 0xdf, 0x7e, 0xbf, 0x52, 0x41, 0xe5, 0x51, 0x87, 0x29, 0x22, 0xf5,
+  0x5c, 0x5a, 0xa6, 0xdc, 0x68, 0xee, 0xdd, 0x22, 0x6c, 0xef, 0x63, 0x9a,
+  0xf3, 0x33, 0x02, 0x05, 0xbb, 0x9d, 0xeb, 0x07, 0x9b, 0x93, 0x4a, 0x44,
+  0x9b, 0x2b, 0x16, 0x6a, 0xb8, 0x58, 0xae, 0xa2, 0x20, 0x5e, 0x75, 0x24,
+  0xdb, 0x97, 0x37, 0x54, 0xfc, 0x2c, 0x90, 0x19, 0x24, 0x82, 0xc2, 0x5d,
+  0x86, 0xdb, 0x5e, 0x9e, 0x37, 0xca, 0x6e, 0x74, 0xc5, 0xd4, 0x18, 0xf4,
+  0xa7, 0x7d, 0xe0, 0x3c, 0xb9, 0x43, 0xf7, 0xe8, 0xd4, 0x7c, 0x70, 0xbb,
+  0xab, 0x66, 0xb3, 0xe9, 0x82, 0xc5, 0xdb, 0x8e, 0xa4, 0x7f, 0x0e, 0xf1,
+  0xe3, 0xae, 0xb9, 0xf0, 0x22, 0x42, 0x29, 0x23, 0x45, 0x32, 0x66, 0xb8,
+  0x2d, 0x06, 0xa7, 0xdd, 0x32, 0x16, 0xd6, 0xff, 0xc4, 0xc5, 0x6b, 0xe1,
+  0x5e, 0x53, 0x40, 0xf6, 0x58, 0x28, 0x7f, 0x1a, 0xa6, 0x95, 0x55, 0xa0,
+  0xd8, 0x43, 0x10, 0xd8, 0x0d, 0xa9, 0x2d, 0x4c, 0x37, 0x2d, 0xdd, 0x1c,
+  0x41, 0xd9, 0xae, 0xdf, 0x6d, 0x6c, 0x0c, 0xcf, 0x8f, 0x8f, 0x8f, 0xa2,
+  0xd3, 0x93, 0x37, 0x27, 0x97, 0x81, 0x40, 0xee, 0x2e, 0x12, 0x33, 0xb8,
+  0x16, 0x56, 0xbb, 0xa5, 0xba, 0x1c, 0x1e, 0x75, 0x50, 0xfa, 0xb3, 0xab,
+  0x7c, 0x96, 0x68, 0x1a, 0xc3, 0xb4, 0xfe, 0x1e, 0x54, 0x6f, 0x00, 0x55,
+  0xa0, 0xbe, 0x86, 0x17, 0xe8, 0x0a, 0x12, 0x6e, 0xc6, 0xae, 0xca, 0x4f,
+  0xff, 0x07, 0x0d, 0xd0, 0xa8, 0x4a, 0x4e, 0x0a, 0x9e, 0xe6, 0x8a, 0x38,
+  0x69, 0x50, 0x6b, 0x6d, 0x54, 0xbc, 0xb6, 0xc9, 0x54, 0x0b, 0x89, 0x3a,
+  0x0b, 0x1d, 0xe2, 0xf5, 0xee, 0x13, 0x24, 0xc4, 0xce, 0x52, 0x81, 0x70,
+  0x0e, 0x83, 0x89, 0x5d, 0xd5, 0x94, 0xcb, 0x4c, 0xf8, 0x78, 0xd8, 0x63,
+  0x58, 0xd0, 0xca, 0x22, 0x69, 0xad, 0xaf, 0xb0, 0x54, 0xd2, 0x93, 0x1d,
+  0x97, 0x2f, 0xb0, 0x00, 0xcf, 0x51, 0x51, 0x9f, 0x3b, 0xdb, 0x8d, 0x48,
+  0x1e, 0x59, 0xb2, 0x54, 0x9f, 0x2f, 0xe7, 0x8d, 0xeb, 0xee, 0x07, 0x79,
+  0x97, 0xe6, 0xff, 0x7c, 0x07, 0xd7, 0xdb, 0x55, 0x9c, 0xf7, 0x49, 0xf2,
+  0x5a, 0xf5, 0xcd, 0xb8, 0x2a, 0x14, 0xa1, 0x81, 0xc6, 0x62, 0xfa, 0x49,
+  0x7c, 0x8d, 0x8f, 0x9a, 0xb4, 0xe8, 0x93, 0x3e, 0x32, 0xb8, 0x24, 0xa7,
+  0x7a, 0x00, 0x78, 0xea, 0xbd, 0x08, 0x15, 0xaa, 0x5d, 0xe8, 0xb3, 0xc8,
+  0x3a, 0x1e, 0x58, 0xcf, 0x76, 0xd1, 0xf3, 0x28, 0x54, 0x3d, 0xcd, 0xd4,
+  0x39, 0x94, 0xf2, 0x34, 0x75, 0x2e, 0x4d, 0xd1, 0x7a, 0x16, 0xed, 0x7e,
+  0xc6, 0xf3, 0xf8, 0xb8, 0xf9, 0x70, 0x2d, 0x0b, 0x8b, 0x62, 0x13, 0x75,
+  0x21, 0xf3, 0xbb, 0x29, 0x79, 0x09, 0x40, 0x2b, 0x97, 0xd5, 0xb5, 0x68,
+  0x58, 0x44, 0xeb, 0xb1, 0x7e, 0xa2, 0xae, 0x74, 0x58, 0xa6, 0xe0, 0xdb,
+  0x16, 0x09, 0x09, 0x55, 0x1b, 0x65, 0x5d, 0xd8, 0xd6, 0x2a, 0xd1, 0x7a,
+  0xdd, 0xdc, 0x67, 0xcc, 0x61, 0x19, 0xd8, 0x3a, 0x42, 0xb4, 0x76, 0x9f,
+  0x4e, 0x20, 0x55, 0x9b, 0x11, 0x00, 0xf4, 0x27, 0xc4, 0x27, 0x41, 0xd2,
+  0x70, 0x5d, 0xc2, 0xe7, 0xe9, 0x46, 0xa6, 0x02, 0x0c, 0x2f, 0x6b, 0x06,
+  0xe3, 0xc2, 0x26, 0xe4, 0x07, 0x2e, 0xc3, 0x52, 0x75, 0x0d, 0x30, 0x6b,
+  0xee, 0xf8, 0x5e, 0x38, 0x70, 0xbf, 0x2c, 0xa7, 0x66, 0x57, 0xf0, 0x75,
+  0x16, 0xaa, 0x73, 0xe6, 0x64, 0xfe, 0x60, 0xda, 0xbb, 0x3b, 0x24, 0xbf,
+  0x4e, 0xb3, 0x7a, 0x41, 0xb6, 0xa6, 0x52, 0x8a, 0x69, 0xf5, 0xb1, 0x3a,
+  0xbb, 0x3b, 0xdf, 0xac, 0x5f, 0x75, 0x80, 0xb4, 0x3e, 0xfa, 0xf2, 0xde,
+  0xd3, 0x47, 0x36, 0xed, 0x2c, 0x77, 0x15, 0x76, 0x3c, 0xd0, 0x88, 0x77,
+  0xc0, 0x34, 0xb6, 0x8d, 0x08, 0x3f, 0xb9, 0x8e, 0x51, 0x82, 0xfd, 0x91,
+  0xd1, 0x5b, 0x82, 0x46, 0x6d, 0x28, 0x6f, 0x34, 0x1c, 0x5b, 0xbe, 0x2c,
+  0xd8, 0x42, 0xb6, 0x00, 0xdc, 0x90, 0x57, 0x63, 0x5d, 0x4a, 0xa7, 0xe4,
+  0x78, 0x07, 0x6f, 0x0b, 0xe7, 0xec, 0x55, 0x99, 0x84, 0x51, 0x4f, 0x9e,
+  0x5c, 0x2f, 0x25, 0x89, 0x3a, 0x13, 0xb5, 0x9f, 0xf1, 0x18, 0xf5, 0xbc,
+  0x12, 0x6f, 0xe6, 0xc8, 0x21, 0xa1, 0x27, 0x30, 0xde, 0x71, 0x6c, 0x22,
+  0xab, 0x88, 0x1c, 0xf5, 0x8b, 0x81, 0xed, 0xb3, 0x63, 0x76, 0x86, 0x81,
+  0x1b, 0xc8, 0xf1, 0x0a, 0x4b, 0x3d, 0x49, 0x15, 0xa4, 0x01, 0x32, 0x14,
+  0x85, 0x50, 0x1c, 0xb3, 0xe7, 0xbc, 0x2e, 0x76, 0x8a, 0x95, 0xe2, 0x21,
+  0x40, 0x03, 0x3d, 0xa5, 0x5a, 0xb4, 0xe4, 0xba, 0x62, 0x8e, 0x5f, 0x58,
+  0x0a, 0xaa, 0xc0, 0xc4, 0xb2, 0xdd, 0xff, 0xf0, 0xec, 0xed, 0xeb, 0x93,
+  0xaf, 0x1c, 0xb0, 0x85, 0x30, 0xf1, 0x65, 0x99, 0xb1, 0x5d, 0x53, 0x8c,
+  0x86, 0xae, 0x08, 0x97, 0x73, 0x78, 0x6b, 0xa5, 0x0d, 0x0d, 0xbb, 0x25,
+  0xf6, 0xf4, 0x3e, 0xfc, 0x00, 0x0c, 0x64, 0xfe, 0x84, 0x6d, 0xe5, 0x92,
+  0x3d, 0x5e, 0x6c, 0x79, 0xcb, 0x43, 0x0d, 0x7a, 0x47, 0xd2, 0x33, 0xe2,
+  0xbc, 0x5c, 0x2e, 0x5c, 0xf4, 0x60, 0x50, 0xa9, 0x43, 0x01, 0x24, 0xf9,
+  0x56, 0xe0, 0x8a, 0xd1, 0xcb, 0x85, 0xb0, 0x26, 0x89, 0x7a, 0xac, 0x1a,
+  0x76, 0xe5, 0x0e, 0x60, 0xcb, 0x82, 0xa6, 0xdb, 0xeb, 0x05, 0xd0, 0x08,
+  0xc9, 0x99, 0x32, 0x1e, 0x56, 0x18, 0x28, 0x6f, 0xae, 0x1c, 0x2e, 0xd3,
+  0x25, 0x13, 0xb5, 0x22, 0x4b, 0x33, 0xd1, 0xcc, 0x78, 0xde, 0x52, 0xbb,
+  0xf5, 0x07, 0x57, 0xc5, 0x56, 0xc3, 0x7e, 0xbd, 0xab, 0xa8, 0x70, 0x25,
+  0x49, 0x5d, 0x68, 0x92, 0x0c, 0x16, 0x21, 0x84, 0x45, 0x4f, 0x5c, 0x9e,
+  0xf8, 0xe4, 0x15, 0x7b, 0x68, 0xf6, 0x07, 0x28, 0x74, 0x89, 0xf8, 0x9d,
+  0xb0, 0x06, 0x95, 0x72, 0x49, 0x0f, 0x76, 0x7a, 0x72, 0x15, 0xa4, 0x94,
+  0x49, 0x88, 0xa0, 0x11, 0x9d, 0x98, 0x8b, 0xd9, 0xd6, 0xd2, 0xfd, 0xa4,
+  0xdb, 0x2f, 0x56, 0xb3, 0x51, 0x36, 0xb5, 0x8c, 0x0b, 0x97, 0x54, 0x6d,
+  0x0f, 0x95, 0x34, 0x0d, 0xc4, 0x0c, 0x4a, 0xd1, 0x41, 0x74, 0x1d, 0x58,
+  0x28, 0x7d, 0x98, 0x94, 0x1f, 0xbf, 0xa0, 0xeb, 0xc3, 0x53, 0x64, 0xb3,
+  0x70, 0x19, 0xfe, 0xc9, 0x7c, 0x3c, 0xcd, 0x94, 0xaa, 0x39, 0x31, 0x16,
+  0x2b, 0x55, 0x9d, 0x3a, 0xfb, 0xfe, 0xb2, 0x25, 0x1b, 0x3b, 0x80, 0x9c,
+  0x4d, 0xe2, 0x0e, 0x1b, 0x87, 0xbf, 0xb3, 0x09, 0xf2, 0xdb, 0xf2, 0x85,
+  0x86, 0xe3, 0x1b, 0x34, 0x02, 0x35, 0x24, 0x50, 0xdb, 0x34, 0xd4, 0xbf,
+  0x88, 0x6d, 0x51, 0x3c, 0x80, 0x3f, 0x58, 0xe7, 0xf6, 0x68, 0x6d, 0xe9,
+  0x89, 0x9e, 0xe2, 0xfc, 0x5a, 0x31, 0x87, 0xd4, 0xa9, 0x06, 0x25, 0xd1,
+  0x01, 0xa0, 0x3b, 0x1b, 0x25, 0x0b, 0x25, 0x2e, 0x5c, 0x06, 0xe2, 0xd3,
+  0x52, 0x92, 0xfa, 0x34, 0xfd, 0x49, 0xac, 0x93, 0x8e, 0x10, 0x03, 0x8e,
+  0xf3, 0x89, 0x0b, 0x49, 0x89, 0xfd, 0x5d, 0x66, 0xc8, 0xcc, 0xde, 0x54,
+  0xab, 0x97, 0x59, 0xf0, 0x1a, 0xdb, 0xf3, 0xa0, 0x09, 0x27, 0x6a, 0x43,
+  0x91, 0xae, 0x20, 0x4b, 0x30, 0xe0, 0x16, 0xb2, 0x7e, 0x92, 0xc2, 0x37,
+  0x21, 0xdf, 0xbf, 0xd2, 0x14, 0x73, 0x3a, 0xcf, 0x0a, 0x1a, 0xa0, 0x60,
+  0x48, 0x9f, 0xed, 0xa8, 0x25, 0xae, 0xd4, 0x38, 0xd5, 0x22, 0x3a, 0xb8,
+  0x38, 0x26, 0xc9, 0xf6, 0x7a, 0x8e, 0xa4, 0x70, 0x1e, 0x61, 0xa9, 0xfb,
+  0x03, 0xc1, 0x9a, 0x57, 0x41, 0xcf, 0x07, 0x77, 0x78, 0x1f, 0xbc, 0xc9,
+  0xc4, 0xa4, 0xf1, 0x01, 0x74, 0xc8, 0x5c, 0x00, 0x1a, 0x93, 0xdc, 0xd8,
+  0xc0, 0xfa, 0xc0, 0x75, 0x38, 0xbb, 0x5b, 0x48, 0x8a, 0xbd, 0x25, 0xd4,
+  0x55, 0x66, 0x40, 0x7d, 0xe7, 0x0d, 0xb6, 0x1e, 0x22, 0xf4, 0xd9, 0x5a,
+  0xe3, 0x54, 0xfb, 0x1c, 0x84, 0xbf, 0x19, 0xce, 0x98, 0xf6, 0x55, 0xf1,
+  0x80, 0x7a, 0x72, 0xea, 0xb5, 0x5b, 0x8f, 0xfe, 0x86, 0x7b, 0x86, 0x65,
+  0x91, 0xba, 0x5c, 0x90, 0xb8, 0xd0, 0x7a, 0x31, 0x64, 0x4f, 0x02, 0xe1,
+  0x57, 0xf2, 0xf1, 0x38, 0xb8, 0x5a, 0x6c, 0xd4, 0x2c, 0xfc, 0xc4, 0x45,
+  0x62, 0x15, 0x95, 0xa0, 0x0e, 0x4c, 0xf4, 0xac, 0x32, 0x55, 0x70, 0x9c,
+  0xf0, 0x88, 0x81, 0x36, 0x6e, 0x45, 0x00, 0x08, 0xf9, 0x53, 0xab, 0x99,
+  0xf7, 0x13, 0x37, 0x5b, 0x3f, 0x06, 0xf7, 0x25, 0x7f, 0xf4, 0xca, 0xe1,
+  0x0e, 0xf1, 0x28, 0x06, 0xdc, 0x11, 0x58, 0x2a, 0xdc, 0xa7, 0xfc, 0x0b,
+  0x3e, 0x46, 0xc0, 0x9b, 0xa1, 0xb7, 0x55, 0xb0, 0x43, 0x14, 0xf2, 0x3d,
+  0x1c, 0x88, 0xf8, 0xf8, 0xc0, 0xa1, 0x47, 0xa1, 0x68, 0x1c, 0x54, 0x39,
+  0x62, 0x53, 0x0e, 0x67, 0xf0, 0xda, 0x81, 0x2f, 0x92, 0x4a, 0x55, 0x24,
+  0x97, 0x22, 0xd4, 0xe9, 0x77, 0x68, 0x2d, 0xba, 0xd3, 0xa9, 0x67, 0xf8,
+  0xf6, 0x18, 0xef, 0x2a, 0xb2, 0xe9, 0xbc, 0xc0, 0xa4, 0xbc, 0x8b, 0xf1,
+  0xa4, 0x57, 0x95, 0xdc, 0x06, 0xae, 0xc7, 0xc1, 0xa9, 0x3f, 0x0e, 0xfb,
+  0x05, 0xf9, 0x21, 0x08, 0x17, 0xb8, 0x4b, 0x0b, 0xf3, 0x43, 0x12, 0x6d,
+  0x8f, 0x35, 0x36, 0x42, 0x12, 0xa9, 0x93, 0x72, 0x1c, 0x2c, 0x65, 0x32,
+  0xbe, 0xc9, 0x24, 0x9c, 0x96, 0x16, 0x2d, 0x48, 0xbb, 0xec, 0x44, 0xff,
+  0xa5, 0x34, 0xf0, 0x8d, 0xcf, 0xd6, 0x63, 0x42, 0x18, 0x08, 0xaa, 0xd6,
+  0xc0, 0x13, 0xc4, 0xf1, 0xf7, 0x97, 0x17, 0x07, 0xd1, 0xd7, 0xc7, 0x07,
+  0x47, 0xc7, 0x17, 0xc3, 0xda, 0xa5, 0xaf, 0x51, 0x20, 0x22, 0xa1, 0xb1,
+  0x3d, 0x18, 0xa2, 0xb1, 0xe5, 0xfc, 0x6b, 0xc0, 0xbe, 0x71, 0xbd, 0x78,
+  0x85, 0x83, 0x44, 0xe7, 0x83, 0x15, 0x22, 0x71, 0x1c, 0x70, 0x54, 0x1a,
+  0x47, 0x3e, 0x67, 0x41, 0x1b, 0x5a, 0xfa, 0xd7, 0x59, 0xcf, 0xc3, 0x54,
+  0x19, 0x0f, 0xe7, 0xe4, 0x2f, 0x93, 0x49, 0x66, 0x59, 0x80, 0xd5, 0x9d,
+  0xfb, 0xda, 0x27, 0x5c, 0x07, 0x6c, 0x4b, 0x2f, 0x19, 0x35, 0x20, 0x76,
+  0xbe, 0xef, 0x53, 0xbf, 0x7d, 0x5a, 0xfc, 0x3e, 0x23, 0x6e, 0xad, 0x92,
+  0xa2, 0x53, 0xb3, 0x06, 0x56, 0xbb, 0xdf, 0x90, 0x02, 0x97, 0x8d, 0x93,
+  0xf4, 0x75, 0x6b, 0x4b, 0x7c, 0xba, 0xa6, 0x5c, 0x19, 0xa0, 0xae, 0x41,
+  0xe0, 0x52, 0x0d, 0x84, 0x64, 0x3d, 0x41, 0x8d, 0xbc, 0x16, 0x8d, 0x53,
+  0xf2, 0x6a, 0xa6, 0x86, 0x85, 0x61, 0x20, 0x3a, 0x05, 0xc8, 0x3a, 0x69,
+  0xa9, 0x97, 0x3a, 0xec, 0x22, 0x06, 0x07, 0x49, 0xc3, 0xd2, 0x87, 0xc2,
+  0xfb, 0x01, 0xbe, 0x10, 0x0d, 0xd0, 0x2f, 0x2a, 0xae, 0x52, 0xb5, 0x8b,
+  0x6a, 0x71, 0x1a, 0x6d, 0x8e, 0xc7, 0xe0, 0x68, 0xde, 0xe2, 0xfa, 0xb9,
+  0x4b, 0x03, 0xc6, 0xd6, 0x77, 0x25, 0x18, 0x8c, 0x95, 0x7a, 0x98, 0x3a,
+  0x39, 0xdc, 0x4c, 0x36, 0xde, 0xe4, 0xd5, 0x20, 0x09, 0x28, 0x24, 0x66,
+  0x14, 0xf1, 0x40, 0xe0, 0xb8, 0x7b, 0x2e, 0x89, 0xbe, 0xce, 0x0a, 0xdc,
+  0x05, 0xcd, 0xc7, 0xf9, 0x92, 0x6f, 0x5b, 0x7e, 0xbc, 0xa1, 0xae, 0x2e,
+  0x07, 0x79, 0x07, 0x8c, 0x48, 0xb0, 0xaf, 0xf3, 0x83, 0xcb, 0xaf, 0xe1,
+  0x68, 0x05, 0x09, 0x1f, 0x01, 0xe9, 0xc1, 0xdc, 0x6b, 0xcd, 0x5c, 0x2c,
+  0xa7, 0xc0, 0x89, 0xfc, 0x6b, 0xd8, 0x5d, 0x26, 0x4f, 0xc2, 0x91, 0x07,
+  0x13, 0x25, 0xa0, 0x80, 0x52, 0x35, 0x3c, 0x56, 0x4b, 0xcb, 0x20, 0xea,
+  0xdd, 0x25, 0xda, 0xb9, 0xb0, 0xcb, 0xae, 0x64, 0xa2, 0x77, 0x65, 0x4e,
+  0x20, 0x7a, 0x16, 0xe6, 0x58, 0xe3, 0x09, 0x91, 0x14, 0xf1, 0xc5, 0x95,
+  0xa6, 0xd8, 0xf6, 0x68, 0x4f, 0xdb, 0xa1, 0xb1, 0x82, 0x23, 0xfd, 0xc5,
+  0x6c, 0x35, 0x68, 0xe2, 0x86, 0x44, 0x5f, 0x2e, 0xcb, 0x2a, 0x5b, 0xa9,
+  0xe1, 0x39, 0x3a, 0xc9, 0x32, 0xcf, 0xb2, 0xb2, 0x8a, 0x88, 0x88, 0xd5,
+  0x91, 0x13, 0x2d, 0x18, 0x68, 0x32, 0x16, 0x6e, 0x6a, 0xae, 0x72, 0x77,
+  0x28, 0x18, 0xc6, 0xa3, 0x22, 0x9b, 0x2e, 0xcb, 0x20, 0xf0, 0xfa, 0x97,
+  0x8d, 0x39, 0x18, 0xf4, 0xe6, 0xc9, 0x20, 0x31, 0x82, 0xe2, 0xc8, 0xe1,
+  0x3c, 0x26, 0x4d, 0x9f, 0xab, 0xc0, 0xb2, 0xdf, 0x31, 0xcf, 0xe6, 0xd5,
+  0xea, 0x27, 0x88, 0xf1, 0xde, 0xda, 0xd8, 0x18, 0xda, 0x66, 0x33, 0xf8,
+  0x5e, 0x73, 0xd3, 0x81, 0x13, 0x01, 0x84, 0x3f, 0xf1, 0x1b, 0x8c, 0xe9,
+  0x17, 0xc3, 0x43, 0x4a, 0x64, 0x4f, 0xc1, 0xc2, 0x65, 0x8f, 0xd3, 0xa2,
+  0x3a, 0x29, 0x7c, 0xe5, 0x3c, 0x17, 0x96, 0x58, 0x76, 0x99, 0x19, 0x50,
+  0xae, 0x7a, 0xee, 0x3c, 0x41, 0x54, 0x52, 0xd3, 0x5b, 0x11, 0x33, 0xf9,
+  0x12, 0x50, 0x70, 0x2e, 0x1f, 0x95, 0xcb, 0x83, 0xdc, 0xfe, 0xef, 0xed,
+  0xa8, 0x27, 0x30, 0x37, 0x2d, 0x60, 0x23, 0xcb, 0xe8, 0xff, 0x43, 0x08,
+  0x96, 0x82, 0x15, 0x72, 0x9b, 0x35, 0x84, 0xbf, 0x01, 0xa9, 0x50, 0x37,
+  0xf9, 0xd8, 0x53, 0x3f, 0x49, 0x07, 0xc9, 0x3d, 0xeb, 0x2f, 0xa6, 0x23,
+  0xf0, 0x17, 0x96, 0x65, 0xea, 0x81, 0x63, 0x80, 0x77, 0x71, 0xe5, 0xac,
+  0x7a, 0x5c, 0x38, 0x4a, 0xca, 0x28, 0x89, 0x58, 0x8f, 0x2a, 0x02, 0xe6,
+  0x41, 0xdd, 0x88, 0x2a, 0x7a, 0x7b, 0x11, 0x15, 0x99, 0xfc, 0xb4, 0x6c,
+  0x23, 0x8d, 0xf1, 0x52, 0xf2, 0x57, 0x35, 0x4a, 0x2b, 0xb6, 0x68, 0x19,
+  0x33, 0x8b, 0x3b, 0x95, 0xb0, 0x3a, 0x73, 0x4c, 0xda, 0x18, 0x4d, 0x08,
+  0x60, 0xbf, 0x25, 0x80, 0xcf, 0x70, 0xd9, 0x14, 0xbe, 0x30, 0x2a, 0x92,
+  0xb5, 0xb9, 0xea, 0x90, 0x29, 0x32, 0x76, 0xa3, 0x5a, 0x02, 0x87, 0xdb,
+  0x28, 0x3f, 0x7a, 0xbd, 0xfa, 0x91, 0x10, 0x0f, 0x1f, 0xdd, 0x7d, 0x9c,
+  0x96, 0xa1, 0x44, 0x60, 0x33, 0x22, 0x0d, 0x4f, 0xe1, 0xea, 0x47, 0xab,
+  0x4a, 0x68, 0x8a, 0x8f, 0xdb, 0xbc, 0xe6, 0xfc, 0x0e, 0xb5, 0x48, 0x29,
+  0x96, 0x08, 0xcc, 0x5f, 0x37, 0xa9, 0x46, 0x97, 0xca, 0xa2, 0x9b, 0x39,
+  0x90, 0xed, 0x19, 0x30, 0xef, 0x71, 0x68, 0x81, 0xf7, 0xae, 0xba, 0x00,
+  0x88, 0x41, 0xf3, 0xb4, 0x0c, 0x1c, 0xea, 0x9e, 0xde, 0x20, 0x27, 0x61,
+  0x26, 0x39, 0x56, 0xc5, 0x85, 0x3b, 0x7f, 0x54, 0xd7, 0x61, 0x7f, 0x1c,
+  0xc5, 0x3a, 0x8f, 0xfc, 0x7a, 0x14, 0x72, 0x95, 0xec, 0xed, 0x42, 0x25,
+  0x95, 0xc0, 0x0d, 0x80, 0xd8, 0x59, 0x39, 0xab, 0x4a, 0xf5, 0x91, 0x60,
+  0xdd, 0x51, 0x2f, 0x13, 0x18, 0x89, 0x96, 0x64, 0xaf, 0x7e, 0x66, 0x91,
+  0x08, 0x03, 0x8f, 0x53, 0xa5, 0xec, 0x89, 0x24, 0x6e, 0x17, 0x65, 0xbe,
+  0x1c, 0x57, 0x00, 0xab, 0x40, 0x0c, 0x15, 0xff, 0xbc, 0x5b, 0xde, 0x2c,
+  0xd4, 0xea, 0x37, 0xe3, 0x4a, 0x1a, 0x8b, 0x3e, 0x19, 0x76, 0xb1, 0x25,
+  0x65, 0x40, 0xb5, 0x08, 0x32, 0xb4, 0x13, 0x1a, 0xbf, 0x23, 0xb0, 0xfe,
+  0xb9, 0x4b, 0xa2, 0xaf, 0xe0, 0x7e, 0x49, 0x4a, 0x42, 0x70, 0xeb, 0xaa,
+  0x08, 0x06, 0x91, 0x23, 0x8f, 0x14, 0x81, 0x0c, 0x02, 0x0d, 0x1b, 0x2b,
+  0x37, 0x1c, 0x4a, 0x18, 0x75, 0xd7, 0xf7, 0x75, 0x3f, 0xa9, 0xbf, 0x6d,
+  0x5a, 0x48, 0x03, 0xde, 0x77, 0x65, 0x1d, 0x0a, 0x8f, 0x34, 0x56, 0x8b,
+  0x55, 0x4d, 0xa6, 0x34, 0x65, 0x27, 0x19, 0xca, 0x49, 0x9c, 0xe9, 0xfa,
+  0x0d, 0x5c, 0x25, 0x4e, 0x2b, 0x77, 0x5a, 0x13, 0x24, 0x9a, 0xb7, 0xe2,
+  0xb9, 0xa0, 0x90, 0x34, 0x88, 0xe8, 0xc8, 0xac, 0xa9, 0x60, 0x36, 0x58,
+  0x30, 0xd6, 0x69, 0x6c, 0x93, 0x4e, 0xce, 0x5d, 0x17, 0x34, 0x04, 0x9e,
+  0x71, 0x77, 0x9a, 0xec, 0x74, 0x83, 0xba, 0x14, 0x9b, 0x12, 0xf5, 0x9f,
+  0x41, 0xef, 0x61, 0xcb, 0x21, 0x26, 0x28, 0x76, 0x0b, 0x8e, 0x70, 0xdb,
+  0x6a, 0x19, 0x0a, 0x35, 0xf1, 0x4b, 0x07, 0xb3, 0xfb, 0x62, 0x6f, 0xb0,
+  0xfb, 0xfc, 0xb3, 0xc1, 0xce, 0x60, 0x77, 0x87, 0x39, 0x0b, 0x0f, 0x25,
+  0x18, 0x9c, 0xac, 0x4b, 0x4b, 0x57, 0x95, 0xf7, 0x9a, 0x7d, 0xbe, 0x3d,
+  0xbe, 0xfc, 0xee, 0xec, 0xe2, 0x9b, 0xe8, 0xe4, 0xed, 0xe5, 0xf1, 0xc5,
+  0xeb, 0x83, 0xc3, 0x8f, 0x85, 0x1e, 0x0e, 0x0d, 0xd6, 0x41, 0x21, 0xc2,
+  0xc4, 0x2f, 0x4c, 0xd3, 0x2a, 0xe8, 0xd7, 0x2c, 0x29, 0x6f, 0x76, 0xf6,
+  0x77, 0x1f, 0xc5, 0x2b, 0x6d, 0x31, 0x0c, 0xfa, 0xf7, 0x6d, 0x52, 0xbb,
+  0x3c, 0xa9, 0xf5, 0xad, 0x38, 0x14, 0xb4, 0xa1, 0x04, 0x58, 0xb9, 0xe0,
+  0x5c, 0x30, 0x78, 0x14, 0x25, 0x48, 0x47, 0x79, 0x6c, 0x26, 0xa9, 0x91,
+  0x80, 0x26, 0x4a, 0x46, 0xad, 0xe2, 0xbb, 0x68, 0x10, 0xba, 0xb2, 0x5b,
+  0x8e, 0x51, 0x5e, 0xa6, 0xd3, 0x52, 0x0d, 0x29, 0x82, 0x81, 0x38, 0x81,
+  0x70, 0x67, 0x0c, 0xd9, 0x0a, 0xf3, 0xa2, 0x2e, 0x2f, 0x0a, 0x73, 0x49,
+  0x61, 0xde, 0x89, 0x4b, 0x14, 0x71, 0xc0, 0x03, 0x95, 0x74, 0x1b, 0x8c,
+  0xb5, 0x5a, 0xb7, 0x31, 0x8c, 0xa1, 0xad, 0x01, 0x10, 0x16, 0x16, 0xdb,
+  0x8c, 0x89, 0x55, 0x8c, 0xa2, 0x87, 0x3a, 0x10, 0x9c, 0x86, 0x60, 0x34,
+  0xd2, 0x15, 0x44, 0x29, 0x03, 0xbd, 0xad, 0xc2, 0x67, 0xca, 0xed, 0x84,
+  0xe4, 0x09, 0x91, 0xfc, 0x0c, 0x9f, 0x9b, 0x5b, 0x2f, 0x2a, 0xb0, 0x6a,
+  0x91, 0x14, 0x8a, 0x08, 0x5f, 0x17, 0x21, 0x1b, 0x21, 0x9a, 0x93, 0x3c,
+  0xbe, 0xe7, 0xfa, 0x33, 0x22, 0x36, 0xf8, 0x60, 0xc6, 0xa0, 0xd8, 0x05,
+  0x8b, 0x4c, 0x7e, 0xcd, 0xa3, 0xf3, 0xe3, 0x37, 0x7d, 0xab, 0x83, 0x47,
+  0xbf, 0x8b, 0x19, 0xca, 0x60, 0x37, 0x25, 0xb9, 0x67, 0x91, 0xcc, 0x2d,
+  0xa0, 0x06, 0x3c, 0x51, 0x23, 0x80, 0xc2, 0x09, 0xf0, 0xa1, 0x11, 0x8b,
+  0x84, 0xf0, 0x5a, 0xc5, 0x2f, 0xb3, 0x4b, 0xab, 0x05, 0x01, 0x8f, 0xf7,
+  0x53, 0xa3, 0x96, 0xa3, 0x4d, 0x17, 0xa9, 0xcb, 0xfd, 0x21, 0x1c, 0x15,
+  0xd1, 0x02, 0x2e, 0x40, 0x20, 0xb3, 0x64, 0xeb, 0xf3, 0x6f, 0x0e, 0x87,
+  0x9f, 0xec, 0xee, 0xe9, 0x70, 0xb6, 0x06, 0x1e, 0xce, 0xb2, 0x91, 0x87,
+  0x0f, 0x76, 0x1d, 0x8e, 0xd1, 0xb2, 0xaa, 0x71, 0xc0, 0xb1, 0x19, 0x9b,
+  0x2e, 0x33, 0x68, 0xab, 0x92, 0x1a, 0xb4, 0x21, 0xd5, 0x47, 0x4d, 0xb8,
+  0x74, 0x75, 0xea, 0xd8, 0x19, 0x82, 0x6a, 0x0b, 0x5a, 0xef, 0xa0, 0x74,
+  0xf1, 0x7e, 0xf1, 0xdc, 0x3e, 0x92, 0x96, 0xb5, 0x35, 0xa4, 0x8d, 0xfb,
+  0x98, 0x96, 0xfa, 0x9e, 0xf3, 0x7a, 0xfb, 0x6f, 0x19, 0x35, 0x51, 0x2f,
+  0x75, 0xc3, 0xe5, 0xf1, 0xdd, 0xe0, 0x00, 0x68, 0x08, 0xfb, 0xc4, 0x2a,
+  0xaa, 0xcc, 0x3d, 0xa0, 0x3b, 0x3f, 0x7d, 0x46, 0x1b, 0x45, 0x27, 0x4b,
+  0xa0, 0x1a, 0x98, 0x29, 0x64, 0x53, 0x56, 0x5a, 0xdc, 0x23, 0x47, 0x39,
+  0x03, 0xe7, 0x2f, 0x24, 0x98, 0xf4, 0xed, 0x20, 0xfa, 0x3a, 0x99, 0x17,
+  0x5a, 0xad, 0xd8, 0x92, 0xaf, 0x10, 0x1c, 0xc8, 0x45, 0x93, 0x50, 0xe2,
+  0xe6, 0x34, 0x89, 0x15, 0x44, 0x90, 0x78, 0x5d, 0x21, 0xba, 0xad, 0x95,
+  0x77, 0x88, 0x39, 0x44, 0x0f, 0x37, 0x91, 0x1a, 0x68, 0x51, 0xe3, 0x30,
+  0x2d, 0xb4, 0x81, 0xcd, 0x2a, 0x14, 0x20, 0xa0, 0xa9, 0xd1, 0x9c, 0x1e,
+  0x73, 0x78, 0x99, 0xd4, 0x9e, 0x7c, 0x03, 0xac, 0x55, 0xb6, 0x13, 0x8a,
+  0xae, 0xe5, 0x99, 0xca, 0x24, 0xbf, 0x61, 0xa3, 0x47, 0x41, 0xd7, 0x4d,
+  0x3c, 0x1f, 0xaf, 0x06, 0x13, 0x92, 0x62, 0xd9, 0x6c, 0x36, 0x58, 0xde,
+  0x6e, 0x07, 0xc7, 0x94, 0x59, 0xfe, 0x8d, 0xc0, 0x02, 0x54, 0x4d, 0xde,
+  0x56, 0x9f, 0xaf, 0x89, 0xda, 0x15, 0x57, 0xce, 0x04, 0x93, 0x84, 0x25,
+  0xf8, 0xcb, 0xf1, 0x5c, 0x8b, 0x6f, 0x75, 0x1c, 0x39, 0x98, 0x4f, 0x6e,
+  0x61, 0xb0, 0x48, 0x66, 0xfb, 0x2e, 0x05, 0xd9, 0xf8, 0x83, 0xa2, 0x83,
+  0x3b, 0x95, 0x22, 0x30, 0xcf, 0xce, 0x93, 0xeb, 0xa9, 0x0a, 0x14, 0xa1,
+  0xd2, 0xe2, 0x61, 0x5b, 0x9b, 0x69, 0x20, 0xa2, 0xea, 0xc0, 0x03, 0x81,
+  0xe2, 0x4b, 0xc4, 0xa9, 0x66, 0xa8, 0x8a, 0x62, 0x8c, 0x5f, 0x4b, 0xc2,
+  0xfa, 0x46, 0x14, 0x2c, 0x04, 0x88, 0xa3, 0x2c, 0x06, 0xab, 0x71, 0xc7,
+  0xc2, 0x91, 0xd4, 0xf1, 0x44, 0xdf, 0x0a, 0x85, 0x00, 0xe3, 0x57, 0x43,
+  0xa3, 0xe1, 0xf6, 0xb4, 0x22, 0x78, 0x72, 0x56, 0xe8, 0xeb, 0xbb, 0x27,
+  0x6c, 0xeb, 0xbe, 0x3c, 0x1d, 0xf6, 0x84, 0x1e, 0xe6, 0xc9, 0x7d, 0x40,
+  0x59, 0x02, 0x4b, 0xad, 0xe4, 0xc7, 0x96, 0x1f, 0x09, 0x5f, 0xb3, 0x02,
+  0xbc, 0xb9, 0x8c, 0x46, 0x38, 0x83, 0x77, 0x92, 0xf9, 0x2c, 0x08, 0x5b,
+  0x08, 0x8d, 0x27, 0xe6, 0xe1, 0x58, 0x35, 0x11, 0x11, 0x88, 0x1c, 0xc0,
+  0x0b, 0x43, 0xe7, 0x91, 0xc0, 0xf4, 0xa4, 0x17, 0xf5, 0xf7, 0x00, 0x9b,
+  0xb3, 0x5b, 0x5d, 0xc8, 0x98, 0x8b, 0x7c, 0xc4, 0x63, 0x14, 0x35, 0xda,
+  0x70, 0xc5, 0xd6, 0x8d, 0x25, 0x6c, 0x2a, 0x59, 0xdf, 0xd1, 0xfb, 0xfc,
+  0x63, 0x4f, 0x27, 0x75, 0xb7, 0x8b, 0xd0, 0x6d, 0x96, 0x47, 0xef, 0x92,
+  0xe9, 0xaa, 0x29, 0x36, 0xec, 0x3d, 0xba, 0xb3, 0x48, 0x92, 0xb8, 0x4f,
+  0x1d, 0xa4, 0xaa, 0xa0, 0x6a, 0xc3, 0x10, 0xaa, 0x40, 0x86, 0x36, 0x00,
+  0x5a, 0x46, 0x35, 0x71, 0xcf, 0xa3, 0xbb, 0x3d, 0xf3, 0x34, 0xf3, 0x37,
+  0xb6, 0x78, 0x62, 0xaa, 0xf7, 0x8c, 0xa4, 0x91, 0xbb, 0xc8, 0xe1, 0x6e,
+  0x01, 0xe5, 0x72, 0xea, 0x13, 0xd1, 0x2d, 0x71, 0x92, 0x0a, 0xa7, 0x61,
+  0x0d, 0xaa, 0x74, 0xe8, 0x43, 0xbc, 0xfd, 0x40, 0x7c, 0x25, 0x59, 0xd8,
+  0x07, 0x39, 0x21, 0x04, 0x1c, 0x67, 0x9a, 0x24, 0xd8, 0x62, 0x39, 0xd3,
+  0xea, 0x4c, 0x60, 0xc4, 0x3d, 0x5c, 0xb7, 0x65, 0x44, 0x9c, 0x38, 0x95,
+  0x90, 0xbf, 0x29, 0x84, 0x69, 0x08, 0x58, 0x6a, 0x2c, 0xf5, 0x0b, 0xc5,
+  0x16, 0x30, 0x81, 0xd3, 0x03, 0xbd, 0xdc, 0xa4, 0x62, 0xc3, 0x40, 0x84,
+  0x2a, 0x16, 0x8c, 0x58, 0x45, 0x37, 0xa2, 0xd3, 0xb7, 0xe4, 0x46, 0xcb,
+  0x0c, 0x21, 0xb0, 0x4e, 0x60, 0x90, 0x36, 0x86, 0x10, 0x3a, 0xa3, 0x6e,
+  0xc8, 0x23, 0xfb, 0x9f, 0xf3, 0x1a, 0x14, 0x5d, 0xbf, 0x68, 0x0a, 0x12,
+  0x5c, 0x5d, 0x01, 0x75, 0x8f, 0x14, 0x0a, 0x76, 0x71, 0x9e, 0x5b, 0x31,
+  0xd1, 0x6e, 0xf2, 0xc0, 0x02, 0x52, 0x57, 0x7b, 0x95, 0xaf, 0x05, 0x05,
+  0x00, 0x8b, 0x7b, 0x7e, 0xf2, 0x56, 0xea, 0x63, 0xba, 0x83, 0x94, 0x30,
+  0x64, 0xe2, 0x86, 0x94, 0x76, 0xc5, 0x78, 0x62, 0xc5, 0x99, 0x88, 0xc4,
+  0xde, 0xc4, 0xc4, 0xc6, 0x07, 0x24, 0xd5, 0xbe, 0x2e, 0x96, 0xd2, 0x7b,
+  0x97, 0x2f, 0xc9, 0xa2, 0x98, 0x76, 0x6b, 0x45, 0xdf, 0xdc, 0x66, 0xd6,
+  0x6e, 0x23, 0x67, 0xc8, 0x1a, 0x4f, 0xc2, 0x2a, 0xb6, 0xda, 0x4a, 0x85,
+  0x49, 0xf6, 0x6a, 0x79, 0x92, 0xa1, 0x05, 0xfd, 0x93, 0x68, 0xb0, 0x4d,
+  0x1d, 0x16, 0xdb, 0xf6, 0xe2, 0xe2, 0x76, 0x5c, 0xd0, 0xf5, 0xc8, 0x49,
+  0xc1, 0x3f, 0x3a, 0x24, 0x67, 0x1e, 0xf1, 0xe4, 0xa7, 0xa8, 0x3f, 0x9e,
+  0x62, 0x7e, 0x11, 0x2a, 0x4c, 0xfe, 0x48, 0x24, 0xc3, 0x4f, 0xfc, 0xb4,
+  0xc1, 0x59, 0x72, 0xc3, 0x77, 0x6f, 0x18, 0x47, 0x1d, 0x25, 0xfc, 0x2e,
+  0x2f, 0x0e, 0xde, 0x0e, 0x5f, 0x8b, 0x91, 0xf5, 0x32, 0xf3, 0xc5, 0x01,
+  0xd5, 0xb2, 0xe0, 0x3c, 0x91, 0x0e, 0x69, 0xec, 0x5e, 0xc0, 0xbd, 0x2d,
+  0x48, 0x5b, 0xcb, 0x06, 0xf6, 0xea, 0x20, 0xc6, 0x52, 0x76, 0x10, 0xbc,
+  0x9a, 0x0e, 0xd3, 0x66, 0xb1, 0xe5, 0x2e, 0xd6, 0x22, 0xac, 0x56, 0xe2,
+  0x31, 0xee, 0x0c, 0x1b, 0x55, 0x1f, 0x62, 0x42, 0x39, 0xb4, 0xc1, 0xd8,
+  0xa7, 0xc2, 0xcb, 0xd7, 0xe2, 0x4a, 0x1e, 0x92, 0xea, 0xd1, 0x57, 0x58,
+  0xfc, 0xa0, 0x36, 0x8b, 0x33, 0xcc, 0x09, 0x2f, 0x57, 0x34, 0x38, 0xd7,
+  0x78, 0x98, 0x48, 0x68, 0x4d, 0x6f, 0xfe, 0x71, 0x77, 0xab, 0xbd, 0xf9,
+  0xcb, 0x5f, 0xda, 0x7c, 0xfb, 0xd8, 0x4d, 0xd6, 0xf7, 0x79, 0x2a, 0x9b,
+  0x7f, 0xdc, 0xdb, 0x7a, 0x74, 0x46, 0x61, 0xa6, 0x9d, 0xef, 0x93, 0xde,
+  0xe0, 0xc1, 0x46, 0xaf, 0xac, 0x0e, 0xac, 0xde, 0xc1, 0x2e, 0xd6, 0xe3,
+  0xca, 0xa3, 0xdc, 0x55, 0x50, 0x1f, 0x38, 0x16, 0xd8, 0x49, 0x7e, 0xde,
+  0x85, 0xa3, 0x29, 0x0b, 0x27, 0xff, 0xf3, 0x38, 0x44, 0x07, 0x24, 0x45,
+  0x3c, 0x64, 0x77, 0x9c, 0x6e, 0x5e, 0x64, 0x03, 0xf4, 0xbd, 0xf7, 0x48,
+  0xdf, 0x7e, 0x76, 0x81, 0x9a, 0xcb, 0xfe, 0x50, 0x0e, 0xa8, 0x32, 0x3c,
+  0x58, 0xed, 0x67, 0xc3, 0x97, 0x9c, 0x5c, 0xdf, 0xdf, 0xe5, 0xc9, 0x9b,
+  0x63, 0xc6, 0x8d, 0x3d, 0x3a, 0x61, 0xfc, 0xb2, 0xa1, 0x22, 0x08, 0x9a,
+  0x46, 0xeb, 0xc0, 0x55, 0x43, 0x70, 0x7b, 0x71, 0x14, 0xba, 0xb8, 0x25,
+  0x77, 0xfa, 0xdd, 0x4e, 0x70, 0xd7, 0x1a, 0x58, 0x5b, 0x58, 0xfa, 0xde,
+  0xc9, 0x55, 0xff, 0x4d, 0x36, 0x81, 0xd6, 0xd5, 0x17, 0x38, 0x6a, 0x7a,
+  0x8b, 0x3e, 0x7c, 0x37, 0x9f, 0x55, 0x3e, 0x0e, 0x93, 0x04, 0x55, 0xa1,
+  0xde, 0x58, 0x57, 0x00, 0xe0, 0xe7, 0xed, 0x7e, 0x1f, 0x25, 0x5f, 0x25,
+  0x3e, 0x48, 0xbd, 0x04, 0x15, 0x8c, 0x07, 0x3b, 0xfb, 0xb4, 0x3e, 0xe9,
+  0x74, 0x25, 0x1e, 0xed, 0xd8, 0xc7, 0x21, 0xf9, 0x8c, 0xc0, 0x6b, 0xce,
+  0x4a, 0xf2, 0xc6, 0x22, 0x31, 0x07, 0x6d, 0x84, 0x90, 0x94, 0x90, 0xcb,
+  0x93, 0x7b, 0x1f, 0x48, 0xa3, 0xc5, 0xf5, 0xb2, 0xc5, 0x0a, 0x93, 0xbc,
+  0xaf, 0xf8, 0xe8, 0x5b, 0x1d, 0x75, 0x3f, 0xcb, 0x3b, 0x95, 0x92, 0x17,
+  0xd2, 0x43, 0x48, 0x80, 0xfa, 0x89, 0x56, 0x88, 0x38, 0xcb, 0x03, 0x06,
+  0xa6, 0xc3, 0xb6, 0xa2, 0x2f, 0x01, 0x5c, 0x65, 0x80, 0xae, 0x59, 0x1d,
+  0xa7, 0xb7, 0x5e, 0x6e, 0xf0, 0xb5, 0x36, 0x60, 0xa3, 0xb9, 0x79, 0x59,
+  0x88, 0xeb, 0x2c, 0xaa, 0xe5, 0xeb, 0x92, 0xc8, 0x92, 0x86, 0x25, 0x27,
+  0xbc, 0xdb, 0xef, 0x02, 0x51, 0x3b, 0x9d, 0xb7, 0x4c, 0xa6, 0xff, 0xcb,
+  0x67, 0xd3, 0xf0, 0xe1, 0x45, 0x9d, 0x2b, 0x06, 0x56, 0x60, 0x87, 0x48,
+  0x47, 0x06, 0x20, 0x58, 0x23, 0x42, 0x5b, 0x24, 0xcf, 0x33, 0x5b, 0x33,
+  0xbd, 0x44, 0x74, 0x34, 0x17, 0x62, 0xe9, 0xac, 0xad, 0x62, 0xe4, 0x62,
+  0x3e, 0xba, 0x5c, 0x4c, 0xe0, 0xdd, 0x97, 0xb8, 0xc6, 0xff, 0x8c, 0xe7,
+  0xcb, 0x38, 0x5f, 0x45, 0xbb, 0x7b, 0xbd, 0x68, 0x6f, 0x67, 0x77, 0xaf,
+  0x65, 0x0e, 0x9d, 0xff, 0xe4, 0xe8, 0x9a, 0x3d, 0x7c, 0xdd, 0xf9, 0xd8,
+  0x59, 0xf8, 0x18, 0x79, 0xdc, 0xaa, 0x9a, 0x4d, 0x4a, 0xbc, 0x87, 0x1d,
+  0x7d, 0x52, 0xe1, 0x96, 0x6b, 0xda, 0x01, 0x10, 0x0d, 0x32, 0x85, 0xd8,
+  0x9c, 0xac, 0xf6, 0x94, 0x2b, 0x53, 0xc2, 0x4f, 0x6c, 0x68, 0x59, 0x31,
+  0x84, 0x50, 0x38, 0xc3, 0x5b, 0x9c, 0xa3, 0xb0, 0x56, 0x75, 0x8f, 0xd2,
+  0xd2, 0xb6, 0x85, 0x63, 0x34, 0x78, 0x6f, 0x88, 0xde, 0x8f, 0x4e, 0x0e,
+  0x2f, 0x0d, 0x31, 0xef, 0x8a, 0xaf, 0xd3, 0x7c, 0xf5, 0x71, 0x35, 0x8a,
+  0x1e, 0x7d, 0x66, 0xb2, 0x7f, 0x93, 0x90, 0x44, 0x36, 0x1f, 0x2d, 0xaf,
+  0xf7, 0xff, 0x1a, 0xe7, 0xd7, 0xd9, 0xfc, 0x43, 0xcf, 0x4f, 0x90, 0xa4,
+  0xb4, 0x4f, 0x0c, 0x6a, 0xf7, 0xc5, 0xee, 0x13, 0x89, 0x80, 0x4f, 0xb9,
+  0xa4, 0x19, 0xf8, 0x43, 0x77, 0xd6, 0x15, 0xc0, 0x06, 0x84, 0xde, 0x3b,
+  0x94, 0x86, 0xf9, 0xa4, 0x2b, 0xea, 0x56, 0x1c, 0x3e, 0x3b, 0xd1, 0x67,
+  0x25, 0x9b, 0xb9, 0xbb, 0x21, 0xe5, 0x0b, 0xbb, 0x9c, 0xfa, 0xb7, 0x5c,
+  0x74, 0x07, 0x95, 0x13, 0xfe, 0x81, 0xb9, 0x72, 0x17, 0xae, 0x24, 0xd3,
+  0xa1, 0xf0, 0x64, 0x65, 0xa7, 0xa3, 0x3c, 0x89, 0x6f, 0x7d, 0x91, 0x3b,
+  0x8f, 0xe6, 0x60, 0xb6, 0xf3, 0x8b, 0xd7, 0x87, 0x82, 0x81, 0x69, 0x39,
+  0x38, 0x58, 0xea, 0xc8, 0x59, 0x3a, 0xb6, 0x78, 0x94, 0x1f, 0xe8, 0x9f,
+  0x83, 0xe4, 0xf7, 0x27, 0xa3, 0x8f, 0x78, 0x88, 0xce, 0x9d, 0xc0, 0x8d,
+  0x1d, 0x54, 0xcb, 0x19, 0xb0, 0xcc, 0x5f, 0x32, 0xa9, 0x59, 0x35, 0xbb,
+  0x4d, 0x29, 0xd0, 0x26, 0xb6, 0x6b, 0xa9, 0xa2, 0xae, 0x45, 0x77, 0xd5,
+  0x58, 0x40, 0xe3, 0xe6, 0xea, 0x67, 0x47, 0x07, 0xe7, 0x81, 0xde, 0x04,
+  0xbd, 0xc4, 0xdb, 0x88, 0xf8, 0x39, 0x96, 0x99, 0x51, 0x30, 0x53, 0x4c,
+  0x49, 0xab, 0x9e, 0x97, 0x76, 0x4b, 0xf0, 0xc9, 0xc9, 0x5d, 0x2c, 0x91,
+  0xd6, 0x99, 0x5e, 0x27, 0x30, 0x67, 0x00, 0xcf, 0x7b, 0x3a, 0x89, 0xe1,
+  0x51, 0xd3, 0x4b, 0x08, 0x42, 0x28, 0xda, 0x4a, 0x35, 0xac, 0x86, 0xf6,
+  0xe6, 0x21, 0xd2, 0x6c, 0x00, 0x4d, 0x7b, 0x90, 0xdf, 0xe5, 0x31, 0xce,
+  0x74, 0x5d, 0xd9, 0x04, 0x84, 0x3f, 0xd3, 0xe0, 0xe3, 0xe2, 0x96, 0x58,
+  0xa9, 0x78, 0x82, 0xa9, 0xf7, 0x74, 0x9c, 0x98, 0x4d, 0x75, 0x92, 0x4a,
+  0x44, 0x06, 0x5b, 0x33, 0x80, 0xa5, 0x53, 0xd9, 0x30, 0xb9, 0x81, 0x58,
+  0x79, 0x99, 0x16, 0x89, 0xe0, 0xde, 0x45, 0x97, 0xf7, 0x99, 0x08, 0x9d,
+  0x0e, 0x70, 0x40, 0x62, 0x1a, 0x8b, 0x65, 0x2a, 0xd0, 0x19, 0xb4, 0x79,
+  0xe0, 0x07, 0x41, 0x79, 0xb5, 0x8e, 0x33, 0xa4, 0x1c, 0x39, 0x07, 0xda,
+  0xf0, 0xe8, 0x9b, 0x88, 0x73, 0xb4, 0xb9, 0x8f, 0x43, 0xae, 0x49, 0xc0,
+  0xbe, 0xf0, 0x19, 0x14, 0x89, 0xaf, 0x96, 0x7c, 0xde, 0x0f, 0x6f, 0xe2,
+  0x05, 0x8b, 0xc4, 0xbb, 0x3b, 0xac, 0x7d, 0x7f, 0x67, 0xd9, 0x5e, 0x7c,
+  0x50, 0xad, 0x1c, 0x69, 0xd1, 0x09, 0x14, 0xf3, 0x09, 0x57, 0x13, 0x65,
+  0x99, 0xb8, 0x6a, 0xf3, 0xa3, 0xdb, 0xb3, 0xd8, 0x9e, 0x31, 0xc3, 0x9a,
+  0x16, 0x44, 0x1a, 0x79, 0x31, 0xb9, 0xdd, 0x1e, 0xd3, 0x3f, 0x4f, 0x76,
+  0xb6, 0x01, 0xc5, 0x58, 0xc2, 0x44, 0xc6, 0x34, 0xb9, 0xb7, 0xf7, 0xec,
+  0x59, 0x2f, 0xea, 0xb0, 0xd1, 0xca, 0x3a, 0xe0, 0x23, 0x41, 0x27, 0xab,
+  0xd3, 0x56, 0x67, 0x6e, 0x3b, 0xbf, 0x1a, 0xf3, 0x7f, 0xfc, 0x9a, 0xd5,
+  0x8a, 0xba, 0xd4, 0xf4, 0x0d, 0xac, 0xc3, 0x3c, 0xc4, 0x5a, 0x31, 0xb2,
+  0xba, 0xa7, 0x7d, 0x30, 0xb3, 0x04, 0x7b, 0x20, 0x16, 0x49, 0xb6, 0x30,
+  0x37, 0xe3, 0x4c, 0x01, 0xf2, 0xd1, 0x7d, 0xe0, 0x9c, 0x81, 0x63, 0x58,
+  0xe2, 0xaa, 0x34, 0xb1, 0xbe, 0x58, 0x8e, 0xfa, 0x9a, 0x61, 0x2a, 0x7a,
+  0x46, 0x4a, 0x27, 0x97, 0xfe, 0x9c, 0x9a, 0xf5, 0xb7, 0xc1, 0x91, 0xbf,
+  0x8c, 0x3a, 0x4a, 0x5b, 0xfc, 0x63, 0x00, 0x2f, 0x61, 0x32, 0xe6, 0x69,
+  0x64, 0xaf, 0xf4, 0x8f, 0xff, 0xf8, 0x0f, 0x6a, 0xf6, 0x3f, 0xb8, 0x95,
+  0x57, 0x7f, 0x2c, 0xca, 0x9b, 0xe0, 0x99, 0x8e, 0x12, 0xfc, 0x89, 0xf7,
+  0x91, 0x22, 0xee, 0x09, 0x40, 0xa5, 0x48, 0x84, 0x7a, 0x73, 0xaa, 0x1c,
+  0xb9, 0x17, 0xcc, 0x2f, 0x45, 0x8a, 0x9a, 0xd8, 0xdc, 0x5c, 0xd8, 0xc1,
+  0x97, 0xec, 0xbf, 0x4c, 0x38, 0xb5, 0x99, 0xa8, 0x10, 0x48, 0x74, 0x5b,
+  0x26, 0x62, 0x1c, 0xbf, 0xfd, 0xf6, 0xe4, 0xe2, 0xec, 0xed, 0x9b, 0xe3,
+  0xb7, 0x97, 0xd1, 0xb7, 0x07, 0x17, 0x27, 0x07, 0x5f, 0x9e, 0x6a, 0x06,
+  0x35, 0x4f, 0x81, 0xa3, 0x45, 0x44, 0xf4, 0xae, 0xe1, 0x88, 0x06, 0x19,
+  0x2d, 0xad, 0xe0, 0xf9, 0xb5, 0x72, 0x81, 0xef, 0x15, 0x98, 0x1a, 0xe6,
+  0xd5, 0xf7, 0x28, 0x60, 0xd1, 0x63, 0x87, 0xdf, 0x7b, 0xab, 0x65, 0xc1,
+  0x66, 0xcb, 0x55, 0x90, 0x93, 0xcb, 0x81, 0x2c, 0x4c, 0xa5, 0xc6, 0x9f,
+  0x7c, 0xdd, 0x21, 0x85, 0xf7, 0x1f, 0x44, 0x5f, 0x49, 0x5a, 0xb7, 0x86,
+  0x54, 0xb9, 0x57, 0x35, 0xc5, 0x08, 0x66, 0x1c, 0x37, 0x86, 0x83, 0xd3,
+  0x53, 0xdf, 0xd5, 0xe3, 0x55, 0x18, 0x14, 0xce, 0x47, 0xb2, 0x80, 0x6e,
+  0xac, 0xa2, 0xf0, 0x75, 0xe6, 0x51, 0xb6, 0xe7, 0xab, 0x10, 0x50, 0x9b,
+  0x3b, 0xa3, 0xed, 0xd8, 0x14, 0x2c, 0x06, 0x76, 0x37, 0xd2, 0x01, 0x4a,
+  0x8b, 0xdb, 0x5e, 0xd4, 0xfd, 0x63, 0x57, 0xb2, 0xb3, 0x12, 0xc0, 0xcd,
+  0x4a, 0x8d, 0x87, 0x2d, 0x3f, 0xa8, 0xb7, 0x67, 0x7e, 0x4c, 0xea, 0x44,
+  0x73, 0x03, 0x70, 0x2f, 0x7a, 0xff, 0x67, 0x61, 0xf2, 0x0c, 0x02, 0x0f,
+  0xfd, 0xe3, 0x8a, 0xe8, 0xef, 0x52, 0xcc, 0x95, 0x46, 0xd9, 0x4f, 0xd2,
+  0xfa, 0x2e, 0x94, 0xb6, 0x78, 0x1c, 0xa0, 0x0a, 0x8b, 0x19, 0x87, 0x95,
+  0x5f, 0xc8, 0x01, 0x52, 0xff, 0x58, 0x2e, 0x87, 0x07, 0x29, 0x9b, 0xbd,
+  0x61, 0xc5, 0x7a, 0x95, 0x83, 0x82, 0xaa, 0x1e, 0xb6, 0xad, 0xd6, 0x03,
+  0x5c, 0x56, 0x1c, 0x58, 0x9e, 0xa7, 0x13, 0xc5, 0xa9, 0x6b, 0xa5, 0x8a,
+  0x01, 0x3c, 0x1d, 0x17, 0x87, 0x00, 0xf5, 0x9e, 0x73, 0x01, 0x28, 0x57,
+  0x08, 0x41, 0x82, 0x50, 0x89, 0x8b, 0xe4, 0x9c, 0xd9, 0x35, 0x57, 0x21,
+  0x04, 0x81, 0x9d, 0x10, 0xd1, 0xe3, 0xeb, 0xcc, 0xc4, 0xef, 0xd8, 0xb9,
+  0x5f, 0x25, 0x63, 0x4b, 0x62, 0x76, 0x4c, 0x0a, 0x73, 0x40, 0x54, 0xce,
+  0x02, 0x06, 0x47, 0xad, 0xd9, 0x9b, 0x39, 0x4e, 0x09, 0xf6, 0x32, 0x8d,
+  0x63, 0x28, 0x82, 0x74, 0x5f, 0x1f, 0x06, 0xcf, 0xbc, 0x44, 0x5c, 0x94,
+  0x86, 0x0c, 0x05, 0xfc, 0x2d, 0x4b, 0x0f, 0x46, 0xc4, 0x1c, 0x86, 0xc5,
+  0x0f, 0xa2, 0x49, 0x0d, 0x7e, 0x44, 0x93, 0x66, 0x0a, 0xa5, 0xd3, 0x33,
+  0xe5, 0x4c, 0x24, 0xe3, 0x44, 0x71, 0x34, 0x4a, 0xaf, 0x23, 0xb3, 0x82,
+  0x44, 0x4c, 0x25, 0x40, 0x09, 0xcb, 0x66, 0x09, 0x6f, 0x15, 0x30, 0xc0,
+  0x20, 0xbb, 0xdf, 0x70, 0x85, 0x78, 0x0f, 0x5a, 0x65, 0x33, 0x29, 0x38,
+  0x52, 0x3f, 0xb0, 0xa2, 0xc1, 0x92, 0xbe, 0xe4, 0x75, 0xb4, 0xb0, 0x26,
+  0xc5, 0xb7, 0xd6, 0x20, 0x2f, 0x36, 0xd1, 0x02, 0x6e, 0x6f, 0x8e, 0x94,
+  0x12, 0x4b, 0xcf, 0xc5, 0x3a, 0x58, 0x00, 0x2c, 0x73, 0x0b, 0x58, 0x56,
+  0xb8, 0xda, 0xd4, 0xa6, 0x03, 0xa8, 0xe6, 0x56, 0xc6, 0x02, 0xf1, 0xc9,
+  0x44, 0x2f, 0xf1, 0xe9, 0x95, 0x6a, 0x12, 0xb6, 0x59, 0x0a, 0xc5, 0x74,
+  0x25, 0x65, 0xed, 0x69, 0x7c, 0x9b, 0x01, 0xe3, 0x99, 0x13, 0x89, 0xc8,
+  0x63, 0xa2, 0x3f, 0xea, 0x5f, 0x7d, 0xf1, 0x5e, 0xc6, 0x56, 0x78, 0xab,
+  0xd8, 0xf2, 0x1e, 0x6c, 0x91, 0x02, 0x98, 0x5a, 0xc7, 0x5a, 0xd0, 0x0a,
+  0xe3, 0xa5, 0xfd, 0x32, 0x43, 0x54, 0x68, 0xc7, 0x8a, 0x2c, 0x73, 0x63,
+  0x3a, 0x0d, 0x20, 0xaa, 0xc5, 0x1c, 0x11, 0x37, 0x84, 0x0f, 0x57, 0x9e,
+  0xfe, 0x40, 0x63, 0x48, 0x04, 0xce, 0x36, 0x98, 0x89, 0x46, 0x27, 0xb3,
+  0x78, 0x56, 0x33, 0x8f, 0x05, 0x1c, 0xcd, 0xbc, 0xad, 0xe1, 0xcd, 0xa4,
+  0x95, 0x11, 0xd2, 0x78, 0x26, 0xc2, 0xa3, 0x27, 0xbf, 0xd9, 0x4a, 0xe2,
+  0xd7, 0x36, 0x36, 0x0e, 0xdf, 0x0d, 0x2f, 0xcf, 0xde, 0x44, 0x67, 0xef,
+  0x2e, 0xcf, 0xdf, 0x5d, 0xea, 0xd5, 0x35, 0x92, 0xe8, 0x5f, 0xd1, 0x11,
+  0x45, 0x0a, 0xb0, 0xdd, 0x9c, 0xa9, 0x0b, 0x19, 0xc1, 0x0a, 0x19, 0xa0,
+  0xe9, 0x02, 0x94, 0x1a, 0x97, 0xdd, 0x03, 0xec, 0x26, 0x41, 0xbc, 0xc5,
+  0x9a, 0xdf, 0xd3, 0x9a, 0x23, 0x33, 0x13, 0xb6, 0x1d, 0x4b, 0x16, 0x82,
+  0xde, 0xd3, 0x5e, 0x75, 0xa4, 0x56, 0xc7, 0x0c, 0xce, 0xde, 0x2a, 0x28,
+  0x90, 0x8f, 0xc8, 0x31, 0xdb, 0x8e, 0x37, 0xfd, 0x84, 0xc1, 0x81, 0x08,
+  0x8b, 0x19, 0x97, 0x66, 0xcc, 0xb4, 0xf8, 0x4c, 0x04, 0xad, 0x54, 0x53,
+  0xd4, 0xc2, 0x4c, 0xb9, 0x32, 0xa3, 0x19, 0xde, 0xb8, 0xd8, 0x6a, 0x8e,
+  0x47, 0x41, 0x4c, 0x99, 0x38, 0xe4, 0x39, 0x78, 0xcb, 0x0a, 0xcc, 0xdf,
+  0xb3, 0x09, 0xbc, 0x71, 0xcd, 0xde, 0x47, 0xdd, 0xef, 0x92, 0xb0, 0xc1,
+  0xdf, 0xff, 0x9d, 0x13, 0x00, 0xdf, 0xdb, 0x27, 0xff, 0x90, 0x2e, 0xff,
+  0x32, 0xef, 0x22, 0x14, 0xab, 0xea, 0x79, 0xfd, 0xe6, 0xf8, 0xe2, 0xcb,
+  0xe3, 0x8b, 0xb3, 0x21, 0xc2, 0x4f, 0xcc, 0xdc, 0xd5, 0x24, 0xf6, 0xdb,
+  0x24, 0x1f, 0x25, 0x79, 0xa6, 0x85, 0x64, 0xec, 0xaf, 0x67, 0xdb, 0x5f,
+  0x0d, 0x87, 0x07, 0xe7, 0x27, 0xae, 0xe6, 0x88, 0x4b, 0x45, 0x12, 0x1d,
+  0x69, 0x2e, 0xc9, 0x72, 0x3c, 0x7f, 0x7b, 0x85, 0xe8, 0x62, 0x7c, 0x2b,
+  0x21, 0xaa, 0x0d, 0x1f, 0xa7, 0xd9, 0x68, 0xd9, 0xb9, 0xa9, 0x19, 0x6a,
+  0xdc, 0xb0, 0xa1, 0x0b, 0x49, 0xa2, 0xb6, 0x10, 0xf0, 0x6b, 0x36, 0x29,
+  0xf7, 0x5c, 0x18, 0xd7, 0x6d, 0x3e, 0xea, 0x13, 0xa1, 0xdf, 0x5a, 0x7d,
+  0x48, 0x09, 0xa6, 0x27, 0x36, 0x29, 0x51, 0xb6, 0xde, 0xce, 0x70, 0xcb,
+  0x55, 0x61, 0xb7, 0x6f, 0xf9, 0x68, 0x70, 0x59, 0x8c, 0xe9, 0x40, 0x38,
+  0xbb, 0x9c, 0x25, 0x0b, 0x9d, 0x64, 0xf6, 0xfa, 0x18, 0xd8, 0x01, 0xf5,
+  0xe6, 0xea, 0x55, 0x89, 0xa9, 0x8b, 0x3e, 0x79, 0xea, 0x40, 0x9f, 0xc2,
+  0x82, 0xa1, 0x57, 0x24, 0x7c, 0x2f, 0xee, 0x27, 0x7a, 0x81, 0x00, 0xe2,
+  0x78, 0x2e, 0x56, 0x6e, 0xe1, 0xdf, 0x75, 0x5f, 0x07, 0x17, 0xd8, 0x42,
+  0xd4, 0xbf, 0xc6, 0x34, 0x47, 0xa3, 0x69, 0x3c, 0xbf, 0xc5, 0x4d, 0x86,
+  0xbb, 0x89, 0xd5, 0x4d, 0xc3, 0x32, 0xe2, 0x72, 0x64, 0x70, 0x6d, 0x29,
+  0xbc, 0x00, 0x04, 0x40, 0x2b, 0x7e, 0xce, 0x96, 0x5d, 0x07, 0xd9, 0x14,
+  0x38, 0x71, 0x70, 0x92, 0xfc, 0x22, 0xb0, 0xd5, 0xe8, 0xf8, 0x94, 0x2e,
+  0x25, 0x97, 0xa9, 0x00, 0xf5, 0x3c, 0x99, 0x32, 0xf0, 0x8e, 0x05, 0x97,
+  0x48, 0x72, 0x5e, 0x0a, 0x26, 0x26, 0x8c, 0xc3, 0xd0, 0xb7, 0xe1, 0x86,
+  0x00, 0xa5, 0x20, 0x07, 0xb1, 0x70, 0x35, 0x2a, 0x94, 0x6b, 0x0b, 0x03,
+  0x03, 0xb8, 0xa4, 0x2f, 0x59, 0x11, 0x16, 0x31, 0xd1, 0x98, 0xad, 0x43,
+  0x1f, 0x5a, 0x12, 0xdb, 0x77, 0x32, 0x08, 0x2f, 0x92, 0x3a, 0x67, 0x55,
+  0x25, 0x45, 0x62, 0xed, 0x36, 0xc9, 0xeb, 0x6d, 0x06, 0x00, 0x30, 0x40,
+  0x6a, 0x40, 0xac, 0xdf, 0x0e, 0x5e, 0xc6, 0xe2, 0x5e, 0xab, 0xb1, 0xa6,
+  0x36, 0xf0, 0x81, 0x55, 0x57, 0x47, 0xf8, 0x93, 0xf8, 0x9f, 0x10, 0x27,
+  0xa9, 0xb7, 0x6f, 0x39, 0x01, 0xb7, 0xc9, 0x2b, 0x48, 0xa7, 0x61, 0x88,
+  0xa7, 0x20, 0x20, 0xc0, 0x2c, 0x28, 0x41, 0xff, 0xd0, 0x60, 0x9c, 0x6c,
+  0xdb, 0x7f, 0xcb, 0x57, 0x45, 0xd6, 0x1f, 0x2d, 0xa1, 0x93, 0x79, 0xac,
+  0x2e, 0x4d, 0x04, 0xe4, 0xa2, 0xc0, 0x00, 0xe7, 0xc2, 0xf7, 0xec, 0xd6,
+  0x40, 0x8a, 0xb5, 0x78, 0x3a, 0x90, 0x73, 0x57, 0x05, 0x6e, 0x71, 0x70,
+  0x1d, 0x12, 0xc8, 0x8e, 0x80, 0x5e, 0x8d, 0x5a, 0xd6, 0x11, 0xea, 0x26,
+  0xbb, 0x90, 0xb3, 0xb9, 0x56, 0xcd, 0x83, 0x9d, 0xbd, 0x1a, 0xb6, 0x5b,
+  0x3a, 0xb4, 0xf4, 0x4b, 0x88, 0x08, 0x89, 0x62, 0x88, 0x5b, 0x3c, 0xae,
+  0x45, 0xff, 0xdf, 0x95, 0x5c, 0x1f, 0x48, 0x90, 0x06, 0xe2, 0xa9, 0x14,
+  0x79, 0x58, 0x7b, 0x8b, 0xc8, 0x61, 0x2a, 0x2f, 0x2f, 0x7f, 0x38, 0x3f,
+  0x7e, 0x65, 0x6f, 0x3e, 0xb6, 0x67, 0x02, 0xc0, 0x85, 0xf0, 0x8b, 0x44,
+  0xc1, 0x2e, 0x83, 0x1a, 0x9c, 0x44, 0x64, 0xfd, 0xd2, 0xdc, 0xc2, 0xd2,
+  0x4d, 0x3f, 0xfa, 0xfe, 0xe8, 0x64, 0x78, 0x7e, 0x7a, 0x76, 0xf8, 0xea,
+  0xe5, 0xf7, 0xc6, 0x8d, 0x3f, 0x67, 0xc4, 0x19, 0x91, 0xd1, 0xdc, 0x67,
+  0x1e, 0x20, 0x40, 0xdf, 0x7b, 0x7b, 0xfc, 0xdd, 0x7b, 0xd2, 0x0c, 0x5e,
+  0x31, 0x28, 0x78, 0xef, 0x2e, 0x9e, 0xea, 0x4b, 0xac, 0x5e, 0xb5, 0xc8,
+  0x75, 0x41, 0x3a, 0x47, 0xdb, 0xc2, 0xb2, 0x3c, 0x11, 0x20, 0xb4, 0xae,
+  0x20, 0x41, 0x6b, 0x44, 0x56, 0x50, 0x4f, 0x28, 0xae, 0xe4, 0x66, 0xb6,
+  0x14, 0x67, 0xcc, 0xdc, 0xcd, 0xdf, 0x2d, 0x25, 0x32, 0x8f, 0xbd, 0xd1,
+  0xa1, 0x93, 0x17, 0xc1, 0x8f, 0xfa, 0x8d, 0x0f, 0x0a, 0x55, 0xf8, 0xdd,
+  0x9c, 0x63, 0x21, 0x1c, 0x96, 0xa1, 0x56, 0xc8, 0x84, 0xfb, 0x54, 0x01,
+  0x0f, 0x15, 0xc9, 0x87, 0xe3, 0x30, 0x2d, 0x24, 0xdb, 0x55, 0x61, 0x16,
+  0xf1, 0xc5, 0x8d, 0x25, 0x1e, 0x8f, 0xe9, 0x07, 0x63, 0x4c, 0x72, 0x39,
+  0x97, 0x73, 0xae, 0xca, 0x3e, 0xbc, 0x64, 0x15, 0x4a, 0xab, 0x96, 0xa9,
+  0xf9, 0xd9, 0x4a, 0xca, 0x21, 0xf1, 0xbf, 0x8a, 0x5d, 0x19, 0x96, 0x9a,
+  0xa8, 0x9c, 0x68, 0xc7, 0xe6, 0xaa, 0x99, 0x80, 0x6c, 0x45, 0x90, 0xf4,
+  0x42, 0x16, 0x42, 0x05, 0x81, 0x35, 0xbe, 0xb2, 0x03, 0x9c, 0x29, 0x69,
+  0xd4, 0x2a, 0x2e, 0xa0, 0x5a, 0x0a, 0x76, 0x67, 0x9a, 0x8e, 0xbc, 0xc1,
+  0xbc, 0xe6, 0x89, 0x64, 0x47, 0xb7, 0x22, 0x3e, 0x84, 0x47, 0xc8, 0x4c,
+  0xe1, 0x3e, 0xbd, 0xb6, 0xc8, 0xac, 0x7c, 0xa2, 0x10, 0x3f, 0x4c, 0xd5,
+  0x61, 0x12, 0xa4, 0x53, 0x52, 0xa1, 0x98, 0x98, 0x88, 0xe6, 0x3e, 0x0d,
+  0x42, 0x19, 0x15, 0x44, 0x08, 0xd8, 0xa7, 0xca, 0xb2, 0x51, 0xaf, 0x5c,
+  0xd2, 0x99, 0xd8, 0xc8, 0x42, 0x02, 0x0b, 0xd2, 0xb3, 0x11, 0x72, 0xa2,
+  0x33, 0x6b, 0x48, 0x1f, 0x2a, 0x36, 0x5e, 0x73, 0x1e, 0x14, 0x90, 0x9a,
+  0x26, 0x2c, 0x6a, 0xc1, 0xfa, 0x16, 0x76, 0x66, 0x37, 0x29, 0xaf, 0xe0,
+  0x68, 0x19, 0xd6, 0xf3, 0x72, 0xa3, 0x97, 0x92, 0x16, 0x58, 0x78, 0x04,
+  0xdb, 0xc5, 0x39, 0x90, 0x10, 0x4b, 0x45, 0x1a, 0x37, 0xa5, 0x47, 0x23,
+  0xe7, 0x06, 0x55, 0x50, 0x18, 0xa3, 0x4b, 0x2b, 0xd5, 0xf7, 0xd8, 0x8a,
+  0xba, 0xd5, 0x14, 0xf2, 0xcd, 0x13, 0x0b, 0x81, 0x11, 0x13, 0x43, 0xc1,
+  0xbe, 0x86, 0xf9, 0xd8, 0x5d, 0xc6, 0x9c, 0xb9, 0xc2, 0xa1, 0x20, 0xb9,
+  0x02, 0xee, 0x2c, 0xb9, 0x38, 0xba, 0x56, 0x10, 0x45, 0xfd, 0x4b, 0x76,
+  0xb8, 0x19, 0x18, 0x9b, 0x8f, 0x05, 0x96, 0xe5, 0x0e, 0xc8, 0x4a, 0x4c,
+  0xeb, 0x2b, 0xed, 0xd0, 0x65, 0x59, 0xdb, 0x66, 0xf5, 0x24, 0x69, 0x27,
+  0x46, 0x8e, 0x88, 0xd9, 0x74, 0x83, 0x5c, 0xc3, 0x42, 0x33, 0x38, 0x9d,
+  0xb3, 0x52, 0x18, 0x1e, 0x2a, 0x16, 0xf9, 0x9c, 0xa7, 0x8a, 0x53, 0x90,
+  0x24, 0xcb, 0x05, 0xca, 0xef, 0x8c, 0x15, 0x81, 0x1c, 0xc1, 0x9f, 0xae,
+  0x3d, 0xbb, 0x43, 0xfc, 0x5a, 0xd1, 0xa2, 0xbe, 0x79, 0x77, 0x7a, 0x79,
+  0x72, 0x1e, 0x3a, 0x1e, 0xa3, 0xef, 0x4e, 0x2e, 0xbf, 0x26, 0x79, 0x9d,
+  0x6b, 0x3b, 0x9f, 0xb2, 0x77, 0xe7, 0xcd, 0x9b, 0x83, 0xb7, 0x9c, 0xa1,
+  0xfe, 0x16, 0x31, 0x72, 0x07, 0xd0, 0x19, 0x98, 0x1b, 0xd1, 0x0a, 0x33,
+  0xe9, 0x70, 0xee, 0x72, 0xaf, 0xe9, 0x65, 0xa8, 0x9d, 0x3e, 0x30, 0x1c,
+  0x3e, 0x42, 0xe1, 0x1a, 0xf1, 0x86, 0xab, 0x4e, 0xb0, 0x62, 0x9b, 0x0e,
+  0x4e, 0x2d, 0xeb, 0x59, 0xbc, 0xce, 0x75, 0xe8, 0x71, 0xe4, 0xc9, 0x89,
+  0x6c, 0x0e, 0x9f, 0xaa, 0x5c, 0xdd, 0xde, 0x73, 0x81, 0x0d, 0x75, 0x20,
+  0xa6, 0x88, 0x59, 0x25, 0x91, 0x69, 0xae, 0x2a, 0x8d, 0x5c, 0x97, 0xd5,
+  0xb8, 0x75, 0xea, 0x11, 0x43, 0x82, 0x53, 0x39, 0xf3, 0xc6, 0x40, 0x56,
+  0x36, 0x59, 0x5f, 0xbe, 0x38, 0x0d, 0xef, 0xd3, 0x6a, 0xfd, 0x60, 0x0b,
+  0x34, 0xbb, 0xce, 0x12, 0x7f, 0x70, 0xfb, 0x67, 0xd6, 0x8c, 0x59, 0x7e,
+  0xa1, 0x81, 0xc9, 0xdd, 0xd2, 0x67, 0xb6, 0xd6, 0xa7, 0x2d, 0xd9, 0x72,
+  0x35, 0x6a, 0xd4, 0x72, 0xb6, 0x2f, 0x52, 0x65, 0xa5, 0x8a, 0x37, 0x90,
+  0x63, 0xcf, 0x5c, 0xcb, 0x1a, 0xd0, 0x80, 0xb8, 0x5e, 0x4d, 0x8d, 0xd1,
+  0x39, 0x83, 0x59, 0xda, 0x63, 0x95, 0xcc, 0xde, 0x5a, 0x29, 0x71, 0x4b,
+  0x8d, 0x42, 0x42, 0x24, 0x43, 0xb8, 0x78, 0x9f, 0x29, 0xca, 0x72, 0x65,
+  0xd9, 0x20, 0x79, 0x48, 0xd8, 0xbd, 0xc9, 0xbf, 0xfe, 0x75, 0x71, 0x1d,
+  0x66, 0x4d, 0x61, 0xae, 0x9a, 0x1e, 0xdc, 0x8e, 0x09, 0x2c, 0x52, 0x91,
+  0x16, 0x27, 0xab, 0x8c, 0x40, 0x2b, 0x8e, 0xed, 0xae, 0xeb, 0x50, 0xbf,
+  0xdf, 0x6b, 0x7e, 0xbf, 0x27, 0x16, 0x47, 0xae, 0x40, 0xef, 0xf0, 0x34,
+  0x25, 0x17, 0x38, 0x94, 0xde, 0x4c, 0x26, 0x60, 0x0a, 0x93, 0x62, 0xf5,
+  0x70, 0xab, 0x08, 0x4b, 0x14, 0xb3, 0x3f, 0xc7, 0x22, 0x2d, 0x73, 0xe4,
+  0x38, 0xe2, 0x11, 0x58, 0x88, 0x25, 0x80, 0x14, 0xe1, 0x5a, 0x60, 0x53,
+  0x7c, 0x5b, 0x51, 0x83, 0xf4, 0xfd, 0x53, 0x17, 0xd0, 0xed, 0x59, 0x1a,
+  0x0a, 0x7c, 0x69, 0x46, 0x4d, 0x3f, 0x5d, 0xdc, 0x59, 0x81, 0x4b, 0xfa,
+  0xf5, 0xb9, 0x2b, 0xee, 0x52, 0x54, 0xdc, 0x53, 0x15, 0xe0, 0x5a, 0xe3,
+  0xfd, 0x18, 0x1c, 0x02, 0xec, 0x98, 0x31, 0x38, 0xcc, 0xd7, 0x41, 0x6d,
+  0x5c, 0x49, 0x35, 0xb4, 0x37, 0x28, 0x35, 0x09, 0xdb, 0xf2, 0x14, 0xd9,
+  0x95, 0x60, 0x47, 0x01, 0x6f, 0x09, 0x71, 0xe2, 0x75, 0xd7, 0x7f, 0xdc,
+  0xdb, 0xd9, 0xd9, 0xdd, 0xdf, 0xfd, 0xec, 0xc5, 0xce, 0xfe, 0xee, 0xee,
+  0xee, 0xde, 0xfe, 0xee, 0xfe, 0xfe, 0xde, 0xce, 0x4f, 0xdb, 0x6c, 0x3a,
+  0xba, 0x4b, 0x93, 0x7b, 0x57, 0x49, 0xfe, 0x3b, 0xb9, 0xa6, 0xe1, 0x2f,
+  0x58, 0x89, 0x1b, 0x90, 0xb9, 0xa4, 0x6a, 0xb8, 0x26, 0xf8, 0x38, 0x64,
+  0x02, 0x09, 0xbe, 0x16, 0x40, 0xb2, 0x85, 0xcf, 0x56, 0xc4, 0x19, 0x0c,
+  0x00, 0x93, 0x31, 0xaa, 0xbf, 0x2d, 0x79, 0xa6, 0x23, 0x96, 0x06, 0x20,
+  0xd2, 0x14, 0x2e, 0x37, 0xec, 0x7a, 0x9a, 0x8d, 0x46, 0x08, 0x80, 0x77,
+  0xe9, 0x91, 0x83, 0x88, 0x91, 0x39, 0x6f, 0x85, 0x24, 0xd4, 0x69, 0x80,
+  0xf0, 0x34, 0x39, 0xe8, 0x7e, 0x75, 0x44, 0xee, 0xd2, 0x90, 0xdc, 0x71,
+  0xc6, 0xa8, 0xf4, 0x13, 0x66, 0x4a, 0xb4, 0x48, 0xb9, 0x4b, 0x9b, 0x88,
+  0xae, 0x92, 0xcf, 0x76, 0xf6, 0xf7, 0xb9, 0x70, 0xc4, 0xef, 0x77, 0x7b,
+  0x1a, 0x59, 0x18, 0x86, 0x4b, 0xf7, 0xdc, 0xed, 0x24, 0x6d, 0xb0, 0xf6,
+  0x11, 0xce, 0x73, 0xbe, 0x9c, 0x25, 0xb9, 0xea, 0x21, 0xb8, 0x0f, 0x05,
+  0x40, 0x86, 0x89, 0xd1, 0x86, 0xec, 0x9e, 0x45, 0x29, 0x14, 0x98, 0xe4,
+  0x25, 0xbf, 0xc1, 0x5f, 0x9e, 0x7a, 0xce, 0x71, 0x54, 0xe6, 0x52, 0x64,
+  0x92, 0x1f, 0x86, 0x40, 0x0e, 0x54, 0x8c, 0xec, 0x36, 0x94, 0x55, 0x35,
+  0xa7, 0xe3, 0xc7, 0x60, 0xf0, 0x7b, 0xcf, 0x76, 0x7f, 0x92, 0x40, 0x36,
+  0x26, 0x70, 0xbf, 0x0a, 0x5a, 0x1a, 0x6c, 0xa2, 0xf2, 0x88, 0xa4, 0x81,
+  0x29, 0x61, 0x6c, 0x26, 0x83, 0xeb, 0x81, 0x09, 0x09, 0x6a, 0x38, 0xec,
+  0x85, 0xe1, 0xc4, 0x82, 0x60, 0x2d, 0x35, 0xd9, 0xa1, 0x76, 0x99, 0x6d,
+  0xc8, 0x6c, 0xbb, 0x62, 0x97, 0xac, 0xd4, 0x78, 0xd9, 0xa0, 0x2b, 0xe3,
+  0xe0, 0xe4, 0x94, 0xe3, 0x55, 0x4e, 0x49, 0x02, 0x1b, 0x1a, 0x2b, 0x43,
+  0x48, 0x0f, 0xe2, 0x6d, 0xe6, 0x29, 0xdf, 0xa6, 0x3d, 0x07, 0x2d, 0x6f,
+  0x61, 0xf1, 0x10, 0x2b, 0xd8, 0xee, 0x2e, 0x92, 0xb9, 0xe2, 0x40, 0x91,
+  0x3c, 0x4c, 0xfc, 0xac, 0x10, 0x73, 0x0a, 0xe0, 0x16, 0x19, 0x87, 0x18,
+  0x3e, 0x0e, 0x48, 0xbc, 0xb2, 0xf0, 0xa8, 0x66, 0x91, 0x27, 0xd3, 0xe4,
+  0x4e, 0xed, 0x1e, 0x02, 0x5e, 0xf7, 0x95, 0xba, 0x17, 0xa4, 0x98, 0x5d,
+  0xe9, 0xbd, 0x24, 0x15, 0x0f, 0x06, 0xf7, 0xb9, 0x2d, 0x79, 0xff, 0x3e,
+  0x9d, 0x1b, 0xc5, 0x7f, 0x1d, 0xe0, 0xb2, 0x79, 0x73, 0xf8, 0xbd, 0x3e,
+  0x8b, 0xa0, 0x1a, 0x87, 0xf4, 0xae, 0xd0, 0x8c, 0xdd, 0x7a, 0x54, 0xa0,
+  0xa8, 0xf2, 0x56, 0x0e, 0x49, 0xcc, 0x62, 0x3d, 0xc3, 0xc4, 0x14, 0x63,
+  0x1e, 0x4b, 0x2d, 0x3d, 0x36, 0xa1, 0xa0, 0xa5, 0x2b, 0x92, 0x97, 0x18,
+  0xf9, 0xbc, 0x17, 0xf9, 0xc2, 0xf1, 0xd9, 0x94, 0xfe, 0x44, 0xa0, 0x03,
+  0xaf, 0x3a, 0x9e, 0x65, 0x4c, 0xbf, 0x20, 0xfc, 0x88, 0xfe, 0x94, 0xb0,
+  0x57, 0xfd, 0x0b, 0x4d, 0xe5, 0x4b, 0x40, 0x47, 0xf6, 0x84, 0x58, 0xd9,
+  0x1f, 0x50, 0x8e, 0x07, 0x6e, 0xf4, 0xea, 0x8e, 0x93, 0xf1, 0x1f, 0x99,
+  0xb7, 0xc8, 0xd8, 0x44, 0x96, 0xdb, 0xea, 0xca, 0x2e, 0x8c, 0xa4, 0x7a,
+  0xd5, 0x97, 0x4b, 0xb6, 0x53, 0xbb, 0xea, 0x0c, 0x3c, 0x8a, 0x19, 0x93,
+  0x56, 0x22, 0x85, 0xe2, 0x5c, 0xe3, 0x2c, 0x70, 0x2d, 0x69, 0x77, 0xa5,
+  0xf5, 0xd3, 0xec, 0x9e, 0xab, 0xdc, 0x5d, 0x5d, 0x71, 0xdd, 0xf2, 0xb3,
+  0xb9, 0x87, 0x88, 0x64, 0xae, 0x2a, 0x0f, 0xce, 0xac, 0xb4, 0x06, 0xcd,
+  0xcd, 0x0a, 0xd8, 0x5b, 0xe0, 0xe2, 0x20, 0x3a, 0xc0, 0x2a, 0x91, 0x2c,
+  0x84, 0xe6, 0xc4, 0xcd, 0x06, 0x71, 0xb0, 0x16, 0x27, 0xa7, 0x25, 0x78,
+  0xf9, 0x86, 0x9c, 0xa1, 0xdc, 0x1f, 0xc7, 0x84, 0xcd, 0xb2, 0xb9, 0x85,
+  0x3d, 0x2f, 0x0b, 0x01, 0x0c, 0xb3, 0x7a, 0xbd, 0x1b, 0x62, 0x33, 0x4c,
+  0xa7, 0x8a, 0xd0, 0xab, 0x82, 0x33, 0xde, 0x08, 0x27, 0x33, 0xe9, 0x2f,
+  0x6e, 0x16, 0xb6, 0xd3, 0xc6, 0xaf, 0x84, 0x99, 0x69, 0xa0, 0x2d, 0xae,
+  0xb7, 0xf3, 0xaf, 0xcf, 0x07, 0xd1, 0x31, 0xb7, 0x24, 0x63, 0xd2, 0x7b,
+  0x08, 0x1a, 0x14, 0x7d, 0x47, 0x93, 0xbd, 0x66, 0x06, 0x7e, 0x96, 0xf3,
+  0x5f, 0x68, 0x4d, 0xbf, 0x14, 0xa3, 0x09, 0xbe, 0xad, 0xf6, 0x4a, 0x0d,
+  0x59, 0x44, 0xdc, 0x39, 0x7e, 0xa7, 0xa3, 0x42, 0xdc, 0xd1, 0x6d, 0x93,
+  0xef, 0x21, 0xcb, 0x2b, 0xf0, 0x0a, 0xf2, 0x66, 0x44, 0x4c, 0x13, 0xac,
+  0x6f, 0xb1, 0xc2, 0xfe, 0x41, 0xe1, 0x06, 0x26, 0x87, 0x5e, 0x0f, 0xd2,
+  0x40, 0x40, 0x5a, 0x4a, 0x7e, 0x2e, 0xb0, 0x46, 0xce, 0x55, 0x2e, 0xc0,
+  0x02, 0x79, 0xa2, 0x61, 0x48, 0x99, 0x3a, 0x30, 0x44, 0xdf, 0x28, 0x92,
+  0xda, 0x71, 0x0d, 0xc4, 0x2b, 0xfb, 0x82, 0x85, 0x62, 0x1e, 0x0b, 0x31,
+  0xa1, 0x65, 0x3c, 0x1d, 0x6c, 0xfc, 0x2f, 0xc9, 0x11, 0xc2, 0x43, 0x02,
+  0xff, 0x01, 0x00,
+};
+#define BUF_SIZE 0x10000
+/* Decompress and send to stdout a gzip-compressed buffer */
+void hugehelp(void)
+{
+  unsigned char* buf;
+  int status,headerlen;
+  z_stream z;
+
+  /* Make sure no gzip options are set */
+  if (hugehelpgz[3] & 0xfe)
+    return;
+
+  headerlen = 10;
+  z.avail_in = (unsigned int)(sizeof(hugehelpgz) - headerlen);
+  z.next_in = (unsigned char *)hugehelpgz + headerlen;
+  z.zalloc = (alloc_func)Z_NULL;
+  z.zfree = (free_func)Z_NULL;
+  z.opaque = 0;
+
+  if (inflateInit2(&z, -MAX_WBITS) != Z_OK)
+    return;
+
+  buf = malloc(BUF_SIZE);
+  if (buf) {
+    while(1) {
+      z.avail_out = BUF_SIZE;
+      z.next_out = buf;
+      status = inflate(&z, Z_SYNC_FLUSH);
+      if (status == Z_OK || status == Z_STREAM_END) {
+        fwrite(buf, BUF_SIZE - z.avail_out, 1, stdout);
+        if (status == Z_STREAM_END)
+          break;
+      }
+      else
+        break;    /* Error */
+    }
+    free(buf);
+  }
+  inflateEnd(&z);
+}
+#endif /* USE_MANUAL */
+#endif /* HAVE_LIBZ */
diff --git a/src/hugehelp.h b/src/hugehelp.h
new file mode 100644
index 0000000..b84be17
--- /dev/null
+++ b/src/hugehelp.h
@@ -0,0 +1,26 @@
+#ifndef HEADER_CURL_HUGEHELP_H
+#define HEADER_CURL_HUGEHELP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+void hugehelp(void);
+
+#endif /* HEADER_CURL_HUGEHELP_H */
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..6e3ef3d
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,5830 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <errno.h>
+
+#if defined(MSDOS) || defined(WIN32)
+#  if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
+#    include <libgen.h>
+#  endif
+#endif
+
+#include <curl/curl.h>
+
+#include "urlglob.h"
+#include "writeout.h"
+#include "getpass.h"
+#include "homedir.h"
+#include "curlutil.h"
+#ifdef USE_MANUAL
+#include "hugehelp.h"
+#endif
+#ifdef USE_ENVIRONMENT
+#include "writeenv.h"
+#endif
+#include "rawstr.h"
+
+#define CURLseparator   "--_curl_--"
+
+#ifdef NETWARE
+#ifdef __NOVELL_LIBC__
+#include <screen.h>
+#else
+#include <nwconio.h>
+#define mkdir mkdir_510
+#endif
+#endif
+
+#include "version.h"
+
+#ifdef HAVE_IO_H /* typical win32 habit */
+#include <io.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_UTIME_H
+#include <utime.h>
+#else
+#ifdef HAVE_SYS_UTIME_H
+#include <sys/utime.h>
+#endif
+
+#endif /* HAVE_UTIME_H */
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifdef HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#elif defined(HAVE_POLL_H)
+#include <poll.h>
+#endif
+
+#ifdef HAVE_LOCALE_H
+#include <locale.h> /* for setlocale() */
+#endif
+
+#define ENABLE_CURLX_PRINTF
+/* make the curlx header define all printf() functions to use the curlx_*
+   versions instead */
+#include "curlx.h" /* header from the libcurl directory */
+
+#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
+#include <iconv.h>
+/* set default codesets for iconv */
+#ifndef CURL_ICONV_CODESET_OF_NETWORK
+#define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1"
+#endif
+#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h> /* for IPPROTO_TCP */
+#endif
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h> /* for TCP_KEEPIDLE, TCP_KEEPINTVL */
+#endif
+
+#include "os-specific.h"
+
+/* The last #include file should be: */
+#ifdef CURLDEBUG
+#ifndef CURLTOOLDEBUG
+#define MEMDEBUG_NODEFINES
+#endif
+/* This is low-level hard-hacking memory leak tracking and similar. Using
+   the library level code from this client-side is ugly, but we do this
+   anyway for convenience. */
+#include "memdebug.h"
+#endif
+
+#ifdef __VMS
+static int vms_show = 0;
+#endif
+
+#if defined(NETWARE)
+#define PRINT_LINES_PAUSE 23
+#endif
+
+#if defined(__SYMBIAN32__)
+#define PRINT_LINES_PAUSE 16
+#define pressanykey() getchar()
+#endif
+
+#define DEFAULT_MAXREDIRS  50L
+
+#if defined(O_BINARY) && defined(HAVE_SETMODE)
+  #ifdef __HIGHC__
+    #define SET_BINMODE(file) _setmode(file,O_BINARY)
+  #else
+    #define SET_BINMODE(file) setmode(fileno(file),O_BINARY)
+  #endif
+#else
+  #define SET_BINMODE(file)   ((void)0)
+#endif
+
+#ifndef O_BINARY
+/* since O_BINARY as used in bitmasks, setting it to zero makes it usable in
+   source code but yet it doesn't ruin anything */
+#define O_BINARY 0
+#endif
+
+#if defined(MSDOS) || defined(WIN32)
+
+static const char *msdosify(const char *);
+static char *rename_if_dos_device_name(char *);
+static char *sanitize_dos_name(char *);
+
+#ifndef S_ISCHR
+#  ifdef S_IFCHR
+#    define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#  else
+#    define S_ISCHR(m) (0) /* cannot tell if file is a device */
+#  endif
+#endif
+
+#ifdef WIN32
+#  define _use_lfn(f) (1)  /* long file names always available */
+#elif !defined(__DJGPP__) || (__DJGPP__ < 2)  /* DJGPP 2.0 has _use_lfn() */
+#  define _use_lfn(f) (0)  /* long file names never available */
+#endif
+
+#endif /* MSDOS || WIN32 */
+
+#ifdef MSDOS
+#define USE_WATT32
+#include <dos.h>
+
+#ifdef DJGPP
+/* we want to glob our own argv[] */
+char **__crt0_glob_function (char *arg)
+{
+  (void)arg;
+  return (char**)0;
+}
+#endif /* __DJGPP__ */
+#endif /* MSDOS */
+
+#ifndef STDIN_FILENO
+#define STDIN_FILENO  fileno(stdin)
+#endif
+
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO  fileno(stdout)
+#endif
+
+#ifndef STDERR_FILENO
+#define STDERR_FILENO  fileno(stderr)
+#endif
+
+#define CURL_PROGRESS_STATS 0 /* default progress display */
+#define CURL_PROGRESS_BAR   1
+
+typedef enum {
+  HTTPREQ_UNSPEC,
+  HTTPREQ_GET,
+  HTTPREQ_HEAD,
+  HTTPREQ_POST,
+  HTTPREQ_SIMPLEPOST,
+  HTTPREQ_CUSTOM,
+  HTTPREQ_LAST
+} HttpReq;
+
+/*
+ * Large file support (>2Gb) using WIN32 functions.
+ */
+
+#ifdef USE_WIN32_LARGE_FILES
+#  include <io.h>
+#  include <sys/types.h>
+#  include <sys/stat.h>
+#  define lseek(fdes,offset,whence)  _lseeki64(fdes, offset, whence)
+#  define fstat(fdes,stp)            _fstati64(fdes, stp)
+#  define stat(fname,stp)            _stati64(fname, stp)
+#  define struct_stat                struct _stati64
+#  define LSEEK_ERROR                (__int64)-1
+#endif
+
+/*
+ * Small file support (<2Gb) using WIN32 functions.
+ */
+
+#ifdef USE_WIN32_SMALL_FILES
+#  include <io.h>
+#  include <sys/types.h>
+#  include <sys/stat.h>
+#  define lseek(fdes,offset,whence)  _lseek(fdes, (long)offset, whence)
+#  define fstat(fdes,stp)            _fstat(fdes, stp)
+#  define stat(fname,stp)            _stat(fname, stp)
+#  define struct_stat                struct _stat
+#  define LSEEK_ERROR                (long)-1
+#endif
+
+#ifndef struct_stat
+#  define struct_stat struct stat
+#endif
+
+#ifndef LSEEK_ERROR
+#  define LSEEK_ERROR (off_t)-1
+#endif
+
+#ifdef WIN32
+#  include <direct.h>
+#  define mkdir(x,y) (mkdir)(x)
+#  undef  PATH_MAX
+#  define PATH_MAX MAX_PATH
+#  ifndef __POCC__
+#    define F_OK 0
+#  endif
+#endif
+
+/*
+ * Default sizeof(off_t) in case it hasn't been defined in config file.
+ */
+
+#ifndef SIZEOF_OFF_T
+#  if defined(__VMS) && !defined(__VAX)
+#    if defined(_LARGEFILE)
+#      define SIZEOF_OFF_T 8
+#    endif
+#  elif defined(__OS400__) && defined(__ILEC400__)
+#    if defined(_LARGE_FILES)
+#      define SIZEOF_OFF_T 8
+#    endif
+#  elif defined(__MVS__) && defined(__IBMC__)
+#    if defined(_LP64) || defined(_LARGE_FILES)
+#      define SIZEOF_OFF_T 8
+#    endif
+#  elif defined(__370__) && defined(__IBMC__)
+#    if defined(_LP64) || defined(_LARGE_FILES)
+#      define SIZEOF_OFF_T 8
+#    endif
+#  elif defined(TPF)
+#    define SIZEOF_OFF_T 8
+#  endif
+#  ifndef SIZEOF_OFF_T
+#    define SIZEOF_OFF_T 4
+#  endif
+#endif
+
+#ifdef CURL_DOES_CONVERSIONS
+#ifdef HAVE_ICONV
+iconv_t inbound_cd  = (iconv_t)-1;
+iconv_t outbound_cd = (iconv_t)-1;
+
+/*
+ * convert_to_network() is an internal function to convert
+ * from the host encoding to ASCII on non-ASCII platforms.
+ */
+static CURLcode
+convert_to_network(char *buffer, size_t length)
+{
+  CURLcode rc;
+
+  /* translate from the host encoding to the network encoding */
+  char *input_ptr, *output_ptr;
+  size_t in_bytes, out_bytes;
+
+  /* open an iconv conversion descriptor if necessary */
+  if(outbound_cd == (iconv_t)-1) {
+    outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
+                             CURL_ICONV_CODESET_OF_HOST);
+    if(outbound_cd == (iconv_t)-1) {
+      return CURLE_CONV_FAILED;
+    }
+  }
+  /* call iconv */
+  input_ptr = output_ptr = buffer;
+  in_bytes = out_bytes = length;
+  rc = iconv(outbound_cd, &input_ptr,  &in_bytes,
+                          &output_ptr, &out_bytes);
+  if ((rc == -1) || (in_bytes != 0)) {
+    return CURLE_CONV_FAILED;
+  }
+
+  return CURLE_OK;
+}
+
+/*
+ * convert_from_network() is an internal function
+ * for performing ASCII conversions on non-ASCII platforms.
+ */
+static CURLcode
+convert_from_network(char *buffer, size_t length)
+{
+  CURLcode rc;
+
+  /* translate from the network encoding to the host encoding */
+  char *input_ptr, *output_ptr;
+  size_t in_bytes, out_bytes;
+
+  /* open an iconv conversion descriptor if necessary */
+  if(inbound_cd == (iconv_t)-1) {
+    inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+                            CURL_ICONV_CODESET_OF_NETWORK);
+    if(inbound_cd == (iconv_t)-1) {
+      return CURLE_CONV_FAILED;
+    }
+  }
+  /* call iconv */
+  input_ptr = output_ptr = buffer;
+  in_bytes = out_bytes = length;
+  rc = iconv(inbound_cd, &input_ptr,  &in_bytes,
+                         &output_ptr, &out_bytes);
+  if ((rc == -1) || (in_bytes != 0)) {
+    return CURLE_CONV_FAILED;
+  }
+
+  return CURLE_OK;
+}
+#endif /* HAVE_ICONV */
+
+static
+char convert_char(curl_infotype infotype, char this_char)
+{
+/* determine how this specific character should be displayed */
+  switch(infotype) {
+  case CURLINFO_DATA_IN:
+  case CURLINFO_DATA_OUT:
+  case CURLINFO_SSL_DATA_IN:
+  case CURLINFO_SSL_DATA_OUT:
+    /* data, treat as ASCII */
+    if ((this_char >= 0x20) && (this_char < 0x7f)) {
+      /* printable ASCII hex value: convert to host encoding */
+      convert_from_network(&this_char, 1);
+    }
+    else {
+      /* non-printable ASCII, use a replacement character */
+      return UNPRINTABLE_CHAR;
+    }
+    /* fall through to default */
+  default:
+    /* treat as host encoding */
+    if (ISPRINT(this_char)
+        &&  (this_char != '\t')
+        &&  (this_char != '\r')
+        &&  (this_char != '\n')) {
+      /* printable characters excluding tabs and line end characters */
+      return this_char;
+    }
+    break;
+  }
+  /* non-printable, use a replacement character  */
+  return UNPRINTABLE_CHAR;
+}
+#endif /* CURL_DOES_CONVERSIONS */
+
+#ifdef WIN32
+
+#ifdef __BORLANDC__
+   /* 64-bit lseek-like function unavailable */
+#  define _lseeki64(hnd,ofs,whence) lseek(hnd,ofs,whence)
+#endif
+
+#ifdef __POCC__
+#  if (__POCC__ < 450)
+     /* 64-bit lseek-like function unavailable */
+#    define _lseeki64(hnd,ofs,whence) _lseek(hnd,ofs,whence)
+#  else
+#    define _lseeki64(hnd,ofs,whence) _lseek64(hnd,ofs,whence)
+#  endif
+#endif
+
+#ifndef HAVE_FTRUNCATE
+#define HAVE_FTRUNCATE 1
+#endif
+
+/*
+ * Truncate a file handle at a 64-bit position 'where'.
+ */
+
+static int ftruncate64 (int fd, curl_off_t where)
+{
+  if(_lseeki64(fd, where, SEEK_SET) < 0)
+    return -1;
+
+  if(!SetEndOfFile((HANDLE)_get_osfhandle(fd)))
+    return -1;
+
+  return 0;
+}
+#define ftruncate(fd,where) ftruncate64(fd,where)
+
+#endif /* WIN32 */
+
+typedef enum {
+  TRACE_NONE,  /* no trace/verbose output at all! */
+  TRACE_BIN,   /* tcpdump inspired look */
+  TRACE_ASCII, /* like *BIN but without the hex output */
+  TRACE_PLAIN  /* -v/--verbose type */
+} trace;
+
+struct OutStruct {
+  char *filename;
+  FILE *stream;
+  struct Configurable *config;
+  curl_off_t bytes; /* amount written so far */
+  curl_off_t init;  /* original size (non-zero when appending) */
+};
+
+struct Configurable {
+  CURL *easy; /* once we have one, we keep it here */
+  bool remote_time;
+  char *random_file;
+  char *egd_file;
+  char *useragent;
+  char *cookie;     /* single line with specified cookies */
+  char *cookiejar;  /* write to this file */
+  char *cookiefile; /* read from this file */
+  bool cookiesession; /* new session? */
+  bool encoding;    /* Accept-Encoding please */
+  long authtype;    /* auth bitmask */
+  bool use_resume;
+  bool resume_from_current;
+  bool disable_epsv;
+  bool disable_eprt;
+  bool ftp_pret;
+  curl_off_t resume_from;
+  char *postfields;
+  curl_off_t postfieldsize;
+  char *referer;
+  long timeout;
+  long connecttimeout;
+  long maxredirs;
+  curl_off_t max_filesize;
+  char *headerfile;
+  char *ftpport;
+  char *iface;
+  int localport;
+  int localportrange;
+  unsigned short porttouse;
+  char *range;
+  long low_speed_limit;
+  long low_speed_time;
+  bool showerror;
+  char *userpwd;
+  char *proxyuserpwd;
+  char *proxy;
+  int proxyver;     /* set to CURLPROXY_HTTP* define */
+  char *noproxy;
+  char *mail_from;
+  struct curl_slist *mail_rcpt;
+  bool proxytunnel;
+  bool ftp_append;         /* APPE on ftp */
+  bool mute;               /* shutup */
+  bool use_ascii;          /* select ascii or text transfer */
+  bool autoreferer;        /* automatically set referer */
+  bool failonerror;        /* fail on (HTTP) errors */
+  bool include_headers;    /* send headers to data output */
+  bool no_body;            /* don't get the body */
+  bool dirlistonly;        /* only get the FTP dir list */
+  bool followlocation;     /* follow http redirects */
+  bool unrestricted_auth;  /* Continue to send authentication (user+password)
+                              when following ocations, even when hostname
+                              changed */
+  bool netrc_opt;
+  bool netrc;
+  bool noprogress;
+  bool isatty;             /* updated internally only if the output is a tty */
+  struct getout *url_list; /* point to the first node */
+  struct getout *url_last; /* point to the last/current node */
+  struct getout *url_get;  /* point to the node to fill in URL */
+  struct getout *url_out;  /* point to the node to fill in outfile */
+  char *cipher_list;
+  char *cert;
+  char *cert_type;
+  char *cacert;
+  char *capath;
+  char *crlfile;
+  char *key;
+  char *key_type;
+  char *key_passwd;
+  char *pubkey;
+  char *hostpubmd5;
+  char *engine;
+  bool list_engines;
+  bool crlf;
+  char *customrequest;
+  char *krblevel;
+  char *trace_dump; /* file to dump the network trace to, or NULL */
+  FILE *trace_stream;
+  bool trace_fopened;
+  trace tracetype;
+  bool tracetime; /* include timestamp? */
+  long httpversion;
+  int progressmode;
+  bool nobuffer;
+  bool readbusy; /* set when reading input returns EAGAIN */
+  bool globoff;
+  bool use_httpget;
+  bool insecure_ok; /* set TRUE to allow insecure SSL connects */
+  bool create_dirs;
+  bool ftp_create_dirs;
+  bool ftp_skip_ip;
+  bool proxynegotiate;
+  bool proxyntlm;
+  bool proxydigest;
+  bool proxybasic;
+  bool proxyanyauth;
+  char *writeout; /* %-styled format string to output */
+  bool writeenv; /* write results to environment, if available */
+  FILE *errors; /* if stderr redirect is requested */
+  bool errors_fopened;
+  struct curl_slist *quote;
+  struct curl_slist *postquote;
+  struct curl_slist *prequote;
+  long ssl_version;
+  long ip_version;
+  curl_TimeCond timecond;
+  time_t condtime;
+  struct curl_slist *headers;
+  struct curl_httppost *httppost;
+  struct curl_httppost *last_post;
+  struct curl_slist *telnet_options;
+  HttpReq httpreq;
+
+  /* for bandwidth limiting features: */
+  curl_off_t sendpersecond; /* send to peer */
+  curl_off_t recvpersecond; /* receive from peer */
+
+  bool ftp_ssl;
+  bool ftp_ssl_reqd;
+  bool ftp_ssl_control;
+  bool ftp_ssl_ccc;
+  int ftp_ssl_ccc_mode;
+
+  char *socksproxy; /* set to server string */
+  int socksver;     /* set to CURLPROXY_SOCKS* define */
+  char *socks5_gssapi_service;  /* set service name for gssapi principal
+                                 * default rcmd */
+  int socks5_gssapi_nec ;  /* The NEC reference server does not protect
+                            * the encryption type exchange */
+
+  bool tcp_nodelay;
+  long req_retry;   /* number of retries */
+  long retry_delay; /* delay between retries (in seconds) */
+  long retry_maxtime; /* maximum time to keep retrying */
+
+  char *ftp_account; /* for ACCT */
+  char *ftp_alternative_to_user; /* send command if USER/PASS fails */
+  int ftp_filemethod;
+  long tftp_blksize; /* TFTP BLKSIZE option */
+  bool ignorecl; /* --ignore-content-length */
+  bool disable_sessionid;
+
+  char *libcurl; /* output libcurl code to this file name */
+  bool raw;
+  bool post301;
+  bool post302;
+  bool nokeepalive; /* for keepalive needs */
+  long alivetime;
+  bool content_disposition; /* use Content-disposition filename */
+
+  int default_node_flags; /* default flags to seach for each 'node', which is
+                             basically each given URL to transfer */
+  struct OutStruct *outs;
+};
+
+#define WARN_PREFIX "Warning: "
+#define WARN_TEXTWIDTH (79 - (int)strlen(WARN_PREFIX))
+/* produce this text message to the user unless mute was selected */
+static void warnf(struct Configurable *config, const char *fmt, ...)
+{
+  if(!config->mute) {
+    va_list ap;
+    int len;
+    char *ptr;
+    char print_buffer[256];
+
+    va_start(ap, fmt);
+    len = vsnprintf(print_buffer, sizeof(print_buffer), fmt, ap);
+    va_end(ap);
+
+    ptr = print_buffer;
+    while(len > 0) {
+      fputs(WARN_PREFIX, config->errors);
+
+      if(len > (int)WARN_TEXTWIDTH) {
+        int cut = WARN_TEXTWIDTH-1;
+
+        while(!ISSPACE(ptr[cut]) && cut) {
+          cut--;
+        }
+        if(0 == cut)
+          /* not a single cutting position was found, just cut it at the
+             max text width then! */
+          cut = WARN_TEXTWIDTH-1;
+
+        (void)fwrite(ptr, cut + 1, 1, config->errors);
+        fputs("\n", config->errors);
+        ptr += cut+1; /* skip the space too */
+        len -= cut;
+      }
+      else {
+        fputs(ptr, config->errors);
+        len = 0;
+      }
+    }
+  }
+}
+
+/*
+ * This is the main global constructor for the app. Call this before
+ * _any_ libcurl usage. If this fails, *NO* libcurl functions may be
+ * used, or havoc may be the result.
+ */
+static CURLcode main_init(void)
+{
+#ifdef DJGPP
+  /* stop stat() wasting time */
+  _djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE;
+#endif
+
+  return curl_global_init(CURL_GLOBAL_DEFAULT);
+}
+
+/*
+ * This is the main global destructor for the app. Call this after
+ * _all_ libcurl usage is done.
+ */
+static void main_free(void)
+{
+  curl_global_cleanup();
+#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
+  /* close iconv conversion descriptor */
+  if(inbound_cd != (iconv_t)-1)
+    iconv_close(inbound_cd);
+  if(outbound_cd != (iconv_t)-1)
+    iconv_close(outbound_cd);
+#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
+}
+
+static int SetHTTPrequest(struct Configurable *config,
+                          HttpReq req, HttpReq *store)
+{
+  if((*store == HTTPREQ_UNSPEC) ||
+     (*store == req)) {
+    *store = req;
+    return 0;
+  }
+  warnf(config, "You can only select one HTTP request!\n");
+  return 1;
+}
+
+static void helpf(FILE *errors, const char *fmt, ...)
+{
+  va_list ap;
+  if(fmt) {
+    va_start(ap, fmt);
+    fputs("curl: ", errors); /* prefix it */
+    vfprintf(errors, fmt, ap);
+    va_end(ap);
+  }
+  fprintf(errors, "curl: try 'curl --help' "
+#ifdef USE_MANUAL
+          "or 'curl --manual' "
+#endif
+          "for more information\n");
+}
+
+/*
+ * A chain of these nodes contain URL to get and where to put the URL's
+ * contents.
+ */
+struct getout {
+  struct getout *next; /* next one */
+  char *url;     /* the URL we deal with */
+  char *outfile; /* where to store the output */
+  char *infile;  /* file to upload, if GETOUT_UPLOAD is set */
+  int flags;     /* options */
+};
+#define GETOUT_OUTFILE (1<<0)   /* set when outfile is deemed done */
+#define GETOUT_URL     (1<<1)   /* set when URL is deemed done */
+#define GETOUT_USEREMOTE (1<<2) /* use remote file name locally */
+#define GETOUT_UPLOAD  (1<<3)   /* if set, -T has been used */
+#define GETOUT_NOUPLOAD  (1<<4) /* if set, -T "" has been used */
+
+static void help(void)
+{
+  int i;
+  /* A few of these source lines are >80 columns wide, but that's only because
+     breaking the strings narrower makes this chunk look even worse!
+
+     Starting with 7.18.0, this list of command line options is sorted based
+     on the long option name. It is not done automatically, although a command
+     line like the following can help out:
+
+     curl --help | cut -c5- | grep "^-" | sort
+  */
+  static const char * const helptext[]={
+    "Usage: curl [options...] <url>",
+    "Options: (H) means HTTP/HTTPS only, (F) means FTP only",
+    "    --anyauth       Pick \"any\" authentication method (H)",
+    " -a/--append        Append to target file when uploading (F/SFTP)",
+    "    --basic         Use HTTP Basic Authentication (H)",
+    "    --cacert <file> CA certificate to verify peer against (SSL)",
+    "    --capath <directory> CA directory to verify peer against (SSL)",
+    " -E/--cert <cert[:passwd]> Client certificate file and password (SSL)",
+    "    --cert-type <type> Certificate file type (DER/PEM/ENG) (SSL)",
+    "    --ciphers <list> SSL ciphers to use (SSL)",
+    "    --compressed    Request compressed response (using deflate or gzip)",
+    " -K/--config <file> Specify which config file to read",
+    "    --connect-timeout <seconds> Maximum time allowed for connection",
+    " -C/--continue-at <offset> Resumed transfer offset",
+    " -b/--cookie <name=string/file> Cookie string or file to read cookies from (H)",
+    " -c/--cookie-jar <file> Write cookies to this file after operation (H)",
+    "    --create-dirs   Create necessary local directory hierarchy",
+    "    --crlf          Convert LF to CRLF in upload",
+    "    --crlfile <file> Get a CRL list in PEM format from the given file",
+    " -d/--data <data>   HTTP POST data (H)",
+    "    --data-ascii <data>  HTTP POST ASCII data (H)",
+    "    --data-binary <data> HTTP POST binary data (H)",
+    "    --data-urlencode <name=data/name@filename> HTTP POST data url encoded (H)",
+    "    --digest        Use HTTP Digest Authentication (H)",
+    "    --disable-eprt  Inhibit using EPRT or LPRT (F)",
+    "    --disable-epsv  Inhibit using EPSV (F)",
+    " -D/--dump-header <file> Write the headers to this file",
+    "    --egd-file <file> EGD socket path for random data (SSL)",
+    "    --engine <eng>  Crypto engine to use (SSL). \"--engine list\" for list",
+#ifdef USE_ENVIRONMENT
+    "    --environment   Write results to environment variables (RISC OS)",
+#endif
+    " -f/--fail          Fail silently (no output at all) on HTTP errors (H)",
+    " -F/--form <name=content> Specify HTTP multipart POST data (H)",
+    "    --form-string <name=string> Specify HTTP multipart POST data (H)",
+    "    --ftp-account <data> Account data to send when requested by server (F)",
+    "    --ftp-alternative-to-user <cmd> String to replace \"USER [name]\" (F)",
+    "    --ftp-create-dirs Create the remote dirs if not present (F)",
+    "    --ftp-method [multicwd/nocwd/singlecwd] Control CWD usage (F)",
+    "    --ftp-pasv      Use PASV/EPSV instead of PORT (F)",
+    " -P/--ftp-port <address> Use PORT with address instead of PASV (F)",
+    "    --ftp-skip-pasv-ip Skip the IP address for PASV (F)\n"
+    "    --ftp-pret      Send PRET before PASV (for drftpd) (F)",
+    "    --ftp-ssl-ccc   Send CCC after authenticating (F)",
+    "    --ftp-ssl-ccc-mode [active/passive] Set CCC mode (F)",
+    "    --ftp-ssl-control Require SSL/TLS for ftp login, clear for transfer (F)",
+    " -G/--get           Send the -d data with a HTTP GET (H)",
+    " -g/--globoff       Disable URL sequences and ranges using {} and []",
+    " -H/--header <line> Custom header to pass to server (H)",
+    " -I/--head          Show document info only",
+    " -h/--help          This help text",
+    "    --hostpubmd5 <md5> Hex encoded MD5 string of the host public key. (SSH)",
+    " -0/--http1.0       Use HTTP 1.0 (H)",
+    "    --ignore-content-length  Ignore the HTTP Content-Length header",
+    " -i/--include       Include protocol headers in the output (H/F)",
+    " -k/--insecure      Allow connections to SSL sites without certs (H)",
+    "    --interface <interface> Specify network interface/address to use",
+    " -4/--ipv4          Resolve name to IPv4 address",
+    " -6/--ipv6          Resolve name to IPv6 address",
+    " -j/--junk-session-cookies Ignore session cookies read from file (H)",
+    "    --keepalive-time <seconds> Interval between keepalive probes",
+    "    --key <key>     Private key file name (SSL/SSH)",
+    "    --key-type <type> Private key file type (DER/PEM/ENG) (SSL)",
+    "    --krb <level>   Enable Kerberos with specified security level (F)",
+    "    --libcurl <file> Dump libcurl equivalent code of this command line",
+    "    --limit-rate <rate> Limit transfer speed to this rate",
+    " -J/--remote-header-name Use the header-provided filename (H)",
+    " -l/--list-only     List only names of an FTP directory (F)",
+    "    --local-port <num>[-num] Force use of these local port numbers",
+    " -L/--location      Follow Location: hints (H)",
+    "    --location-trusted Follow Location: and send auth to other hosts (H)",
+    " -M/--manual        Display the full manual",
+    "    --mail-from <from> Mail from this address",
+    "    --mail-rcpt <to> Mail to this receiver(s)",
+    "    --max-filesize <bytes> Maximum file size to download (H/F)",
+    "    --max-redirs <num> Maximum number of redirects allowed (H)",
+    " -m/--max-time <seconds> Maximum time allowed for the transfer",
+    "    --negotiate     Use HTTP Negotiate Authentication (H)",
+    " -n/--netrc         Must read .netrc for user name and password",
+    "    --netrc-optional Use either .netrc or URL; overrides -n",
+    " -N/--no-buffer     Disable buffering of the output stream",
+    "    --no-keepalive  Disable keepalive use on the connection",
+    "    --no-sessionid  Disable SSL session-ID reusing (SSL)",
+    "    --noproxy       Comma-separated list of hosts which do not use proxy",
+    "    --ntlm          Use HTTP NTLM authentication (H)",
+    " -o/--output <file> Write output to <file> instead of stdout",
+    "    --pass  <pass>  Pass phrase for the private key (SSL/SSH)",
+    "    --post301       Do not switch to GET after following a 301 redirect (H)",
+    "    --post302       Do not switch to GET after following a 302 redirect (H)",
+    " -#/--progress-bar  Display transfer progress as a progress bar",
+    " -x/--proxy <host[:port]> Use HTTP proxy on given port",
+    "    --proxy-anyauth Pick \"any\" proxy authentication method (H)",
+    "    --proxy-basic   Use Basic authentication on the proxy (H)",
+    "    --proxy-digest  Use Digest authentication on the proxy (H)",
+    "    --proxy-negotiate Use Negotiate authentication on the proxy (H)",
+    "    --proxy-ntlm    Use NTLM authentication on the proxy (H)",
+    " -U/--proxy-user <user[:password]> Set proxy user and password",
+    "    --proxy1.0 <host[:port]> Use HTTP/1.0 proxy on given port",
+    " -p/--proxytunnel   Operate through a HTTP proxy tunnel (using CONNECT)",
+    "    --pubkey <key>  Public key file name (SSH)",
+    " -Q/--quote <cmd>   Send command(s) to server before file transfer (F/SFTP)",
+    "    --random-file <file> File for reading random data from (SSL)",
+    " -r/--range <range> Retrieve only the bytes within a range",
+    "    --raw           Pass HTTP \"raw\", without any transfer decoding (H)",
+    " -e/--referer       Referer URL (H)",
+    " -O/--remote-name   Write output to a file named as the remote file",
+    "    --remote-name-all Use the remote file name for all URLs",
+    " -R/--remote-time   Set the remote file's time on the local output",
+    " -X/--request <command> Specify request command to use",
+    "    --retry <num>   Retry request <num> times if transient problems occur",
+    "    --retry-delay <seconds> When retrying, wait this many seconds between each",
+    "    --retry-max-time <seconds> Retry only within this period",
+    " -S/--show-error    Show error. With -s, make curl show errors when they occur",
+    " -s/--silent        Silent mode. Don't output anything",
+    "    --socks4 <host[:port]> SOCKS4 proxy on given host + port",
+    "    --socks4a <host[:port]> SOCKS4a proxy on given host + port",
+    "    --socks5 <host[:port]> SOCKS5 proxy on given host + port",
+    "    --socks5-hostname <host[:port]> SOCKS5 proxy, pass host name to proxy",
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+    "    --socks5-gssapi-service <name> SOCKS5 proxy service name for gssapi",
+    "    --socks5-gssapi-nec  Compatibility with NEC SOCKS5 server",
+#endif
+    " -Y/--speed-limit   Stop transfer if below speed-limit for 'speed-time' secs",
+    " -y/--speed-time    Time needed to trig speed-limit abort. Defaults to 30",
+    "    --ssl           Try SSL/TLS (FTP, IMAP, POP3, SMTP)",
+    "    --ssl-reqd      Require SSL/TLS (FTP, IMAP, POP3, SMTP)",
+    " -2/--sslv2         Use SSLv2 (SSL)",
+    " -3/--sslv3         Use SSLv3 (SSL)",
+    "    --stderr <file> Where to redirect stderr. - means stdout",
+    "    --tcp-nodelay   Use the TCP_NODELAY option",
+    " -t/--telnet-option <OPT=val> Set telnet option",
+    "    --tftp-blksize <value> Set TFTP BLKSIZE option (must be >512)",
+    " -z/--time-cond <time> Transfer based on a time condition",
+    " -1/--tlsv1         Use TLSv1 (SSL)",
+    "    --trace <file>  Write a debug trace to the given file",
+    "    --trace-ascii <file> Like --trace but without the hex output",
+    "    --trace-time    Add time stamps to trace/verbose output",
+    " -T/--upload-file <file> Transfer <file> to remote site",
+    "    --url <URL>     Set URL to work with",
+    " -B/--use-ascii     Use ASCII/text transfer",
+    " -u/--user <user[:password]> Set server user and password",
+    " -A/--user-agent <string> User-Agent to send to server (H)",
+    " -v/--verbose       Make the operation more talkative",
+    " -V/--version       Show version number and quit",
+
+#ifdef USE_WATT32
+    "    --wdebug        Turn on Watt-32 debugging",
+#endif
+    " -w/--write-out <format> What to output after completion",
+    " -q                 If used as the first parameter disables .curlrc",
+    NULL
+  };
+  for(i=0; helptext[i]; i++) {
+    puts(helptext[i]);
+#ifdef PRINT_LINES_PAUSE
+    if (i && ((i % PRINT_LINES_PAUSE) == 0))
+      pressanykey();
+#endif
+  }
+}
+
+struct LongShort {
+  const char *letter;
+  const char *lname;
+  bool extraparam;
+};
+
+/* global variable to hold info about libcurl */
+static curl_version_info_data *curlinfo;
+
+static int parseconfig(const char *filename,
+                       struct Configurable *config);
+static char *my_get_line(FILE *fp);
+static int create_dir_hierarchy(const char *outfile, FILE *errors);
+
+static void GetStr(char **string,
+                   const char *value)
+{
+  if(*string)
+    free(*string);
+  if(value)
+    *string = strdup(value);
+  else
+    *string = NULL;
+}
+
+static void clean_getout(struct Configurable *config)
+{
+  struct getout *node=config->url_list;
+  struct getout *next;
+
+  while(node) {
+    next = node->next;
+    if(node->url)
+      free(node->url);
+    if(node->outfile)
+      free(node->outfile);
+    if(node->infile)
+      free(node->infile);
+    free(node);
+
+    node = next; /* GOTO next */
+  }
+}
+
+static struct getout *new_getout(struct Configurable *config)
+{
+  struct getout *node =malloc(sizeof(struct getout));
+  struct getout *last= config->url_last;
+  if(node) {
+    /* clear the struct */
+    memset(node, 0, sizeof(struct getout));
+
+    /* append this new node last in the list */
+    if(last)
+      last->next = node;
+    else
+      config->url_list = node; /* first node */
+
+    /* move the last pointer */
+    config->url_last = node;
+
+    node->flags = config->default_node_flags;
+  }
+  return node;
+}
+
+/* Structure for storing the information needed to build a multiple files
+ * section
+*/
+struct multi_files {
+  struct curl_forms   form;
+  struct multi_files *next;
+};
+
+/* Add a new list entry possibly with a type_name
+ */
+static struct multi_files *
+AddMultiFiles (const char *file_name,
+               const char *type_name,
+               const char *show_filename,
+               struct multi_files **multi_start,
+               struct multi_files **multi_current)
+{
+  struct multi_files *multi;
+  struct multi_files *multi_type = NULL;
+  struct multi_files *multi_name = NULL;
+  multi = malloc(sizeof(struct multi_files));
+  if (multi) {
+    memset(multi, 0, sizeof(struct multi_files));
+    multi->form.option = CURLFORM_FILE;
+    multi->form.value = file_name;
+  }
+  else
+    return NULL;
+
+  if (!*multi_start)
+    *multi_start = multi;
+
+  if (type_name) {
+    multi_type = malloc(sizeof(struct multi_files));
+    if (multi_type) {
+      memset(multi_type, 0, sizeof(struct multi_files));
+      multi_type->form.option = CURLFORM_CONTENTTYPE;
+      multi_type->form.value = type_name;
+      multi->next = multi_type;
+
+      multi = multi_type;
+    }
+    else {
+      free (multi);
+      return NULL;
+    }
+  }
+  if (show_filename) {
+    multi_name = malloc(sizeof(struct multi_files));
+    if (multi_name) {
+      memset(multi_name, 0, sizeof(struct multi_files));
+      multi_name->form.option = CURLFORM_FILENAME;
+      multi_name->form.value = show_filename;
+      multi->next = multi_name;
+
+      multi = multi_name;
+    }
+    else {
+      free (multi);
+      return NULL;
+    }
+  }
+
+  if (*multi_current)
+    (*multi_current)->next = multi;
+
+  *multi_current = multi;
+
+  return *multi_current;
+}
+
+/* Free the items of the list.
+ */
+static void FreeMultiInfo (struct multi_files *multi_start)
+{
+  struct multi_files *multi;
+  while (multi_start) {
+    multi = multi_start;
+    multi_start = multi_start->next;
+    free (multi);
+  }
+}
+
+/* Print list of OpenSSL engines supported.
+ */
+static void list_engines (const struct curl_slist *engines)
+{
+  puts ("Build-time engines:");
+  if (!engines) {
+    puts ("  <none>");
+    return;
+  }
+  for ( ; engines; engines = engines->next)
+    printf ("  %s\n", engines->data);
+}
+
+/***************************************************************************
+ *
+ * formparse()
+ *
+ * Reads a 'name=value' parameter and builds the appropriate linked list.
+ *
+ * Specify files to upload with 'name=@filename'. Supports specified
+ * given Content-Type of the files. Such as ';type=<content-type>'.
+ *
+ * If literal_value is set, any initial '@' or '<' in the value string
+ * loses its special meaning, as does any embedded ';type='.
+ *
+ * You may specify more than one file for a single name (field). Specify
+ * multiple files by writing it like:
+ *
+ * 'name=@filename,filename2,filename3'
+ *
+ * If you want content-types specified for each too, write them like:
+ *
+ * 'name=@filename;type=image/gif,filename2,filename3'
+ *
+ * If you want custom headers added for a single part, write them in a separate
+ * file and do like this:
+ *
+ * 'name=foo;headers=@headerfile' or why not
+ * 'name=@filemame;headers=@headerfile'
+ *
+ * To upload a file, but to fake the file name that will be included in the
+ * formpost, do like this:
+ *
+ * 'name=@filename;filename=/dev/null'
+ *
+ * This function uses curl_formadd to fulfill it's job. Is heavily based on
+ * the old curl_formparse code.
+ *
+ ***************************************************************************/
+
+#define FORM_FILE_SEPARATOR ','
+#define FORM_TYPE_SEPARATOR ';'
+
+static int formparse(struct Configurable *config,
+                     const char *input,
+                     struct curl_httppost **httppost,
+                     struct curl_httppost **last_post,
+                     bool literal_value)
+{
+  /* nextarg MUST be a string in the format 'name=contents' and we'll
+     build a linked list with the info */
+  char name[256];
+  char *contents;
+  char major[128];
+  char minor[128];
+  char *contp;
+  const char *type = NULL;
+  char *sep;
+  char *sep2;
+
+  if((1 == sscanf(input, "%255[^=]=", name)) &&
+     (contp = strchr(input, '='))) {
+    /* the input was using the correct format */
+
+    /* Allocate the contents */
+    contents = strdup(contp+1);
+    if(!contents) {
+      fprintf(config->errors, "out of memory\n");
+      return 1;
+    }
+    contp = contents;
+
+    if('@' == contp[0] && !literal_value) {
+      struct multi_files *multi_start = NULL, *multi_current = NULL;
+      /* we use the @-letter to indicate file name(s) */
+      contp++;
+
+      multi_start = multi_current=NULL;
+
+      do {
+        /* since this was a file, it may have a content-type specifier
+           at the end too, or a filename. Or both. */
+        char *ptr;
+        char *filename=NULL;
+
+        sep=strchr(contp, FORM_TYPE_SEPARATOR);
+        sep2=strchr(contp, FORM_FILE_SEPARATOR);
+
+        /* pick the closest */
+        if(sep2 && (sep2 < sep)) {
+          sep = sep2;
+
+          /* no type was specified! */
+        }
+
+        type = NULL;
+
+        if(sep) {
+
+          /* if we got here on a comma, don't do much */
+          if(FORM_FILE_SEPARATOR == *sep)
+            ptr = NULL;
+          else
+            ptr = sep+1;
+
+          *sep=0; /* terminate file name at separator */
+
+          while(ptr && (FORM_FILE_SEPARATOR!= *ptr)) {
+
+            /* pass all white spaces */
+            while(ISSPACE(*ptr))
+              ptr++;
+
+            if(curlx_strnequal("type=", ptr, 5)) {
+              /* set type pointer */
+              type = &ptr[5];
+
+              /* verify that this is a fine type specifier */
+              if(2 != sscanf(type, "%127[^/]/%127[^;,\n]",
+                             major, minor)) {
+                warnf(config, "Illegally formatted content-type field!\n");
+                free(contents);
+                FreeMultiInfo (multi_start);
+                return 2; /* illegal content-type syntax! */
+              }
+              /* now point beyond the content-type specifier */
+              sep = (char *)type + strlen(major)+strlen(minor)+1;
+
+              if(*sep) {
+                *sep=0; /* zero terminate type string */
+
+                ptr=sep+1;
+              }
+              else
+                ptr = NULL; /* end */
+            }
+            else if(curlx_strnequal("filename=", ptr, 9)) {
+              filename = &ptr[9];
+              ptr=strchr(filename, FORM_TYPE_SEPARATOR);
+              if(!ptr) {
+                ptr=strchr(filename, FORM_FILE_SEPARATOR);
+              }
+              if(ptr) {
+                *ptr=0; /* zero terminate */
+                ptr++;
+              }
+            }
+            else
+              /* confusion, bail out of loop */
+              break;
+          }
+          /* find the following comma */
+          if(ptr)
+            sep=strchr(ptr, FORM_FILE_SEPARATOR);
+          else
+            sep=NULL;
+        }
+        else {
+          sep=strchr(contp, FORM_FILE_SEPARATOR);
+        }
+        if(sep) {
+          /* the next file name starts here */
+          *sep =0;
+          sep++;
+        }
+        /* if type == NULL curl_formadd takes care of the problem */
+
+        if (!AddMultiFiles (contp, type, filename, &multi_start,
+                            &multi_current)) {
+          warnf(config, "Error building form post!\n");
+          free(contents);
+          FreeMultiInfo (multi_start);
+          return 3;
+        }
+        contp = sep; /* move the contents pointer to after the separator */
+
+      } while(sep && *sep); /* loop if there's another file name */
+
+      /* now we add the multiple files section */
+      if (multi_start) {
+        struct curl_forms *forms = NULL;
+        struct multi_files *ptr = multi_start;
+        unsigned int i, count = 0;
+        while (ptr) {
+          ptr = ptr->next;
+          ++count;
+        }
+        forms = malloc((count+1)*sizeof(struct curl_forms));
+        if (!forms)
+        {
+          fprintf(config->errors, "Error building form post!\n");
+          free(contents);
+          FreeMultiInfo (multi_start);
+          return 4;
+        }
+        for (i = 0, ptr = multi_start; i < count; ++i, ptr = ptr->next)
+        {
+          forms[i].option = ptr->form.option;
+          forms[i].value = ptr->form.value;
+        }
+        forms[count].option = CURLFORM_END;
+        FreeMultiInfo (multi_start);
+        if (curl_formadd(httppost, last_post,
+                         CURLFORM_COPYNAME, name,
+                         CURLFORM_ARRAY, forms, CURLFORM_END) != 0) {
+          warnf(config, "curl_formadd failed!\n");
+          free(forms);
+          free(contents);
+          return 5;
+        }
+        free(forms);
+      }
+    }
+    else {
+      struct curl_forms info[4];
+      int i = 0;
+      char *ct = literal_value? NULL: strstr(contp, ";type=");
+
+      info[i].option = CURLFORM_COPYNAME;
+      info[i].value = name;
+      i++;
+
+      if(ct) {
+        info[i].option = CURLFORM_CONTENTTYPE;
+        info[i].value = &ct[6];
+        i++;
+        ct[0]=0; /* zero terminate here */
+      }
+
+      if( contp[0]=='<' && !literal_value) {
+        info[i].option = CURLFORM_FILECONTENT;
+        info[i].value = contp+1;
+        i++;
+        info[i].option = CURLFORM_END;
+
+        if (curl_formadd(httppost, last_post,
+                         CURLFORM_ARRAY, info, CURLFORM_END ) != 0) {
+          warnf(config, "curl_formadd failed, possibly the file %s is bad!\n",
+                contp+1);
+          free(contents);
+          return 6;
+        }
+      }
+      else {
+#ifdef CURL_DOES_CONVERSIONS
+        convert_to_network(contp, strlen(contp));
+#endif
+        info[i].option = CURLFORM_COPYCONTENTS;
+        info[i].value = contp;
+        i++;
+        info[i].option = CURLFORM_END;
+        if (curl_formadd(httppost, last_post,
+                         CURLFORM_ARRAY, info, CURLFORM_END) != 0) {
+          warnf(config, "curl_formadd failed!\n");
+          free(contents);
+          return 7;
+        }
+      }
+    }
+
+  }
+  else {
+    warnf(config, "Illegally formatted input field!\n");
+    return 1;
+  }
+  free(contents);
+  return 0;
+}
+
+
+typedef enum {
+  PARAM_OK,
+  PARAM_OPTION_AMBIGUOUS,
+  PARAM_OPTION_UNKNOWN,
+  PARAM_REQUIRES_PARAMETER,
+  PARAM_BAD_USE,
+  PARAM_HELP_REQUESTED,
+  PARAM_GOT_EXTRA_PARAMETER,
+  PARAM_BAD_NUMERIC,
+  PARAM_LIBCURL_DOESNT_SUPPORT,
+  PARAM_NO_MEM,
+  PARAM_LAST
+} ParameterError;
+
+static const char *param2text(int res)
+{
+  ParameterError error = (ParameterError)res;
+  switch(error) {
+  case PARAM_GOT_EXTRA_PARAMETER:
+    return "had unsupported trailing garbage";
+  case PARAM_OPTION_UNKNOWN:
+    return "is unknown";
+  case PARAM_OPTION_AMBIGUOUS:
+    return "is ambiguous";
+  case PARAM_REQUIRES_PARAMETER:
+    return "requires parameter";
+  case PARAM_BAD_USE:
+    return "is badly used here";
+  case PARAM_BAD_NUMERIC:
+    return "expected a proper numerical parameter";
+  case PARAM_LIBCURL_DOESNT_SUPPORT:
+    return "the installed libcurl version doesn't support this";
+  case PARAM_NO_MEM:
+    return "out of memory";
+  default:
+    return "unknown error";
+  }
+}
+
+static ParameterError file2string(char **bufp, FILE *file)
+{
+  char buffer[256];
+  char *ptr;
+  char *string = NULL;
+  size_t stringlen = 0;
+  size_t buflen;
+
+  if(file) {
+    while(fgets(buffer, sizeof(buffer), file)) {
+      if((ptr = strchr(buffer, '\r')) != NULL)
+        *ptr = '\0';
+      if((ptr = strchr(buffer, '\n')) != NULL)
+        *ptr = '\0';
+      buflen = strlen(buffer);
+      if((ptr = realloc(string, stringlen+buflen+1)) == NULL) {
+        if(string)
+          free(string);
+        return PARAM_NO_MEM;
+      }
+      string = ptr;
+      strcpy(string+stringlen, buffer);
+      stringlen += buflen;
+    }
+  }
+  *bufp = string;
+  return PARAM_OK;
+}
+
+static ParameterError file2memory(char **bufp, size_t *size, FILE *file)
+{
+  char *newbuf;
+  char *buffer = NULL;
+  size_t alloc = 512;
+  size_t nused = 0;
+  size_t nread;
+
+  if(file) {
+    do {
+      if(!buffer || (alloc == nused)) {
+        /* size_t overflow detection for huge files */
+        if(alloc+1 > ((size_t)-1)/2) {
+          if(buffer)
+            free(buffer);
+          return PARAM_NO_MEM;
+        }
+        alloc *= 2;
+        /* allocate an extra char, reserved space, for null termination */
+        if((newbuf = realloc(buffer, alloc+1)) == NULL) {
+          if(buffer)
+            free(buffer);
+          return PARAM_NO_MEM;
+        }
+        buffer = newbuf;
+      }
+      nread = fread(buffer+nused, 1, alloc-nused, file);
+      nused += nread;
+    } while(nread);
+    /* null terminate the buffer in case it's used as a string later */
+    buffer[nused] = '\0';
+    /* free trailing slack space, if possible */
+    if(alloc != nused) {
+      if((newbuf = realloc(buffer, nused+1)) != NULL)
+        buffer = newbuf;
+    }
+    /* discard buffer if nothing was read */
+    if(!nused) {
+      free(buffer);
+      buffer = NULL; /* no string */
+    }
+  }
+  *size = nused;
+  *bufp = buffer;
+  return PARAM_OK;
+}
+
+static void cleanarg(char *str)
+{
+#ifdef HAVE_WRITABLE_ARGV
+  /* now that GetStr has copied the contents of nextarg, wipe the next
+   * argument out so that the username:password isn't displayed in the
+   * system process list */
+  if (str) {
+    size_t len = strlen(str);
+    memset(str, ' ', len);
+  }
+#else
+  (void)str;
+#endif
+}
+
+/*
+ * Parse the string and write the integer in the given address. Return
+ * non-zero on failure, zero on success.
+ *
+ * The string must start with a digit to be valid.
+ *
+ * Since this function gets called with the 'nextarg' pointer from within the
+ * getparameter a lot, we must check it for NULL before accessing the str
+ * data.
+ */
+
+static int str2num(long *val, const char *str)
+{
+  int retcode = 0;
+  if(str && ISDIGIT(*str))
+    *val = atoi(str);
+  else
+    retcode = 1; /* badness */
+  return retcode;
+}
+
+/**
+ * Parses the given string looking for an offset (which may be
+ * a larger-than-integer value).
+ *
+ * @param val  the offset to populate
+ * @param str  the buffer containing the offset
+ * @return zero if successful, non-zero if failure.
+ */
+static int str2offset(curl_off_t *val, const char *str)
+{
+#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
+  *val = curlx_strtoofft(str, NULL, 0);
+  if((*val == CURL_LLONG_MAX || *val == CURL_LLONG_MIN) && (ERRNO == ERANGE))
+    return 1;
+#else
+  *val = strtol(str, NULL, 0);
+  if ((*val == LONG_MIN || *val == LONG_MAX) && ERRNO == ERANGE)
+    return 1;
+#endif
+  return 0;
+}
+
+static void checkpasswd(const char *kind, /* for what purpose */
+                        char **userpwd) /* pointer to allocated string */
+{
+  char *ptr;
+  if(!*userpwd)
+    return;
+
+  ptr = strchr(*userpwd, ':');
+  if(!ptr) {
+    /* no password present, prompt for one */
+    char passwd[256]="";
+    char prompt[256];
+    size_t passwdlen;
+    size_t userlen = strlen(*userpwd);
+    char *passptr;
+
+    /* build a nice-looking prompt */
+    curlx_msnprintf(prompt, sizeof(prompt),
+                   "Enter %s password for user '%s':",
+                   kind, *userpwd);
+
+    /* get password */
+    getpass_r(prompt, passwd, sizeof(passwd));
+    passwdlen = strlen(passwd);
+
+    /* extend the allocated memory area to fit the password too */
+    passptr = realloc(*userpwd,
+                      passwdlen + 1 + /* an extra for the colon */
+                      userlen + 1);   /* an extra for the zero */
+
+    if(passptr) {
+      /* append the password separated with a colon */
+      passptr[userlen]=':';
+      memcpy(&passptr[userlen+1], passwd, passwdlen+1);
+      *userpwd = passptr;
+    }
+  }
+}
+
+static ParameterError add2list(struct curl_slist **list,
+                               const char *ptr)
+{
+  struct curl_slist *newlist = curl_slist_append(*list, ptr);
+  if(newlist)
+    *list = newlist;
+  else
+    return PARAM_NO_MEM;
+
+  return PARAM_OK;
+}
+
+static int ftpfilemethod(struct Configurable *config, const char *str)
+{
+  if(curlx_raw_equal("singlecwd", str))
+    return CURLFTPMETHOD_SINGLECWD;
+  if(curlx_raw_equal("nocwd", str))
+    return CURLFTPMETHOD_NOCWD;
+  if(curlx_raw_equal("multicwd", str))
+    return CURLFTPMETHOD_MULTICWD;
+  warnf(config, "unrecognized ftp file method '%s', using default\n", str);
+  return CURLFTPMETHOD_MULTICWD;
+}
+
+static int ftpcccmethod(struct Configurable *config, const char *str)
+{
+  if(curlx_raw_equal("passive", str))
+    return CURLFTPSSL_CCC_PASSIVE;
+  if(curlx_raw_equal("active", str))
+    return CURLFTPSSL_CCC_ACTIVE;
+  warnf(config, "unrecognized ftp CCC method '%s', using default\n", str);
+  return CURLFTPSSL_CCC_PASSIVE;
+}
+
+
+static int sockoptcallback(void *clientp, curl_socket_t curlfd,
+                           curlsocktype purpose)
+{
+  struct Configurable *config = (struct Configurable *)clientp;
+  int onoff = 1; /* this callback is only used if we ask for keepalives on the
+                    connection */
+#if defined(TCP_KEEPIDLE) || defined(TCP_KEEPINTVL)
+  int keepidle = (int)config->alivetime;
+#endif
+
+  switch (purpose) {
+  case CURLSOCKTYPE_IPCXN:
+    if(setsockopt(curlfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&onoff,
+                  sizeof(onoff)) < 0) {
+      /* don't abort operation, just issue a warning */
+      SET_SOCKERRNO(0);
+      warnf(clientp, "Could not set SO_KEEPALIVE!\n");
+      return 0;
+    }
+    else {
+      if (config->alivetime) {
+#ifdef TCP_KEEPIDLE
+        if(setsockopt(curlfd, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&keepidle,
+                      sizeof(keepidle)) < 0) {
+          /* don't abort operation, just issue a warning */
+          SET_SOCKERRNO(0);
+          warnf(clientp, "Could not set TCP_KEEPIDLE!\n");
+          return 0;
+        }
+#endif
+#ifdef TCP_KEEPINTVL
+        if(setsockopt(curlfd, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&keepidle,
+                      sizeof(keepidle)) < 0) {
+          /* don't abort operation, just issue a warning */
+          SET_SOCKERRNO(0);
+          warnf(clientp, "Could not set TCP_KEEPINTVL!\n");
+          return 0;
+        }
+#endif
+      }
+    }
+    break;
+  default:
+    break;
+  }
+
+  return 0;
+}
+
+
+static ParameterError getparameter(char *flag, /* f or -long-flag */
+                                   char *nextarg, /* NULL if unset */
+                                   bool *usedarg, /* set to TRUE if the arg
+                                                     has been used */
+                                   struct Configurable *config)
+{
+  char letter;
+  char subletter=0; /* subletters can only occur on long options */
+  int rc; /* generic return code variable */
+  const char *parse=NULL;
+  unsigned int j;
+  time_t now;
+  int hit=-1;
+  bool longopt=FALSE;
+  bool singleopt=FALSE; /* when true means '-o foo' used '-ofoo' */
+  ParameterError err;
+  bool toggle=TRUE; /* how to switch boolean options, on or off. Controlled
+                       by using --OPTION or --no-OPTION */
+
+  /* single-letter,
+     long-name,
+     boolean whether it takes an additional argument
+     */
+  static const struct LongShort aliases[]= {
+    /* all these ones, starting with "*" or "$" as a short-option have *no*
+       short option to mention. */
+    {"*", "url",         TRUE},
+    {"*a", "random-file", TRUE},
+    {"*b", "egd-file",   TRUE},
+    {"*c", "connect-timeout", TRUE},
+    {"*d", "ciphers",    TRUE},
+    {"*e", "disable-epsv", FALSE},
+    {"*E", "epsv", FALSE}, /* made like this to make --no-epsv and --epsv to
+                              work although --disable-epsv is the documented
+                              option */
+#ifdef USE_ENVIRONMENT
+    {"*f", "environment", FALSE},
+#endif
+    {"*g", "trace",      TRUE},
+    {"*h", "trace-ascii", TRUE},
+    {"*i", "limit-rate", TRUE},
+    {"*j", "compressed",  FALSE}, /* might take an arg someday */
+    {"*k", "digest",     FALSE},
+    {"*l", "negotiate",  FALSE},
+    {"*m", "ntlm",       FALSE},
+    {"*n", "basic",      FALSE},
+    {"*o", "anyauth",    FALSE},
+#ifdef USE_WATT32
+    {"*p", "wdebug",     FALSE},
+#endif
+    {"*q", "ftp-create-dirs", FALSE},
+    {"*r", "create-dirs", FALSE},
+    {"*s", "max-redirs",   TRUE},
+    {"*t", "proxy-ntlm",   FALSE},
+    {"*u", "crlf",        FALSE},
+    {"*v", "stderr",      TRUE},
+    {"*w", "interface",   TRUE},
+    {"*x", "krb" ,        TRUE},
+    {"*x", "krb4" ,       TRUE}, /* this is the previous name */
+    {"*y", "max-filesize", TRUE},
+    {"*z", "disable-eprt", FALSE},
+    {"*Z", "eprt", FALSE}, /* made like this to make --no-eprt and --eprt to
+                              work although --disable-eprt is the documented
+                              option */
+    {"$a", "ftp-ssl",    FALSE}, /* deprecated name since 7.20.0 */
+    {"$a", "ssl",        FALSE}, /* new option name in 7.20.0, previously this
+                                    was ftp-ssl */
+    {"$b", "ftp-pasv",   FALSE},
+    {"$c", "socks5",   TRUE},
+    {"$c", "socks",      TRUE}, /* this is how the option once was documented
+                                   but we prefer the --socks5 version for
+                                   explicit version */
+    {"$d", "tcp-nodelay",FALSE},
+    {"$e", "proxy-digest", FALSE},
+    {"$f", "proxy-basic", FALSE},
+    {"$g", "retry",      TRUE},
+    {"$h", "retry-delay", TRUE},
+    {"$i", "retry-max-time", TRUE},
+    {"$k", "proxy-negotiate",   FALSE},
+    {"$m", "ftp-account", TRUE},
+    {"$n", "proxy-anyauth", FALSE},
+    {"$o", "trace-time", FALSE},
+    {"$p", "ignore-content-length", FALSE},
+    {"$q", "ftp-skip-pasv-ip", FALSE},
+    {"$r", "ftp-method", TRUE},
+    {"$s", "local-port", TRUE},
+    {"$t", "socks4",     TRUE},
+    {"$T", "socks4a",    TRUE},
+    {"$u", "ftp-alternative-to-user", TRUE},
+    {"$v", "ftp-ssl-reqd", FALSE}, /* deprecated name since 7.20.0 */
+    {"$v", "ssl-reqd", FALSE},  /* new option name in 7.20.0, previously this
+                                   was ftp-ssl-reqd */
+    {"$w", "sessionid", FALSE}, /* listed as --no-sessionid in the help */
+    {"$x", "ftp-ssl-control", FALSE},
+    {"$y", "ftp-ssl-ccc", FALSE},
+    {"$j", "ftp-ssl-ccc-mode", TRUE},
+    {"$z", "libcurl",    TRUE},
+    {"$#", "raw",        FALSE},
+    {"$0", "post301",    FALSE},
+    {"$1", "keepalive",   FALSE}, /* listed as --no-keepalive in the help */
+    {"$2", "socks5-hostname", TRUE},
+    {"$3", "keepalive-time",  TRUE},
+    {"$4", "post302",    FALSE},
+    {"$5", "noproxy",    TRUE},
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+    {"$6", "socks5-gssapi-service",  TRUE},
+    {"$7", "socks5-gssapi-nec",  FALSE},
+#endif
+    {"$8", "proxy1.0",   TRUE},
+    {"$9", "tftp-blksize", TRUE},
+    {"$A", "mail-from", TRUE},
+    {"$B", "mail-rcpt", TRUE},
+    {"$C", "ftp-pret",   FALSE},
+    {"0", "http1.0",     FALSE},
+    {"1", "tlsv1",       FALSE},
+    {"2", "sslv2",       FALSE},
+    {"3", "sslv3",       FALSE},
+    {"4", "ipv4",       FALSE},
+    {"6", "ipv6",       FALSE},
+    {"a", "append",      FALSE},
+    {"A", "user-agent",  TRUE},
+    {"b", "cookie",      TRUE},
+    {"B", "use-ascii",   FALSE},
+    {"c", "cookie-jar",  TRUE},
+    {"C", "continue-at", TRUE},
+    {"d", "data",        TRUE},
+    {"da", "data-ascii", TRUE},
+    {"db", "data-binary", TRUE},
+    {"de", "data-urlencode", TRUE},
+    {"D", "dump-header", TRUE},
+    {"e", "referer",     TRUE},
+    {"E", "cert",        TRUE},
+    {"Ea", "cacert",     TRUE},
+    {"Eb","cert-type",   TRUE},
+    {"Ec","key",         TRUE},
+    {"Ed","key-type",    TRUE},
+    {"Ee","pass",        TRUE},
+    {"Ef","engine",      TRUE},
+    {"Eg","capath ",     TRUE},
+    {"Eh","pubkey",      TRUE},
+    {"Ei", "hostpubmd5", TRUE},
+    {"Ej","crlfile",     TRUE},
+    {"f", "fail",        FALSE},
+    {"F", "form",        TRUE},
+    {"Fs","form-string", TRUE},
+    {"g", "globoff",     FALSE},
+    {"G", "get",         FALSE},
+    {"h", "help",        FALSE},
+    {"H", "header",      TRUE},
+    {"i", "include",     FALSE},
+    {"I", "head",        FALSE},
+    {"j", "junk-session-cookies", FALSE},
+    {"J", "remote-header-name", FALSE},
+    {"k", "insecure",    FALSE},
+    {"K", "config",      TRUE},
+    {"l", "list-only",   FALSE},
+    {"L", "location",    FALSE},
+    {"Lt", "location-trusted", FALSE},
+    {"m", "max-time",    TRUE},
+    {"M", "manual",      FALSE},
+    {"n", "netrc",       FALSE},
+    {"no", "netrc-optional", FALSE},
+    {"N", "buffer",   FALSE}, /* listed as --no-buffer in the help */
+    {"o", "output",      TRUE},
+    {"O",  "remote-name", FALSE},
+    {"Oa", "remote-name-all", FALSE},
+    {"p", "proxytunnel", FALSE},
+    {"P", "ftpport",     TRUE}, /* older version */
+    {"P", "ftp-port",    TRUE},
+    {"q", "disable",     FALSE},
+    {"Q", "quote",       TRUE},
+    {"r", "range",       TRUE},
+    {"R", "remote-time", FALSE},
+    {"s", "silent",      FALSE},
+    {"S", "show-error",  FALSE},
+    {"t", "telnet-options", TRUE}, /* this is documented as telnet-option */
+    {"T", "upload-file", TRUE},
+    {"u", "user",        TRUE},
+    {"U", "proxy-user",  TRUE},
+    {"v", "verbose",     FALSE},
+    {"V", "version",     FALSE},
+    {"w", "write-out",   TRUE},
+    {"x", "proxy",       TRUE},
+    {"X", "request",     TRUE},
+    {"X", "http-request", TRUE}, /* OBSOLETE VERSION */
+    {"Y", "speed-limit",  TRUE},
+    {"y", "speed-time", TRUE},
+    {"z", "time-cond",   TRUE},
+    {"#", "progress-bar",FALSE},
+  };
+
+  if(('-' != flag[0]) ||
+     (('-' == flag[0]) && ('-' == flag[1]))) {
+    /* this should be a long name */
+    char *word=('-' == flag[0])?flag+2:flag;
+    size_t fnam=strlen(word);
+    int numhits=0;
+
+    if(!strncmp(word, "no-", 3)) {
+      /* disable this option but ignore the "no-" part when looking for it */
+      word += 3;
+      toggle = FALSE;
+    }
+
+    for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) {
+      if(curlx_strnequal(aliases[j].lname, word, fnam)) {
+        longopt = TRUE;
+        numhits++;
+        if(curlx_raw_equal(aliases[j].lname, word)) {
+          parse = aliases[j].letter;
+          hit = j;
+          numhits = 1; /* a single unique hit */
+          break;
+        }
+        parse = aliases[j].letter;
+        hit = j;
+      }
+    }
+    if(numhits>1) {
+      /* this is at least the second match! */
+      return PARAM_OPTION_AMBIGUOUS;
+    }
+    if(hit < 0) {
+      return PARAM_OPTION_UNKNOWN;
+    }
+  }
+  else {
+    flag++; /* prefixed with one dash, pass it */
+    hit=-1;
+    parse = flag;
+  }
+
+  do {
+    /* we can loop here if we have multiple single-letters */
+
+    if(!longopt) {
+      if(NULL != parse) {
+        letter = (char)*parse;
+      }
+      else {
+        letter = '\0';
+      }
+      subletter='\0';
+    }
+    else {
+      letter = parse[0];
+      subletter = parse[1];
+    }
+    *usedarg = FALSE; /* default is that we don't use the arg */
+
+    if(hit < 0) {
+      for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) {
+        if(letter == aliases[j].letter[0]) {
+          hit = j;
+          break;
+        }
+      }
+      if(hit < 0) {
+        return PARAM_OPTION_UNKNOWN;
+      }
+    }
+
+    if(aliases[hit].extraparam) {
+      /* this option requires an extra parameter */
+      if(!longopt && parse[1]) {
+        nextarg=(char *)&parse[1]; /* this is the actual extra parameter */
+        singleopt=TRUE;   /* don't loop anymore after this */
+      }
+      else if(!nextarg)
+        return PARAM_REQUIRES_PARAMETER;
+      else
+        *usedarg = TRUE; /* mark it as used */
+    }
+
+    switch(letter) {
+    case '*': /* options without a short option */
+      switch(subletter) {
+      case 'a': /* random-file */
+        GetStr(&config->random_file, nextarg);
+        break;
+      case 'b': /* egd-file */
+        GetStr(&config->egd_file, nextarg);
+        break;
+      case 'c': /* connect-timeout */
+        if(str2num(&config->connecttimeout, nextarg))
+          return PARAM_BAD_NUMERIC;
+        break;
+      case 'd': /* ciphers */
+        GetStr(&config->cipher_list, nextarg);
+        break;
+      case 'e': /* --disable-epsv */
+        config->disable_epsv = toggle;
+        break;
+      case 'E': /* --epsv */
+        config->disable_epsv = (bool)(!toggle);
+        break;
+#ifdef USE_ENVIRONMENT
+      case 'f':
+        config->writeenv = toggle;
+        break;
+#endif
+      case 'g': /* --trace */
+        GetStr(&config->trace_dump, nextarg);
+        if(config->tracetype && (config->tracetype != TRACE_BIN))
+          warnf(config, "--trace overrides an earlier trace/verbose option\n");
+        config->tracetype = TRACE_BIN;
+        break;
+      case 'h': /* --trace-ascii */
+        GetStr(&config->trace_dump, nextarg);
+        if(config->tracetype && (config->tracetype != TRACE_ASCII))
+          warnf(config,
+                "--trace-ascii overrides an earlier trace/verbose option\n");
+        config->tracetype = TRACE_ASCII;
+        break;
+      case 'i': /* --limit-rate */
+        {
+          /* We support G, M, K too */
+          char *unit;
+          curl_off_t value = curlx_strtoofft(nextarg, &unit, 0);
+
+          if(!*unit)
+            unit=(char *)"b";
+          else if(strlen(unit) > 1)
+            unit=(char *)"w"; /* unsupported */
+
+          switch(*unit) {
+          case 'G':
+          case 'g':
+            value *= 1024*1024*1024;
+            break;
+          case 'M':
+          case 'm':
+            value *= 1024*1024;
+            break;
+          case 'K':
+          case 'k':
+            value *= 1024;
+            break;
+          case 'b':
+          case 'B':
+            /* for plain bytes, leave as-is */
+            break;
+          default:
+            warnf(config, "unsupported rate unit. Use G, M, K or B!\n");
+            return PARAM_BAD_USE;
+          }
+          config->recvpersecond = value;
+          config->sendpersecond = value;
+        }
+        break;
+
+      case 'j': /* --compressed */
+        config->encoding = toggle;
+        break;
+
+      case 'k': /* --digest */
+        if(toggle)
+          config->authtype |= CURLAUTH_DIGEST;
+        else
+          config->authtype &= ~CURLAUTH_DIGEST;
+        break;
+
+      case 'l': /* --negotiate */
+        if(toggle) {
+          if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE)
+            config->authtype |= CURLAUTH_GSSNEGOTIATE;
+          else
+            return PARAM_LIBCURL_DOESNT_SUPPORT;
+        }
+        else
+          config->authtype &= ~CURLAUTH_GSSNEGOTIATE;
+        break;
+
+      case 'm': /* --ntlm */
+        if(toggle) {
+          if(curlinfo->features & CURL_VERSION_NTLM)
+            config->authtype |= CURLAUTH_NTLM;
+          else
+            return PARAM_LIBCURL_DOESNT_SUPPORT;
+        }
+        else
+          config->authtype &= ~CURLAUTH_NTLM;
+        break;
+
+      case 'n': /* --basic for completeness */
+        if(toggle)
+          config->authtype |= CURLAUTH_BASIC;
+        else
+          config->authtype &= ~CURLAUTH_BASIC;
+        break;
+
+      case 'o': /* --anyauth, let libcurl pick it */
+        if(toggle)
+          config->authtype = CURLAUTH_ANY;
+        /* --no-anyauth simply doesn't touch it */
+        break;
+
+#ifdef USE_WATT32
+      case 'p': /* --wdebug */
+        dbug_init();
+        break;
+#endif
+      case 'q': /* --ftp-create-dirs */
+        config->ftp_create_dirs = toggle;
+        break;
+
+      case 'r': /* --create-dirs */
+        config->create_dirs = TRUE;
+        break;
+
+      case 's': /* --max-redirs */
+        /* specified max no of redirects (http(s)) */
+        if(str2num(&config->maxredirs, nextarg))
+          return PARAM_BAD_NUMERIC;
+        break;
+
+      case 't': /* --proxy-ntlm */
+        if(curlinfo->features & CURL_VERSION_NTLM)
+          config->proxyntlm = toggle;
+        else
+          return PARAM_LIBCURL_DOESNT_SUPPORT;
+        break;
+
+      case 'u': /* --crlf */
+        /* LF -> CRLF conversion? */
+        config->crlf = TRUE;
+        break;
+
+      case 'v': /* --stderr */
+        if(strcmp(nextarg, "-")) {
+          FILE *newfile = fopen(nextarg, "wt");
+          if(!newfile)
+            warnf(config, "Failed to open %s!\n", nextarg);
+          else {
+            if(config->errors_fopened)
+              fclose(config->errors);
+            config->errors = newfile;
+            config->errors_fopened = TRUE;
+          }
+        }
+        else
+          config->errors = stdout;
+      break;
+      case 'w': /* --interface */
+        /* interface */
+        GetStr(&config->iface, nextarg);
+        break;
+      case 'x': /* --krb */
+        /* kerberos level string */
+        if(curlinfo->features & (CURL_VERSION_KERBEROS4 |
+                                 CURL_VERSION_GSSNEGOTIATE))
+          GetStr(&config->krblevel, nextarg);
+        else
+          return PARAM_LIBCURL_DOESNT_SUPPORT;
+        break;
+      case 'y': /* --max-filesize */
+        if(str2offset(&config->max_filesize, nextarg))
+          return PARAM_BAD_NUMERIC;
+        break;
+      case 'z': /* --disable-eprt */
+        config->disable_eprt = toggle;
+        break;
+      case 'Z': /* --eprt */
+        config->disable_eprt = (bool)(!toggle);
+        break;
+
+      default: /* the URL! */
+        {
+          struct getout *url;
+          if(config->url_get || (config->url_get=config->url_list)) {
+            /* there's a node here, if it already is filled-in continue to find
+               an "empty" node */
+            while(config->url_get && (config->url_get->flags&GETOUT_URL))
+              config->url_get = config->url_get->next;
+          }
+
+          /* now there might or might not be an available node to fill in! */
+
+          if(config->url_get)
+            /* existing node */
+            url = config->url_get;
+          else
+            /* there was no free node, create one! */
+            url=new_getout(config);
+
+          if(url) {
+            /* fill in the URL */
+            GetStr(&url->url, nextarg);
+            url->flags |= GETOUT_URL;
+          }
+        }
+      }
+      break;
+    case '$': /* more options without a short option */
+      switch(subletter) {
+      case 'a': /* --ftp-ssl */
+        config->ftp_ssl = toggle;
+        break;
+      case 'b': /* --ftp-pasv */
+        if(config->ftpport)
+          free(config->ftpport);
+        config->ftpport = NULL;
+        break;
+      case 'c': /* --socks5 specifies a socks5 proxy to use, and resolves
+                   the name locally and passes on the resolved address */
+        GetStr(&config->socksproxy, nextarg);
+        config->socksver = CURLPROXY_SOCKS5;
+        break;
+      case 't': /* --socks4 specifies a socks4 proxy to use */
+        GetStr(&config->socksproxy, nextarg);
+        config->socksver = CURLPROXY_SOCKS4;
+        break;
+      case 'T': /* --socks4a specifies a socks4a proxy to use */
+        GetStr(&config->socksproxy, nextarg);
+        config->socksver = CURLPROXY_SOCKS4A;
+        break;
+      case '2': /* --socks5-hostname specifies a socks5 proxy and enables name
+                   resolving with the proxy */
+        GetStr(&config->socksproxy, nextarg);
+        config->socksver = CURLPROXY_SOCKS5_HOSTNAME;
+        break;
+      case 'd': /* --tcp-nodelay option */
+        config->tcp_nodelay = toggle;
+        break;
+      case 'e': /* --proxy-digest */
+        config->proxydigest = toggle;
+        break;
+      case 'f': /* --proxy-basic */
+        config->proxybasic = toggle;
+        break;
+      case 'g': /* --retry */
+        if(str2num(&config->req_retry, nextarg))
+          return PARAM_BAD_NUMERIC;
+        break;
+      case 'h': /* --retry-delay */
+        if(str2num(&config->retry_delay, nextarg))
+          return PARAM_BAD_NUMERIC;
+        break;
+      case 'i': /* --retry-max-time */
+        if(str2num(&config->retry_maxtime, nextarg))
+          return PARAM_BAD_NUMERIC;
+        break;
+
+      case 'k': /* --proxy-negotiate */
+        if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE)
+          config->proxynegotiate = toggle;
+        else
+          return PARAM_LIBCURL_DOESNT_SUPPORT;
+        break;
+      case 'm': /* --ftp-account */
+        GetStr(&config->ftp_account, nextarg);
+        break;
+      case 'n': /* --proxy-anyauth */
+        config->proxyanyauth = toggle;
+        break;
+      case 'o': /* --trace-time */
+        config->tracetime = toggle;
+        break;
+      case 'p': /* --ignore-content-length */
+        config->ignorecl = toggle;
+        break;
+      case 'q': /* --ftp-skip-pasv-ip */
+        config->ftp_skip_ip = toggle;
+        break;
+      case 'r': /* --ftp-method (undocumented at this point) */
+        config->ftp_filemethod = ftpfilemethod(config, nextarg);
+        break;
+      case 's': /* --local-port */
+        rc = sscanf(nextarg, "%d - %d",
+                    &config->localport,
+                    &config->localportrange);
+        if(!rc)
+          return PARAM_BAD_USE;
+        else if(rc == 1)
+          config->localportrange = 1; /* default number of ports to try */
+        else {
+          config->localportrange -= config->localport;
+          if(config->localportrange < 1) {
+            warnf(config, "bad range input\n");
+            return PARAM_BAD_USE;
+          }
+        }
+        break;
+      case 'u': /* --ftp-alternative-to-user */
+        GetStr(&config->ftp_alternative_to_user, nextarg);
+        break;
+      case 'v': /* --ftp-ssl-reqd */
+        config->ftp_ssl_reqd = toggle;
+        break;
+      case 'w': /* --no-sessionid */
+        config->disable_sessionid = (bool)(!toggle);
+        break;
+      case 'x': /* --ftp-ssl-control */
+        config->ftp_ssl_control = toggle;
+        break;
+      case 'y': /* --ftp-ssl-ccc */
+        config->ftp_ssl_ccc = toggle;
+        if(!config->ftp_ssl_ccc_mode)
+            config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE;
+        break;
+      case 'j': /* --ftp-ssl-ccc-mode */
+        config->ftp_ssl_ccc = TRUE;
+        config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg);
+        break;
+      case 'z': /* --libcurl */
+        GetStr(&config->libcurl, nextarg);
+        break;
+      case '#': /* --raw */
+        config->raw = toggle;
+        break;
+      case '0': /* --post301 */
+        config->post301 = toggle;
+        break;
+      case '1': /* --no-keepalive */
+        config->nokeepalive = (bool)(!toggle);
+        break;
+      case '3': /* --keepalive-time */
+        if(str2num(&config->alivetime, nextarg))
+          return PARAM_BAD_NUMERIC;
+        break;
+      case '4': /* --post302 */
+        config->post302 = toggle;
+        break;
+      case '5': /* --noproxy */
+        /* This specifies the noproxy list */
+        GetStr(&config->noproxy, nextarg);
+        break;
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+      case '6': /* --socks5-gssapi-service */
+        GetStr(&config->socks5_gssapi_service, nextarg);
+        break;
+      case '7': /* --socks5-gssapi-nec*/
+        config->socks5_gssapi_nec = TRUE;
+        break;
+#endif
+      case '8': /* --proxy1.0 */
+        /* http 1.0 proxy */
+        GetStr(&config->proxy, nextarg);
+        config->proxyver = CURLPROXY_HTTP_1_0;
+        break;
+      case '9': /* --tftp-blksize */
+        str2num(&config->tftp_blksize, nextarg);
+        break;
+      case 'A': /* --mail-from */
+        GetStr(&config->mail_from, nextarg);
+        break;
+      case 'B': /* --mail-rcpt */
+        /* append receiver to a list */
+        err = add2list(&config->mail_rcpt, nextarg);
+        if(err)
+          return err;
+        break;
+      case 'C': /* --ftp-pret */
+        config->ftp_pret = toggle;
+        break;
+      }
+      break;
+    case '#': /* --progress-bar */
+      if(toggle)
+        config->progressmode = CURL_PROGRESS_BAR;
+      else
+        config->progressmode = CURL_PROGRESS_STATS;
+      break;
+    case '0':
+      /* HTTP version 1.0 */
+      config->httpversion = CURL_HTTP_VERSION_1_0;
+      break;
+    case '1':
+      /* TLS version 1 */
+      config->ssl_version = CURL_SSLVERSION_TLSv1;
+      break;
+    case '2':
+      /* SSL version 2 */
+      config->ssl_version = CURL_SSLVERSION_SSLv2;
+      break;
+    case '3':
+      /* SSL version 3 */
+      config->ssl_version = CURL_SSLVERSION_SSLv3;
+      break;
+    case '4':
+      /* IPv4 */
+      config->ip_version = 4;
+      break;
+    case '6':
+      /* IPv6 */
+      config->ip_version = 6;
+      break;
+    case 'a':
+      /* This makes the FTP sessions use APPE instead of STOR */
+      config->ftp_append = toggle;
+      break;
+    case 'A':
+      /* This specifies the User-Agent name */
+      GetStr(&config->useragent, nextarg);
+      break;
+    case 'b': /* cookie string coming up: */
+      if(nextarg[0] == '@') {
+        nextarg++;
+      }
+      else if(strchr(nextarg, '=')) {
+        /* A cookie string must have a =-letter */
+        GetStr(&config->cookie, nextarg);
+        break;
+      }
+      /* We have a cookie file to read from! */
+      GetStr(&config->cookiefile, nextarg);
+      break;
+    case 'B':
+      /* use ASCII/text when transfering */
+      config->use_ascii = toggle;
+      break;
+    case 'c':
+      /* get the file name to dump all cookies in */
+      GetStr(&config->cookiejar, nextarg);
+      break;
+    case 'C':
+      /* This makes us continue an ftp transfer at given position */
+      if(!curlx_strequal(nextarg, "-")) {
+        if(str2offset(&config->resume_from, nextarg))
+          return PARAM_BAD_NUMERIC;
+        config->resume_from_current = FALSE;
+      }
+      else {
+        config->resume_from_current = TRUE;
+        config->resume_from = 0;
+      }
+      config->use_resume=TRUE;
+      break;
+    case 'd':
+      /* postfield data */
+      {
+        char *postdata=NULL;
+        FILE *file;
+
+        if(subletter == 'e') { /* --data-urlencode*/
+          /* [name]=[content], we encode the content part only
+           * [name]@[file name]
+           *
+           * Case 2: we first load the file using that name and then encode
+           * the content.
+           */
+          const char *p = strchr(nextarg, '=');
+          size_t size = 0;
+          size_t nlen;
+          char is_file;
+          if(!p)
+            /* there was no '=' letter, check for a '@' instead */
+            p = strchr(nextarg, '@');
+          if (p) {
+            nlen = p - nextarg; /* length of the name part */
+            is_file = *p++; /* pass the separator */
+          }
+          else {
+            /* neither @ nor =, so no name and it isn't a file */
+            nlen = is_file = 0;
+            p = nextarg;
+          }
+          if('@' == is_file) {
+            /* a '@' letter, it means that a file name or - (stdin) follows */
+
+            if(curlx_strequal("-", p)) {
+              file = stdin;
+              SET_BINMODE(stdin);
+            }
+            else {
+              file = fopen(p, "rb");
+              if(!file)
+                warnf(config,
+                      "Couldn't read data from file \"%s\", this makes "
+                      "an empty POST.\n", nextarg);
+            }
+
+            err = file2memory(&postdata, &size, file);
+
+            if(file && (file != stdin))
+              fclose(file);
+            if(err)
+              return err;
+          }
+          else {
+            GetStr(&postdata, p);
+            size = strlen(postdata);
+          }
+
+          if(!postdata) {
+            /* no data from the file, point to a zero byte string to make this
+               get sent as a POST anyway */
+            postdata=strdup("");
+          }
+          else {
+            char *enc = curl_easy_escape(config->easy, postdata, (int)size);
+            free(postdata); /* no matter if it worked or not */
+            if(enc) {
+              /* now make a string with the name from above and append the
+                 encoded string */
+              size_t outlen = nlen + strlen(enc) + 2;
+              char *n = malloc(outlen);
+              if(!n) {
+                curl_free(enc);
+                return PARAM_NO_MEM;
+              }
+              if (nlen > 0) /* only append '=' if we have a name */
+                snprintf(n, outlen, "%.*s=%s", nlen, nextarg, enc);
+              else
+                strcpy(n, enc);
+              curl_free(enc);
+              postdata = n;
+            }
+            else
+              return PARAM_NO_MEM;
+          }
+        }
+        else if('@' == *nextarg) {
+          size_t size = 0;
+          /* the data begins with a '@' letter, it means that a file name
+             or - (stdin) follows */
+          nextarg++; /* pass the @ */
+
+          if(curlx_strequal("-", nextarg)) {
+            file = stdin;
+            if(subletter == 'b') /* forced data-binary */
+              SET_BINMODE(stdin);
+          }
+          else {
+            file = fopen(nextarg, "rb");
+            if(!file)
+              warnf(config, "Couldn't read data from file \"%s\", this makes "
+                    "an empty POST.\n", nextarg);
+          }
+
+          if(subletter == 'b') {
+            /* forced binary */
+            err = file2memory(&postdata, &size, file);
+            config->postfieldsize = (curl_off_t)size;
+          }
+          else
+            err = file2string(&postdata, file);
+
+          if(file && (file != stdin))
+            fclose(file);
+          if(err)
+            return err;
+
+          if(!postdata) {
+            /* no data from the file, point to a zero byte string to make this
+               get sent as a POST anyway */
+            postdata=strdup("");
+          }
+        }
+        else {
+          GetStr(&postdata, nextarg);
+        }
+
+#ifdef CURL_DOES_CONVERSIONS
+        if(subletter != 'b') { /* NOT forced binary, convert to ASCII */
+          convert_to_network(postdata, strlen(postdata));
+        }
+#endif
+
+        if(config->postfields) {
+          /* we already have a string, we append this one
+             with a separating &-letter */
+          char *oldpost=config->postfields;
+          size_t newlen = strlen(oldpost) + strlen(postdata) + 2;
+          config->postfields=malloc(newlen);
+          if(!config->postfields) {
+            free(postdata);
+            return PARAM_NO_MEM;
+          }
+          /* use ASCII value 0x26 for '&' to accommodate non-ASCII platforms */
+          snprintf(config->postfields, newlen, "%s\x26%s", oldpost, postdata);
+          free(oldpost);
+          free(postdata);
+        }
+        else
+          config->postfields=postdata;
+      }
+      /*
+        We can't set the request type here, as this data might be used in
+        a simple GET if -G is used. Already or soon.
+
+        if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq))
+          return PARAM_BAD_USE;
+      */
+      break;
+    case 'D':
+      /* dump-header to given file name */
+      GetStr(&config->headerfile, nextarg);
+      break;
+    case 'e':
+      {
+        char *ptr = strstr(nextarg, ";auto");
+        if(ptr) {
+          /* Automatic referer requested, this may be combined with a
+             set initial one */
+          config->autoreferer = TRUE;
+          *ptr = 0; /* zero terminate here */
+        }
+        else
+          config->autoreferer = FALSE;
+        GetStr(&config->referer, nextarg);
+      }
+      break;
+    case 'E':
+      switch(subletter) {
+      case 'a': /* CA info PEM file */
+        /* CA info PEM file */
+        GetStr(&config->cacert, nextarg);
+        break;
+      case 'b': /* cert file type */
+        GetStr(&config->cert_type, nextarg);
+        break;
+      case 'c': /* private key file */
+        GetStr(&config->key, nextarg);
+        break;
+      case 'd': /* private key file type */
+        GetStr(&config->key_type, nextarg);
+        break;
+      case 'e': /* private key passphrase */
+        GetStr(&config->key_passwd, nextarg);
+        cleanarg(nextarg);
+        break;
+      case 'f': /* crypto engine */
+        GetStr(&config->engine, nextarg);
+        if (config->engine && curlx_raw_equal(config->engine,"list"))
+           config->list_engines = TRUE;
+        break;
+      case 'g': /* CA info PEM file */
+        /* CA cert directory */
+        GetStr(&config->capath, nextarg);
+        break;
+      case 'h': /* --pubkey public key file */
+        GetStr(&config->pubkey, nextarg);
+        break;
+      case 'i': /* --hostpubmd5 md5 of the host public key */
+        GetStr(&config->hostpubmd5, nextarg);
+        if (!config->hostpubmd5 || strlen(config->hostpubmd5) != 32)
+           return PARAM_BAD_USE;
+        break;
+      case 'j': /* CRL info PEM file */
+        /* CRL file */
+        GetStr(&config->crlfile, nextarg);
+        break;
+      default: /* certificate file */
+        {
+          char *ptr = strchr(nextarg, ':');
+          /* Since we live in a world of weirdness and confusion, the win32
+             dudes can use : when using drive letters and thus
+             c:\file:password needs to work. In order not to break
+             compatibility, we still use : as separator, but we try to detect
+             when it is used for a file name! On windows. */
+#ifdef WIN32
+          if(ptr &&
+             (ptr == &nextarg[1]) &&
+             (nextarg[2] == '\\' || nextarg[2] == '/') &&
+             (ISALPHA(nextarg[0])) )
+             /* colon in the second column, followed by a backslash, and the
+                first character is an alphabetic letter:
+
+                this is a drive letter colon */
+            ptr = strchr(&nextarg[3], ':'); /* find the next one instead */
+#endif
+          if(ptr) {
+            /* we have a password too */
+            *ptr=0;
+            ptr++;
+            GetStr(&config->key_passwd, ptr);
+          }
+          GetStr(&config->cert, nextarg);
+          cleanarg(nextarg);
+        }
+      }
+      break;
+    case 'f':
+      /* fail hard on errors  */
+      config->failonerror = toggle;
+      break;
+    case 'F':
+      /* "form data" simulation, this is a little advanced so lets do our best
+         to sort this out slowly and carefully */
+      if(formparse(config,
+                   nextarg,
+                   &config->httppost,
+                   &config->last_post,
+                   (bool) (subletter=='s'))) /* 's' means literal string */
+        return PARAM_BAD_USE;
+      if(SetHTTPrequest(config, HTTPREQ_POST, &config->httpreq))
+        return PARAM_BAD_USE;
+      break;
+
+    case 'g': /* g disables URLglobbing */
+      config->globoff = toggle;
+      break;
+
+    case 'G': /* HTTP GET */
+      config->use_httpget = TRUE;
+      break;
+
+    case 'h': /* h for help */
+      if(toggle) {
+        help();
+        return PARAM_HELP_REQUESTED;
+      }
+      /* we now actually support --no-help too! */
+      break;
+    case 'H':
+      /* A custom header to append to a list */
+      err = add2list(&config->headers, nextarg);
+      if(err)
+        return err;
+      break;
+    case 'i':
+      config->include_headers = toggle; /* include the headers as well in the
+                                           general output stream */
+      break;
+    case 'j':
+      config->cookiesession = toggle;
+      break;
+    case 'I':
+      /*
+       * no_body will imply include_headers later on
+       */
+      config->no_body = toggle;
+      if(SetHTTPrequest(config,
+                        (config->no_body)?HTTPREQ_HEAD:HTTPREQ_GET,
+                        &config->httpreq))
+        return PARAM_BAD_USE;
+      break;
+    case 'J': /* --remote-header-name */
+      if (config->include_headers) {
+        warnf(config,
+              "--include and --remote-header-name cannot be combined.\n");
+        return PARAM_BAD_USE;
+      }
+      config->content_disposition = toggle;
+      break;
+    case 'k': /* allow insecure SSL connects */
+      config->insecure_ok = toggle;
+      break;
+    case 'K': /* parse config file */
+      if(parseconfig(nextarg, config))
+        warnf(config, "error trying read config from the '%s' file\n",
+              nextarg);
+      break;
+    case 'l':
+      config->dirlistonly = toggle; /* only list the names of the FTP dir */
+      break;
+    case 'L':
+      config->followlocation = toggle; /* Follow Location: HTTP headers */
+      switch (subletter) {
+      case 't':
+        /* Continue to send authentication (user+password) when following
+         * locations, even when hostname changed */
+        config->unrestricted_auth = toggle;
+        break;
+      }
+      break;
+    case 'm':
+      /* specified max time */
+      if(str2num(&config->timeout, nextarg))
+        return PARAM_BAD_NUMERIC;
+      break;
+    case 'M': /* M for manual, huge help */
+      if(toggle) { /* --no-manual shows no manual... */
+#ifdef USE_MANUAL
+        hugehelp();
+        return PARAM_HELP_REQUESTED;
+#else
+        warnf(config,
+              "built-in manual was disabled at build-time!\n");
+        return PARAM_OPTION_UNKNOWN;
+#endif
+      }
+      break;
+    case 'n':
+      switch(subletter) {
+      case 'o': /* CA info PEM file */
+        /* use .netrc or URL */
+        config->netrc_opt = toggle;
+        break;
+      default:
+        /* pick info from .netrc, if this is used for http, curl will
+           automatically enfore user+password with the request */
+        config->netrc = toggle;
+        break;
+      }
+      break;
+    case 'N':
+      /* disable the output I/O buffering. note that the option is called
+         --buffer but is mostly used in the negative form: --no-buffer */
+      if(longopt)
+        config->nobuffer = (bool)(!toggle);
+      else
+        config->nobuffer = toggle;
+      break;
+    case 'O': /* --remote-name */
+      if(subletter == 'a') { /* --remote-name-all */
+        config->default_node_flags = toggle?GETOUT_USEREMOTE:0;
+        break;
+      }
+    /* fall-through! */
+    case 'o': /* --output */
+      /* output file */
+      {
+        struct getout *url;
+        if(config->url_out || (config->url_out=config->url_list)) {
+          /* there's a node here, if it already is filled-in continue to find
+             an "empty" node */
+          while(config->url_out && (config->url_out->flags&GETOUT_OUTFILE))
+            config->url_out = config->url_out->next;
+        }
+
+        /* now there might or might not be an available node to fill in! */
+
+        if(config->url_out)
+          /* existing node */
+          url = config->url_out;
+        else
+          /* there was no free node, create one! */
+          url=new_getout(config);
+
+        if(url) {
+          /* fill in the outfile */
+          if('o' == letter) {
+            GetStr(&url->outfile, nextarg);
+            url->flags &= ~GETOUT_USEREMOTE; /* switch off */
+          }
+          else {
+            url->outfile=NULL; /* leave it */
+            if(toggle)
+              url->flags |= GETOUT_USEREMOTE;  /* switch on */
+            else
+              url->flags &= ~GETOUT_USEREMOTE; /* switch off */
+          }
+          url->flags |= GETOUT_OUTFILE;
+        }
+      }
+      break;
+    case 'P':
+      /* This makes the FTP sessions use PORT instead of PASV */
+      /* use <eth0> or <192.168.10.10> style addresses. Anything except
+         this will make us try to get the "default" address.
+         NOTE: this is a changed behaviour since the released 4.1!
+         */
+      GetStr(&config->ftpport, nextarg);
+      break;
+    case 'p':
+      /* proxy tunnel for non-http protocols */
+      config->proxytunnel = toggle;
+      break;
+
+    case 'q': /* if used first, already taken care of, we do it like
+                 this so we don't cause an error! */
+      break;
+    case 'Q':
+      /* QUOTE command to send to FTP server */
+      switch(nextarg[0]) {
+      case '-':
+        /* prefixed with a dash makes it a POST TRANSFER one */
+        nextarg++;
+        err = add2list(&config->postquote, nextarg);
+        break;
+      case '+':
+        /* prefixed with a plus makes it a just-before-transfer one */
+        nextarg++;
+        err = add2list(&config->prequote, nextarg);
+        break;
+      default:
+        err = add2list(&config->quote, nextarg);
+        break;
+      }
+      if(err)
+        return err;
+      break;
+    case 'r':
+      /* Specifying a range WITHOUT A DASH will create an illegal HTTP range
+         (and won't actually be range by definition). The man page previously
+         claimed that to be a good way, why this code is added to work-around
+         it. */
+      if(ISDIGIT(*nextarg) && !strchr(nextarg, '-')) {
+        char buffer[32];
+        curl_off_t off;
+        warnf(config,
+              "A specified range MUST include at least one dash (-). "
+              "Appending one for you!\n");
+        off = curlx_strtoofft(nextarg, NULL, 10);
+        snprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", off);
+        GetStr(&config->range, buffer);
+      }
+      {
+        /* byte range requested */
+        char* tmp_range;
+        tmp_range=nextarg;
+        while(*tmp_range != '\0') {
+          if(!ISDIGIT(*tmp_range)&&*tmp_range!='-'&&*tmp_range!=',') {
+            warnf(config,"Invalid character is found in given range. "
+                  "A specified range MUST have only digits in "
+                  "\'start\'-\'stop\'. The server's response to this "
+                  "request is uncertain.\n");
+            break;
+          }
+          tmp_range++;
+        }
+        /* byte range requested */
+        GetStr(&config->range, nextarg);
+      }
+      break;
+    case 'R':
+      /* use remote file's time */
+      config->remote_time = toggle;
+      break;
+    case 's':
+      /* don't show progress meter, don't show errors : */
+      if(toggle)
+        config->mute = config->noprogress = TRUE;
+      else
+        config->mute = config->noprogress = FALSE;
+      config->showerror = (bool)(!toggle); /* toggle off */
+      break;
+    case 'S':
+      /* show errors */
+      config->showerror = toggle; /* toggle on if used with -s */
+      break;
+    case 't':
+      /* Telnet options */
+      err = add2list(&config->telnet_options, nextarg);
+      if(err)
+        return err;
+      break;
+    case 'T':
+      /* we are uploading */
+      {
+        struct getout *url;
+        if(config->url_out || (config->url_out=config->url_list)) {
+          /* there's a node here, if it already is filled-in continue to find
+             an "empty" node */
+          while(config->url_out && (config->url_out->flags&GETOUT_UPLOAD))
+            config->url_out = config->url_out->next;
+        }
+
+        /* now there might or might not be an available node to fill in! */
+
+        if(config->url_out)
+          /* existing node */
+          url = config->url_out;
+        else
+          /* there was no free node, create one! */
+          url=new_getout(config);
+
+        if(url) {
+          url->flags |= GETOUT_UPLOAD; /* mark -T used */
+          if(!*nextarg)
+            url->flags |= GETOUT_NOUPLOAD;
+          else {
+            /* "-" equals stdin, but keep the string around for now */
+            GetStr(&url->infile, nextarg);
+          }
+        }
+      }
+      break;
+    case 'u':
+      /* user:password  */
+      GetStr(&config->userpwd, nextarg);
+      cleanarg(nextarg);
+      checkpasswd("host", &config->userpwd);
+      break;
+    case 'U':
+      /* Proxy user:password  */
+      GetStr(&config->proxyuserpwd, nextarg);
+      cleanarg(nextarg);
+      checkpasswd("proxy", &config->proxyuserpwd);
+      break;
+    case 'v':
+      if(toggle) {
+        /* the '%' thing here will cause the trace get sent to stderr */
+        GetStr(&config->trace_dump, (char *)"%");
+        if(config->tracetype && (config->tracetype != TRACE_PLAIN))
+          warnf(config,
+                "-v/--verbose overrides an earlier trace/verbose option\n");
+        config->tracetype = TRACE_PLAIN;
+      }
+      else
+        /* verbose is disabled here */
+        config->tracetype = TRACE_NONE;
+      break;
+    case 'V':
+    {
+      const char * const *proto;
+
+      if(!toggle)
+        /* --no-version yields no output! */
+        break;
+
+      printf(CURL_ID "%s\n", curl_version());
+      if (curlinfo->protocols) {
+        printf("Protocols: ");
+        for (proto=curlinfo->protocols; *proto; ++proto) {
+          printf("%s ", *proto);
+        }
+        puts(""); /* newline */
+      }
+      if(curlinfo->features) {
+        unsigned int i;
+        struct feat {
+          const char *name;
+          int bitmask;
+        };
+        static const struct feat feats[] = {
+          {"AsynchDNS", CURL_VERSION_ASYNCHDNS},
+          {"Debug", CURL_VERSION_DEBUG},
+          {"TrackMemory", CURL_VERSION_CURLDEBUG},
+          {"GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE},
+          {"IDN", CURL_VERSION_IDN},
+          {"IPv6", CURL_VERSION_IPV6},
+          {"Largefile", CURL_VERSION_LARGEFILE},
+          {"NTLM", CURL_VERSION_NTLM},
+          {"SPNEGO", CURL_VERSION_SPNEGO},
+          {"SSL",  CURL_VERSION_SSL},
+          {"SSPI",  CURL_VERSION_SSPI},
+          {"krb4", CURL_VERSION_KERBEROS4},
+          {"libz", CURL_VERSION_LIBZ},
+          {"CharConv", CURL_VERSION_CONV}
+        };
+        printf("Features: ");
+        for(i=0; i<sizeof(feats)/sizeof(feats[0]); i++) {
+          if(curlinfo->features & feats[i].bitmask)
+            printf("%s ", feats[i].name);
+        }
+        puts(""); /* newline */
+      }
+    }
+    return PARAM_HELP_REQUESTED;
+    case 'w':
+      /* get the output string */
+      if('@' == *nextarg) {
+        /* the data begins with a '@' letter, it means that a file name
+           or - (stdin) follows */
+        FILE *file;
+        const char *fname;
+        nextarg++; /* pass the @ */
+        if(curlx_strequal("-", nextarg)) {
+          fname = "<stdin>";
+          file = stdin;
+        }
+        else {
+          fname = nextarg;
+          file = fopen(nextarg, "r");
+        }
+        err = file2string(&config->writeout, file);
+        if(file && (file != stdin))
+          fclose(file);
+        if(err)
+          return err;
+        if(!config->writeout)
+          warnf(config, "Failed to read %s", fname);
+      }
+      else
+        GetStr(&config->writeout, nextarg);
+      break;
+    case 'x':
+      /* proxy */
+      GetStr(&config->proxy, nextarg);
+      config->proxyver = CURLPROXY_HTTP;
+      break;
+    case 'X':
+      /* set custom request */
+      GetStr(&config->customrequest, nextarg);
+      break;
+    case 'y':
+      /* low speed time */
+      if(str2num(&config->low_speed_time, nextarg))
+        return PARAM_BAD_NUMERIC;
+      if(!config->low_speed_limit)
+        config->low_speed_limit = 1;
+      break;
+    case 'Y':
+      /* low speed limit */
+      if(str2num(&config->low_speed_limit, nextarg))
+        return PARAM_BAD_NUMERIC;
+      if(!config->low_speed_time)
+        config->low_speed_time=30;
+      break;
+    case 'z': /* time condition coming up */
+      switch(*nextarg) {
+      case '+':
+        nextarg++;
+      default:
+        /* If-Modified-Since: (section 14.28 in RFC2068) */
+        config->timecond = CURL_TIMECOND_IFMODSINCE;
+        break;
+      case '-':
+        /* If-Unmodified-Since:  (section 14.24 in RFC2068) */
+        config->timecond = CURL_TIMECOND_IFUNMODSINCE;
+        nextarg++;
+        break;
+      case '=':
+        /* Last-Modified:  (section 14.29 in RFC2068) */
+        config->timecond = CURL_TIMECOND_LASTMOD;
+        nextarg++;
+        break;
+      }
+      now=time(NULL);
+      config->condtime=curl_getdate(nextarg, &now);
+      if(-1 == (int)config->condtime) {
+        /* now let's see if it is a file name to get the time from instead! */
+        struct_stat statbuf;
+        if(-1 == stat(nextarg, &statbuf)) {
+          /* failed, remove time condition */
+          config->timecond = CURL_TIMECOND_NONE;
+          warnf(config,
+                "Illegal date format for -z/--timecond (and not "
+                "a file name). Disabling time condition. "
+                "See curl_getdate(3) for valid date syntax.\n");
+        }
+        else {
+          /* pull the time out from the file */
+          config->condtime = statbuf.st_mtime;
+        }
+      }
+      break;
+    default: /* unknown flag */
+      return PARAM_OPTION_UNKNOWN;
+    }
+    hit = -1;
+
+  } while(!longopt && !singleopt && *++parse && !*usedarg);
+
+  return PARAM_OK;
+}
+
+/*
+ * Copies the string from line to the buffer at param, unquoting
+ * backslash-quoted characters and NUL-terminating the output string.
+ * Stops at the first non-backslash-quoted double quote character or the
+ * end of the input string. param must be at least as long as the input
+ * string.  Returns the pointer after the last handled input character.
+ */
+static const char *unslashquote(const char *line, char *param)
+{
+  while(*line && (*line != '\"')) {
+    if(*line == '\\') {
+      char out;
+      line++;
+
+      /* default is to output the letter after the backslash */
+      switch(out = *line) {
+      case '\0':
+        continue; /* this'll break out of the loop */
+      case 't':
+        out='\t';
+        break;
+      case 'n':
+        out='\n';
+        break;
+      case 'r':
+        out='\r';
+        break;
+      case 'v':
+        out='\v';
+        break;
+      }
+      *param++=out;
+      line++;
+    }
+    else
+      *param++=*line++;
+  }
+  *param=0; /* always zero terminate */
+  return line;
+}
+
+/* return 0 on everything-is-fine, and non-zero otherwise */
+static int parseconfig(const char *filename,
+                       struct Configurable *config)
+{
+  int res;
+  FILE *file;
+  char filebuffer[512];
+  bool usedarg;
+  char *home;
+  int rc = 0;
+
+  if(!filename || !*filename) {
+    /* NULL or no file name attempts to load .curlrc from the homedir! */
+
+#define CURLRC DOT_CHAR "curlrc"
+
+#ifndef __AMIGA__
+    filename = CURLRC;   /* sensible default */
+    home = homedir();    /* portable homedir finder */
+    if(home) {
+      if(strlen(home)<(sizeof(filebuffer)-strlen(CURLRC))) {
+        snprintf(filebuffer, sizeof(filebuffer),
+                 "%s%s%s", home, DIR_CHAR, CURLRC);
+
+#ifdef WIN32
+        /* Check if the file exists - if not, try CURLRC in the same
+         * directory as our executable
+         */
+        file = fopen(filebuffer, "r");
+        if (file != NULL) {
+          fclose(file);
+          filename = filebuffer;
+        }
+        else {
+          /* Get the filename of our executable. GetModuleFileName is
+           * already declared via inclusions done in setup header file.
+           * We assume that we are using the ASCII version here.
+           */
+          int n = GetModuleFileName(0, filebuffer, sizeof(filebuffer));
+          if (n > 0 && n < (int)sizeof(filebuffer)) {
+            /* We got a valid filename - get the directory part */
+            char *lastdirchar = strrchr(filebuffer, '\\');
+            if (lastdirchar) {
+              size_t remaining;
+              *lastdirchar = 0;
+              /* If we have enough space, build the RC filename */
+              remaining = sizeof(filebuffer) - strlen(filebuffer);
+              if (strlen(CURLRC) < remaining - 1) {
+                snprintf(lastdirchar, remaining,
+                         "%s%s", DIR_CHAR, CURLRC);
+                /* Don't bother checking if it exists - we do
+                 * that later
+                 */
+                filename = filebuffer;
+              }
+            }
+          }
+        }
+#else /* WIN32 */
+        filename = filebuffer;
+#endif /* WIN32 */
+      }
+      free(home); /* we've used it, now free it */
+    }
+
+# else /* __AMIGA__ */
+  /* On AmigaOS all the config files are into env:
+   */
+  filename = "ENV:" CURLRC;
+
+#endif
+  }
+
+  if(strcmp(filename,"-"))
+    file = fopen(filename, "r");
+  else
+    file = stdin;
+
+  if(file) {
+    char *line;
+    char *aline;
+    char *option;
+    char *param;
+    int lineno=0;
+    bool alloced_param;
+
+#define ISSEP(x) (((x)=='=') || ((x) == ':'))
+
+    while (NULL != (aline = my_get_line(file))) {
+      lineno++;
+      line = aline;
+      alloced_param=FALSE;
+
+      /* line with # in the first non-blank column is a comment! */
+      while(*line && ISSPACE(*line))
+        line++;
+
+      switch(*line) {
+      case '#':
+      case '/':
+      case '\r':
+      case '\n':
+      case '*':
+      case '\0':
+        free(aline);
+        continue;
+      }
+
+      /* the option keywords starts here */
+      option = line;
+      while(*line && !ISSPACE(*line) && !ISSEP(*line))
+        line++;
+      /* ... and has ended here */
+
+      if(*line)
+        *line++=0; /* zero terminate, we have a local copy of the data */
+
+#ifdef DEBUG_CONFIG
+      fprintf(stderr, "GOT: %s\n", option);
+#endif
+
+      /* pass spaces and separator(s) */
+      while(*line && (ISSPACE(*line) || ISSEP(*line)))
+        line++;
+
+      /* the parameter starts here (unless quoted) */
+      if(*line == '\"') {
+        /* quoted parameter, do the quote dance */
+        line++;
+        param=malloc(strlen(line)+1); /* parameter */
+        if (!param) {
+          /* out of memory */
+          free(aline);
+          rc = 1;
+          break;
+        }
+        alloced_param=TRUE;
+        line = (char*) unslashquote(line, param);
+      }
+      else {
+        param=line; /* parameter starts here */
+        while(*line && !ISSPACE(*line))
+          line++;
+        *line=0; /* zero terminate */
+      }
+
+      if (param && !*param) {
+        /* do this so getparameter can check for required parameters.
+           Otherwise it always thinks there's a parameter. */
+        if (alloced_param)
+          free(param);
+        param = NULL;
+      }
+
+#ifdef DEBUG_CONFIG
+      fprintf(stderr, "PARAM: \"%s\"\n",(param ? param : "(null)"));
+#endif
+      res = getparameter(option, param, &usedarg, config);
+
+      if (param && *param && !usedarg)
+        /* we passed in a parameter that wasn't used! */
+        res = PARAM_GOT_EXTRA_PARAMETER;
+
+      if(res != PARAM_OK) {
+        /* the help request isn't really an error */
+        if(!strcmp(filename, "-")) {
+          filename=(char *)"<stdin>";
+        }
+        if(PARAM_HELP_REQUESTED != res) {
+          const char *reason = param2text(res);
+          warnf(config, "%s:%d: warning: '%s' %s\n",
+                filename, lineno, option, reason);
+        }
+      }
+
+      if(alloced_param)
+      {
+        free(param);
+        param = NULL;
+      }
+
+      free(aline);
+    }
+    if(file != stdin)
+      fclose(file);
+  }
+  else
+    rc = 1; /* couldn't open the file */
+  return rc;
+}
+
+static void go_sleep(long ms)
+{
+#ifdef HAVE_POLL_FINE
+  /* portable subsecond "sleep" */
+  poll((void *)0, 0, (int)ms);
+#else
+  /* systems without poll() need other solutions */
+
+#ifdef WIN32
+  /* Windows offers a millisecond sleep */
+  Sleep(ms);
+#elif defined(MSDOS)
+  delay(ms);
+#else
+  /* Other systems must use select() for this */
+  struct timeval timeout;
+
+  timeout.tv_sec = ms/1000;
+  ms = ms%1000;
+  timeout.tv_usec = ms * 1000;
+
+  select(0, NULL,  NULL, NULL, &timeout);
+#endif
+
+#endif
+}
+
+static size_t my_fwrite(void *buffer, size_t sz, size_t nmemb, void *stream)
+{
+  size_t rc;
+  struct OutStruct *out=(struct OutStruct *)stream;
+  struct Configurable *config = out->config;
+
+  /*
+   * Once that libcurl has called back my_fwrite() the returned value
+   * is checked against the amount that was intended to be written, if
+   * it does not match then it fails with CURLE_WRITE_ERROR. So at this
+   * point returning a value different from sz*nmemb indicates failure.
+   */
+  const size_t err_rc = (sz * nmemb) ? 0 : 1;
+
+  if(!out->stream) {
+    if (!out->filename) {
+      warnf(config, "Remote filename has no length!\n");
+      return err_rc; /* Failure */
+    }
+
+    if (config->content_disposition) {
+      /* don't overwrite existing files */
+      FILE* f = fopen(out->filename, "r");
+      if (f) {
+        fclose(f);
+        warnf(config, "Refusing to overwrite %s: %s\n", out->filename,
+              strerror(EEXIST));
+        return err_rc; /* Failure */
+      }
+    }
+
+    /* open file for writing */
+    out->stream=fopen(out->filename, "wb");
+    if(!out->stream) {
+      warnf(config, "Failed to create the file %s: %s\n", out->filename,
+            strerror(errno));
+      return err_rc; /* failure */
+    }
+  }
+
+  rc = fwrite(buffer, sz, nmemb, out->stream);
+
+  if((sz * nmemb) == rc) {
+    /* we added this amount of data to the output */
+    out->bytes += (sz * nmemb);
+  }
+
+  if(config->readbusy) {
+    config->readbusy = FALSE;
+    curl_easy_pause(config->easy, CURLPAUSE_CONT);
+  }
+
+  if(config->nobuffer) {
+    /* disable output buffering */
+    int res = fflush(out->stream);
+    if(res) {
+      /* return a value that isn't the same as sz * nmemb */
+      return err_rc; /* failure */
+    }
+  }
+
+  return rc;
+}
+
+struct InStruct {
+  int fd;
+  struct Configurable *config;
+};
+
+#define MAX_SEEK 2147483647
+
+/*
+ * my_seek() is the CURLOPT_SEEKFUNCTION we use
+ */
+static int my_seek(void *stream, curl_off_t offset, int whence)
+{
+  struct InStruct *in=(struct InStruct *)stream;
+
+#if (CURL_SIZEOF_CURL_OFF_T > SIZEOF_OFF_T) && !defined(USE_WIN32_LARGE_FILES)
+  /* The offset check following here is only interesting if curl_off_t is
+     larger than off_t and we are not using the WIN32 large file support
+     macros that provide the support to do 64bit seeks correctly */
+
+  if(offset > MAX_SEEK) {
+    /* Some precaution code to work around problems with different data sizes
+       to allow seeking >32bit even if off_t is 32bit. Should be very rare and
+       is really valid on weirdo-systems. */
+    curl_off_t left = offset;
+
+    if(whence != SEEK_SET)
+      /* this code path doesn't support other types */
+      return 1;
+
+    if(LSEEK_ERROR == lseek(in->fd, 0, SEEK_SET))
+      /* couldn't rewind to beginning */
+      return 1;
+
+    while(left) {
+      long step = (left>MAX_SEEK ? MAX_SEEK : (long)left);
+      if(LSEEK_ERROR == lseek(in->fd, step, SEEK_CUR))
+        /* couldn't seek forwards the desired amount */
+        return 1;
+      left -= step;
+    }
+    return 0;
+  }
+#endif
+  if(LSEEK_ERROR == lseek(in->fd, offset, whence))
+    /* couldn't rewind, the reason is in errno but errno is just not portable
+       enough and we don't actually care that much why we failed. We'll let
+       libcurl know that it may try other means if it wants to. */
+    return CURL_SEEKFUNC_CANTSEEK;
+
+  return 0;
+}
+
+static size_t my_fread(void *buffer, size_t sz, size_t nmemb, void *userp)
+{
+  ssize_t rc;
+  struct InStruct *in=(struct InStruct *)userp;
+
+  rc = read(in->fd, buffer, sz*nmemb);
+  if(rc < 0) {
+    if(errno == EAGAIN) {
+      errno = 0;
+      in->config->readbusy = TRUE;
+      return CURL_READFUNC_PAUSE;
+    }
+    /* since size_t is unsigned we can't return negative values fine */
+    rc = 0;
+  }
+  in->config->readbusy = FALSE;
+  return (size_t)rc;
+}
+
+struct ProgressData {
+  int calls;
+  curl_off_t prev;
+  int width;
+  FILE *out; /* where to write everything to */
+  curl_off_t initial_size;
+};
+
+static int myprogress (void *clientp,
+                       double dltotal,
+                       double dlnow,
+                       double ultotal,
+                       double ulnow)
+{
+  /* The original progress-bar source code was written for curl by Lars Aas,
+     and this new edition inherits some of his concepts. */
+
+  char line[256];
+  char outline[256];
+  char format[40];
+  double frac;
+  double percent;
+  int barwidth;
+  int num;
+  int i;
+
+  struct ProgressData *bar = (struct ProgressData *)clientp;
+  curl_off_t total = (curl_off_t)dltotal + (curl_off_t)ultotal +
+    bar->initial_size; /* expected transfer size */
+  curl_off_t point = (curl_off_t)dlnow + (curl_off_t)ulnow +
+    bar->initial_size; /* we've come this far */
+
+  if(point > total)
+    /* we have got more than the expected total! */
+    total = point;
+
+  bar->calls++; /* simply count invokes */
+
+  if(total < 1) {
+    curl_off_t prevblock = bar->prev / 1024;
+    curl_off_t thisblock = point / 1024;
+    while ( thisblock > prevblock ) {
+      fprintf( bar->out, "#" );
+      prevblock++;
+    }
+  }
+  else {
+    frac = (double)point / (double)total;
+    percent = frac * 100.0f;
+    barwidth = bar->width - 7;
+    num = (int) (((double)barwidth) * frac);
+    for ( i = 0; i < num; i++ ) {
+      line[i] = '#';
+    }
+    line[i] = '\0';
+    snprintf( format, sizeof(format), "%%-%ds %%5.1f%%%%", barwidth );
+    snprintf( outline, sizeof(outline), format, line, percent );
+    fprintf( bar->out, "\r%s", outline );
+  }
+  fflush(bar->out);
+  bar->prev = point;
+
+  return 0;
+}
+
+static
+void progressbarinit(struct ProgressData *bar,
+                     struct Configurable *config)
+{
+#ifdef __EMX__
+  /* 20000318 mgs */
+  int scr_size [2];
+#endif
+  char *colp;
+
+  memset(bar, 0, sizeof(struct ProgressData));
+
+  /* pass this through to progress function so
+   * it can display progress towards total file
+   * not just the part that's left. (21-may-03, dbyron) */
+  if (config->use_resume)
+    bar->initial_size = config->resume_from;
+
+/* TODO: get terminal width through ansi escapes or something similar.
+         try to update width when xterm is resized... - 19990617 larsa */
+#ifndef __EMX__
+  /* 20000318 mgs
+   * OS/2 users most likely won't have this env var set, and besides that
+   * we're using our own way to determine screen width */
+  colp = curlx_getenv("COLUMNS");
+  if (colp != NULL) {
+    bar->width = atoi(colp);
+    curl_free(colp);
+  }
+  else
+    bar->width = 79;
+#else
+  /* 20000318 mgs
+   * We use this emx library call to get the screen width, and subtract
+   * one from what we got in order to avoid a problem with the cursor
+   * advancing to the next line if we print a string that is as long as
+   * the screen is wide. */
+
+  _scrsize(scr_size);
+  bar->width = scr_size[0] - 1;
+#endif
+
+  bar->out = config->errors;
+}
+
+
+static
+void dump(const char *timebuf, const char *text,
+          FILE *stream, const unsigned char *ptr, size_t size,
+          trace tracetype, curl_infotype infotype)
+{
+  size_t i;
+  size_t c;
+
+  unsigned int width=0x10;
+
+  if(tracetype == TRACE_ASCII)
+    /* without the hex output, we can fit more on screen */
+    width = 0x40;
+
+  fprintf(stream, "%s%s, %zd bytes (0x%zx)\n", timebuf, text, size, size);
+
+  for(i=0; i<size; i+= width) {
+
+    fprintf(stream, "%04zx: ", i);
+
+    if(tracetype == TRACE_BIN) {
+      /* hex not disabled, show it */
+      for(c = 0; c < width; c++)
+        if(i+c < size)
+          fprintf(stream, "%02x ", ptr[i+c]);
+        else
+          fputs("   ", stream);
+    }
+
+    for(c = 0; (c < width) && (i+c < size); c++) {
+      /* check for 0D0A; if found, skip past and start a new line of output */
+      if ((tracetype == TRACE_ASCII) &&
+          (i+c+1 < size) && ptr[i+c]==0x0D && ptr[i+c+1]==0x0A) {
+        i+=(c+2-width);
+        break;
+      }
+#ifdef CURL_DOES_CONVERSIONS
+      /* repeat the 0D0A check above but use the host encoding for CRLF */
+      if ((tracetype == TRACE_ASCII) &&
+          (i+c+1 < size) && ptr[i+c]=='\r' && ptr[i+c+1]=='\n') {
+        i+=(c+2-width);
+        break;
+      }
+      /* convert to host encoding and print this character */
+      fprintf(stream, "%c", convert_char(infotype, ptr[i+c]));
+#else
+      (void)infotype;
+      fprintf(stream, "%c",
+              (ptr[i+c]>=0x20) && (ptr[i+c]<0x80)?ptr[i+c]:UNPRINTABLE_CHAR);
+#endif /* CURL_DOES_CONVERSIONS */
+      /* check again for 0D0A, to avoid an extra \n if it's at width */
+      if ((tracetype == TRACE_ASCII) &&
+          (i+c+2 < size) && ptr[i+c+1]==0x0D && ptr[i+c+2]==0x0A) {
+        i+=(c+3-width);
+        break;
+      }
+    }
+    fputc('\n', stream); /* newline */
+  }
+  fflush(stream);
+}
+
+static
+int my_trace(CURL *handle, curl_infotype type,
+             unsigned char *data, size_t size,
+             void *userp)
+{
+  struct Configurable *config = (struct Configurable *)userp;
+  FILE *output=config->errors;
+  const char *text;
+  struct timeval tv;
+  struct tm *now;
+  char timebuf[20];
+  time_t secs;
+  static time_t epoch_offset;
+  static int    known_offset;
+
+  (void)handle; /* prevent compiler warning */
+
+  if(config->tracetime) {
+    tv = cutil_tvnow();
+    if(!known_offset) {
+      epoch_offset = time(NULL) - tv.tv_sec;
+      known_offset = 1;
+    }
+    secs = epoch_offset + tv.tv_sec;
+    now = localtime(&secs);  /* not thread safe but we don't care */
+    snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld ",
+             now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec);
+  }
+  else
+    timebuf[0]=0;
+
+  if(!config->trace_stream) {
+    /* open for append */
+    if(curlx_strequal("-", config->trace_dump))
+      config->trace_stream = stdout;
+    else if(curlx_strequal("%", config->trace_dump))
+      /* Ok, this is somewhat hackish but we do it undocumented for now */
+      config->trace_stream = config->errors;  /* aka stderr */
+    else {
+      config->trace_stream = fopen(config->trace_dump, "w");
+      config->trace_fopened = TRUE;
+    }
+  }
+
+  if(config->trace_stream)
+    output = config->trace_stream;
+
+  if(!output) {
+    warnf(config, "Failed to create/open output");
+    return 0;
+  }
+
+  if(config->tracetype == TRACE_PLAIN) {
+    /*
+     * This is the trace look that is similar to what libcurl makes on its
+     * own.
+     */
+    static const char * const s_infotype[] = {
+      "*", "<", ">", "{", "}", "{", "}"
+    };
+    size_t i;
+    size_t st=0;
+    static bool newl = FALSE;
+    static bool traced_data = FALSE;
+
+    switch(type) {
+    case CURLINFO_HEADER_OUT:
+      for(i=0; i<size-1; i++) {
+        if(data[i] == '\n') { /* LF */
+          if(!newl) {
+            fprintf(output, "%s%s ", timebuf, s_infotype[type]);
+          }
+          (void)fwrite(data+st, i-st+1, 1, output);
+          st = i+1;
+          newl = FALSE;
+        }
+      }
+      if(!newl)
+        fprintf(output, "%s%s ", timebuf, s_infotype[type]);
+      (void)fwrite(data+st, i-st+1, 1, output);
+      newl = (bool)(size && (data[size-1] != '\n'));
+      traced_data = FALSE;
+      break;
+    case CURLINFO_TEXT:
+    case CURLINFO_HEADER_IN:
+      if(!newl)
+        fprintf(output, "%s%s ", timebuf, s_infotype[type]);
+      (void)fwrite(data, size, 1, output);
+      newl = (bool)(size && (data[size-1] != '\n'));
+      traced_data = FALSE;
+      break;
+    case CURLINFO_DATA_OUT:
+    case CURLINFO_DATA_IN:
+    case CURLINFO_SSL_DATA_IN:
+    case CURLINFO_SSL_DATA_OUT:
+      if(!traced_data) {
+        /* if the data is output to a tty and we're sending this debug trace
+           to stderr or stdout, we don't display the alert about the data not
+           being shown as the data _is_ shown then just not via this
+           function */
+        if(!config->isatty ||
+           ((output != stderr) && (output != stdout))) {
+          if(!newl)
+            fprintf(output, "%s%s ", timebuf, s_infotype[type]);
+          fprintf(output, "[data not shown]\n");
+          newl = FALSE;
+          traced_data = TRUE;
+        }
+      }
+      break;
+    default: /* nada */
+      newl = FALSE;
+      traced_data = FALSE;
+      break;
+    }
+
+    return 0;
+  }
+
+#ifdef CURL_DOES_CONVERSIONS
+  /* Special processing is needed for CURLINFO_HEADER_OUT blocks
+   * if they contain both headers and data (separated by CRLFCRLF).
+   * We dump the header text and then switch type to CURLINFO_DATA_OUT.
+   */
+  if((type == CURLINFO_HEADER_OUT) && (size > 4)) {
+    size_t i;
+    for(i = 0; i < size - 4; i++) {
+      if(memcmp(&data[i], "\r\n\r\n", 4) == 0) {
+        /* dump everthing through the CRLFCRLF as a sent header */
+        text = "=> Send header";
+        dump(timebuf, text, output, data, i+4, config->tracetype, type);
+        data += i + 3;
+        size -= i + 4;
+        type = CURLINFO_DATA_OUT;
+        data += 1;
+        break;
+      }
+    }
+  }
+#endif /* CURL_DOES_CONVERSIONS */
+
+  switch (type) {
+  case CURLINFO_TEXT:
+    fprintf(output, "%s== Info: %s", timebuf, data);
+  default: /* in case a new one is introduced to shock us */
+    return 0;
+
+  case CURLINFO_HEADER_OUT:
+    text = "=> Send header";
+    break;
+  case CURLINFO_DATA_OUT:
+    text = "=> Send data";
+    break;
+  case CURLINFO_HEADER_IN:
+    text = "<= Recv header";
+    break;
+  case CURLINFO_DATA_IN:
+    text = "<= Recv data";
+    break;
+  case CURLINFO_SSL_DATA_IN:
+    text = "<= Recv SSL data";
+    break;
+  case CURLINFO_SSL_DATA_OUT:
+    text = "=> Send SSL data";
+    break;
+  }
+
+  dump(timebuf, text, output, data, size, config->tracetype, type);
+  return 0;
+}
+
+static void free_config_fields(struct Configurable *config)
+{
+  if(config->random_file)
+    free(config->random_file);
+  if(config->egd_file)
+    free(config->egd_file);
+  if(config->trace_dump)
+    free(config->trace_dump);
+  if(config->cipher_list)
+    free(config->cipher_list);
+  if(config->userpwd)
+    free(config->userpwd);
+  if(config->postfields)
+    free(config->postfields);
+  if(config->proxy)
+    free(config->proxy);
+  if(config->proxyuserpwd)
+    free(config->proxyuserpwd);
+  if(config->noproxy)
+    free(config->noproxy);
+  if(config->cookie)
+    free(config->cookie);
+  if(config->cookiefile)
+    free(config->cookiefile);
+  if(config->krblevel)
+    free(config->krblevel);
+  if(config->headerfile)
+    free(config->headerfile);
+  if(config->ftpport)
+    free(config->ftpport);
+  if(config->range)
+    free(config->range);
+  if(config->customrequest)
+    free(config->customrequest);
+  if(config->writeout)
+    free(config->writeout);
+  if(config->httppost)
+    curl_formfree(config->httppost);
+  if (config->cert)
+    free(config->cert);
+  if(config->cacert)
+    free(config->cacert);
+  if (config->cert_type)
+    free(config->cert_type);
+  if(config->capath)
+    free(config->capath);
+  if(config->crlfile)
+    free(config->crlfile);
+  if(config->cookiejar)
+    free(config->cookiejar);
+  if(config->ftp_account)
+    free(config->ftp_account);
+  if(config->ftp_alternative_to_user)
+    free(config->ftp_alternative_to_user);
+  if(config->iface)
+    free(config->iface);
+  if(config->socksproxy)
+    free(config->socksproxy);
+  if(config->libcurl)
+    free(config->libcurl);
+  if (config->key_passwd)
+    free(config->key_passwd);
+  if (config->key)
+    free(config->key);
+  if (config->key_type)
+    free(config->key_type);
+  if (config->pubkey)
+    free(config->pubkey);
+  if (config->referer)
+    free(config->referer);
+  if (config->hostpubmd5)
+    free(config->hostpubmd5);
+  if(config->mail_from)
+    free(config->mail_from);
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+  if(config->socks5_gssapi_service)
+    free(config->socks5_gssapi_service);
+#endif
+
+  curl_slist_free_all(config->quote); /* checks for config->quote == NULL */
+  curl_slist_free_all(config->prequote);
+  curl_slist_free_all(config->postquote);
+  curl_slist_free_all(config->headers);
+  curl_slist_free_all(config->telnet_options);
+  curl_slist_free_all(config->mail_rcpt);
+
+  if(config->easy)
+    curl_easy_cleanup(config->easy);
+}
+
+#ifdef WIN32
+
+/* Function to find CACert bundle on a Win32 platform using SearchPath.
+ * (SearchPath is already declared via inclusions done in setup header file)
+ * (Use the ASCII version instead of the unicode one!)
+ * The order of the directories it searches is:
+ *  1. application's directory
+ *  2. current working directory
+ *  3. Windows System directory (e.g. C:\windows\system32)
+ *  4. Windows Directory (e.g. C:\windows)
+ *  5. all directories along %PATH%
+ */
+static void FindWin32CACert(struct Configurable *config,
+                            const char *bundle_file)
+{
+  /* only check for cert file if "we" support SSL */
+  if(curlinfo->features & CURL_VERSION_SSL) {
+    DWORD buflen;
+    char *ptr = NULL;
+    char *retval = malloc(sizeof (TCHAR) * (MAX_PATH + 1));
+    if (!retval)
+      return;
+    retval[0] = '\0';
+    buflen = SearchPathA(NULL, bundle_file, NULL, MAX_PATH+2, retval, &ptr);
+    if (buflen > 0) {
+      GetStr(&config->cacert, retval);
+    }
+    free(retval);
+  }
+}
+
+#endif
+
+#define RETRY_SLEEP_DEFAULT 1000  /* ms */
+#define RETRY_SLEEP_MAX     600000 /* ms == 10 minutes */
+
+static bool
+output_expected(const char* url, const char* uploadfile)
+{
+  if(!uploadfile)
+    return TRUE;  /* download */
+  if(checkprefix("http://", url) || checkprefix("https://", url))
+    return TRUE;   /* HTTP(S) upload */
+
+  return FALSE; /* non-HTTP upload, probably no output should be expected */
+}
+
+#define my_setopt(x,y,z) _my_setopt(x, 0, config, #y, y, z)
+#define my_setopt_str(x,y,z) _my_setopt(x, 1, config, #y, y, z)
+
+static struct curl_slist *easycode;
+
+static CURLcode _my_setopt(CURL *curl, bool str, struct Configurable *config,
+                           const char *name, CURLoption tag, ...);
+
+static CURLcode _my_setopt(CURL *curl, bool str, struct Configurable *config,
+                           const char *name, CURLoption tag, ...)
+{
+  va_list arg;
+  CURLcode ret;
+  char *bufp;
+  char value[256];
+  bool remark=FALSE;
+
+  va_start(arg, tag);
+
+  if(tag < CURLOPTTYPE_OBJECTPOINT) {
+    long lval = va_arg(arg, long);
+    snprintf(value, sizeof(value), "%ld", lval);
+    ret = curl_easy_setopt(curl, tag, lval);
+
+  }
+  else if(tag < CURLOPTTYPE_OFF_T) {
+    void *pval = va_arg(arg, void *);
+    unsigned char *ptr = (unsigned char *)pval;
+
+    /* function pointers are never printable */
+    if (tag >= CURLOPTTYPE_FUNCTIONPOINT) {
+      if (pval) {
+        snprintf(value, sizeof(value), "%p", pval);
+        remark = TRUE;
+      }
+      else
+        strcpy(value, "NULL");
+    }
+
+    else if(pval && str)
+      snprintf(value, sizeof(value), "\"%s\"", (char *)ptr);
+    else if(pval) {
+      snprintf(value, sizeof(value), "%p", pval);
+      remark = TRUE;
+    }
+    else {
+      strcpy(value, "NULL"); /* value fits more than 5 bytes */
+    }
+    ret = curl_easy_setopt(curl, tag, pval);
+
+  }
+  else {
+    curl_off_t oval = va_arg(arg, curl_off_t);
+    snprintf(value, sizeof(value), "%" CURL_FORMAT_CURL_OFF_T, oval);
+    ret = curl_easy_setopt(curl, tag, oval);
+  }
+
+  if(config->libcurl) {
+    /* we only use this for real if --libcurl was used */
+
+    bufp = curlx_maprintf("%scurl_easy_setopt(hnd, %s, %s);%s",
+                          remark?"/* ":"", name, value,
+                          remark?" [REMARK] */":"");
+
+    if (!bufp || !curl_slist_append(easycode, bufp))
+      ret = CURLE_OUT_OF_MEMORY;
+    if (bufp)
+      curl_free(bufp);
+  }
+  va_end(arg);
+
+  return ret;
+}
+
+static const char * const srchead[]={
+  "/********* Sample code generated by the curl command line tool **********",
+  " * Lines with [REMARK] below might need to be modified to make this code ",
+  " * usable. Add error code checking where appropriate.",
+  " * Compile this with a suitable header include path. Then link with ",
+  " * libcurl.",
+  " * If you use any *_LARGE options, make sure your compiler figure",
+  " * out the correct size for the curl_off_t variable.",
+  " * Read the details for all curl_easy_setopt() options online on:",
+  " * http://curlm.haxx.se/libcurl/c/curl_easy_setopt.html",
+  " ************************************************************************/",
+  "[m]",
+  "#include <curl/curl.h>",
+  "",
+  "int main(int argc, char *argv[])",
+  "{",
+  "  CURLcode ret;",
+  NULL
+};
+
+static void dumpeasycode(struct Configurable *config)
+{
+  struct curl_slist *ptr = easycode;
+  char *o = config->libcurl;
+
+  if(o) {
+    FILE *out;
+    bool fopened = FALSE;
+    if(strcmp(o, "-")) {
+      out = fopen(o, "wt");
+      fopened = TRUE;
+    }
+    else
+      out= stdout;
+    if(!out)
+      warnf(config, "Failed to open %s to write libcurl code!\n", o);
+    else {
+      int i;
+      const char *c;
+
+      for(i=0; (c = srchead[i]); i++) {
+        if(!memcmp((char *)c, "[m]", 3)) {
+#if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS > 32)
+          fprintf(out, "#define _FILE_OFFSET_BITS %d "
+                  "/* for pre libcurl 7.19.0 curl_off_t magic */\n",
+                  _FILE_OFFSET_BITS);
+#endif
+        }
+        else
+          fprintf(out, "%s\n", c);
+      }
+
+      while(ptr) {
+        fprintf(out, "  %s\n", ptr->data);
+        ptr = ptr->next;
+      }
+      fprintf(out,
+              "  return (int)ret;\n"
+              "}\n"
+              "/**** End of sample code ****/\n");
+      if(fopened)
+        fclose(out);
+    }
+  }
+  curl_slist_free_all(easycode);
+}
+
+static bool stdin_upload(const char *uploadfile)
+{
+  return (bool)(curlx_strequal(uploadfile, "-") ||
+                curlx_strequal(uploadfile, "."));
+}
+
+/* Adds the file name to the URL if it doesn't already have one.
+ * url will be freed before return if the returned pointer is different
+ */
+static char *add_file_name_to_url(CURL *curl, char *url, const char *filename)
+{
+  /* If no file name part is given in the URL, we add this file name */
+  char *ptr=strstr(url, "://");
+  if(ptr)
+    ptr+=3;
+  else
+    ptr=url;
+  ptr = strrchr(ptr, '/');
+  if(!ptr || !strlen(++ptr)) {
+    /* The URL has no file name part, add the local file name. In order
+       to be able to do so, we have to create a new URL in another
+       buffer.*/
+
+    /* We only want the part of the local path that is on the right
+       side of the rightmost slash and backslash. */
+    const char *filep = strrchr(filename, '/');
+    char *file2 = strrchr(filep?filep:filename, '\\');
+    char *encfile;
+
+    if(file2)
+      filep = file2+1;
+    else if(filep)
+      filep++;
+    else
+      filep = filename;
+
+    /* URL encode the file name */
+    encfile = curl_easy_escape(curl, filep, 0 /* use strlen */);
+    if(encfile) {
+      char *urlbuffer = malloc(strlen(url) + strlen(encfile) + 3);
+      if(!urlbuffer) {
+        free(url);
+        return NULL;
+      }
+      if(ptr)
+        /* there is a trailing slash on the URL */
+        sprintf(urlbuffer, "%s%s", url, encfile);
+      else
+        /* there is no trailing slash on the URL */
+        sprintf(urlbuffer, "%s/%s", url, encfile);
+
+      curl_free(encfile);
+
+      free(url);
+      url = urlbuffer; /* use our new URL instead! */
+    }
+  }
+  return url;
+}
+
+/* Extracts the name portion of the URL.
+ * Returns a heap-allocated string, or NULL if no name part
+ */
+static char *get_url_file_name(const char *url)
+{
+  char *fn = NULL;
+
+  /* Find and get the remote file name */
+  const char * pc =strstr(url, "://");
+  if(pc)
+    pc+=3;
+  else
+    pc=url;
+  pc = strrchr(pc, '/');
+
+  if(pc) {
+    /* duplicate the string beyond the slash */
+    pc++;
+    fn = *pc ? strdup(pc): NULL;
+  }
+  return fn;
+}
+
+static char*
+parse_filename(char *ptr, size_t len)
+{
+  char* copy;
+  char* p;
+  char* q;
+  char quote = 0;
+
+  /* simple implementation of strndup() */
+  copy = malloc(len+1);
+  if (!copy)
+    return NULL;
+  strncpy(copy, ptr, len);
+  copy[len] = 0;
+
+  p = copy;
+  if (*p == '\'' || *p == '"') {
+    /* store the starting quote */
+    quote = *p;
+    p++;
+  }
+
+  /* if the filename contains a path, only use filename portion */
+  q = strrchr(copy, '/');
+  if (q) {
+    p=q+1;
+    if (!*p) {
+      free(copy);
+      return NULL;
+    }
+  }
+
+  q = strrchr(p, quote);
+  if (q)
+    *q = 0;
+
+  if (copy!=p)
+    memmove(copy, p, strlen(p)+1);
+
+  return copy;
+}
+
+static size_t
+header_callback(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+  struct OutStruct* outs = (struct OutStruct*)stream;
+  const char* str = (char*)ptr;
+  const size_t cb = size*nmemb;
+  const char* end = (char*)ptr + cb;
+
+  if (cb > 20 && curlx_strnequal(str, "Content-disposition:", 20)) {
+    char *p = (char*)str + 20;
+
+    /* look for the 'filename=' parameter
+       (encoded filenames (*=) are not supported) */
+    for(;;) {
+      char *filename;
+
+      while (*p && (p < end) && !ISALPHA(*p))
+        p++;
+      if (p > end-9)
+        break;
+
+      if (memcmp(p, "filename=", 9)) {
+        /* no match, find next parameter */
+        while ((p < end) && (*p != ';'))
+          p++;
+        continue;
+      }
+      p+=9;
+      filename = parse_filename(p, cb - (p - str));
+      if (filename) {
+        outs->filename = filename;
+        break;
+      }
+    }
+  }
+
+  return cb;
+}
+
+static int
+operate(struct Configurable *config, int argc, argv_item_t argv[])
+{
+  char errorbuffer[CURL_ERROR_SIZE];
+  char useragent[256]; /* buah, we don't want a larger default user agent */
+  struct ProgressData progressbar;
+  struct getout *urlnode;
+  struct getout *nextnode;
+
+  struct OutStruct outs;
+  struct OutStruct heads;
+  struct InStruct input;
+
+  URLGlob *urls=NULL;
+  URLGlob *inglob=NULL;
+  int urlnum;
+  int infilenum;
+  char *uploadfile=NULL; /* a single file, never a glob */
+
+  curl_off_t uploadfilesize; /* -1 means unknown */
+  bool stillflags=TRUE;
+
+  bool allocuseragent=FALSE;
+
+  char *httpgetfields=NULL;
+
+  CURL *curl;
+  int res = 0;
+  int i;
+  long retry_sleep_default;
+  long retry_sleep;
+
+  char *env;
+
+  memset(&heads, 0, sizeof(struct OutStruct));
+
+#ifdef CURLDEBUG
+  /* this sends all memory debug messages to a logfile named memdump */
+  env = curlx_getenv("CURL_MEMDEBUG");
+  if(env) {
+    /* use the value as file name */
+    char *s = strdup(env);
+    curl_free(env);
+    curl_memdebug(s);
+    free(s);
+    /* this weird strdup() and stuff here is to make the curl_free() get
+       called before the memdebug() as otherwise the memdebug tracing will
+       with tracing a free() without an alloc! */
+  }
+  env = curlx_getenv("CURL_MEMLIMIT");
+  if(env) {
+    curl_memlimit(atoi(env));
+    curl_free(env);
+  }
+#endif
+
+  /* Initialize curl library - do not call any libcurl functions before.
+     Note that the CURLDEBUG magic above is an exception, but then that's not
+     part of the official public API.
+   */
+  if (main_init() != CURLE_OK) {
+    helpf(config->errors, "error initializing curl library\n");
+    return CURLE_FAILED_INIT;
+  }
+
+  /*
+   * Get a curl handle to use for all forthcoming curl transfers.  Cleanup
+   * when all transfers are done.
+   */
+  curl = curl_easy_init();
+  if(!curl) {
+    clean_getout(config);
+    return CURLE_FAILED_INIT;
+  }
+  config->easy = curl;
+
+  memset(&outs,0,sizeof(outs));
+
+  config->outs = &outs;
+
+  /* we get libcurl info right away */
+  curlinfo = curl_version_info(CURLVERSION_NOW);
+
+  errorbuffer[0]=0; /* prevent junk from being output */
+
+  /* setup proper locale from environment */
+#ifdef HAVE_SETLOCALE
+  setlocale(LC_ALL, "");
+#endif
+
+  /* inits */
+  config->postfieldsize = -1;
+  config->showerror=TRUE;
+  config->use_httpget=FALSE;
+  config->create_dirs=FALSE;
+  config->maxredirs = DEFAULT_MAXREDIRS;
+
+  if(argc>1 &&
+     (!curlx_strnequal("--", argv[1], 2) && (argv[1][0] == '-')) &&
+     strchr(argv[1], 'q')) {
+    /*
+     * The first flag, that is not a verbose name, but a shortname
+     * and it includes the 'q' flag!
+     */
+    ;
+  }
+  else {
+    parseconfig(NULL, config); /* ignore possible failure */
+  }
+
+  if ((argc < 2)  && !config->url_list) {
+    helpf(config->errors, NULL);
+    return CURLE_FAILED_INIT;
+  }
+
+  /* Parse options */
+  for (i = 1; i < argc; i++) {
+    if(stillflags &&
+       ('-' == argv[i][0])) {
+      char *nextarg;
+      bool passarg;
+      char *origopt=argv[i];
+
+      char *flag = argv[i];
+
+      if(curlx_strequal("--", argv[i]))
+        /* this indicates the end of the flags and thus enables the
+           following (URL) argument to start with -. */
+        stillflags=FALSE;
+      else {
+        nextarg= (i < argc - 1)? argv[i+1]: NULL;
+
+        res = getparameter(flag, nextarg, &passarg, config);
+        if(res) {
+          int retval = CURLE_OK;
+          if(res != PARAM_HELP_REQUESTED) {
+            const char *reason = param2text(res);
+            helpf(config->errors, "option %s: %s\n", origopt, reason);
+            retval = CURLE_FAILED_INIT;
+          }
+          clean_getout(config);
+          return retval;
+        }
+
+        if(passarg) /* we're supposed to skip this */
+          i++;
+      }
+    }
+    else {
+      bool used;
+      /* just add the URL please */
+      res = getparameter((char *)"--url", argv[i], &used, config);
+      if(res)
+        return res;
+    }
+  }
+
+  retry_sleep_default = config->retry_delay?
+    config->retry_delay*1000:RETRY_SLEEP_DEFAULT; /* ms */
+  retry_sleep = retry_sleep_default;
+
+  if((!config->url_list || !config->url_list->url) && !config->list_engines) {
+    clean_getout(config);
+    helpf(config->errors, "no URL specified!\n");
+    return CURLE_FAILED_INIT;
+  }
+  if(NULL == config->useragent) {
+    /* set non-zero default values: */
+    snprintf(useragent, sizeof(useragent),
+             CURL_NAME "/" CURL_VERSION " (" OS ") " "%s", curl_version());
+    config->useragent= useragent;
+  }
+  else
+    allocuseragent = TRUE;
+
+  /* On WIN32 we can't set the path to curl-ca-bundle.crt
+   * at compile time. So we look here for the file in two ways:
+   * 1: look at the environment variable CURL_CA_BUNDLE for a path
+   * 2: if #1 isn't found, use the windows API function SearchPath()
+   *    to find it along the app's path (includes app's dir and CWD)
+   *
+   * We support the environment variable thing for non-Windows platforms
+   * too. Just for the sake of it.
+   */
+  if (!config->cacert &&
+      !config->capath &&
+      !config->insecure_ok) {
+    env = curlx_getenv("CURL_CA_BUNDLE");
+    if(env)
+      GetStr(&config->cacert, env);
+    else {
+      env = curlx_getenv("SSL_CERT_DIR");
+      if(env)
+        GetStr(&config->capath, env);
+      else {
+        env = curlx_getenv("SSL_CERT_FILE");
+        if(env)
+          GetStr(&config->cacert, env);
+      }
+    }
+
+    if(env)
+      curl_free(env);
+#ifdef WIN32
+    else
+      FindWin32CACert(config, "curl-ca-bundle.crt");
+#endif
+  }
+
+  if (config->postfields) {
+    if (config->use_httpget) {
+      /* Use the postfields data for a http get */
+      httpgetfields = strdup(config->postfields);
+      free(config->postfields);
+      config->postfields = NULL;
+      if(SetHTTPrequest(config,
+                        (config->no_body?HTTPREQ_HEAD:HTTPREQ_GET),
+                        &config->httpreq)) {
+        free(httpgetfields);
+        return PARAM_BAD_USE;
+      }
+    }
+    else {
+      if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq))
+        return PARAM_BAD_USE;
+    }
+  }
+
+  /* This is the first entry added to easycode and it initializes the slist */
+  easycode = curl_slist_append(easycode, "CURL *hnd = curl_easy_init();");
+  if(!easycode) {
+    clean_getout(config);
+    res = CURLE_OUT_OF_MEMORY;
+    goto quit_curl;
+  }
+
+  if (config->list_engines) {
+    struct curl_slist *engines = NULL;
+
+    curl_easy_getinfo(curl, CURLINFO_SSL_ENGINES, &engines);
+    list_engines(engines);
+    curl_slist_free_all(engines);
+    res = CURLE_OK;
+    goto quit_curl;
+  }
+
+  /* After this point, we should call curl_easy_cleanup() if we decide to bail
+   * out from this function! */
+
+  urlnode = config->url_list;
+
+  if(config->headerfile) {
+    /* open file for output: */
+    if(strcmp(config->headerfile,"-")) {
+      heads.filename = config->headerfile;
+    }
+    else
+      heads.stream=stdout;
+    heads.config = config;
+  }
+
+  /* loop through the list of given URLs */
+  while(urlnode) {
+    int up; /* upload file counter within a single upload glob */
+    char *dourl;
+    char *url;
+    char *infiles; /* might be a glob pattern */
+    char *outfiles=NULL;
+
+    /* get the full URL (it might be NULL) */
+    dourl=urlnode->url;
+
+    url = dourl;
+
+    if(NULL == url) {
+      /* This node had no URL, skip it and continue to the next */
+      if(urlnode->outfile)
+        free(urlnode->outfile);
+
+      /* move on to the next URL */
+      nextnode=urlnode->next;
+      free(urlnode); /* free the node */
+      urlnode = nextnode;
+      continue; /* next please */
+    }
+
+    /* default output stream is stdout */
+    outs.stream = stdout;
+    outs.config = config;
+    outs.bytes = 0; /* nothing written yet */
+
+    /* save outfile pattern before expansion */
+    if (urlnode->outfile) {
+      outfiles = strdup(urlnode->outfile);
+      if (!outfiles) {
+        clean_getout(config);
+        break;
+      }
+    }
+
+    infiles = urlnode->infile;
+
+    if(!config->globoff && infiles) {
+      /* Unless explicitly shut off */
+      res = glob_url(&inglob, infiles, &infilenum,
+                     config->showerror?config->errors:NULL);
+      if(res != CURLE_OK) {
+        clean_getout(config);
+        if(outfiles)
+          free(outfiles);
+        break;
+      }
+    }
+
+    /* Here's the loop for uploading multiple files within the same
+       single globbed string. If no upload, we enter the loop once anyway. */
+    for(up = 0;
+        (!up && !infiles) ||
+          (uploadfile = inglob?
+           glob_next_url(inglob):
+           (!up?strdup(infiles):NULL));
+        up++) {
+      int separator = 0;
+      long retry_numretries;
+      uploadfilesize=-1;
+
+      if(!config->globoff) {
+        /* Unless explicitly shut off, we expand '{...}' and '[...]'
+           expressions and return total number of URLs in pattern set */
+        res = glob_url(&urls, dourl, &urlnum,
+                       config->showerror?config->errors:NULL);
+        if(res != CURLE_OK) {
+          break;
+        }
+      }
+      else
+        urlnum = 1; /* without globbing, this is a single URL */
+
+      /* if multiple files extracted to stdout, insert separators! */
+      separator= ((!outfiles || curlx_strequal(outfiles, "-")) && urlnum > 1);
+
+      /* Here's looping around each globbed URL */
+      for(i = 0;
+          (url = urls?glob_next_url(urls):(i?NULL:strdup(url)));
+          i++) {
+        /* NOTE: In the condition expression in the for() statement above, the
+           'url' variable is only ever strdup()ed if (i == 0) and thus never
+           when this loops later on. Further down in this function we call
+           free(url) and then the code loops. Static code parsers may thus get
+           tricked into believing that we have a potential access-after-free
+           here.  I can however not spot any such case. */
+
+        int infd = STDIN_FILENO;
+        bool infdopen;
+        char *outfile;
+        struct timeval retrystart;
+        outfile = outfiles?strdup(outfiles):NULL;
+
+        if((urlnode->flags&GETOUT_USEREMOTE) ||
+           (outfile && !curlx_strequal("-", outfile)) ) {
+
+          /*
+           * We have specified a file name to store the result in, or we have
+           * decided we want to use the remote file name.
+           */
+
+          if(!outfile) {
+            /* extract the file name from the URL */
+            outfile = get_url_file_name(url);
+            if((!outfile || !*outfile) && !config->content_disposition) {
+              helpf(config->errors, "Remote file name has no length!\n");
+              res = CURLE_WRITE_ERROR;
+              free(url);
+              break;
+            }
+#if defined(MSDOS) || defined(WIN32)
+            /* For DOS and WIN32, we do some major replacing of
+             bad characters in the file name before using it */
+            outfile = sanitize_dos_name(outfile);
+            if(!outfile) {
+              res = CURLE_OUT_OF_MEMORY;
+              break;
+            }
+#endif /* MSDOS || WIN32 */
+          }
+          else if(urls) {
+            /* fill '#1' ... '#9' terms from URL pattern */
+            char *storefile = outfile;
+            outfile = glob_match_url(storefile, urls);
+            free(storefile);
+            if(!outfile) {
+              /* bad globbing */
+              warnf(config, "bad output glob!\n");
+              free(url);
+              res = CURLE_FAILED_INIT;
+              break;
+            }
+          }
+
+          /* Create the directory hierarchy, if not pre-existant to a multiple
+             file output call */
+
+          if(config->create_dirs &&
+             (-1 == create_dir_hierarchy(outfile, config->errors))) {
+            free(url);
+            res = CURLE_WRITE_ERROR;
+            break;
+          }
+
+          if(config->resume_from_current) {
+            /* We're told to continue from where we are now. Get the
+               size of the file as it is now and open it for append instead */
+
+            struct_stat fileinfo;
+
+            /* VMS -- Danger, the filesize is only valid for stream files */
+            if(0 == stat(outfile, &fileinfo))
+              /* set offset to current file size: */
+              config->resume_from = fileinfo.st_size;
+            else
+              /* let offset be 0 */
+              config->resume_from = 0;
+          }
+
+          outs.filename = outfile;
+
+          if(config->resume_from) {
+            outs.init = config->resume_from;
+            /* open file for output: */
+            outs.stream=(FILE *) fopen(outfile, config->resume_from?"ab":"wb");
+            if (!outs.stream) {
+              helpf(config->errors, "Can't open '%s'!\n", outfile);
+              free(url);
+              res = CURLE_WRITE_ERROR;
+              break;
+            }
+          }
+          else {
+            outs.stream = NULL; /* open when needed */
+          }
+        }
+        infdopen=FALSE;
+        if(uploadfile && !stdin_upload(uploadfile)) {
+          /*
+           * We have specified a file to upload and it isn't "-".
+           */
+          struct_stat fileinfo;
+
+          url = add_file_name_to_url(curl, url, uploadfile);
+          if(!url) {
+            helpf(config->errors, "out of memory\n");
+            res = CURLE_OUT_OF_MEMORY;
+            break;
+          }
+          /* VMS Note:
+           *
+           * Reading binary from files can be a problem...  Only FIXED, VAR
+           * etc WITHOUT implied CC will work Others need a \n appended to a
+           * line
+           *
+           * - Stat gives a size but this is UNRELIABLE in VMS As a f.e. a
+           * fixed file with implied CC needs to have a byte added for every
+           * record processed, this can by derived from Filesize & recordsize
+           * for VARiable record files the records need to be counted!  for
+           * every record add 1 for linefeed and subtract 2 for the record
+           * header for VARIABLE header files only the bare record data needs
+           * to be considered with one appended if implied CC
+           */
+
+          infd= open(uploadfile, O_RDONLY | O_BINARY);
+          if ((infd == -1) || fstat(infd, &fileinfo)) {
+            helpf(config->errors, "Can't open '%s'!\n", uploadfile);
+            if(infd != -1)
+              close(infd);
+
+            /* Free the list of remaining URLs and globbed upload files
+             * to force curl to exit immediately
+             */
+            if(urls) {
+              glob_cleanup(urls);
+              urls = NULL;
+            }
+            if(inglob) {
+              glob_cleanup(inglob);
+              inglob = NULL;
+            }
+
+            res = CURLE_READ_ERROR;
+            goto quit_urls;
+          }
+          infdopen=TRUE;
+          uploadfilesize=fileinfo.st_size;
+
+        }
+        else if(uploadfile && stdin_upload(uploadfile)) {
+          SET_BINMODE(stdin);
+          infd = STDIN_FILENO;
+          if (curlx_strequal(uploadfile, ".")) {
+            if (curlx_nonblock((curl_socket_t)infd, TRUE) < 0)
+              warnf(config,
+                    "fcntl failed on fd=%d: %s\n", infd, strerror(errno));
+          }
+        }
+
+        if(uploadfile && config->resume_from_current)
+          config->resume_from = -1; /* -1 will then force get-it-yourself */
+
+        if(output_expected(url, uploadfile)
+           && outs.stream && isatty(fileno(outs.stream)))
+          /* we send the output to a tty, therefore we switch off the progress
+             meter */
+          config->noprogress = config->isatty = TRUE;
+
+        if (urlnum > 1 && !(config->mute)) {
+          fprintf(config->errors, "\n[%d/%d]: %s --> %s\n",
+                  i+1, urlnum, url, outfile ? outfile : "<stdout>");
+          if (separator)
+            printf("%s%s\n", CURLseparator, url);
+        }
+        if (httpgetfields) {
+          char *urlbuffer;
+          /* Find out whether the url contains a file name */
+          const char *pc =strstr(url, "://");
+          char sep='?';
+          if(pc)
+            pc+=3;
+          else
+            pc=url;
+
+          pc = strrchr(pc, '/'); /* check for a slash */
+
+          if(pc) {
+            /* there is a slash present in the URL */
+
+            if(strchr(pc, '?'))
+              /* Ouch, there's already a question mark in the URL string, we
+                 then append the data with an ampersand separator instead! */
+              sep='&';
+          }
+          /*
+           * Then append ? followed by the get fields to the url.
+           */
+          urlbuffer = malloc(strlen(url) + strlen(httpgetfields) + 3);
+          if(!urlbuffer) {
+            helpf(config->errors, "out of memory\n");
+
+            /* Free the list of remaining URLs and globbed upload files
+             * to force curl to exit immediately
+             */
+            if(urls) {
+              glob_cleanup(urls);
+              urls = NULL;
+            }
+            if(inglob) {
+              glob_cleanup(inglob);
+              inglob = NULL;
+            }
+
+            res = CURLE_OUT_OF_MEMORY;
+            goto quit_urls;
+          }
+          if (pc)
+            sprintf(urlbuffer, "%s%c%s", url, sep, httpgetfields);
+          else
+            /* Append  / before the ? to create a well-formed url
+               if the url contains a hostname only
+            */
+            sprintf(urlbuffer, "%s/?%s", url, httpgetfields);
+
+          free(url); /* free previous URL */
+          url = urlbuffer; /* use our new URL instead! */
+        }
+
+        if(!config->errors)
+          config->errors = stderr;
+
+        if((!outfile || !strcmp(outfile, "-")) && !config->use_ascii) {
+          /* We get the output to stdout and we have not got the ASCII/text
+             flag, then set stdout to be binary */
+          SET_BINMODE(stdout);
+        }
+
+        if(1 == config->tcp_nodelay)
+          my_setopt(curl, CURLOPT_TCP_NODELAY, 1);
+
+        /* where to store */
+        my_setopt(curl, CURLOPT_WRITEDATA, &outs);
+        /* what call to write */
+        my_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
+
+        /* for uploads */
+        input.fd = infd;
+        input.config = config;
+        my_setopt(curl, CURLOPT_READDATA, &input);
+        /* what call to read */
+        my_setopt(curl, CURLOPT_READFUNCTION, my_fread);
+
+        /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what
+           CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */
+        my_setopt(curl, CURLOPT_SEEKDATA, &input);
+        my_setopt(curl, CURLOPT_SEEKFUNCTION, my_seek);
+
+        if(config->recvpersecond)
+          /* tell libcurl to use a smaller sized buffer as it allows us to
+             make better sleeps! 7.9.9 stuff! */
+          my_setopt(curl, CURLOPT_BUFFERSIZE, config->recvpersecond);
+
+        /* size of uploaded file: */
+        my_setopt(curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize);
+        my_setopt_str(curl, CURLOPT_URL, url);     /* what to fetch */
+        my_setopt_str(curl, CURLOPT_PROXY, config->proxy); /* proxy to use */
+        if(config->proxy)
+          my_setopt(curl, CURLOPT_PROXYTYPE, config->proxyver);
+        my_setopt(curl, CURLOPT_NOPROGRESS, config->noprogress);
+        if(config->no_body) {
+          my_setopt(curl, CURLOPT_NOBODY, 1);
+          my_setopt(curl, CURLOPT_HEADER, 1);
+        }
+        else
+          my_setopt(curl, CURLOPT_HEADER, config->include_headers);
+
+        my_setopt(curl, CURLOPT_FAILONERROR, config->failonerror);
+        my_setopt(curl, CURLOPT_UPLOAD, uploadfile?TRUE:FALSE);
+        my_setopt(curl, CURLOPT_DIRLISTONLY, config->dirlistonly);
+        my_setopt(curl, CURLOPT_APPEND, config->ftp_append);
+
+        if (config->netrc_opt)
+          my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL);
+        else if (config->netrc)
+          my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_REQUIRED);
+        else
+          my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED);
+
+        my_setopt(curl, CURLOPT_FOLLOWLOCATION, config->followlocation);
+        my_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, config->unrestricted_auth);
+        my_setopt(curl, CURLOPT_TRANSFERTEXT, config->use_ascii);
+        my_setopt_str(curl, CURLOPT_USERPWD, config->userpwd);
+        my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
+        my_setopt(curl, CURLOPT_NOPROXY, config->noproxy);
+        my_setopt_str(curl, CURLOPT_RANGE, config->range);
+        my_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer);
+        my_setopt(curl, CURLOPT_TIMEOUT, config->timeout);
+
+        switch(config->httpreq) {
+        case HTTPREQ_SIMPLEPOST:
+          my_setopt_str(curl, CURLOPT_POSTFIELDS, config->postfields);
+          my_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, config->postfieldsize);
+          break;
+        case HTTPREQ_POST:
+          my_setopt(curl, CURLOPT_HTTPPOST, config->httppost);
+          break;
+        default:
+          break;
+        }
+        my_setopt_str(curl, CURLOPT_REFERER, config->referer);
+        my_setopt(curl, CURLOPT_AUTOREFERER, config->autoreferer);
+        my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent);
+        my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport);
+        my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT,
+                  config->low_speed_limit);
+        my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time);
+        my_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE,
+                  config->sendpersecond);
+        my_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE,
+                  config->recvpersecond);
+        my_setopt(curl, CURLOPT_RESUME_FROM_LARGE,
+                  config->use_resume?config->resume_from:0);
+        my_setopt_str(curl, CURLOPT_COOKIE, config->cookie);
+        my_setopt(curl, CURLOPT_HTTPHEADER, config->headers);
+        my_setopt(curl, CURLOPT_SSLCERT, config->cert);
+        my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type);
+        my_setopt(curl, CURLOPT_SSLKEY, config->key);
+        my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type);
+        my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd);
+
+        /* SSH private key uses the same command-line option as SSL private
+           key */
+        my_setopt_str(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key);
+        my_setopt_str(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey);
+
+        /* SSH host key md5 checking allows us to fail if we are
+         * not talking to who we think we should
+         */
+        my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5,
+                      config->hostpubmd5);
+
+        /* default to strict verifyhost */
+        my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
+        if(config->cacert || config->capath) {
+          if (config->cacert)
+            my_setopt_str(curl, CURLOPT_CAINFO, config->cacert);
+
+          if (config->capath)
+            my_setopt_str(curl, CURLOPT_CAPATH, config->capath);
+          my_setopt(curl, CURLOPT_SSL_VERIFYPEER, TRUE);
+        }
+        if (config->crlfile)
+          my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile);
+        if(config->insecure_ok) {
+          /* new stuff needed for libcurl 7.10 */
+          my_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
+          my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
+        }
+        else {
+          char *home = homedir();
+          char *file = aprintf("%s/%sssh/known_hosts", home, DOT_CHAR);
+          if(home)
+            free(home);
+
+          if(file) {
+            my_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, file);
+            curl_free(file);
+          }
+          else {
+            /* Free the list of remaining URLs and globbed upload files
+             * to force curl to exit immediately
+             */
+            if(urls) {
+              glob_cleanup(urls);
+              urls = NULL;
+            }
+            if(inglob) {
+              glob_cleanup(inglob);
+              inglob = NULL;
+            }
+
+            res = CURLE_OUT_OF_MEMORY;
+            goto quit_urls;
+          }
+        }
+
+        if(config->no_body || config->remote_time) {
+          /* no body or use remote time */
+          my_setopt(curl, CURLOPT_FILETIME, TRUE);
+        }
+
+        my_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs);
+        my_setopt(curl, CURLOPT_CRLF, config->crlf);
+        my_setopt(curl, CURLOPT_QUOTE, config->quote);
+        my_setopt(curl, CURLOPT_POSTQUOTE, config->postquote);
+        my_setopt(curl, CURLOPT_PREQUOTE, config->prequote);
+        my_setopt(curl, CURLOPT_HEADERDATA,
+                  config->headerfile?&heads:NULL);
+        my_setopt_str(curl, CURLOPT_COOKIEFILE, config->cookiefile);
+        /* cookie jar was added in 7.9 */
+        if(config->cookiejar)
+          my_setopt_str(curl, CURLOPT_COOKIEJAR, config->cookiejar);
+        /* cookie session added in 7.9.7 */
+        my_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession);
+
+        my_setopt(curl, CURLOPT_SSLVERSION, config->ssl_version);
+        my_setopt(curl, CURLOPT_TIMECONDITION, config->timecond);
+        my_setopt(curl, CURLOPT_TIMEVALUE, config->condtime);
+        my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest);
+        my_setopt(curl, CURLOPT_STDERR, config->errors);
+
+        /* three new ones in libcurl 7.3: */
+        my_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel);
+        my_setopt_str(curl, CURLOPT_INTERFACE, config->iface);
+        my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel);
+
+        progressbarinit(&progressbar, config);
+        if((config->progressmode == CURL_PROGRESS_BAR) &&
+           !config->noprogress && !config->mute) {
+          /* we want the alternative style, then we have to implement it
+             ourselves! */
+          my_setopt(curl, CURLOPT_PROGRESSFUNCTION, myprogress);
+          my_setopt(curl, CURLOPT_PROGRESSDATA, &progressbar);
+        }
+
+        /* new in libcurl 7.6.2: */
+        my_setopt(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);
+
+        /* new in libcurl 7.7: */
+        my_setopt_str(curl, CURLOPT_RANDOM_FILE, config->random_file);
+        my_setopt(curl, CURLOPT_EGDSOCKET, config->egd_file);
+        my_setopt(curl, CURLOPT_CONNECTTIMEOUT, config->connecttimeout);
+
+        if(config->cipher_list)
+          my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list);
+
+        if(config->httpversion)
+          my_setopt(curl, CURLOPT_HTTP_VERSION, config->httpversion);
+
+        /* new in libcurl 7.9.2: */
+        if(config->disable_epsv)
+          /* disable it */
+          my_setopt(curl, CURLOPT_FTP_USE_EPSV, FALSE);
+
+        /* new in libcurl 7.10.5 */
+        if(config->disable_eprt)
+          /* disable it */
+          my_setopt(curl, CURLOPT_FTP_USE_EPRT, FALSE);
+
+        /* new in libcurl 7.10.6 (default is Basic) */
+        if(config->authtype)
+          my_setopt(curl, CURLOPT_HTTPAUTH, config->authtype);
+
+        if(config->tracetype != TRACE_NONE) {
+          my_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace);
+          my_setopt(curl, CURLOPT_DEBUGDATA, config);
+          my_setopt(curl, CURLOPT_VERBOSE, TRUE);
+        }
+
+        res = CURLE_OK;
+
+        /* new in curl ?? */
+        if (config->engine) {
+          res = my_setopt_str(curl, CURLOPT_SSLENGINE, config->engine);
+          my_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1);
+        }
+
+        if (res != CURLE_OK)
+           goto show_error;
+
+        /* new in curl 7.10 */
+        my_setopt_str(curl, CURLOPT_ENCODING,
+                  (config->encoding) ? "" : NULL);
+
+        /* new in curl 7.10.7, extended in 7.19.4 but this only sets 0 or 1 */
+        my_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS,
+                  config->ftp_create_dirs);
+        if(config->proxyanyauth)
+          my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
+        else if(config->proxynegotiate)
+          my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_GSSNEGOTIATE);
+        else if(config->proxyntlm)
+          my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);
+        else if(config->proxydigest)
+          my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST);
+        else if(config->proxybasic)
+          my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
+
+        /* new in curl 7.10.8 */
+        if(config->max_filesize)
+          my_setopt(curl, CURLOPT_MAXFILESIZE_LARGE,
+                           config->max_filesize);
+
+        if(4 == config->ip_version)
+          my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+        else if(6 == config->ip_version)
+          my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
+        else
+          my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
+
+        /* new in curl 7.15.5 */
+        if(config->ftp_ssl_reqd)
+          my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
+
+        /* new in curl 7.11.0 */
+        else if(config->ftp_ssl)
+          my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY);
+
+        /* new in curl 7.16.0 */
+        else if(config->ftp_ssl_control)
+          my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_CONTROL);
+
+        /* new in curl 7.16.1 */
+        if(config->ftp_ssl_ccc)
+            my_setopt(curl, CURLOPT_FTP_SSL_CCC, config->ftp_ssl_ccc_mode);
+
+        /* new in curl 7.11.1, modified in 7.15.2 */
+        if(config->socksproxy) {
+          my_setopt_str(curl, CURLOPT_PROXY, config->socksproxy);
+          my_setopt(curl, CURLOPT_PROXYTYPE, config->socksver);
+        }
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+        /* new in curl 7.19.4 */
+        if(config->socks5_gssapi_service)
+          my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_SERVICE,
+                    config->socks5_gssapi_service);
+
+        /* new in curl 7.19.4 */
+        if(config->socks5_gssapi_nec)
+          my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_NEC,
+                        config->socks5_gssapi_nec);
+#endif
+        /* curl 7.13.0 */
+        my_setopt_str(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account);
+
+        my_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl);
+
+        /* curl 7.14.2 */
+        my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip);
+
+        /* curl 7.15.1 */
+        my_setopt(curl, CURLOPT_FTP_FILEMETHOD, config->ftp_filemethod);
+
+        /* curl 7.15.2 */
+        if(config->localport) {
+          my_setopt(curl, CURLOPT_LOCALPORT, config->localport);
+          my_setopt_str(curl, CURLOPT_LOCALPORTRANGE,
+                    config->localportrange);
+        }
+
+        /* curl 7.15.5 */
+        my_setopt_str(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER,
+                  config->ftp_alternative_to_user);
+
+        /* curl 7.16.0 */
+        my_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE,
+                  !config->disable_sessionid);
+
+        /* curl 7.16.2 */
+        if(config->raw) {
+          my_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, FALSE);
+          my_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, FALSE);
+        }
+
+        /* curl 7.17.1 */
+        if (!config->nokeepalive) {
+          my_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockoptcallback);
+          my_setopt(curl, CURLOPT_SOCKOPTDATA, config);
+        }
+
+        /* curl 7.19.1 (the 301 version existed in 7.18.2) */
+        my_setopt(curl, CURLOPT_POSTREDIR, config->post301 |
+                  (config->post302 ? CURL_REDIR_POST_302 : FALSE));
+
+        /* curl 7.20.0 */
+        if(config->tftp_blksize)
+          my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize);
+
+        if(config->mail_from)
+          my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from);
+
+        if(config->mail_rcpt)
+          my_setopt(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt);
+
+        /* curl 7.20.x */
+        if(config->ftp_pret)
+          my_setopt(curl, CURLOPT_FTP_USE_PRET, TRUE);
+
+        if ((urlnode->flags & GETOUT_USEREMOTE)
+            && config->content_disposition) {
+          my_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
+          my_setopt(curl, CURLOPT_HEADERDATA, &outs);
+        }
+
+        retry_numretries = config->req_retry;
+
+        retrystart = cutil_tvnow();
+
+        for(;;) {
+          res = curl_easy_perform(curl);
+          if (!curl_slist_append(easycode, "ret = curl_easy_perform(hnd);")) {
+            res = CURLE_OUT_OF_MEMORY;
+            break;
+          }
+
+          if (config->content_disposition && outs.stream && !config->mute)
+            printf("curl: Saved to filename '%s'\n", outs.filename);
+
+          /* if retry-max-time is non-zero, make sure we haven't exceeded the
+             time */
+          if(retry_numretries &&
+             (!config->retry_maxtime ||
+              (cutil_tvdiff(cutil_tvnow(), retrystart)<
+               config->retry_maxtime*1000)) ) {
+            enum {
+              RETRY_NO,
+              RETRY_TIMEOUT,
+              RETRY_HTTP,
+              RETRY_FTP,
+              RETRY_LAST /* not used */
+            } retry = RETRY_NO;
+            long response;
+            if(CURLE_OPERATION_TIMEDOUT == res)
+              /* retry timeout always */
+              retry = RETRY_TIMEOUT;
+            else if(CURLE_OK == res) {
+              /* Check for HTTP transient errors */
+              char *this_url=NULL;
+              curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &this_url);
+              if(this_url &&
+                 curlx_strnequal(this_url, "http", 4)) {
+                /* This was HTTP(S) */
+                curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
+
+                switch(response) {
+                case 500: /* Internal Server Error */
+                case 502: /* Bad Gateway */
+                case 503: /* Service Unavailable */
+                case 504: /* Gateway Timeout */
+                  retry = RETRY_HTTP;
+                  /*
+                   * At this point, we have already written data to the output
+                   * file (or terminal). If we write to a file, we must rewind
+                   * or close/re-open the file so that the next attempt starts
+                   * over from the beginning.
+                   *
+                   * TODO: similar action for the upload case. We might need
+                   * to start over reading from a previous point if we have
+                   * uploaded something when this was returned.
+                   */
+                  break;
+                }
+              }
+            } /* if CURLE_OK */
+            else if(res) {
+              curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
+
+              if(response/100 == 4)
+                /*
+                 * This is typically when the FTP server only allows a certain
+                 * amount of users and we are not one of them.  All 4xx codes
+                 * are transient.
+                 */
+                retry = RETRY_FTP;
+            }
+
+            if(retry) {
+              static const char * const m[]={
+                NULL, "timeout", "HTTP error", "FTP error"
+              };
+              warnf(config, "Transient problem: %s "
+                    "Will retry in %ld seconds. "
+                    "%ld retries left.\n",
+                    m[retry], retry_sleep/1000, retry_numretries);
+
+              go_sleep(retry_sleep);
+              retry_numretries--;
+              if(!config->retry_delay) {
+                retry_sleep *= 2;
+                if(retry_sleep > RETRY_SLEEP_MAX)
+                  retry_sleep = RETRY_SLEEP_MAX;
+              }
+              if(outs.bytes && outs.filename) {
+                /* We have written data to a output file, we truncate file
+                 */
+                if(!config->mute)
+                  fprintf(config->errors, "Throwing away %"
+                          CURL_FORMAT_CURL_OFF_T " bytes\n",
+                          outs.bytes);
+                fflush(outs.stream);
+                /* truncate file at the position where we started appending */
+#ifdef HAVE_FTRUNCATE
+                if(ftruncate( fileno(outs.stream), outs.init)) {
+                  /* when truncate fails, we can't just append as then we'll
+                     create something strange, bail out */
+                  if(!config->mute)
+                    fprintf(config->errors,
+                            "failed to truncate, exiting\n");
+                  break;
+                }
+                /* now seek to the end of the file, the position where we
+                   just truncated the file in a large file-safe way */
+                fseek(outs.stream, 0, SEEK_END);
+#else
+                /* ftruncate is not available, so just reposition the file
+                   to the location we would have truncated it. This won't
+                   work properly with large files on 32-bit systems, but
+                   most of those will have ftruncate. */
+                fseek(outs.stream, (long)outs.init, SEEK_SET);
+#endif
+                outs.bytes = 0; /* clear for next round */
+              }
+              continue;
+            }
+          } /* if retry_numretries */
+
+          /* In all ordinary cases, just break out of loop here */
+          retry_sleep = retry_sleep_default;
+          break;
+
+        }
+
+        if((config->progressmode == CURL_PROGRESS_BAR) &&
+           progressbar.calls)
+          /* if the custom progress bar has been displayed, we output a
+             newline here */
+          fputs("\n", progressbar.out);
+
+        if(config->writeout)
+          ourWriteOut(curl, config->writeout);
+#ifdef USE_ENVIRONMENT
+        if (config->writeenv)
+          ourWriteEnv(curl);
+#endif
+
+show_error:
+
+#ifdef __VMS
+        if(is_vms_shell()) {
+          /* VMS DCL shell behavior */
+          if(!config->showerror) {
+            vms_show = VMSSTS_HIDE;
+          }
+        }
+        else
+#endif
+        {
+          if((res!=CURLE_OK) && config->showerror) {
+            fprintf(config->errors, "curl: (%d) %s\n", res,
+                    errorbuffer[0]? errorbuffer:
+                    curl_easy_strerror((CURLcode)res));
+            if(CURLE_SSL_CACERT == res) {
+#define CURL_CA_CERT_ERRORMSG1 \
+"More details here: http://curl.haxx.se/docs/sslcerts.html\n\n" \
+"curl performs SSL certificate verification by default, using a \"bundle\"\n" \
+" of Certificate Authority (CA) public keys (CA certs). If the default\n" \
+" bundle file isn't adequate, you can specify an alternate file\n" \
+" using the --cacert option.\n"
+
+#define CURL_CA_CERT_ERRORMSG2 \
+"If this HTTPS server uses a certificate signed by a CA represented in\n" \
+" the bundle, the certificate verification probably failed due to a\n" \
+" problem with the certificate (it might be expired, or the name might\n" \
+" not match the domain name in the URL).\n" \
+"If you'd like to turn off curl's verification of the certificate, use\n" \
+" the -k (or --insecure) option.\n"
+
+              fprintf(config->errors, "%s%s",
+                      CURL_CA_CERT_ERRORMSG1,
+                      CURL_CA_CERT_ERRORMSG2 );
+            }
+          }
+        }
+
+        if (outfile && !curlx_strequal(outfile, "-") && outs.stream) {
+          int rc = fclose(outs.stream);
+          if(!res && rc) {
+            /* something went wrong in the writing process */
+            res = CURLE_WRITE_ERROR;
+            fprintf(config->errors, "(%d) Failed writing body\n", res);
+          }
+        }
+
+#ifdef HAVE_UTIME
+        /* Important that we set the time _after_ the file has been
+           closed, as is done above here */
+        if(config->remote_time && outs.filename) {
+          /* ask libcurl if we got a time. Pretty please */
+          long filetime;
+          curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime);
+          if(filetime >= 0) {
+            struct utimbuf times;
+            times.actime = (time_t)filetime;
+            times.modtime = (time_t)filetime;
+            utime(outs.filename, &times); /* set the time we got */
+          }
+        }
+#endif
+#ifdef __AMIGA__
+        /* Set the url as comment for the file. (up to 80 chars are allowed)
+         */
+        if( strlen(url) > 78 )
+          url[79] = '\0';
+
+        SetComment( outs.filename, url);
+#endif
+
+quit_urls:
+        if(url)
+          free(url);
+
+        if(outfile)
+          free(outfile);
+
+        if(infdopen)
+          close(infd);
+
+      } /* loop to the next URL */
+
+      if(urls) {
+        /* cleanup memory used for URL globbing patterns */
+        glob_cleanup(urls);
+        urls = NULL;
+      }
+
+      if(uploadfile)
+        free(uploadfile);
+
+    } /* loop to the next globbed upload file */
+
+    if(inglob) {
+      glob_cleanup(inglob);
+      inglob = NULL;
+    }
+
+    if(outfiles)
+      free(outfiles);
+
+    /* empty this urlnode struct */
+    if(urlnode->url)
+      free(urlnode->url);
+    if(urlnode->outfile)
+      free(urlnode->outfile);
+    if(urlnode->infile)
+      free(urlnode->infile);
+
+    /* move on to the next URL */
+    nextnode=urlnode->next;
+    free(urlnode); /* free the node */
+    urlnode = nextnode;
+
+  } /* while-loop through all URLs */
+
+quit_curl:
+  if (httpgetfields)
+    free(httpgetfields);
+
+  if (config->engine)
+    free(config->engine);
+
+  /* cleanup the curl handle! */
+  curl_easy_cleanup(curl);
+  config->easy = NULL; /* cleanup now */
+  if (easycode)
+    curl_slist_append(easycode, "curl_easy_cleanup(hnd);");
+
+  if(heads.stream && (heads.stream != stdout))
+    fclose(heads.stream);
+
+  if(allocuseragent)
+    free(config->useragent);
+
+  if(config->trace_fopened && config->trace_stream)
+    fclose(config->trace_stream);
+
+  /* Dump the libcurl code if previously enabled.
+     NOTE: that this function relies on config->errors amongst other things
+     so not everything can be closed and cleaned before this is called */
+  dumpeasycode(config);
+
+  if(config->errors_fopened)
+    fclose(config->errors);
+
+  main_free(); /* cleanup */
+
+  return res;
+}
+
+/* Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are
+   open before starting to run.  Otherwise, the first three network
+   sockets opened by curl could be used for input sources, downloaded data
+   or error logs as they will effectively be stdin, stdout and/or stderr.
+*/
+static void checkfds(void)
+{
+#ifdef HAVE_PIPE
+  int fd[2] = { STDIN_FILENO, STDIN_FILENO };
+  while( fd[0] == STDIN_FILENO ||
+         fd[0] == STDOUT_FILENO ||
+         fd[0] == STDERR_FILENO ||
+         fd[1] == STDIN_FILENO ||
+         fd[1] == STDOUT_FILENO ||
+         fd[1] == STDERR_FILENO )
+    if (pipe(fd) < 0)
+      return;   /* Out of handles. This isn't really a big problem now, but
+                   will be when we try to create a socket later. */
+  close(fd[0]);
+  close(fd[1]);
+#endif
+}
+
+
+
+int main(int argc, char *argv[])
+{
+  int res;
+  struct Configurable config;
+
+  memset(&config, 0, sizeof(struct Configurable));
+
+  config.errors = stderr; /* default errors to stderr */
+
+  checkfds();
+
+  res = operate(&config, argc, argv);
+#ifdef __SYMBIAN32__
+  if (config.showerror)
+    pressanykey();
+#endif
+  free_config_fields(&config);
+
+#ifdef __NOVELL_LIBC__
+  if (getenv("_IN_NETWARE_BASH_") == NULL)
+    pressanykey();
+#endif
+#ifdef __VMS
+  vms_special_exit(res, vms_show);
+#else
+  return res;
+#endif
+}
+
+/*
+ * Reads a line from the given file, ensuring is NUL terminated.
+ * The pointer must be freed by the caller.
+ * NULL is returned on an out of memory condition.
+ */
+static char *my_get_line(FILE *fp)
+{
+   char buf[4096];
+   char *nl = NULL;
+   char *retval = NULL;
+
+   do {
+     if (NULL == fgets(buf, sizeof(buf), fp))
+       break;
+     if (NULL == retval) {
+       retval = strdup(buf);
+       if(!retval)
+         return NULL;
+     }
+     else {
+       char *ptr;
+       ptr = realloc(retval, strlen(retval) + strlen(buf) + 1);
+       if (NULL == ptr) {
+         free(retval);
+         return NULL;
+       }
+       retval = ptr;
+       strcat(retval, buf);
+     }
+   }
+   while (NULL == (nl = strchr(retval, '\n')));
+
+   if (NULL != nl)
+     *nl = '\0';
+
+   return retval;
+}
+
+static void show_dir_errno(FILE *errors, const char *name)
+{
+  switch (ERRNO) {
+#ifdef EACCES
+  case EACCES:
+    fprintf(errors,"You don't have permission to create %s.\n", name);
+    break;
+#endif
+#ifdef ENAMETOOLONG
+  case ENAMETOOLONG:
+    fprintf(errors,"The directory name %s is too long.\n", name);
+    break;
+#endif
+#ifdef EROFS
+  case EROFS:
+    fprintf(errors,"%s resides on a read-only file system.\n", name);
+    break;
+#endif
+#ifdef ENOSPC
+  case ENOSPC:
+    fprintf(errors,"No space left on the file system that will "
+            "contain the directory %s.\n", name);
+    break;
+#endif
+#ifdef EDQUOT
+  case EDQUOT:
+    fprintf(errors,"Cannot create directory %s because you "
+            "exceeded your quota.\n", name);
+    break;
+#endif
+  default :
+    fprintf(errors,"Error creating directory %s.\n", name);
+    break;
+  }
+}
+
+/* Create the needed directory hierarchy recursively in order to save
+   multi-GETs in file output, ie:
+   curl "http://my.site/dir[1-5]/file[1-5].txt" -o "dir#1/file#2.txt"
+   should create all the dir* automagically
+*/
+static int create_dir_hierarchy(const char *outfile, FILE *errors)
+{
+  char *tempdir;
+  char *tempdir2;
+  char *outdup;
+  char *dirbuildup;
+  int result=0;
+
+  outdup = strdup(outfile);
+  if(!outdup)
+    return -1;
+
+  dirbuildup = malloc(sizeof(char) * strlen(outfile));
+  if(!dirbuildup) {
+    free(outdup);
+    return -1;
+  }
+  dirbuildup[0] = '\0';
+
+  tempdir = strtok(outdup, DIR_CHAR);
+
+  while (tempdir != NULL) {
+    tempdir2 = strtok(NULL, DIR_CHAR);
+    /* since strtok returns a token for the last word even
+       if not ending with DIR_CHAR, we need to prune it */
+    if (tempdir2 != NULL) {
+      size_t dlen = strlen(dirbuildup);
+      if (dlen)
+        sprintf(&dirbuildup[dlen], "%s%s", DIR_CHAR, tempdir);
+      else {
+        if (0 != strncmp(outdup, DIR_CHAR, 1))
+          strcpy(dirbuildup, tempdir);
+        else
+          sprintf(dirbuildup, "%s%s", DIR_CHAR, tempdir);
+      }
+      if (access(dirbuildup, F_OK) == -1) {
+        result = mkdir(dirbuildup,(mode_t)0000750);
+        if (-1 == result) {
+          show_dir_errno(errors, dirbuildup);
+          break; /* get out of loop */
+        }
+      }
+    }
+    tempdir = tempdir2;
+  }
+  free(dirbuildup);
+  free(outdup);
+
+  return result; /* 0 is fine, -1 is badness */
+}
+
+#if defined(MSDOS) || defined(WIN32)
+
+#ifndef HAVE_BASENAME
+/* basename() returns a pointer to the last component of a pathname.
+ * Ripped from lib/formdata.c.
+ */
+static char *Curl_basename(char *path)
+{
+  /* Ignore all the details above for now and make a quick and simple
+     implementaion here */
+  char *s1;
+  char *s2;
+
+  s1=strrchr(path, '/');
+  s2=strrchr(path, '\\');
+
+  if(s1 && s2) {
+    path = (s1 > s2? s1 : s2)+1;
+  }
+  else if(s1)
+    path = s1 + 1;
+  else if(s2)
+    path = s2 + 1;
+
+  return path;
+}
+#define basename(x) Curl_basename((x))
+#endif /* HAVE_BASENAME */
+
+/* The following functions are taken with modification from the DJGPP
+ * port of tar 1.12. They use algorithms originally from DJTAR. */
+
+static const char *
+msdosify (const char *file_name)
+{
+  static char dos_name[PATH_MAX];
+  static const char illegal_chars_dos[] = ".+, ;=[]" /* illegal in DOS */
+                                       "|<>\\\":?*"; /* illegal in DOS & W95 */
+  static const char *illegal_chars_w95 = &illegal_chars_dos[8];
+  int idx, dot_idx;
+  const char *s = file_name;
+  char *d = dos_name;
+  const char * const dlimit = dos_name + sizeof(dos_name) - 1;
+  const char *illegal_aliens = illegal_chars_dos;
+  size_t len = sizeof (illegal_chars_dos) - 1;
+
+  /* Support for Windows 9X VFAT systems, when available. */
+  if (_use_lfn (file_name)) {
+    illegal_aliens = illegal_chars_w95;
+    len -= (illegal_chars_w95 - illegal_chars_dos);
+  }
+
+  /* Get past the drive letter, if any. */
+  if (s[0] >= 'A' && s[0] <= 'z' && s[1] == ':') {
+    *d++ = *s++;
+    *d++ = *s++;
+  }
+
+  for (idx = 0, dot_idx = -1; *s && d < dlimit; s++, d++) {
+    if (memchr (illegal_aliens, *s, len)) {
+      /* Dots are special: DOS doesn't allow them as the leading character,
+         and a file name cannot have more than a single dot.  We leave the
+         first non-leading dot alone, unless it comes too close to the
+         beginning of the name: we want sh.lex.c to become sh_lex.c, not
+         sh.lex-c.  */
+      if (*s == '.') {
+        if (idx == 0 && (s[1] == '/' || (s[1] == '.' && s[2] == '/'))) {
+          /* Copy "./" and "../" verbatim.  */
+          *d++ = *s++;
+          if (*s == '.')
+            *d++ = *s++;
+          *d = *s;
+        }
+        else if (idx == 0)
+          *d = '_';
+        else if (dot_idx >= 0) {
+          if (dot_idx < 5) { /* 5 is a heuristic ad-hoc'ery */
+            d[dot_idx - idx] = '_'; /* replace previous dot */
+            *d = '.';
+          }
+          else
+            *d = '-';
+        }
+        else
+          *d = '.';
+
+        if (*s == '.')
+          dot_idx = idx;
+      }
+      else if (*s == '+' && s[1] == '+') {
+        if (idx - 2 == dot_idx) { /* .c++, .h++ etc. */
+          *d++ = 'x';
+          *d   = 'x';
+        }
+        else {
+          /* libg++ etc.  */
+          memcpy (d, "plus", 4);
+          d += 3;
+        }
+        s++;
+        idx++;
+      }
+      else
+        *d = '_';
+    }
+    else
+      *d = *s;
+    if (*s == '/') {
+      idx = 0;
+      dot_idx = -1;
+    }
+    else
+      idx++;
+  }
+
+  *d = '\0';
+  return dos_name;
+}
+
+static char *
+rename_if_dos_device_name (char *file_name)
+{
+  /* We could have a file whose name is a device on MS-DOS.  Trying to
+   * retrieve such a file would fail at best and wedge us at worst.  We need
+   * to rename such files. */
+  char *base;
+  struct_stat st_buf;
+  char fname[PATH_MAX];
+
+  strncpy(fname, file_name, PATH_MAX-1);
+  fname[PATH_MAX-1] = 0;
+  base = basename(fname);
+  if (((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) {
+    size_t blen = strlen (base);
+
+    if (strlen(fname) >= PATH_MAX-1) {
+      /* Make room for the '_' */
+      blen--;
+      base[blen] = 0;
+    }
+    /* Prepend a '_'.  */
+    memmove (base + 1, base, blen + 1);
+    base[0] = '_';
+    strcpy (file_name, fname);
+  }
+  return file_name;
+}
+
+/* Replace bad characters in the file name before using it.
+ * fn will always be freed before return
+ * The returned pointer must be freed by the caller if not NULL
+ */
+static char *sanitize_dos_name(char *fn)
+{
+  char tmpfn[PATH_MAX];
+  fn[PATH_MAX-1]=0; /* ensure fn is not too long by possibly truncating it */
+  strcpy(tmpfn, msdosify(fn));
+  free(fn);
+  return strdup(rename_if_dos_device_name(tmpfn));
+}
+#endif /* MSDOS || WIN32 */
diff --git a/src/os-specific.c b/src/os-specific.c
new file mode 100644
index 0000000..ac07c4c
--- /dev/null
+++ b/src/os-specific.c
@@ -0,0 +1,221 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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>
+
+#define ENABLE_CURLX_PRINTF
+#include "curlx.h"
+
+#include "os-specific.h"
+
+#if defined(CURLDEBUG) && defined(CURLTOOLDEBUG)
+#  include "memdebug.h"
+#endif
+
+#ifdef __VMS
+
+#include "curlmsg_vms.h"
+
+void decc$__posix_exit(int __status);
+void decc$exit(int __status);
+
+static int vms_shell = -1;
+
+/* VMS has a DCL shell and and also has Unix shells ported to it.
+ * When curl is running under a Unix shell, we want it to be as much
+ * like Unix as possible.
+ */
+int is_vms_shell(void)
+{
+  char *shell;
+
+  /* Have we checked the shell yet? */
+  if(vms_shell >= 0)
+    return vms_shell;
+
+  shell = getenv("SHELL");
+
+  /* No shell, means DCL */
+  if(shell == NULL) {
+    vms_shell = 1;
+    return 1;
+  }
+
+  /* Have to make sure some one did not set shell to DCL */
+  if(strcmp(shell, "DCL") == 0) {
+    vms_shell = 1;
+    return 1;
+  }
+
+  vms_shell = 0;
+  return 0;
+}
+
+/*
+ * VMS has two exit() routines.  When running under a Unix style shell, then
+ * Unix style and the __posix_exit() routine is used.
+ *
+ * When running under the DCL shell, then the VMS encoded codes and decc$exit()
+ * is used.
+ *
+ * We can not use exit() or return a code from main() because the actual
+ * routine called depends on both the compiler version, compile options, and
+ * feature macro settings, and one of the exit routines is hidden at compile
+ * time.
+ *
+ * Since we want Curl to work properly under the VMS DCL shell and Unix
+ * shells under VMS, this routine should compile correctly regardless of
+ * the settings.
+ */
+
+void vms_special_exit(int code, int vms_show)
+{
+  int vms_code;
+
+  /* The Posix exit mode is only available after VMS 7.0 */
+#if __CRTL_VER >= 70000000
+  if(is_vms_shell() == 0) {
+    decc$__posix_exit(code);
+  }
+#endif
+
+  if(code > CURL_LAST) {   /* If CURL_LAST exceeded then */
+    vms_code = CURL_LAST;  /* curlmsg.h is out of sync.  */
+  }
+  else {
+    vms_code = vms_cond[code] | vms_show;
+  }
+  decc$exit(vms_code);
+}
+
+#if defined(__DECC) && !defined(__VAX) && \
+    defined(__CRTL_VER) && (__CRTL_VER >= 70301000)
+
+/*
+ * 2004-09-19 SMS.
+ *
+ * decc_init()
+ *
+ * On non-VAX systems, use LIB$INITIALIZE to set a collection of C
+ * RTL features without using the DECC$* logical name method, nor
+ * requiring the user to define the corresponding logical names.
+ */
+
+#include <unixlib.h>
+
+/* Structure to hold a DECC$* feature name and its desired value. */
+typedef struct {
+  char *name;
+  int value;
+} decc_feat_t;
+
+/* Array of DECC$* feature names and their desired values. */
+static decc_feat_t decc_feat_array[] = {
+  /* Preserve command-line case with SET PROCESS/PARSE_STYLE=EXTENDED */
+  { "DECC$ARGV_PARSE_STYLE", 1 },
+  /* Preserve case for file names on ODS5 disks. */
+  { "DECC$EFS_CASE_PRESERVE", 1 },
+  /* Enable multiple dots (and most characters) in ODS5 file names,
+     while preserving VMS-ness of ";version". */
+  { "DECC$EFS_CHARSET", 1 },
+  /* List terminator. */
+  { (char *)NULL, 0 }
+};
+
+/* Flag to sense if decc_init() was called. */
+static int decc_init_done = -1;
+
+/* LIB$INITIALIZE initialization function. */
+static void decc_init(void)
+{
+  int feat_index;
+  int feat_value;
+  int feat_value_max;
+  int feat_value_min;
+  int i;
+  int sts;
+
+  /* Set the global flag to indicate that LIB$INITIALIZE worked. */
+  decc_init_done = 1;
+
+  /* Loop through all items in the decc_feat_array[]. */
+  for(i = 0; decc_feat_array[i].name != NULL; i++) {
+
+    /* Get the feature index. */
+    feat_index = decc$feature_get_index( decc_feat_array[i].name);
+
+    if(feat_index >= 0) {
+      /* Valid item.  Collect its properties. */
+      feat_value = decc$feature_get_value( feat_index, 1);
+      feat_value_min = decc$feature_get_value( feat_index, 2);
+      feat_value_max = decc$feature_get_value( feat_index, 3);
+
+      if((decc_feat_array[i].value >= feat_value_min) &&
+         (decc_feat_array[i].value <= feat_value_max)) {
+        /* Valid value.  Set it if necessary. */
+        if(feat_value != decc_feat_array[i].value) {
+          sts = decc$feature_set_value( feat_index, 1,
+                                        decc_feat_array[i].value);
+        }
+      }
+      else {
+        /* Invalid DECC feature value. */
+        printf(" INVALID DECC FEATURE VALUE, %d: %d <= %s <= %d.\n",
+               feat_value,
+               feat_value_min, decc_feat_array[i].name, feat_value_max);
+      }
+    }
+    else {
+      /* Invalid DECC feature name. */
+      printf(" UNKNOWN DECC FEATURE: %s.\n", decc_feat_array[i].name);
+    }
+
+  }
+}
+
+/* Get "decc_init()" into a valid, loaded LIB$INITIALIZE PSECT. */
+
+#pragma nostandard
+
+/* Establish the LIB$INITIALIZE PSECTs, with proper alignment and
+   other attributes.  Note that "nopic" is significant only on VAX. */
+#pragma extern_model save
+#pragma extern_model strict_refdef "LIB$INITIALIZ" 2, nopic, nowrt
+const int spare[8] = {0};
+#pragma extern_model strict_refdef "LIB$INITIALIZE" 2, nopic, nowrt
+void (*const x_decc_init)() = decc_init;
+#pragma extern_model restore
+
+/* Fake reference to ensure loading the LIB$INITIALIZE PSECT. */
+#pragma extern_model save
+int LIB$INITIALIZE(void);
+#pragma extern_model strict_refdef
+int dmy_lib$initialize = (int) LIB$INITIALIZE;
+#pragma extern_model restore
+
+#pragma standard
+
+#endif /* __DECC && !__VAX && __CRTL_VER && __CRTL_VER >= 70301000 */
+
+#endif /* __VMS */
+
diff --git a/src/os-specific.h b/src/os-specific.h
new file mode 100644
index 0000000..93cac74
--- /dev/null
+++ b/src/os-specific.h
@@ -0,0 +1,38 @@
+#ifndef HEADER_CURL_OS_SPECIFIC_H
+#define HEADER_CURL_OS_SPECIFIC_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+#ifdef __VMS
+
+int is_vms_shell(void);
+void vms_special_exit(int code, int vms_show);
+
+#undef exit
+#define exit(__code) vms_special_exit((__code), (0))
+
+#define  VMS_STS(c,f,e,s) (((c&0xF)<<28)|((f&0xFFF)<<16)|((e&0x1FFF)<3)|(s&7))
+#define  VMSSTS_HIDE  VMS_STS(1,0,0,0)
+
+#endif /* __VMS */
+
+#endif /* HEADER_CURL_OS_SPECIFIC_H */
diff --git a/src/setup.h b/src/setup.h
new file mode 100644
index 0000000..69da710
--- /dev/null
+++ b/src/setup.h
@@ -0,0 +1,218 @@
+#ifndef HEADER_CURL_SRC_SETUP_H
+#define HEADER_CURL_SRC_SETUP_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+#define CURL_NO_OLDIES
+
+/*
+ * Define WIN32 when build target is Win32 API
+ */
+
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) && !defined(__SYMBIAN32__)
+#define WIN32
+#endif
+
+/*
+ * Include configuration script results or hand-crafted
+ * configuration file for platforms which lack config tool.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "curl_config.h"
+#else
+
+#ifdef WIN32
+#include "config-win32.h"
+#endif
+
+#if defined(macintosh) && defined(__MRC__)
+#  include "config-mac.h"
+#endif
+
+#ifdef __riscos__
+#include "config-riscos.h"
+#endif
+
+#ifdef __AMIGA__
+#include "config-amigaos.h"
+#endif
+
+#ifdef __SYMBIAN32__
+#include "config-symbian.h"
+#endif
+
+#ifdef TPF
+#include "config-tpf.h"
+#endif
+
+#endif /* HAVE_CONFIG_H */
+
+/*
+ * AIX 4.3 and newer needs _THREAD_SAFE defined to build
+ * proper reentrant code. Others may also need it.
+ */
+
+#ifdef NEED_THREAD_SAFE
+#  ifndef _THREAD_SAFE
+#    define _THREAD_SAFE
+#  endif
+#endif
+
+/*
+ * Tru64 needs _REENTRANT set for a few function prototypes and
+ * things to appear in the system header files. Unixware needs it
+ * to build proper reentrant code. Others may also need it.
+ */
+
+#ifdef NEED_REENTRANT
+#  ifndef _REENTRANT
+#    define _REENTRANT
+#  endif
+#endif
+
+/*
+ * Include header files for windows builds before redefining anything.
+ * Use this preproessor block only to include or exclude windows.h,
+ * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs
+ * to any other further and independent block.  Under Cygwin things work
+ * just as under linux (e.g. <sys/socket.h>) and the winsock headers should
+ * never be included when __CYGWIN__ is defined.  configure script takes
+ * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H,
+ * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined.
+ */
+
+#ifdef HAVE_WINDOWS_H
+#  ifndef WIN32_LEAN_AND_MEAN
+#    define WIN32_LEAN_AND_MEAN
+#  endif
+#  include <windows.h>
+#  ifdef HAVE_WINSOCK2_H
+#    include <winsock2.h>
+#    ifdef HAVE_WS2TCPIP_H
+#       include <ws2tcpip.h>
+#    endif
+#  else
+#    ifdef HAVE_WINSOCK_H
+#      include <winsock.h>
+#    endif
+#  endif
+#endif
+
+/*
+ * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else
+ * define USE_WINSOCK to 1 if we have and use WINSOCK  API, else
+ * undefine USE_WINSOCK.
+ */
+
+#undef USE_WINSOCK
+
+#ifdef HAVE_WINSOCK2_H
+#  define USE_WINSOCK 2
+#else
+#  ifdef HAVE_WINSOCK_H
+#    define USE_WINSOCK 1
+#  endif
+#endif
+
+#ifdef TPF
+#  include <sys/socket.h>
+   /* change which select is used for the curl command line tool */
+#  define select(a,b,c,d,e) tpf_select_bsd(a,b,c,d,e)
+   /* and turn off the progress meter */
+#  define CONF_DEFAULT (0|CONF_NOPROGRESS)
+#endif
+
+#include <stdio.h>
+
+#ifdef __TANDEM
+#include <floss.h>
+#endif
+
+
+#ifndef OS
+#define OS "unknown"
+#endif
+
+#if !defined(fileno) && !defined(WIN32) /* sunos 4 have this as a macro! */
+int fileno( FILE *stream);
+#endif
+
+#ifdef WIN32
+#define DIR_CHAR      "\\"
+#define DOT_CHAR      "_"
+#else
+#ifdef __EMX__
+/* 20000318 mgs
+ * OS/2 supports leading dots in filenames if the volume is formatted
+ * with JFS or HPFS. */
+#define DIR_CHAR      "\\"
+#define DOT_CHAR      "."
+#else
+
+#ifdef DJGPP
+#include <tcp.h>
+#ifdef word
+#undef word
+#endif
+#define DIR_CHAR      "/"
+#define DOT_CHAR      "_"
+#else
+
+#define DIR_CHAR      "/"
+#define DOT_CHAR      "."
+
+#endif /* !DJGPP */
+#endif /* !__EMX__ */
+#endif /* !WIN32 */
+
+#ifdef __riscos__
+#define USE_ENVIRONMENT
+#endif
+
+#ifdef __BEOS__
+#define typedef_bool
+#endif
+
+#if (defined(NETWARE) && !defined(__NOVELL_LIBC__))
+#include <sys/timeval.h>
+#endif
+
+#ifndef UNPRINTABLE_CHAR
+/* define what to use for unprintable characters */
+#define UNPRINTABLE_CHAR '.'
+#endif
+
+#ifndef HAVE_STRDUP
+#include "strdup.h"
+#define strdup(ptr) curlx_strdup(ptr)
+#endif
+
+/*
+ * Include macros and defines that should only be processed once.
+ */
+
+#ifndef __SETUP_ONCE_H
+#include "setup_once.h"
+#endif
+
+#endif /* HEADER_CURL_SRC_SETUP_H */
diff --git a/src/urlglob.c b/src/urlglob.c
new file mode 100644
index 0000000..5f8fb28
--- /dev/null
+++ b/src/urlglob.c
@@ -0,0 +1,567 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+/* client-local setup.h */
+#include "setup.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <curl/curl.h>
+
+#define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */
+#include <curl/mprintf.h>
+
+#include "urlglob.h"
+#include "os-specific.h"
+
+#if defined(CURLDEBUG) && defined(CURLTOOLDEBUG)
+#include "memdebug.h"
+#endif
+
+typedef enum {
+  GLOB_OK,
+  GLOB_ERROR
+} GlobCode;
+
+/*
+ * glob_word()
+ *
+ * Input a full globbed string, set the forth argument to the amount of
+ * strings we get out of this. Return GlobCode.
+ */
+static GlobCode glob_word(URLGlob *, /* object anchor */
+                          char *,    /* globbed string */
+                          size_t,       /* position */
+                          int *);    /* returned number of strings */
+
+static GlobCode glob_set(URLGlob *glob, char *pattern,
+                         size_t pos, int *amount)
+{
+  /* processes a set expression with the point behind the opening '{'
+     ','-separated elements are collected until the next closing '}'
+  */
+  bool done = FALSE;
+  char* buf = glob->glob_buffer;
+  URLPattern *pat;
+
+  pat = (URLPattern*)&glob->pattern[glob->size / 2];
+  /* patterns 0,1,2,... correspond to size=1,3,5,... */
+  pat->type = UPTSet;
+  pat->content.Set.size = 0;
+  pat->content.Set.ptr_s = 0;
+  /* FIXME: Here's a nasty zero size malloc */
+  pat->content.Set.elements = (char**)malloc(0);
+  ++glob->size;
+
+  while (!done) {
+    bool skip;
+
+    switch (*pattern) {
+    case '\0':                  /* URL ended while set was still open */
+      snprintf(glob->errormsg, sizeof(glob->errormsg),
+               "unmatched brace at pos %zu\n", pos);
+      return GLOB_ERROR;
+
+    case '{':
+    case '[':                   /* no nested expressions at this time */
+      snprintf(glob->errormsg, sizeof(glob->errormsg),
+               "nested braces not supported at pos %zu\n", pos);
+      return GLOB_ERROR;
+
+    case ',':
+    case '}':                           /* set element completed */
+      *buf = '\0';
+      pat->content.Set.elements =
+        realloc(pat->content.Set.elements,
+                (pat->content.Set.size + 1) * sizeof(char*));
+      if (!pat->content.Set.elements) {
+        snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory");
+        return GLOB_ERROR;
+      }
+      pat->content.Set.elements[pat->content.Set.size] =
+        strdup(glob->glob_buffer);
+      ++pat->content.Set.size;
+
+      if (*pattern == '}') {
+        /* entire set pattern completed */
+        int wordamount;
+
+        /* always check for a literal (may be "") between patterns */
+        if(GLOB_ERROR == glob_word(glob, ++pattern, ++pos, &wordamount))
+          wordamount=1;
+        *amount = pat->content.Set.size * wordamount;
+
+        done = TRUE;
+        continue;
+      }
+
+      buf = glob->glob_buffer;
+      ++pattern;
+      ++pos;
+      break;
+
+    case ']':                           /* illegal closing bracket */
+      snprintf(glob->errormsg, sizeof(glob->errormsg),
+               "illegal pattern at pos %zu\n", pos);
+      return GLOB_ERROR;
+
+    case '\\':                          /* escaped character, skip '\' */
+      switch(pattern[1]) {
+      case '[':
+      case ']':
+      case '{':
+      case '}':
+      case ',':
+        skip = TRUE;
+        break;
+      default:
+        skip = FALSE;
+        break;
+      }
+      if(skip) {
+        if (*(buf+1) == '\0') {           /* but no escaping of '\0'! */
+          snprintf(glob->errormsg, sizeof(glob->errormsg),
+                   "illegal pattern at pos %zu\n", pos);
+          return GLOB_ERROR;
+        }
+        ++pattern;
+        ++pos;
+      }
+      /* intentional fallthrough */
+    default:
+      *buf++ = *pattern++;              /* copy character to set element */
+      ++pos;
+    }
+  }
+  return GLOB_OK;
+}
+
+static GlobCode glob_range(URLGlob *glob, char *pattern,
+                           size_t pos, int *amount)
+{
+  /* processes a range expression with the point behind the opening '['
+     - char range: e.g. "a-z]", "B-Q]"
+     - num range: e.g. "0-9]", "17-2000]"
+     - num range with leading zeros: e.g. "001-999]"
+     expression is checked for well-formedness and collected until the next ']'
+  */
+  URLPattern *pat;
+  char *c;
+  int wordamount=1;
+  char sep;
+  char sep2;
+  int step;
+  int rc;
+
+  pat = (URLPattern*)&glob->pattern[glob->size / 2];
+  /* patterns 0,1,2,... correspond to size=1,3,5,... */
+  ++glob->size;
+
+  if (ISALPHA(*pattern)) {         /* character range detected */
+    char min_c;
+    char max_c;
+
+    pat->type = UPTCharRange;
+    rc = sscanf(pattern, "%c-%c%c%d%c", &min_c, &max_c, &sep, &step, &sep2);
+    if ((rc < 3) || (min_c >= max_c) || ((max_c - min_c) > ('z' - 'a'))) {
+      /* the pattern is not well-formed */
+      snprintf(glob->errormsg, sizeof(glob->errormsg),
+               "error: bad range specification after pos %zu\n", pos);
+      return GLOB_ERROR;
+    }
+
+    /* check the (first) separating character */
+    if((sep != ']') && (sep != ':')) {
+      snprintf(glob->errormsg, sizeof(glob->errormsg),
+               "error: unsupported character (%c) after range at pos %zu\n",
+               sep, pos);
+      return GLOB_ERROR;
+    }
+
+    /* if there was a ":[num]" thing, use that as step or else use 1 */
+    pat->content.CharRange.step =
+      ((sep == ':') && (rc == 5) && (sep2 == ']'))?step:1;
+
+    pat->content.CharRange.ptr_c = pat->content.CharRange.min_c = min_c;
+    pat->content.CharRange.max_c = max_c;
+  }
+  else if (ISDIGIT(*pattern)) { /* numeric range detected */
+    int min_n;
+    int max_n;
+
+    pat->type = UPTNumRange;
+    pat->content.NumRange.padlength = 0;
+
+    rc = sscanf(pattern, "%d-%d%c%d%c", &min_n, &max_n, &sep, &step, &sep2);
+
+    if ((rc < 2) || (min_n > max_n)) {
+      /* the pattern is not well-formed */
+      snprintf(glob->errormsg, sizeof(glob->errormsg),
+               "error: bad range specification after pos %zu\n", pos);
+      return GLOB_ERROR;
+    }
+    pat->content.NumRange.ptr_n =  pat->content.NumRange.min_n = min_n;
+    pat->content.NumRange.max_n = max_n;
+
+    /* if there was a ":[num]" thing, use that as step or else use 1 */
+    pat->content.NumRange.step =
+      ((sep == ':') && (rc == 5) && (sep2 == ']'))?step:1;
+
+    if (*pattern == '0') {              /* leading zero specified */
+      c = pattern;
+      while (ISDIGIT(*c)) {
+        c++;
+        ++pat->content.NumRange.padlength; /* padding length is set for all
+                                              instances of this pattern */
+      }
+    }
+
+  }
+  else {
+    snprintf(glob->errormsg, sizeof(glob->errormsg),
+             "illegal character in range specification at pos %zu\n", pos);
+    return GLOB_ERROR;
+  }
+
+  c = (char*)strchr(pattern, ']'); /* continue after next ']' */
+  if(c)
+    c++;
+  else {
+    snprintf(glob->errormsg, sizeof(glob->errormsg), "missing ']'");
+    return GLOB_ERROR; /* missing ']' */
+  }
+
+  /* always check for a literal (may be "") between patterns */
+
+  if(GLOB_ERROR == glob_word(glob, c, pos + (c - pattern), &wordamount))
+    wordamount = 1;
+
+  if(pat->type == UPTCharRange)
+    *amount = (pat->content.CharRange.max_c -
+               pat->content.CharRange.min_c + 1) *
+      wordamount;
+  else
+    *amount = (pat->content.NumRange.max_n -
+               pat->content.NumRange.min_n + 1) * wordamount;
+
+  return GLOB_OK;
+}
+
+static GlobCode glob_word(URLGlob *glob, char *pattern,
+                          size_t pos, int *amount)
+{
+  /* processes a literal string component of a URL
+     special characters '{' and '[' branch to set/range processing functions
+   */
+  char* buf = glob->glob_buffer;
+  size_t litindex;
+  GlobCode res = GLOB_OK;
+
+  *amount = 1; /* default is one single string */
+
+  while (*pattern != '\0' && *pattern != '{' && *pattern != '[') {
+    if (*pattern == '}' || *pattern == ']')
+      return GLOB_ERROR;
+
+    /* only allow \ to escape known "special letters" */
+    if (*pattern == '\\' &&
+        (*(pattern+1) == '{' || *(pattern+1) == '[' ||
+         *(pattern+1) == '}' || *(pattern+1) == ']') ) {
+
+      /* escape character, skip '\' */
+      ++pattern;
+      ++pos;
+      if (*pattern == '\0')             /* but no escaping of '\0'! */
+        return GLOB_ERROR;
+    }
+    *buf++ = *pattern++;                /* copy character to literal */
+    ++pos;
+  }
+  *buf = '\0';
+  litindex = glob->size / 2;
+  /* literals 0,1,2,... correspond to size=0,2,4,... */
+  glob->literal[litindex] = strdup(glob->glob_buffer);
+  if(!glob->literal[litindex])
+    return GLOB_ERROR;
+  ++glob->size;
+
+  switch (*pattern) {
+  case '\0':
+    break;                      /* singular URL processed  */
+
+  case '{':
+    /* process set pattern */
+    res = glob_set(glob, ++pattern, ++pos, amount);
+    break;
+
+  case '[':
+    /* process range pattern */
+    res= glob_range(glob, ++pattern, ++pos, amount);
+    break;
+  }
+
+  if(GLOB_OK != res)
+    /* free that strdup'ed string again */
+    free(glob->literal[litindex]);
+
+  return res; /* something got wrong */
+}
+
+int glob_url(URLGlob** glob, char* url, int *urlnum, FILE *error)
+{
+  /*
+   * We can deal with any-size, just make a buffer with the same length
+   * as the specified URL!
+   */
+  URLGlob *glob_expand;
+  int amount;
+  char *glob_buffer = malloc(strlen(url)+1);
+
+  *glob = NULL;
+  if(NULL == glob_buffer)
+    return CURLE_OUT_OF_MEMORY;
+
+  glob_expand = calloc(1, sizeof(URLGlob));
+  if(NULL == glob_expand) {
+    free(glob_buffer);
+    return CURLE_OUT_OF_MEMORY;
+  }
+  glob_expand->size = 0;
+  glob_expand->urllen = strlen(url);
+  glob_expand->glob_buffer = glob_buffer;
+  glob_expand->beenhere=0;
+  if(GLOB_OK == glob_word(glob_expand, url, 1, &amount))
+    *urlnum = amount;
+  else {
+    if(error && glob_expand->errormsg[0]) {
+      /* send error description to the error-stream */
+      fprintf(error, "curl: (%d) [globbing] %s\n",
+              CURLE_URL_MALFORMAT, glob_expand->errormsg);
+    }
+    /* it failed, we cleanup */
+    free(glob_buffer);
+    free(glob_expand);
+    glob_expand = NULL;
+    *urlnum = 1;
+    return CURLE_URL_MALFORMAT;
+  }
+
+  *glob = glob_expand;
+  return CURLE_OK;
+}
+
+void glob_cleanup(URLGlob* glob)
+{
+  size_t i;
+  int elem;
+
+  for (i = glob->size - 1; i < glob->size; --i) {
+    if (!(i & 1)) {     /* even indexes contain literals */
+      free(glob->literal[i/2]);
+    }
+    else {              /* odd indexes contain sets or ranges */
+      if (glob->pattern[i/2].type == UPTSet) {
+        for (elem = glob->pattern[i/2].content.Set.size - 1;
+             elem >= 0;
+             --elem) {
+          free(glob->pattern[i/2].content.Set.elements[elem]);
+        }
+        free(glob->pattern[i/2].content.Set.elements);
+      }
+    }
+  }
+  free(glob->glob_buffer);
+  free(glob);
+}
+
+char *glob_next_url(URLGlob *glob)
+{
+  char *buf = glob->glob_buffer;
+  URLPattern *pat;
+  char *lit;
+  size_t i;
+  size_t j;
+  size_t buflen = glob->urllen+1;
+  size_t len;
+
+  if (!glob->beenhere)
+    glob->beenhere = 1;
+  else {
+    bool carry = TRUE;
+
+    /* implement a counter over the index ranges of all patterns,
+       starting with the rightmost pattern */
+    for (i = glob->size / 2 - 1; carry && i < glob->size; --i) {
+      carry = FALSE;
+      pat = &glob->pattern[i];
+      switch (pat->type) {
+      case UPTSet:
+        if (++pat->content.Set.ptr_s == pat->content.Set.size) {
+          pat->content.Set.ptr_s = 0;
+          carry = TRUE;
+        }
+        break;
+      case UPTCharRange:
+        pat->content.CharRange.ptr_c = (char)(pat->content.CharRange.step +
+                           (int)((unsigned char)pat->content.CharRange.ptr_c));
+        if (pat->content.CharRange.ptr_c > pat->content.CharRange.max_c) {
+          pat->content.CharRange.ptr_c = pat->content.CharRange.min_c;
+          carry = TRUE;
+        }
+        break;
+      case UPTNumRange:
+        pat->content.NumRange.ptr_n += pat->content.NumRange.step;
+        if (pat->content.NumRange.ptr_n > pat->content.NumRange.max_n) {
+          pat->content.NumRange.ptr_n = pat->content.NumRange.min_n;
+          carry = TRUE;
+        }
+        break;
+      default:
+        printf("internal error: invalid pattern type (%d)\n", (int)pat->type);
+        exit (CURLE_FAILED_INIT);
+      }
+    }
+    if (carry)          /* first pattern ptr has run into overflow, done! */
+      return NULL;
+  }
+
+  for (j = 0; j < glob->size; ++j) {
+    if (!(j&1)) {              /* every other term (j even) is a literal */
+      lit = glob->literal[j/2];
+      len = snprintf(buf, buflen, "%s", lit);
+      buf += len;
+      buflen -= len;
+    }
+    else {                              /* the rest (i odd) are patterns */
+      pat = &glob->pattern[j/2];
+      switch(pat->type) {
+      case UPTSet:
+        len = strlen(pat->content.Set.elements[pat->content.Set.ptr_s]);
+        snprintf(buf, buflen, "%s",
+                 pat->content.Set.elements[pat->content.Set.ptr_s]);
+        buf += len;
+        buflen -= len;
+        break;
+      case UPTCharRange:
+        *buf++ = pat->content.CharRange.ptr_c;
+        break;
+      case UPTNumRange:
+        len = snprintf(buf, buflen, "%0*d",
+                       pat->content.NumRange.padlength,
+                       pat->content.NumRange.ptr_n);
+        buf += len;
+        buflen -= len;
+        break;
+      default:
+        printf("internal error: invalid pattern type (%d)\n", (int)pat->type);
+        exit (CURLE_FAILED_INIT);
+      }
+    }
+  }
+  *buf = '\0';
+  return strdup(glob->glob_buffer);
+}
+
+char *glob_match_url(char *filename, URLGlob *glob)
+{
+  char *target;
+  size_t allocsize;
+  size_t stringlen=0;
+  char numbuf[18];
+  char *appendthis = NULL;
+  size_t appendlen = 0;
+
+  /* We cannot use the glob_buffer for storage here since the filename may
+   * be longer than the URL we use. We allocate a good start size, then
+   * we need to realloc in case of need.
+   */
+  allocsize=strlen(filename)+1; /* make it at least one byte to store the
+                                   trailing zero */
+  target = malloc(allocsize);
+  if(NULL == target)
+    return NULL; /* major failure */
+
+  while (*filename) {
+    if (*filename == '#' && ISDIGIT(filename[1])) {
+      unsigned long i;
+      char *ptr = filename;
+      unsigned long num = strtoul(&filename[1], &filename, 10);
+      i = num-1;
+
+      if (num && (i <= glob->size / 2)) {
+        URLPattern pat = glob->pattern[i];
+        switch (pat.type) {
+        case UPTSet:
+          appendthis = pat.content.Set.elements[pat.content.Set.ptr_s];
+          appendlen = strlen(pat.content.Set.elements[pat.content.Set.ptr_s]);
+          break;
+        case UPTCharRange:
+          numbuf[0]=pat.content.CharRange.ptr_c;
+          numbuf[1]=0;
+          appendthis=numbuf;
+          appendlen=1;
+          break;
+        case UPTNumRange:
+          snprintf(numbuf, sizeof(numbuf), "%0*d",
+                   pat.content.NumRange.padlength,
+                   pat.content.NumRange.ptr_n);
+          appendthis = numbuf;
+          appendlen = strlen(numbuf);
+          break;
+        default:
+          printf("internal error: invalid pattern type (%d)\n",
+                 (int)pat.type);
+          free(target);
+          return NULL;
+        }
+      }
+      else {
+        /* #[num] out of range, use the #[num] in the output */
+        filename = ptr;
+        appendthis=filename++;
+        appendlen=1;
+      }
+    }
+    else {
+      appendthis=filename++;
+      appendlen=1;
+    }
+    if(appendlen + stringlen >= allocsize) {
+      char *newstr;
+      /* we append a single byte to allow for the trailing byte to be appended
+         at the end of this function outside the while() loop */
+      allocsize = (appendlen + stringlen)*2;
+      newstr=realloc(target, allocsize + 1);
+      if(NULL ==newstr) {
+        free(target);
+        return NULL;
+      }
+      target=newstr;
+    }
+    memcpy(&target[stringlen], appendthis, appendlen);
+    stringlen += appendlen;
+  }
+  target[stringlen]= '\0';
+  return target;
+}
diff --git a/src/urlglob.h b/src/urlglob.h
new file mode 100644
index 0000000..a5b789e
--- /dev/null
+++ b/src/urlglob.h
@@ -0,0 +1,67 @@
+#ifndef __URLGLOB_H
+#define __URLGLOB_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+typedef enum {
+  UPTSet=1,
+  UPTCharRange,
+  UPTNumRange
+} URLPatternType;
+
+typedef struct {
+  URLPatternType type;
+  union {
+    struct {
+      char **elements;
+      short size;
+      short ptr_s;
+    } Set;
+    struct {
+      char min_c, max_c;
+      char ptr_c;
+      int step;
+    } CharRange;
+    struct {
+      int min_n, max_n;
+      short padlength;
+      int ptr_n;
+      int step;
+    } NumRange ;
+  } content;
+} URLPattern;
+
+typedef struct {
+  char* literal[10];
+  URLPattern pattern[9];
+  size_t size;
+  size_t urllen;
+  char *glob_buffer;
+  char beenhere;
+  char errormsg[80]; /* error message buffer */
+} URLGlob;
+
+int glob_url(URLGlob**, char*, int *, FILE *);
+char* glob_next_url(URLGlob*);
+char* glob_match_url(char*, URLGlob *);
+void glob_cleanup(URLGlob* glob);
+
+#endif
diff --git a/src/version.h b/src/version.h
new file mode 100644
index 0000000..8c091b2
--- /dev/null
+++ b/src/version.h
@@ -0,0 +1,35 @@
+#ifndef HEADER_CURL_VERSION_H
+#define HEADER_CURL_VERSION_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 <curl/curlver.h>
+
+#define CURL_NAME "curl"
+#define CURL_COPYRIGHT LIBCURL_COPYRIGHT
+#define CURL_VERSION "7.20.1"
+#define CURL_VERSION_MAJOR LIBCURL_VERSION_MAJOR
+#define CURL_VERSION_MINOR LIBCURL_VERSION_MINOR
+#define CURL_VERSION_PATCH LIBCURL_VERSION_PATCH
+#define CURL_ID CURL_NAME " " CURL_VERSION " (" OS ") "
+
+#endif /* HEADER_CURL_VERSION_H */
diff --git a/src/writeenv.c b/src/writeenv.c
new file mode 100644
index 0000000..18e1a06
--- /dev/null
+++ b/src/writeenv.c
@@ -0,0 +1,120 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+#ifdef USE_ENVIRONMENT
+
+#include <curl/curl.h>
+#include "writeenv.h"
+
+#ifdef __riscos__
+#include <kernel.h>
+#endif
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#if defined(CURLDEBUG) && defined(CURLTOOLDEBUG)
+#include "memdebug.h"
+#endif
+
+static const struct
+{
+  const char * name;
+  CURLINFO id;
+  enum {
+    writeenv_NONE,
+    writeenv_DOUBLE,
+    writeenv_LONG,
+    writeenv_STRING
+  } type;
+} variables[14] =
+{
+  {"curl_url_effective", CURLINFO_EFFECTIVE_URL, writeenv_STRING},
+  {"curl_http_code", CURLINFO_RESPONSE_CODE, writeenv_LONG},
+  {"curl_time_total", CURLINFO_TOTAL_TIME, writeenv_DOUBLE},
+  {"curl_time_namelookup", CURLINFO_NAMELOOKUP_TIME, writeenv_DOUBLE},
+  {"curl_time_connect", CURLINFO_CONNECT_TIME, writeenv_DOUBLE},
+  {"curl_time_pretransfer", CURLINFO_PRETRANSFER_TIME, writeenv_DOUBLE},
+  {"curl_time_starttransfer", CURLINFO_STARTTRANSFER_TIME, writeenv_DOUBLE},
+  {"curl_size_header", CURLINFO_HEADER_SIZE, writeenv_LONG},
+  {"curl_size_request", CURLINFO_REQUEST_SIZE, writeenv_LONG},
+  {"curl_size_download", CURLINFO_SIZE_DOWNLOAD, writeenv_DOUBLE},
+  {"curl_size_upload", CURLINFO_SIZE_UPLOAD, writeenv_DOUBLE},
+  {"curl_speed_download", CURLINFO_SPEED_DOWNLOAD, writeenv_DOUBLE},
+  {"curl_speed_upload", CURLINFO_SPEED_UPLOAD, writeenv_DOUBLE},
+  {NULL, 0, writeenv_NONE}
+ };
+
+static void internalSetEnv(const char * name, char * value)
+{
+  /* Add your OS-specific code here. */
+#ifdef __riscos__
+  _kernel_setenv(name, value);
+#elif defined (CURLDEBUG)
+  curl_memlog("ENV %s = %s\n", name, value);
+#endif
+  return;
+}
+
+void ourWriteEnv(CURL *curl)
+{
+  unsigned int i;
+  char *string, numtext[10];
+  long longinfo;
+  double doubleinfo;
+
+  for (i=0; variables[i].name; i++) {
+    switch (variables[i].type) {
+    case writeenv_STRING:
+      if (curl_easy_getinfo(curl, variables[i].id, &string) == CURLE_OK)
+        internalSetEnv(variables[i].name, string);
+      else
+        internalSetEnv(variables[i].name, NULL);
+      break;
+
+    case writeenv_LONG:
+      if (curl_easy_getinfo(curl, variables[i].id, &longinfo) == CURLE_OK) {
+        curl_msprintf(numtext, "%5ld", longinfo);
+        internalSetEnv(variables[i].name, numtext);
+      }
+      else
+        internalSetEnv(variables[i].name, NULL);
+      break;
+    case writeenv_DOUBLE:
+      if (curl_easy_getinfo(curl, variables[i].id, &doubleinfo) == CURLE_OK) {
+        curl_msprintf(numtext, "%6.2f", doubleinfo);
+        internalSetEnv(variables[i].name, numtext);
+      }
+      else
+        internalSetEnv(variables[i].name, NULL);
+      break;
+    default:
+      break;
+    }
+  }
+
+  return;
+}
+
+#endif
diff --git a/src/writeenv.h b/src/writeenv.h
new file mode 100644
index 0000000..8d92f6c
--- /dev/null
+++ b/src/writeenv.h
@@ -0,0 +1,27 @@
+#ifndef HEADER_CURL_WRITEENV_H
+#define HEADER_CURL_WRITEENV_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+void ourWriteEnv(CURL *curl);
+
+#endif /* HEADER_CURL_WRITEENV_H */
diff --git a/src/writeout.c b/src/writeout.c
new file mode 100644
index 0000000..b8801a4
--- /dev/null
+++ b/src/writeout.c
@@ -0,0 +1,295 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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 <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#include <curl/curl.h>
+
+#define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */
+#include <curl/mprintf.h>
+
+#include "writeout.h"
+
+typedef enum {
+  VAR_NONE,       /* must be the first */
+  VAR_TOTAL_TIME,
+  VAR_NAMELOOKUP_TIME,
+  VAR_CONNECT_TIME,
+  VAR_APPCONNECT_TIME,
+  VAR_PRETRANSFER_TIME,
+  VAR_STARTTRANSFER_TIME,
+  VAR_SIZE_DOWNLOAD,
+  VAR_SIZE_UPLOAD,
+  VAR_SPEED_DOWNLOAD,
+  VAR_SPEED_UPLOAD,
+  VAR_HTTP_CODE,
+  VAR_HTTP_CODE_PROXY,
+  VAR_HEADER_SIZE,
+  VAR_REQUEST_SIZE,
+  VAR_EFFECTIVE_URL,
+  VAR_CONTENT_TYPE,
+  VAR_NUM_CONNECTS,
+  VAR_REDIRECT_TIME,
+  VAR_REDIRECT_COUNT,
+  VAR_FTP_ENTRY_PATH,
+  VAR_REDIRECT_URL,
+  VAR_SSL_VERIFY_RESULT,
+  VAR_NUM_OF_VARS /* must be the last */
+} replaceid;
+
+struct variable {
+  const char *name;
+  replaceid id;
+};
+
+
+static const struct variable replacements[]={
+  {"url_effective", VAR_EFFECTIVE_URL},
+  {"http_code", VAR_HTTP_CODE},
+  {"response_code", VAR_HTTP_CODE},
+  {"http_connect", VAR_HTTP_CODE_PROXY},
+  {"time_total", VAR_TOTAL_TIME},
+  {"time_namelookup", VAR_NAMELOOKUP_TIME},
+  {"time_connect", VAR_CONNECT_TIME},
+  {"time_appconnect", VAR_APPCONNECT_TIME},
+  {"time_pretransfer", VAR_PRETRANSFER_TIME},
+  {"time_starttransfer", VAR_STARTTRANSFER_TIME},
+  {"size_header", VAR_HEADER_SIZE},
+  {"size_request", VAR_REQUEST_SIZE},
+  {"size_download", VAR_SIZE_DOWNLOAD},
+  {"size_upload", VAR_SIZE_UPLOAD},
+  {"speed_download", VAR_SPEED_DOWNLOAD},
+  {"speed_upload", VAR_SPEED_UPLOAD},
+  {"content_type", VAR_CONTENT_TYPE},
+  {"num_connects", VAR_NUM_CONNECTS},
+  {"time_redirect", VAR_REDIRECT_TIME},
+  {"num_redirects", VAR_REDIRECT_COUNT},
+  {"ftp_entry_path", VAR_FTP_ENTRY_PATH},
+  {"redirect_url", VAR_REDIRECT_URL},
+  {"ssl_verify_result", VAR_SSL_VERIFY_RESULT},
+  {NULL, VAR_NONE}
+};
+
+void ourWriteOut(CURL *curl, const char *writeinfo)
+{
+  FILE *stream = stdout;
+  const char *ptr=writeinfo;
+  char *stringp;
+  long longinfo;
+  double doubleinfo;
+
+  while(ptr && *ptr) {
+    if('%' == *ptr) {
+      if('%' == ptr[1]) {
+        /* an escaped %-letter */
+        fputc('%', stream);
+        ptr+=2;
+      }
+      else {
+        /* this is meant as a variable to output */
+        char *end;
+        char keepit;
+        int i;
+        if(('{' == ptr[1]) && ((end = strchr(ptr, '}')) != NULL)) {
+          bool match = FALSE;
+          ptr+=2; /* pass the % and the { */
+          keepit=*end;
+          *end=0; /* zero terminate */
+          for(i=0; replacements[i].name; i++) {
+            if(curl_strequal(ptr, replacements[i].name)) {
+              match = TRUE;
+              switch(replacements[i].id) {
+              case VAR_EFFECTIVE_URL:
+                if((CURLE_OK ==
+                    curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &stringp))
+                   && stringp)
+                  fputs(stringp, stream);
+                break;
+              case VAR_HTTP_CODE:
+                if(CURLE_OK ==
+                   curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &longinfo))
+                  fprintf(stream, "%03ld", longinfo);
+                break;
+              case VAR_HTTP_CODE_PROXY:
+                if(CURLE_OK ==
+                   curl_easy_getinfo(curl, CURLINFO_HTTP_CONNECTCODE,
+                                     &longinfo))
+                  fprintf(stream, "%03ld", longinfo);
+                break;
+              case VAR_HEADER_SIZE:
+                if(CURLE_OK ==
+                   curl_easy_getinfo(curl, CURLINFO_HEADER_SIZE, &longinfo))
+                  fprintf(stream, "%ld", longinfo);
+                break;
+              case VAR_REQUEST_SIZE:
+                if(CURLE_OK ==
+                   curl_easy_getinfo(curl, CURLINFO_REQUEST_SIZE, &longinfo))
+                  fprintf(stream, "%ld", longinfo);
+                break;
+              case VAR_NUM_CONNECTS:
+                if(CURLE_OK ==
+                   curl_easy_getinfo(curl, CURLINFO_NUM_CONNECTS, &longinfo))
+                  fprintf(stream, "%ld", longinfo);
+                break;
+              case VAR_REDIRECT_COUNT:
+                if(CURLE_OK ==
+                   curl_easy_getinfo(curl, CURLINFO_REDIRECT_COUNT, &longinfo))
+                  fprintf(stream, "%ld", longinfo);
+                break;
+              case VAR_REDIRECT_TIME:
+                if(CURLE_OK ==
+                   curl_easy_getinfo(curl, CURLINFO_REDIRECT_TIME, &doubleinfo))
+                  fprintf(stream, "%.3f", doubleinfo);
+                break;
+              case VAR_TOTAL_TIME:
+                if(CURLE_OK ==
+                   curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &doubleinfo))
+                  fprintf(stream, "%.3f", doubleinfo);
+                break;
+              case VAR_NAMELOOKUP_TIME:
+                if(CURLE_OK ==
+                   curl_easy_getinfo(curl, CURLINFO_NAMELOOKUP_TIME,
+                                     &doubleinfo))
+                  fprintf(stream, "%.3f", doubleinfo);
+                break;
+              case VAR_CONNECT_TIME:
+                if(CURLE_OK ==
+                   curl_easy_getinfo(curl, CURLINFO_CONNECT_TIME, &doubleinfo))
+                  fprintf(stream, "%.3f", doubleinfo);
+                break;
+              case VAR_APPCONNECT_TIME:
+                if(CURLE_OK ==
+                   curl_easy_getinfo(curl, CURLINFO_APPCONNECT_TIME,
+                                     &doubleinfo))
+                  fprintf(stream, "%.3f", doubleinfo);
+                break;
+              case VAR_PRETRANSFER_TIME:
+                if(CURLE_OK ==
+                   curl_easy_getinfo(curl, CURLINFO_PRETRANSFER_TIME,
+                                     &doubleinfo))
+                  fprintf(stream, "%.3f", doubleinfo);
+                break;
+              case VAR_STARTTRANSFER_TIME:
+                if(CURLE_OK ==
+                   curl_easy_getinfo(curl, CURLINFO_STARTTRANSFER_TIME,
+                                     &doubleinfo))
+                  fprintf(stream, "%.3f", doubleinfo);
+                break;
+              case VAR_SIZE_UPLOAD:
+                if(CURLE_OK ==
+                   curl_easy_getinfo(curl, CURLINFO_SIZE_UPLOAD, &doubleinfo))
+                  fprintf(stream, "%.0f", doubleinfo);
+                break;
+              case VAR_SIZE_DOWNLOAD:
+                if(CURLE_OK ==
+                   curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &doubleinfo))
+                  fprintf(stream, "%.0f", doubleinfo);
+                break;
+              case VAR_SPEED_DOWNLOAD:
+                if(CURLE_OK ==
+                   curl_easy_getinfo(curl, CURLINFO_SPEED_DOWNLOAD, &doubleinfo))
+                  fprintf(stream, "%.3f", doubleinfo);
+                break;
+              case VAR_SPEED_UPLOAD:
+                if(CURLE_OK ==
+                   curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &doubleinfo))
+                  fprintf(stream, "%.3f", doubleinfo);
+                break;
+              case VAR_CONTENT_TYPE:
+                if((CURLE_OK ==
+                    curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &stringp))
+                   && stringp)
+                  fputs(stringp, stream);
+                break;
+              case VAR_FTP_ENTRY_PATH:
+                if((CURLE_OK ==
+                    curl_easy_getinfo(curl, CURLINFO_FTP_ENTRY_PATH, &stringp))
+                   && stringp)
+                  fputs(stringp, stream);
+                break;
+              case VAR_REDIRECT_URL:
+                if((CURLE_OK ==
+                    curl_easy_getinfo(curl, CURLINFO_REDIRECT_URL, &stringp))
+                   && stringp)
+                  fputs(stringp, stream);
+                break;
+              case VAR_SSL_VERIFY_RESULT:
+                if(CURLE_OK ==
+                   curl_easy_getinfo(curl, CURLINFO_SSL_VERIFYRESULT, &longinfo))
+                  fprintf(stream, "%ld", longinfo);
+                break;
+              default:
+                break;
+              }
+              break;
+            }
+          }
+          if(FALSE == match) {
+            fprintf(stderr, "curl: unknown --write-out variable: '%s'\n", ptr);
+          }
+          ptr=end+1; /* pass the end */
+          *end = keepit;
+        }
+        else {
+          /* illegal syntax, then just output the characters that are used */
+          fputc('%', stream);
+          fputc(ptr[1], stream);
+          ptr+=2;
+        }
+      }
+    }
+    else if('\\' == *ptr) {
+      switch(ptr[1]) {
+      case 'r':
+        fputc('\r', stream);
+        break;
+      case 'n':
+        fputc('\n', stream);
+        break;
+      case 't':
+        fputc('\t', stream);
+        break;
+      default:
+        /* unknown, just output this */
+        fputc(*ptr, stream);
+        fputc(ptr[1], stream);
+        break;
+      }
+      ptr+=2;
+    }
+    else {
+      fputc(*ptr, stream);
+      ptr++;
+    }
+  }
+
+}
diff --git a/src/writeout.h b/src/writeout.h
new file mode 100644
index 0000000..1b22102
--- /dev/null
+++ b/src/writeout.h
@@ -0,0 +1,27 @@
+#ifndef HEADER_CURL_WRITEOUT_H
+#define HEADER_CURL_WRITEOUT_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+void ourWriteOut(CURL *curl, const char *out);
+
+#endif /* HEADER_CURL_WRITEOUT_H */